diff options
14 files changed, 313 insertions, 24 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 89b6f554e..b2fd4438b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ + Default disabled + Detects your SkyBlock Mod automatically + Does detect Chat Triggers and OneConfig itself, but no single mods that require these libraries ++ Added **Arachne Chat Hider** - Hide chat messages about the Arachne Fight while outside of Arachne's Sanctuary ### Changes + Added Options for displays Crop Milestone and Best Crop Time. diff --git a/FEATURES.md b/FEATURES.md index b6568d9bd..2089efb3f 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -20,6 +20,7 @@ - Scan messages sent by players in all-chat for blacklisted words and greys out the message. - Chat peeking (holding key to display chat without opening the chat gui) - Compact Potion Effect Messages +- **Arachne Chat Hider** - Hide chat messages about the Arachne Fight while outside of Arachne's Sanctuary ## Dungeon - Clicked Blocks (Showing the block behind walls AFTER clicked on a chest, wither essence or a lever) diff --git a/build.gradle.kts b/build.gradle.kts index 776a462f8..36ac1ea6f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ plugins { } group = "at.hannibal2.skyhanni" -version = "0.18.Beta.20" +version = "0.18.Beta.21" // Toolchains: java { diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index aaa3231f6..5eb0eec1b 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -12,6 +12,7 @@ import at.hannibal2.skyhanni.features.bazaar.BazaarBestSellMethod import at.hannibal2.skyhanni.features.bazaar.BazaarCancelledBuyOrderClipboard import at.hannibal2.skyhanni.features.bazaar.BazaarOrderHelper import at.hannibal2.skyhanni.features.bingo.* +import at.hannibal2.skyhanni.features.chat.ArachneChatMessageHider import at.hannibal2.skyhanni.features.chat.ChatFilter import at.hannibal2.skyhanni.features.chat.PlayerDeathMessages import at.hannibal2.skyhanni.features.chat.playerchat.PlayerChatFilter @@ -42,7 +43,6 @@ import at.hannibal2.skyhanni.features.minion.MinionCollectLogic import at.hannibal2.skyhanni.features.minion.MinionFeatures import at.hannibal2.skyhanni.features.misc.* import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager -import at.hannibal2.skyhanni.features.misc.GhostCounter import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValue import at.hannibal2.skyhanni.features.misc.items.EstimatedWardrobePrice import at.hannibal2.skyhanni.features.misc.tabcomplete.PlayerTabComplete @@ -94,7 +94,7 @@ import org.apache.logging.log4j.Logger clientSideOnly = true, useMetadata = true, guiFactory = "at.hannibal2.skyhanni.config.ConfigGuiForgeInterop", - version = "0.18.Beta.20", + version = "0.18.Beta.21", ) class SkyHanniMod { @Mod.EventHandler @@ -296,8 +296,10 @@ class SkyHanniMod { loadModule(DetectBrokenHyperion()) loadModule(RestorePieceOfWizardPortalLore()) loadModule(QuickModMenuSwitch) + loadModule(ArachneChatMessageHider()) loadModule(ShowItemUuid()) loadModule(FrozenTreasureTracker()) + loadModule(SlayerRngMeterDisplay()) loadModule(GhostCounter) init() diff --git a/src/main/java/at/hannibal2/skyhanni/config/Storage.java b/src/main/java/at/hannibal2/skyhanni/config/Storage.java index c0a003aad..4a95871cb 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/Storage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/Storage.java @@ -274,5 +274,23 @@ public class Storage { public boolean hidden; } } + + @Expose + public Map<String, SlayerRngMeterStorage> slayerRngMeter = new HashMap<>(); + + public static class SlayerRngMeterStorage { + + @Expose + public long currentMeter = -1; + + @Expose + public long gainPerBoss = -1; + + @Expose + public long goalNeeded = -1; + + @Expose + public String itemGoal = "?"; + } } }
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Chat.java b/src/main/java/at/hannibal2/skyhanni/config/features/Chat.java index bd60e0eee..f149fc624 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Chat.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Chat.java @@ -122,10 +122,15 @@ public class Chat { "except for players who are nearby or during dungeons/a Kuudra fight.") @ConfigEditorBoolean public boolean hideFarDeathMessages = false; - //TODO jawbus + x + //TODO jawbus + thunder @Expose @ConfigOption(name = "Compact Potion Message", desc = "Shorten chat messages about player potion effects.") @ConfigEditorBoolean public boolean compactPotionMessage = true; + + @Expose + @ConfigOption(name = "Arachne Hider", desc = "Hide chat messages about the Arachne Fight while outside of §eArachne's Sanctuary§7.") + @ConfigEditorBoolean + public boolean hideArachneMessages = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/Slayer.java b/src/main/java/at/hannibal2/skyhanni/config/features/Slayer.java index 00392bcc4..852b54970 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/Slayer.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/Slayer.java @@ -144,6 +144,33 @@ public class Slayer { } @Expose + @ConfigOption(name = "RNG Meter Display", desc = "") + @Accordion + public RngMeterDisplay rngMeterDisplay = new RngMeterDisplay(); + + public static class RngMeterDisplay { + + @Expose + @ConfigOption(name = "Enabled", desc = "Display amount of bosses needed until next rng meter drop.") + @ConfigEditorBoolean + public boolean enabled = true; + + @Expose + @ConfigOption(name = "Warn Empty", desc = "Warn when no item is set in the rng meter.") + @ConfigEditorBoolean + public boolean warnEmpty = false; + + @Expose + @ConfigOption(name = "Hide Chat", desc = "Hide the rng meter message from chat if current item is selected.") + @ConfigEditorBoolean + public boolean hideChat = true; + + @Expose + public Position pos = new Position(410, 110, false, true); + + } + + @Expose @ConfigOption(name = "Broken Wither Impact", desc = "Warns when right-clicking with a Wither Impact weapon (e.g. Hyperion) no longer gains combat exp. " + "Kill a mob with melee-hits to fix this hypixel bug. §cOnly works while doing slayers!" diff --git a/src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt b/src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt index 82938994a..0d412f6da 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ApiDataLoader.kt @@ -1,7 +1,6 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.ProfileApiDataLoadedEvent import at.hannibal2.skyhanni.events.ProfileJoinEvent import at.hannibal2.skyhanni.utils.APIUtil @@ -36,19 +35,6 @@ class ApiDataLoader { } @SubscribeEvent - fun onStatusBar(event: LorenzChatEvent) { - val message = event.message - if (message.startsWith("§aYour new API key is §r§b")) { - SkyHanniMod.feature.storage.apiKey = message.substring(26) - LorenzUtils.chat("§b[SkyHanni] A new API Key has been detected and installed") - - if (currentProfileName != "") { - updateApiData() - } - } - } - - @SubscribeEvent fun onProfileJoin(event: ProfileJoinEvent) { currentProfileName = event.name updateApiData() @@ -99,7 +85,6 @@ class ApiDataLoader { LorenzUtils.error("§c[SkyHanni] Invalid API key from $modName") } } - LorenzUtils.error("§c[SkyHanni] SkyHanni has no API key set. Please run /api new") } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt index 1c5c76d92..7e44bd5cf 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/SlayerAPI.kt @@ -27,7 +27,7 @@ object SlayerAPI { var questStartTime = 0L var isInSlayerArea = false - private var latestSlayerCategory = "" + var latestSlayerCategory = "" private var latestProgressChangeTime = 0L var latestWrongAreaWarning = 0L private var latestSlayerProgress = "" @@ -106,10 +106,14 @@ object SlayerAPI { if (event.phase != TickEvent.Phase.START) return if (!LorenzUtils.inSkyBlock) return + // wait with sending SlayerChangeEvent until profile is detected + if (ProfileStorageData.profileSpecific == null) return + val slayerQuest = ScoreboardData.sidebarLinesFormatted.nextAfter("Slayer Quest") ?: "" if (slayerQuest != latestSlayerCategory) { - SlayerChangeEvent(latestSlayerCategory, slayerQuest).postAndCatch() + val old = latestSlayerCategory latestSlayerCategory = slayerQuest + SlayerChangeEvent(old, latestSlayerCategory).postAndCatch() } val slayerProgress = ScoreboardData.sidebarLinesFormatted.nextAfter("Slayer Quest", 2) ?: "" diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/ArachneChatMessageHider.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/ArachneChatMessageHider.kt new file mode 100644 index 000000000..d870197c7 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/ArachneChatMessageHider.kt @@ -0,0 +1,50 @@ +package at.hannibal2.skyhanni.features.chat + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class ArachneChatMessageHider { + private val config get() = SkyHanniMod.feature.chat + private var hideArachneDeadMessage = false + private val arachneCallingPattern = "§4☄ §r.* §r§eplaced an §r§9Arachne's Calling§r§e!.*".toPattern() + private val arachneCrystalPattern = "§4☄ §r.* §r§eplaced an Arachne Crystal! Something is awakening!".toPattern() + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + if (LorenzUtils.skyBlockIsland != IslandType.SPIDER_DEN) return + if (LorenzUtils.skyBlockArea == "Arachne's Sanctuary") return + + if (shouldHide(event.message)) { + event.blockedReason = "arachne" + } + } + + private fun shouldHide(message: String): Boolean { + + arachneCallingPattern.matchMatcher(message) { + return true + } + arachneCrystalPattern.matchMatcher(message) { + return true + } + + if (message == "§c[BOSS] Arachne§r§f: Ahhhh...A Calling...") return true + if (message == "§c[BOSS] Arachne§r§f: The Era of Spiders begins now.") return true + + if (message == "§a§l▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬") { + hideArachneDeadMessage = !hideArachneDeadMessage + return true + } + if (message == " §r§6§lARACHNE DOWN!") { + hideArachneDeadMessage = true + } + return hideArachneDeadMessage + } + + fun isEnabled() = LorenzUtils.inSkyBlock && config.hideArachneMessages +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt index 6549efaa9..fabff46ba 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/NonGodPotEffectDisplay.kt @@ -182,9 +182,13 @@ class NonGodPotEffectDisplay { for (line in lines) { for (effect in NonGodPotEffect.values()) { if (line.startsWith(effect.displayName)) { - val duration = TimeUtils.getMillis(line.split("§f")[1]) - effectDuration[effect] = System.currentTimeMillis() + duration - update() + try { + val duration = TimeUtils.getMillis(line.split("§f")[1]) + effectDuration[effect] = System.currentTimeMillis() + duration + update() + } catch (e: IndexOutOfBoundsException) { + LorenzUtils.debug("Error while reading non god pot effects from tab list! line: '$line'") + } } } patternEffectsCount.matchMatcher(line) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemProfitTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemProfitTracker.kt index f4e380fc4..c04d662e2 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemProfitTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemProfitTracker.kt @@ -211,6 +211,7 @@ object SlayerItemProfitTracker { lastClickDelay = System.currentTimeMillis() + 500 } else { itemProfit.hidden = !hidden + lastClickDelay = System.currentTimeMillis() } update() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerRngMeterDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerRngMeterDisplay.kt new file mode 100644 index 000000000..1d41aaeeb --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerRngMeterDisplay.kt @@ -0,0 +1,189 @@ +package at.hannibal2.skyhanni.features.slayer + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.Storage +import at.hannibal2.skyhanni.data.ProfileStorageData +import at.hannibal2.skyhanni.data.SlayerAPI +import at.hannibal2.skyhanni.data.TitleUtils +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.InventoryOpenEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.SlayerChangeEvent +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.nameWithEnchantment +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.formatNumber +import at.hannibal2.skyhanni.utils.RenderUtils.renderString +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import at.hannibal2.skyhanni.utils.StringUtils.removeWordsAtEnd +import io.github.moulberry.notenoughupdates.util.Constants +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import kotlin.math.ceil + +class SlayerRngMeterDisplay { + private val config get() = SkyHanniMod.feature.slayer.rngMeterDisplay + private var display = "" + private val inventoryNamePattern = "(?<name>.*) RNG Meter".toPattern() + private val updatePattern = " §dRNG Meter §f- §d(?<exp>.*) Stored XP".toPattern() + private val changedItemPattern = "§aYou set your §r.* RNG Meter §r§ato drop §r.*§a!".toPattern() + private var lastItemDroppedTime = 0L + + private var tick = 0 + + @SubscribeEvent + fun onTick(event: TickEvent.ClientTickEvent) { + if (event.phase != TickEvent.Phase.START) return + + if (!isEnabled()) return + tick++ + + if (tick % 20 == 0) { + if (lastItemDroppedTime != 0L) { + if (System.currentTimeMillis() > lastItemDroppedTime + 4_000) { + lastItemDroppedTime = 0L + update() + } + } + } + } + + @SubscribeEvent + fun onSlayerChange(event: SlayerChangeEvent) { + update() + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + + if (!isEnabled()) return + + if (config.hideChat) { + if (SlayerAPI.isInSlayerArea) { + changedItemPattern.matchMatcher(event.message) { + event.blockedReason = "slayer_rng_meter" + } + } + } + + val currentMeter = updatePattern.matchMatcher(event.message) { + group("exp").formatNumber() + } ?: return + + val storage = getStorage() ?: return + val old = storage.currentMeter + storage.currentMeter = currentMeter + + if (old != -1L) { + val item = storage.itemGoal + val hasItemSelected = item != "" && item != "?" + if (!hasItemSelected) { + if (config.warnEmpty) { + LorenzUtils.warning("§c[Skyhanni] No Slayer RNG Meter Item selected!") + TitleUtils.sendTitle("§cNo RNG Meter Item!", 3_000) + } + } + var blockChat = config.hideChat && hasItemSelected + val diff = currentMeter - old + if (diff > 0) { + storage.gainPerBoss = diff + } else { + storage.itemGoal = "" + blockChat = false + val from = old.addSeparators() + val to = storage.goalNeeded.addSeparators() + + var rawPercentage = old.toDouble() / storage.goalNeeded + if (rawPercentage > 1) rawPercentage = 1.0 + val percentage = LorenzUtils.formatPercentage(rawPercentage) + LorenzUtils.chat("§e[SkyHanni] §dRNG Meter §7dropped at §e$percentage §7XP ($from/${to}§7)") + lastItemDroppedTime = System.currentTimeMillis() + } + if (blockChat) { + event.blockedReason = "slayer_rng_meter" + } + } + update() + } + + private fun getStorage(): Storage.ProfileSpecific.SlayerRngMeterStorage? { + return ProfileStorageData.profileSpecific?.slayerRngMeter?.getOrPut(getCurrentSlayer()) { + Storage.ProfileSpecific.SlayerRngMeterStorage() + } + } + + private fun getCurrentSlayer() = SlayerAPI.latestSlayerCategory.removeWordsAtEnd(1).removeColor() + + @SubscribeEvent + fun onInventoryOpen(event: InventoryOpenEvent) { + if (!isEnabled()) return + + val name = inventoryNamePattern.matchMatcher(event.inventoryName) { + group("name") + } ?: return + + if (name != getCurrentSlayer()) return + + val storage = getStorage() ?: return + + val selectedItem = event.inventoryItems.values.find { item -> item.getLore().any { it.contains("§aSELECTED") } } + if (selectedItem == null) { + storage.itemGoal = "" + storage.goalNeeded = -1 + } else { + storage.itemGoal = selectedItem.nameWithEnchantment + val jsonObject = Constants.RNGSCORE["slayer"].asJsonObject.get(getCurrentSlayer()).asJsonObject + storage.goalNeeded = jsonObject.get(selectedItem.getInternalName()).asLong + } + update() + } + + private fun update() { + display = drawDisplay() + } + + private fun drawDisplay(): String { + val storage = getStorage() ?: return "" + + if (SlayerAPI.latestSlayerCategory.let { + it.endsWith(" I") || it.endsWith(" II") + }) { + return "" + } + val latestSlayerCategory = SlayerAPI.latestSlayerCategory + latestSlayerCategory.endsWith(" I") + + with(storage) { + if (itemGoal == "?") return "§cOpen RNG Meter Inventory!" + if (itemGoal == "") { + return if (lastItemDroppedTime != 0L) { + "§a§lRNG Item dropped!" + } else { + "§eNo RNG Item selected!" + } + } + if (currentMeter == -1L || gainPerBoss == -1L) return "§cKill the slayer boss 2 times!" + + val missing = goalNeeded - currentMeter + gainPerBoss + var timesMissing = missing.toDouble() / gainPerBoss + if (timesMissing < 1) timesMissing = 1.0 + timesMissing = ceil(timesMissing) + + return "$itemGoal §7in §e${timesMissing.toInt().addSeparators()} §7bosses!" + } + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent.GameOverlayRenderEvent) { + if (!isEnabled()) return + if (!SlayerAPI.isInSlayerArea) return + if (!SlayerAPI.hasActiveSlayerQuest()) return + + config.pos.renderString(display, posLabel = "Rng Meter Display") + } + + fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt index 90dcddf9b..917ec5c88 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt @@ -105,4 +105,6 @@ object StringUtils { "$format$text" } } + + fun String.removeWordsAtEnd(i: Int) = split(" ").dropLast(i).joinToString(" ") }
\ No newline at end of file |