diff options
author | hannibal2 <24389977+hannibal002@users.noreply.github.com> | 2024-04-19 11:24:36 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-19 11:24:36 +0200 |
commit | f8efe9effd27bee18bced64385fc1ad9b05b68bd (patch) | |
tree | 1429920226fc79af8bae814bb7596b9e65e0cf7e /src | |
parent | 7feb5c67fbc1c9f63118952f1bea649ada1dccd6 (diff) | |
download | skyhanni-f8efe9effd27bee18bced64385fc1ad9b05b68bd.tar.gz skyhanni-f8efe9effd27bee18bced64385fc1ad9b05b68bd.tar.bz2 skyhanni-f8efe9effd27bee18bced64385fc1ad9b05b68bd.zip |
Feature + Fix: Player Chat Rework (#1483)
Co-authored-by: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com>
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Diffstat (limited to 'src')
27 files changed, 737 insertions, 302 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index c23149967..a91d6bcad 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -54,6 +54,8 @@ import at.hannibal2.skyhanni.data.TitleData import at.hannibal2.skyhanni.data.TitleManager import at.hannibal2.skyhanni.data.ToolTipData import at.hannibal2.skyhanni.data.TrackerManager +import at.hannibal2.skyhanni.data.hypixel.chat.PlayerChatManager +import at.hannibal2.skyhanni.data.hypixel.chat.PlayerNameFormatter import at.hannibal2.skyhanni.data.jsonobjects.local.FriendsJson import at.hannibal2.skyhanni.data.jsonobjects.local.JacobContestsJson import at.hannibal2.skyhanni.data.jsonobjects.local.KnownFeaturesJson @@ -319,7 +321,6 @@ import at.hannibal2.skyhanni.features.misc.PatcherSendCoordinates import at.hannibal2.skyhanni.features.misc.PetCandyUsedDisplay import at.hannibal2.skyhanni.features.misc.PetExpTooltip import at.hannibal2.skyhanni.features.misc.PetItemDisplay -import at.hannibal2.skyhanni.features.misc.PlayerChatSymbols import at.hannibal2.skyhanni.features.misc.PocketSackInASackDisplay import at.hannibal2.skyhanni.features.misc.PrivateIslandNoPickaxeAbility import at.hannibal2.skyhanni.features.misc.QuickModMenuSwitch @@ -465,6 +466,8 @@ class SkyHanniMod { // data loadModule(this) loadModule(ChatManager) + loadModule(PlayerChatManager()) + loadModule(PlayerNameFormatter()) loadModule(HypixelData()) loadModule(LocationFixData) loadModule(DungeonAPI) @@ -821,7 +824,6 @@ class SkyHanniMod { loadModule(DungeonRankTabListColor()) loadModule(TerracottaPhase()) loadModule(VolcanoExplosivityDisplay()) - loadModule(PlayerChatSymbols()) loadModule(FixNEUHeavyPearls()) loadModule(QuickCraftFeatures()) loadModule(SkyBlockKickDuration()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt index 9f0b281ff..1e8a576e2 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 = 40 + const val CONFIG_VERSION = 41 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/ChatConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/chat/ChatConfig.java index 72b21411b..f2d187687 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/chat/ChatConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/chat/ChatConfig.java @@ -22,20 +22,17 @@ public class ChatConfig { @Expose @ConfigOption(name = "Chat Filter Types", desc = "") @Accordion + // TODO move into own sub category public FilterTypesConfig filterType = new FilterTypesConfig(); @Expose @ConfigOption(name = "Player Messages", desc = "") @Accordion + // TODO move into own sub category public PlayerMessagesConfig playerMessage = new PlayerMessagesConfig(); @Expose - @ConfigOption(name = "Player Chat Symbols", desc = "") - @Accordion - public ChatSymbols chatSymbols = new ChatSymbols(); - - @Expose @ConfigOption(name = "Dungeon Filter", desc = "Hide specific message types in Dungeons.") @ConfigEditorDraggableList public List<DungeonMessageTypes> dungeonFilteredMessageTypes = new ArrayList<>(); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/chat/ChatSymbols.java b/src/main/java/at/hannibal2/skyhanni/config/features/chat/ChatSymbols.java deleted file mode 100644 index ccead7f7b..000000000 --- a/src/main/java/at/hannibal2/skyhanni/config/features/chat/ChatSymbols.java +++ /dev/null @@ -1,54 +0,0 @@ -package at.hannibal2.skyhanni.config.features.chat; - -import at.hannibal2.skyhanni.config.FeatureToggle; -import at.hannibal2.skyhanni.config.HasLegacyId; -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 ChatSymbols { - - @Expose - @ConfigOption(name = "Enabled", desc = "Adds extra symbols to the chat such as those from ironman, " + - "stranded, bingo or nether factions and places them next to your regular player emblems. " + - "§cDoes not work with hide rank hider!") - @ConfigEditorBoolean - @FeatureToggle - public boolean enabled = true; - - @Expose - @ConfigOption(name = "Chat Symbol Location", desc = "Determines where the symbols should go in chat in relation to the " + - "player's name. Hidden will hide all emblems from the chat. §eRequires above setting to be on to hide the symbols.") - @ConfigEditorDropdown - public SymbolLocationEntry symbolLocation = SymbolLocationEntry.LEFT; - - public enum SymbolLocationEntry implements HasLegacyId { - LEFT("Left", 0), - RIGHT("Right", 1), - HIDDEN("Hidden", 2); - - private final String str; - private final int legacyId; - - SymbolLocationEntry(String str, int legacyId) { - this.str = str; - this.legacyId = legacyId; - } - - // Constructor if new enum elements are added post-migration - SymbolLocationEntry(String str) { - this(str, -1); - } - - @Override - public int getLegacyId() { - return legacyId; - } - - @Override - public String toString() { - return str; - } - } -} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/chat/PlayerMessagesConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PlayerMessagesConfig.java index 5ebad3d0c..a8903f4f1 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/chat/PlayerMessagesConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/chat/PlayerMessagesConfig.java @@ -3,19 +3,84 @@ 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.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class PlayerMessagesConfig { @Expose + @ConfigOption( + name = "Part Order", + desc = "Drag text to change the chat message format order for chat messages." + ) + @ConfigEditorDraggableList + public List<MessagePart> partsOrder = new ArrayList<>(Arrays.asList( + MessagePart.SKYBLOCK_LEVEL, + MessagePart.PRIVATE_ISLAND_RANK, + MessagePart.PRIVATE_ISLAND_GUEST, + MessagePart.PLAYER_NAME, + MessagePart.GUILD_RANK, + MessagePart.EMBLEM + )); + + public enum MessagePart { + SKYBLOCK_LEVEL("SkyBlock Level"), + EMBLEM("Emblem"), + PLAYER_NAME("§bPlayer Name"), + GUILD_RANK("Guild Rank"), + PRIVATE_ISLAND_RANK("Private Island Rank"), + PRIVATE_ISLAND_GUEST("Private Island Guest"), + CRIMSON_FACTION("Crimson Faction"), + MODE_IRONMAN("Ironman Mode"), + BINGO_LEVEL("Bingo Level"), + ; + + private final String str; + + MessagePart(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } + + @Expose + @ConfigOption(name = "Hide Level Brackets", desc = "Hide the gray brackets in front of and behind the level numbers.") + @ConfigEditorBoolean + public boolean hideLevelBrackets = false; + + @Expose + @ConfigOption(name = "Level Color As Name", desc = "Use the color of the SkyBlock level for the player color.") + @ConfigEditorBoolean + public boolean useLevelColorForName = false; + + @Expose @ConfigOption(name = "Player Rank Hider", desc = "Hide player ranks in all chat messages.") @ConfigEditorBoolean @FeatureToggle public boolean playerRankHider = false; @Expose + @ConfigOption(name = "Ignore YouTube", desc = "Do not remove the rank for YouTubers in chat.") + @ConfigEditorBoolean + public boolean ignoreYouTube = false; + + @Expose @ConfigOption(name = "Chat Filter", desc = "Scan messages sent by players for blacklisted words and gray out the message if any are found.") @ConfigEditorBoolean @FeatureToggle public boolean chatFilter = false; + + @Expose + @ConfigOption(name = "Same Chat Color", desc = "All players, also those with ranks, write with the same, white chat color.") + @ConfigEditorBoolean + @FeatureToggle + public boolean sameChatColor = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt index 44a778292..3bd3967be 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt @@ -1,7 +1,7 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.data.hypixel.chat.event.PartyChatEvent import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.events.PartyChatEvent import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.OSUtils @@ -78,16 +78,6 @@ object PartyAPI { "§dParty Finder §f> (?<name>.*?) §ejoined the dungeon group! \\(§[a-fA-F0-9].* Level \\d+§[a-fA-F0-9]\\)" ) - /** - * REGEX-TEST: §9Party §8> §b§l⚛ §b[MVP§f+§b] Dankbarkeit§f: §rx: -190, y: 5, z: -163 - * REGEX-TEST: §9Party §8> §6⚔ §6[MVP§3++§6] RealBacklight§f: §r!warp - * REGEX-TEST: §9Party §8> §b[MVP§3+§b] Eisengolem§f: §r!pt - */ - private val partyChatMessagePattern by patternGroup.pattern( - "chat.message", - "§9Party §8> (?<name>[^:]*): §r(?<message>.*)" - ) - val partyMembers = mutableListOf<String>() var partyLeader: String? = null @@ -114,16 +104,15 @@ object PartyAPI { } @SubscribeEvent + fun onPartyChat(event: PartyChatEvent) { + val name = event.author.cleanPlayerName() + addPlayer(name) + } + + @SubscribeEvent fun onChat(event: LorenzChatEvent) { val message = event.message.trimWhiteSpace().removeResets() - partyChatMessagePattern.matchMatcher(event.message) { - val name = group("name").cleanPlayerName() - val message = group("message") - addPlayer(name) - PartyChatEvent(name, message, event).postAndCatch() - } - // new member joined youJoinedPartyPattern.matchMatcher(message) { val name = group("name").cleanPlayerName() diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerChatManager.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerChatManager.kt new file mode 100644 index 000000000..2b3efb6aa --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerChatManager.kt @@ -0,0 +1,220 @@ +package at.hannibal2.skyhanni.data.hypixel.chat + +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.data.hypixel.chat.event.AbstractChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.GuildChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.NpcChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PartyChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PlayerAllChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PlayerShowItemChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PrivateMessageChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.SystemMessageEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.groupOrNull +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.util.IChatComponent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Matcher + +/** + * Reading normal chat events, and splitting them up into many different player chat events, with all avaliable extra information + */ +class PlayerChatManager { + + private val patternGroup = RepoPattern.group("data.chat.player") + + /** + * REGEX-TEST: §8[§r§6428§r§8] §r§b[MVP§5+§b] Alea1337§f: t + * REGEX-TEST: §8[§r§e102§r§8] §r§7☠ §r§b[MVP§d+§b] cobyjoey§f§r§f: first person to type "halo0011 is my favorite player on the game I love halo0011!!!" + * REGEX-TEST: §8[§r§5396§r§8] §r§7☢ §r§b[MVP§c+§b] hannibal2§f: hello + * REGEX-TEST: §8[§r§e97§r§8] §r§7☃ §r§7Tambaloo§7§r§7: i did capital i + * REGEX-TEST: §8[§r§f76§r§8] §r§7❂ §r§a[VIP] Asymmetrically§f§r§f: i need to put on my necron + * REGEX-TEST: §8[§r§c446§r§8] §r§b§l⚛ §r§6[MVP§1++§6] XueRuu§f§r§f: TROPHY FISH! You caught a Lavahorse DIAMOND. + * REGEX-TEST: §b[MVP§c+§b] hannibal2§f: test + */ + private val globalPattern by patternGroup.pattern( + "global", + "(?:§8\\[§r(?<levelColor>§.)(?<level>\\d+)§r§8] §r)?(?<author>§.+)(?<chatColor>§f|§7§r§7): (?<message>.*)" + ) + + /** + * REGEX-TEST: §9Party §8> §b§l⚛ §b[MVP§f+§b] Dankbarkeit§f: §rx: -190, y: 5, z: -163 + * REGEX-TEST: §9Party §8> §6⚔ §6[MVP§3++§6] RealBacklight§f: §r!warp + * REGEX-TEST: §9Party §8> §b[MVP§3+§b] Eisengolem§f: §r!pt + */ + private val partyPattern by patternGroup.pattern( + "party", + "§9Party §8> (?<author>[^:]*): §r(?<message>.*)" + ) + + /** + * REGEX-TEST: §2Guild > §b§l⚛ §b[MVP§f+§b] Dankbarkeit§f: §rx: -190, y: 5, z: -163 + * REGEX-TEST: §2Guild > §6⚔ §6[MVP§3++§6] RealBacklight§f: §r!warp + * REGEX-TEST: §2Guild > §b[MVP§3+§b] Eisengolem§f: §r!pt + * REGEX-TEST: §2Guild > §b[MVP§d+§b] zunoff §e[VET]§f: §rwas löuft + */ + private val guildPattern by patternGroup.pattern( + "guild", + "§2Guild > (?<author>§.+?)(?<guildRank> §e\\[\\w*])?§f: §r(?<message>.*)" + ) + + /** + * REGEX-TEST: §dFrom §r§b[MVP§r§3+§r§b] Eisengolem§r§7: §r§7Baum + * REGEX-TEST: §dTo §r§b[MVP§r§3+§r§b] Eisengolem§r§7: §r§7hey + * REGEX-TEST: §dTo §r§b[MVP§r§5+§r§b] Alea1337§r§7: §r§d§lBoop! + */ + private val privateMessagePattern by patternGroup.pattern( + "privatemessage", + "§d(?<direction>From|To) §r(?<author>[^:]*)§7: §r(?<message>.*)" + ) + + /** + * REGEX-TEST: §b[MVP§c+§b] hannibal2§f§7 is holding §r§8[§6Heroic Aspect of the Void§8] + * REGEX-TEST: §b[MVP§c+§b] hannibal2§f§7 is holding §r§8[§7[Lvl 2] §dSpider§8] + * REGEX-TEST: §b[MVP§c+§b] hannibal2§f§7 is friends with a §r§8[§7[Lvl 200] §8[§6103§8§4✦§8] §6Golden Dragon§8] + * REGEX-TEST: §b[MVP§c+§b] hannibal2§f§7 is wearing §r§8[§5Glistening Implosion Belt§8] + * REGEX-TEST: §b[MVP§c+§b] hannibal2§f§7 is friends with a §r§8[§7[Lvl 100] §dEnderman§8] + * REGEX-TEST: §b[MVP§c+§b] hannibal2§f§7 has §r§8[§6Heroic Aspect of the Void§8] + * REGEX-TEST: §8[§5396§8] §7☢ §r§b[MVP§c+§b] hannibal2§f§7 is holding §r§8[§6Buzzing InfiniVacuum™ Hooverius§8] + */ + private val itemShowPattern by patternGroup.pattern( + "itemshow", + "(?:§8\\[(?<levelColor>§.)(?<level>\\d+)§8] )?(?<author>.*)§f§7 (?<action>is (?:holding|friends with a|wearing)|has) §r(?<itemName>.*)" + ) + + /** + * REGEX-TEST: §c[Tiffany] §b[MVP§c+§b] hannibal2 + * REGEX-TEST: §b[MVP§c+§b] hannibal2 + * REGEX-TEST: §6§l℻ §r§f[Gamer] §b[MVP§f+§b] SchrankLP§f§r + */ + private val privateIslandRankPattern by patternGroup.pattern( + "privateislandrank", + ".*(?<privateIslandRank>§.\\[\\w+]).*" + ) + + /** + * REGEX-TEST: §8[§r§5396§r§8] §r§7☢ §r§a[✌] §b[MVP§c+§b] hannibal2§f: hey + * REGEX-TEST: §b[MVP§c+§b] hannibal2 + * REGEX-TEST: §6§l℻ §r§f[Gamer] §b[MVP§f+§b] SchrankLP§f§r + * REGEX-TEST: §7☢ §r§a[✌] §b[MVP§c+§b] hannibal2 + */ + private val prrivateIslandGuestPattern by patternGroup.pattern( + "privateislandguest", + ".*(?<guest>§r§a\\[✌]).*" + ) + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + val chatComponent = event.chatComponent + globalPattern.matchMatcher(event.message) { + if (isGlobalChat(event)) return + } + partyPattern.matchMatcher(event.message) { + val author = group("author") + val message = group("message") + PartyChatEvent(author, message, chatComponent).postChat(event) + return + } + guildPattern.matchMatcher(event.message) { + val author = group("author") + val message = group("message") + val guildRank = groupOrNull("guildRank") + GuildChatEvent(author, message, guildRank, chatComponent).postChat(event) + return + } + privateMessagePattern.matchMatcher(event.message) { + val direction = group("direction") + val author = group("author") + val message = group("message") + PrivateMessageChatEvent(direction, author, message, chatComponent).postChat(event) + return + } + itemShowPattern.matchMatcher(event.message) { + val levelColor = groupOrNull("levelColor") + val level = groupOrNull("level")?.formatInt() + val author = group("author") + val action = group("action") + val itemName = group("itemName") + + // for consistency + val message = "§7$action §r$itemName" + PlayerShowItemChatEvent(levelColor, level, author, message, action, itemName, chatComponent).postChat(event) + } + + sendSystemMessage(event) + } + + private fun Matcher.isGlobalChat(event: LorenzChatEvent): Boolean { + var author = group("author") + // TODO move into regex + val isGuild = author.startsWith("§2Guild >") + val isParty = author.startsWith("§9Party") + if (isGuild || isParty) return false + + val message = LorenzUtils.stripVanillaMessage(group("message")) + if (author.contains("[NPC]")) { + NpcChatEvent(author, message.removePrefix("§f"), event.chatComponent).postChat(event) + return true + } + + var privateIslandRank: String? = null + var isAGuest = false + if (IslandType.PRIVATE_ISLAND.isInIsland() || IslandType.PRIVATE_ISLAND_GUEST.isInIsland()) { + privateIslandRankPattern.matchMatcher(author) { + val rank = group("privateIslandRank") + privateIslandRank = rank + author = author.replace(rank, "") + } + prrivateIslandGuestPattern.matchMatcher(author) { + val guest = group("guest") + isAGuest = true + author = author.replace(guest, "") + } + } + + val chatColor = group("chatColor") + val levelColor = groupOrNull("levelColor") + val level = groupOrNull("level")?.formatInt() + PlayerAllChatEvent( + levelColor = levelColor, + level = level, + privateIslandRank = privateIslandRank, + isAGuest = isAGuest, + author = author, + chatColor = chatColor, + message = message, + chatComponent = event.chatComponent, + ).postChat(event) + return true + } + + private fun sendSystemMessage(event: LorenzChatEvent) { + with(SystemMessageEvent(event.message, event.chatComponent)) { + val cancelled = postAndCatch() + event.handleChat(cancelled, blockedReason, chatComponent) + } + } + + private fun AbstractChatEvent.postChat(event: LorenzChatEvent) { + val cancelled = postAndCatch() + event.handleChat(cancelled, blockedReason, chatComponent) + } + + private fun LorenzChatEvent.handleChat( + cancelled: Boolean, + blockedReason: String?, + chatComponent: IChatComponent, + ) { + if (cancelled) { + this.cancel() + } + blockedReason?.let { + this.blockedReason = it + } + this.chatComponent = chatComponent + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerNameFormatter.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerNameFormatter.kt new file mode 100644 index 000000000..4463270b3 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/PlayerNameFormatter.kt @@ -0,0 +1,200 @@ +package at.hannibal2.skyhanni.data.hypixel.chat + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator +import at.hannibal2.skyhanni.config.features.chat.PlayerMessagesConfig +import at.hannibal2.skyhanni.data.hypixel.chat.event.GuildChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PartyChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PlayerAllChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PlayerShowItemChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PrivateMessageChatEvent +import at.hannibal2.skyhanni.features.bingo.BingoAPI +import at.hannibal2.skyhanni.features.chat.playerchat.PlayerChatFilter +import at.hannibal2.skyhanni.features.misc.MarkedPlayerManager +import at.hannibal2.skyhanni.features.misc.compacttablist.AdvancedPlayerList +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.StringUtils +import at.hannibal2.skyhanni.utils.StringUtils.cleanPlayerName +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.replaceAll +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import com.google.gson.JsonArray +import com.google.gson.JsonNull +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +/** + * Listening to the player chat events, and applying custom chat options to them. + * E.g. part order, rank hider, etc + */ +class PlayerNameFormatter { + private val config get() = SkyHanniMod.feature.chat.playerMessage + + private val patternGroup = RepoPattern.group("data.chat.player.name") + + /** + * REGEX-TEST: §7☢ §r§b[MVP§d+§b] hannibal2 + * REGEX-TEST: §7☢ §r§b[MVP§d+§b] hannibal2 + * REGEX-TEST: §7☢ §r§bhannibal2 + * REGEX-TEST: §7☢ §rhannibal2 + * REGEX-TEST: §7☢ §b[MVP§c+§b] hannibal2 + */ + private val emblemPattern by patternGroup.pattern( + "emblem", + "(?<emblem>(?:§.){1,2}.) (?<author>.*)" + ) + + @SubscribeEvent + fun onPlayerAllChat(event: PlayerAllChatEvent) { + if (!isEnabled()) return + val levelColor = event.levelColor + val level = event.level + val message = event.message + val author = event.author + val privateIslandRank = event.privateIslandRank + val isAGuest = event.isAGuest + + val shouldFilter = config.chatFilter && PlayerChatFilter.shouldChatFilter(message) + val chatColor = if (shouldFilter) "§7" else if (config.sameChatColor) "§f" else event.chatColor + + val name = nameFormat(author, levelColor, level, privateIslandRank = privateIslandRank, isAGuest = isAGuest) + val newMessage = "$name$chatColor: $message" + + event.chatComponent = StringUtils.replaceIfNeeded(event.chatComponent, newMessage) ?: return + } + + @SubscribeEvent + fun onPartyChat(event: PartyChatEvent) { + if (!isEnabled()) return + val message = event.message + val author = event.author + val name = nameFormat(author) + val newMessage = "§9Party §8> $name§f: $message" + + event.chatComponent = StringUtils.replaceIfNeeded(event.chatComponent, newMessage) ?: return + } + + @SubscribeEvent + fun onGuildChat(event: GuildChatEvent) { + if (!isEnabled()) return + val message = event.message + val author = event.author + val guildRank = event.guildRank + val name = nameFormat(author, guildRank = guildRank) + val newMessage = "§2Guild > $name§f: $message" + + event.chatComponent = StringUtils.replaceIfNeeded(event.chatComponent, newMessage) ?: return + } + + @SubscribeEvent + fun onPrivateMessageChat(event: PrivateMessageChatEvent) { + if (!isEnabled()) return + val direction = event.direction + val message = event.message + val author = event.author + val name = nameFormat(author) + val newMessage = "§d$direction §f$name§7: §f$message" + + event.chatComponent = StringUtils.replaceIfNeeded(event.chatComponent, newMessage) ?: return + } + + @SubscribeEvent + fun onPlayerShowItemChat(event: PlayerShowItemChatEvent) { + if (!isEnabled()) return + val author = event.author + val action = event.action + val itemName = event.itemName + val levelColor = event.levelColor + val level = event.level + val name = nameFormat(author, levelColor = levelColor, level = level) + val newMessage = "$name §7$action §r$itemName" + + event.chatComponent = StringUtils.replaceIfNeeded(event.chatComponent, newMessage) ?: return + } + + private fun nameFormat( + author: String, + levelColor: String? = null, + level: Int? = null, + guildRank: String? = null, + privateIslandRank: String? = null, + isAGuest: Boolean = false, + ): String { + var cleanAuthor = cleanAuthor(author) + + var emblemFormat = "" + emblemPattern.matchMatcher(author) { + emblemFormat = group("emblem") + cleanAuthor = LorenzUtils.stripVanillaMessage(group("author")) + } + + val name = formatAuthor(cleanAuthor, levelColor) + val levelFormat = formatLevel(levelColor, level) + val guildRankFormat = guildRank ?: "" + val privateIslandRankFormat = privateIslandRank ?: "" + val privateIslandGuestFormat = if (isAGuest) "§a[✌]" else "" + + val cleanName = cleanAuthor.cleanPlayerName() + val (faction, ironman, bingo) = AdvancedPlayerList.tabPlayerData[cleanName]?.let { + val faction = it.faction.icon + val ironman = if (it.ironman) "§7♲" else "" + val bingo = it.bingoLevel?.let { level -> BingoAPI.getBingoIcon(level) } ?: "" + listOf(faction, ironman, bingo) + } ?: listOf("", "", "") + + val map = mutableMapOf<PlayerMessagesConfig.MessagePart, String>() + map[PlayerMessagesConfig.MessagePart.SKYBLOCK_LEVEL] = levelFormat + map[PlayerMessagesConfig.MessagePart.EMBLEM] = emblemFormat + map[PlayerMessagesConfig.MessagePart.PLAYER_NAME] = name + map[PlayerMessagesConfig.MessagePart.CRIMSON_FACTION] = faction + map[PlayerMessagesConfig.MessagePart.MODE_IRONMAN] = ironman + map[PlayerMessagesConfig.MessagePart.BINGO_LEVEL] = bingo + map[PlayerMessagesConfig.MessagePart.GUILD_RANK] = guildRankFormat + map[PlayerMessagesConfig.MessagePart.PRIVATE_ISLAND_RANK] = privateIslandRankFormat + map[PlayerMessagesConfig.MessagePart.PRIVATE_ISLAND_GUEST] = privateIslandGuestFormat + + return config.partsOrder.map { map[it] }.joinToString(" ").replaceAll(" ", " ").trim() + } + + private fun formatLevel(rawColor: String?, rawLevel: Int?): String { + val color = rawColor ?: return "" + val level = rawLevel ?: error("level is null, color is not null") + val levelData = "$color$level" + return if (config.hideLevelBrackets) levelData else "§8[${levelData}§8]" + } + + private fun cleanAuthor(author: String): String { + val text = LorenzUtils.stripVanillaMessage(author) + return text.removeSuffix("§f") + } + + private fun formatAuthor(author: String, levelColor: String?): String { + if (author.contains("ADMIN")) return author + if (config.ignoreYouTube && author.contains("YOUTUBE")) return author + + var result = author.cleanPlayerName(displayName = true) + levelColor?.let { + if (config.useLevelColorForName) { + val cleanPlayerName = author.cleanPlayerName() + result = result.replace(cleanPlayerName, it + cleanPlayerName) + } + } + + return MarkedPlayerManager.replaceInChat(result) + } + + fun isEnabled() = LorenzUtils.inSkyBlock && (config.playerRankHider || config.chatFilter || config.sameChatColor) + + @SubscribeEvent + fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { + event.transform(41, "chat.PlayerMessagesConfig.partsOrder") { element -> + val newList = JsonArray() + for (entry in element.asJsonArray) { + if (entry is JsonNull) continue + if (entry.asString != "EMPTY_CHAR") { + newList.add(entry) + } + } + newList + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/AbstractChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/AbstractChatEvent.kt new file mode 100644 index 000000000..cd0a8f92b --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/AbstractChatEvent.kt @@ -0,0 +1,11 @@ +package at.hannibal2.skyhanni.data.hypixel.chat.event + +import at.hannibal2.skyhanni.events.LorenzEvent +import net.minecraft.util.IChatComponent + +open class AbstractChatEvent( + val author: String, + val message: String, + var chatComponent: IChatComponent, + var blockedReason: String? = null, +) : LorenzEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/GuildChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/GuildChatEvent.kt new file mode 100644 index 000000000..dd3867106 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/GuildChatEvent.kt @@ -0,0 +1,11 @@ +package at.hannibal2.skyhanni.data.hypixel.chat.event + +import net.minecraft.util.IChatComponent + +class GuildChatEvent( + author: String, + message: String, + val guildRank: String? = null, + chatComponent: IChatComponent, + blockedReason: String? = null, +) : AbstractChatEvent(author, message, chatComponent, blockedReason) diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/NpcChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/NpcChatEvent.kt new file mode 100644 index 000000000..574324520 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/NpcChatEvent.kt @@ -0,0 +1,10 @@ +package at.hannibal2.skyhanni.data.hypixel.chat.event + +import net.minecraft.util.IChatComponent + +class NpcChatEvent( + author: String, + message: String, + chatComponent: IChatComponent, + blockedReason: String? = null, +) : AbstractChatEvent(author, message, chatComponent, blockedReason) diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PartyChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PartyChatEvent.kt new file mode 100644 index 000000000..dc9e921cc --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PartyChatEvent.kt @@ -0,0 +1,10 @@ +package at.hannibal2.skyhanni.data.hypixel.chat.event + +import net.minecraft.util.IChatComponent + +class PartyChatEvent( + author: String, + message: String, + chatComponent: IChatComponent, + blockedReason: String? = null, +) : AbstractChatEvent(author, message, chatComponent, blockedReason) diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PlayerAllChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PlayerAllChatEvent.kt new file mode 100644 index 000000000..56ea15a64 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PlayerAllChatEvent.kt @@ -0,0 +1,15 @@ +package at.hannibal2.skyhanni.data.hypixel.chat.event + +import net.minecraft.util.IChatComponent + +class PlayerAllChatEvent( + val levelColor: String?, + val level: Int?, + val privateIslandRank: String? = null, + val isAGuest: Boolean, + author: String, + val chatColor: String?, + message: String, + chatComponent: IChatComponent, + blockedReason: String? = null, +) : AbstractChatEvent(author, message, chatComponent, blockedReason) diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PlayerShowItemChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PlayerShowItemChatEvent.kt new file mode 100644 index 000000000..229264b27 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PlayerShowItemChatEvent.kt @@ -0,0 +1,14 @@ +package at.hannibal2.skyhanni.data.hypixel.chat.event + +import net.minecraft.util.IChatComponent + +class PlayerShowItemChatEvent( + val levelColor: String?, + val level: Int?, + author: String, + message: String, + val action: String, + val itemName: String, + chatComponent: IChatComponent, + blockedReason: String? = null, +) : AbstractChatEvent(author, message, chatComponent, blockedReason) diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PrivateMessageChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PrivateMessageChatEvent.kt new file mode 100644 index 000000000..f23b1d0b0 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/PrivateMessageChatEvent.kt @@ -0,0 +1,11 @@ +package at.hannibal2.skyhanni.data.hypixel.chat.event + +import net.minecraft.util.IChatComponent + +class PrivateMessageChatEvent( + val direction: String?, + author: String, + message: String, + chatComponent: IChatComponent, + blockedReason: String? = null, +) : AbstractChatEvent(author, message, chatComponent, blockedReason) diff --git a/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/SystemMessageEvent.kt b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/SystemMessageEvent.kt new file mode 100644 index 000000000..82c53d0b1 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/hypixel/chat/event/SystemMessageEvent.kt @@ -0,0 +1,10 @@ +package at.hannibal2.skyhanni.data.hypixel.chat.event + +import at.hannibal2.skyhanni.events.LorenzEvent +import net.minecraft.util.IChatComponent + +class SystemMessageEvent( + val message: String, + var chatComponent: IChatComponent, + var blockedReason: String? = null, +) : LorenzEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/events/PartyChatEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/PartyChatEvent.kt deleted file mode 100644 index 76630583e..000000000 --- a/src/main/java/at/hannibal2/skyhanni/events/PartyChatEvent.kt +++ /dev/null @@ -1,7 +0,0 @@ -package at.hannibal2.skyhanni.events - -data class PartyChatEvent( - val author: String, - val text: String, - val trigger: LorenzChatEvent, -) : LorenzEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoAPI.kt index f5361e09a..ccfd85ef7 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/BingoAPI.kt @@ -106,4 +106,13 @@ object BingoAPI { else -> "§c" } + LorenzUtils.formatPercentage(percentage) + + fun getBingoIcon(rank: Int): String { + val rankIcon = getIcon(rank) ?: "" + return if (rank != -1) { + "$rankIcon $rank" + } else { + rankIcon + } + } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/Translator.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/Translator.kt index 4e02f89f3..8e61f4b6c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/Translator.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/Translator.kt @@ -31,6 +31,7 @@ class Translator { if (!isEnabled()) return val message = event.message + // TODO use PlayerAllChatEvent and other player chat events if (message.getPlayerNameFromChatMessage() == null) return val editedComponent = event.chatComponent.transformIf({ siblings.isNotEmpty() }) { siblings.last() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/playerchat/PlayerChatModifier.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/playerchat/PlayerChatModifier.kt index 087769645..4aabeaf6c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/playerchat/PlayerChatModifier.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/playerchat/PlayerChatModifier.kt @@ -2,12 +2,9 @@ package at.hannibal2.skyhanni.features.chat.playerchat import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator -import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.features.dungeon.DungeonMilestonesDisplay +import at.hannibal2.skyhanni.data.hypixel.chat.event.SystemMessageEvent import at.hannibal2.skyhanni.features.misc.MarkedPlayerManager -import at.hannibal2.skyhanni.utils.StringUtils.matches -import net.minecraft.util.ChatComponentText -import net.minecraft.util.IChatComponent +import at.hannibal2.skyhanni.utils.StringUtils import net.minecraftforge.fml.common.eventhandler.SubscribeEvent class PlayerChatModifier { @@ -18,44 +15,13 @@ class PlayerChatModifier { init { patterns.add("§[ab6]\\[(?:VIP|MVP)(?:§.|\\+)*] {1,2}(?:§[7ab6])?(\\w{2,16})".toRegex()) // ranked player with prefix everywhere patterns.add("§[7ab6](\\w{2,16})§r(?!§7x)(?!\$)".toRegex()) // all players without rank prefix in notification messages - patterns.add("(?:§7 )?§7(\\w{2,16})§7§r".toRegex()) // nons user chat } @SubscribeEvent - fun onChat(event: LorenzChatEvent) { - val foundCommands = mutableListOf<IChatComponent>() - val message = event.chatComponent + fun onChat(event: SystemMessageEvent) { + val newMessage = cutMessage(event.chatComponent.formattedText) - addComponent(foundCommands, event.chatComponent) - for (sibling in message.siblings) { - addComponent(foundCommands, sibling) - } - - val size = foundCommands.size - if (size > 1) { - return - } - val original = event.chatComponent.formattedText - val newText = cutMessage(original) - if (original == newText) return - - val text = ChatComponentText(newText) - if (size == 1) { - val chatStyle = foundCommands[0].chatStyle - text.chatStyle.chatClickEvent = chatStyle.chatClickEvent - text.chatStyle.chatHoverEvent = chatStyle.chatHoverEvent - } - event.chatComponent = text - } - - private fun addComponent(foundCommands: MutableList<IChatComponent>, message: IChatComponent) { - val clickEvent = message.chatStyle.chatClickEvent - if (clickEvent != null) { - if (foundCommands.size == 1 && foundCommands[0].chatStyle.chatClickEvent.value == clickEvent.value) { - return - } - foundCommands.add(message) - } + event.chatComponent = StringUtils.replaceIfNeeded(event.chatComponent, newMessage) ?: return } private fun cutMessage(input: String): String { @@ -67,24 +33,9 @@ class PlayerChatModifier { } string = string.replace("§[7ab6]((?:\\w+){2,16})'s", "§b$1's") string = string.replace("§[7ab6]((?:\\w+){2,16}) (§.)", "§b$1 $2") - - // TODO remove workaround - if (!DungeonMilestonesDisplay.milestonePattern.matches(input)) { - // all players same color in chat - string = string.replace("§r§7: ", "§r§f: ") - } } - if (config.chatFilter && string.contains("§r§f: ") && PlayerChatFilter.shouldChatFilter(string)) { - string = string.replace("§r§f: ", "§r§7: ") - } - - if (MarkedPlayerManager.config.highlightInChat) { - val color = MarkedPlayerManager.config.chatColor.getChatColor() - for (markedPlayer in MarkedPlayerManager.playerNamesToMark) { - string = string.replace(markedPlayer, "$color$markedPlayer§r") - } - } + string = MarkedPlayerManager.replaceInChat(string) return string } diff --git a/src/main/java/at/hannibal2/skyhanni/features/commands/PartyChatCommands.kt b/src/main/java/at/hannibal2/skyhanni/features/commands/PartyChatCommands.kt index b2de36a7a..8ead93fcf 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/commands/PartyChatCommands.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/commands/PartyChatCommands.kt @@ -4,7 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.features.misc.PartyCommandsConfig import at.hannibal2.skyhanni.data.FriendAPI import at.hannibal2.skyhanni.data.PartyAPI -import at.hannibal2.skyhanni.events.PartyChatEvent +import at.hannibal2.skyhanni.data.hypixel.chat.event.PartyChatEvent import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -60,9 +60,9 @@ object PartyChatCommands { @SubscribeEvent fun onPartyCommand(event: PartyChatEvent) { - if (event.text.firstOrNull() !in commandBeginChars) + if (event.message.firstOrNull() !in commandBeginChars) return - val commandLabel = event.text.substring(1).substringBefore(' ') + val commandLabel = event.message.substring(1).substringBefore(' ') val command = indexedPartyChatCommands[commandLabel.lowercase()] ?: return if (event.author == LorenzUtils.getPlayerName()) { return diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt index b86e580aa..56bb8396c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt @@ -462,6 +462,7 @@ object GardenVisitorFeatures { event.blockedReason = "new_visitor_arrived" } + // TODO use NpcChatEvent if (GardenAPI.inGarden() && config.hideChat && hideVisitorMessage(event.message)) { event.blockedReason = "garden_visitor_message" } diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/MarkedPlayerManager.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/MarkedPlayerManager.kt index 0adf1d5ec..5edabcbb1 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/MarkedPlayerManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/MarkedPlayerManager.kt @@ -80,6 +80,17 @@ class MarkedPlayerManager { private fun isEnabled() = (LorenzUtils.inSkyBlock || OutsideSbFeature.MARKED_PLAYERS.isSelected()) && config.highlightInWorld + + fun replaceInChat(string: String): String { + if (!config.highlightInChat) return string + + val color = config.chatColor.getChatColor() + var text = string + for (markedPlayer in playerNamesToMark) { + text = text.replace(markedPlayer, "$color$markedPlayer§r") + } + return text + } } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/PlayerChatSymbols.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/PlayerChatSymbols.kt deleted file mode 100644 index 56c6b8bfe..000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/PlayerChatSymbols.kt +++ /dev/null @@ -1,107 +0,0 @@ -package at.hannibal2.skyhanni.features.misc - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator -import at.hannibal2.skyhanni.config.features.chat.ChatSymbols.SymbolLocationEntry -import at.hannibal2.skyhanni.events.LorenzChatEvent -import at.hannibal2.skyhanni.features.misc.compacttablist.TabStringType -import at.hannibal2.skyhanni.mixins.transformers.AccessorChatComponentText -import at.hannibal2.skyhanni.utils.ConfigUtils -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.StringUtils -import at.hannibal2.skyhanni.utils.StringUtils.getPlayerNameAndRankFromChatMessage -import at.hannibal2.skyhanni.utils.StringUtils.getPlayerNameFromChatMessage -import at.hannibal2.skyhanni.utils.StringUtils.removeResets -import at.hannibal2.skyhanni.utils.TabListData -import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import net.minecraft.util.ChatComponentText -import net.minecraft.util.IChatComponent -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent - -// code inspired by SBA but heavily modified to be more functional and actually work -class PlayerChatSymbols { - - private val config get() = SkyHanniMod.feature.chat.chatSymbols - private val nameSymbols = mutableMapOf<String, String>() - - private val patternGroup = RepoPattern.group("misc.chatsymbols") - private val symbolsPattern by patternGroup.pattern( - "symbols", - "^(?<symbols>(?:(?:§\\w)+\\S)+) " - ) - private val symbolPattern by patternGroup.pattern( - "symbol", - "(?:§.)+(\\S)" - ) - - @SubscribeEvent - fun onChat(event: LorenzChatEvent) { - if (!LorenzUtils.inSkyBlock) return - if (!config.enabled) return - - val username = event.message.getPlayerNameFromChatMessage() ?: return - - var usernameWithSymbols = TabListData.getTabList() - .find { playerName -> TabStringType.usernameFromLine(playerName) == username } - - if (usernameWithSymbols != null) { - nameSymbols[username] = usernameWithSymbols - } - - usernameWithSymbols = nameSymbols[username] ?: return - - val split = usernameWithSymbols.split("$username ") - var emblemText = if (split.size > 1) split[1].removeResets() else "" - - var matcher = symbolsPattern.matcher("$emblemText ") - emblemText = if (matcher.find()) { - matcher.group("symbols") - } else "" - - if (emblemText == "") { - return - } - - val emblems = mutableListOf<String>() - matcher = symbolPattern.matcher(emblemText) - while (matcher.find()) { - emblems.add(matcher.group(1)) - } - - for (emblem in emblems) { - event.chatComponent = StringUtils.replaceFirstChatText(event.chatComponent, "$emblem ", "") - } - - val rankAndName = event.message.getPlayerNameAndRankFromChatMessage() ?: return - - StringUtils.modifyFirstChatComponent(event.chatComponent) { component -> - modify(component, emblemText, rankAndName) - } - } - - private fun modify(component: IChatComponent, emblemText: String, rankAndName: String): Boolean { - if (component !is ChatComponentText) return false - component as AccessorChatComponentText - if (!component.text_skyhanni().contains(rankAndName)) return false - val oldText = component.text_skyhanni() - - val newText = getNewText(emblemText, oldText, rankAndName) - component.setText_skyhanni(component.text_skyhanni().replace(oldText, newText)) - return true - } - - private fun getNewText(emblemText: String, oldText: String, rankAndName: String): String = - when (config.symbolLocation) { - SymbolLocationEntry.LEFT -> oldText.replace(rankAndName, "$emblemText $rankAndName") - SymbolLocationEntry.RIGHT -> oldText.replace(rankAndName, "$rankAndName $emblemText ") - SymbolLocationEntry.HIDDEN -> oldText - else -> oldText - } - - @SubscribeEvent - fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { - event.transform(15, "chat.chatSymbols.symbolLocation") { element -> - ConfigUtils.migrateIntToEnum(element, SymbolLocationEntry::class.java) - } - } -} diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/compacttablist/AdvancedPlayerList.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/compacttablist/AdvancedPlayerList.kt index f5bd15750..273942287 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/compacttablist/AdvancedPlayerList.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/compacttablist/AdvancedPlayerList.kt @@ -23,11 +23,14 @@ import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.TimeLimitedCache import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Matcher import kotlin.random.Random import kotlin.time.Duration.Companion.minutes object AdvancedPlayerList { + val tabPlayerData = mutableMapOf<String, PlayerData>() + private val config get() = SkyHanniMod.feature.gui.compactTabList.advancedPlayerList private val levelPattern by RepoPattern.pattern( @@ -62,48 +65,12 @@ object AdvancedPlayerList { extraTitles++ continue } - levelPattern.matchMatcher(line) { + val playerData: PlayerData? = levelPattern.matchMatcher(line) { val levelText = group("level") val removeColor = levelText.removeColor() try { - val playerData = PlayerData(removeColor.toInt()) - currentData[line] = playerData - - var index = 0 - val fullName = group("name") - if (fullName.contains("[")) index++ - val name = fullName.split(" ") - val coloredName = name[index] - if (index == 1) { - playerData.coloredName = name[0] + " " + coloredName - } else { - playerData.coloredName = coloredName - } - playerData.name = coloredName.removeColor() - playerData.levelText = levelText - index++ - if (name.size > index) { - var nameSuffix = name.drop(index).joinToString(" ") - if (nameSuffix.contains("♲")) { - playerData.ironman = true - } else { - playerData.bingoLevel = BingoAPI.getRank(line) - } - if (IslandType.CRIMSON_ISLE.isInIsland()) { - playerData.faction = if (line.contains("§c⚒")) { - nameSuffix = nameSuffix.replace("§c⚒", "") - CrimsonIsleFaction.BARBARIAN - } else if (line.contains("§5ቾ")) { - nameSuffix = nameSuffix.replace("§5ቾ", "") - CrimsonIsleFaction.MAGE - } else { - CrimsonIsleFaction.NONE - } - } - playerData.nameSuffix = nameSuffix - } else { - playerData.nameSuffix = "" - } + val sbLevel = removeColor.toInt() + readPlayerData(sbLevel, levelText, line) } catch (e: NumberFormatException) { ErrorManager.logErrorWithData( e, "Advanced Player List failed to parse user name", @@ -111,7 +78,15 @@ object AdvancedPlayerList { "i" to i, "original" to original, ) + null + } + } + playerData?.let { + val name = it.name + if (name != "?") { + tabPlayerData[name] = it } + currentData[line] = it } } playerDatas = currentData @@ -156,6 +131,50 @@ object AdvancedPlayerList { return newList } + private fun Matcher.readPlayerData( + sbLevel: Int, + levelText: String, + line: String, + ): PlayerData { + val playerData = PlayerData(sbLevel) + var index = 0 + val fullName = group("name") + if (fullName.contains("[")) index++ + val name = fullName.split(" ") + val coloredName = name[index] + if (index == 1) { + playerData.coloredName = name[0] + " " + coloredName + } else { + playerData.coloredName = coloredName + } + playerData.name = coloredName.removeColor() + playerData.levelText = levelText + index++ + if (name.size > index) { + var nameSuffix = name.drop(index).joinToString(" ") + if (nameSuffix.contains("♲")) { + playerData.ironman = true + } else { + playerData.bingoLevel = BingoAPI.getRank(line) + } + if (IslandType.CRIMSON_ISLE.isInIsland()) { + playerData.faction = if (line.contains("§c⚒")) { + nameSuffix = nameSuffix.replace("§c⚒", "") + CrimsonIsleFaction.BARBARIAN + } else if (line.contains("§5ቾ")) { + nameSuffix = nameSuffix.replace("§5ቾ", "") + CrimsonIsleFaction.MAGE + } else { + CrimsonIsleFaction.NONE + } + } + playerData.nameSuffix = nameSuffix + } else { + playerData.nameSuffix = "" + } + return playerData + } + fun ignoreCustomTabList(): Boolean { val denyKeyPressed = SkyHanniMod.feature.dev.debug.bypassAdvancedPlayerTabList.isKeyHeld() return denyKeyPressed || !SkyHanniDebugsAndTests.globalRender @@ -169,6 +188,7 @@ object AdvancedPlayerList { } private fun createCustomName(data: PlayerData): String { + val playerName = if (config.useLevelColorForName) { val c = data.levelText[3] "§$c" + data.name @@ -179,7 +199,7 @@ object AdvancedPlayerList { } else "" var suffix = if (config.hideEmblem) { - if (data.ironman) "§7♲" else data.bingoLevel?.let { getBingoIcon(it) } ?: "" + if (data.ironman) "§7♲" else data.bingoLevel?.let { BingoAPI.getBingoIcon(it) } ?: "" } else data.nameSuffix if (config.markSpecialPersons) { @@ -230,15 +250,6 @@ object AdvancedPlayerList { else -> "" } - private fun getBingoIcon(rank: Int): String { - val rankIcon = BingoAPI.getIcon(rank) ?: "" - return if (config.showBingoRankNumber && rank != -1) { - "$rankIcon $rank" - } else { - rankIcon - } - } - class PlayerData(val sbLevel: Int) { var name: String = "?" diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/compacttablist/TabListReader.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/compacttablist/TabListReader.kt index 9d21c7421..18bdede44 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/compacttablist/TabListReader.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/compacttablist/TabListReader.kt @@ -59,7 +59,6 @@ object TabListReader { private fun updateTablistData(tablist: List<String>? = null) { if (!LorenzUtils.inSkyBlock) return - if (!config.enabled.get()) return var tabLines = tablist ?: TabListData.getTabList() diff --git a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt index 59b82cd8c..68c92f7a7 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/StringUtils.kt @@ -127,6 +127,7 @@ object StringUtils { fun String.cleanPlayerName(displayName: Boolean = false): String { return if (displayName) { if (SkyHanniMod.feature.chat.playerMessage.playerRankHider) { + // TODO custom color "§b" + internalCleanPlayerName() } else this } else { @@ -317,4 +318,58 @@ object StringUtils { fun isEmpty(message: String): Boolean = message.removeColor().trimWhiteSpaceAndResets().isEmpty() fun generateRandomId() = UUID.randomUUID().toString() + + fun replaceIfNeeded( + original: IChatComponent, + newText: String, + ): ChatComponentText? { + val foundCommands = mutableListOf<IChatComponent>() + + addComponent(foundCommands, original) + for (sibling in original.siblings) { + addComponent(foundCommands, sibling) + } + + val size = foundCommands.size + if (size > 1) { + return null + } + + if (LorenzUtils.stripVanillaMessage(original.formattedText) == newText) return null + // TODO remove debug +// println("replaceIfNeeded!") +// println("original: ${original.formattedText}") +// println("newText: $newText") +// println(" ") + + val text = ChatComponentText(newText) + if (size == 1) { + val chatStyle = foundCommands[0].chatStyle + text.chatStyle.chatClickEvent = chatStyle.chatClickEvent + text.chatStyle.chatHoverEvent = chatStyle.chatHoverEvent + } + + return text + } + + private fun addComponent(foundCommands: MutableList<IChatComponent>, message: IChatComponent) { + val clickEvent = message.chatStyle.chatClickEvent + if (clickEvent != null) { + if (foundCommands.size == 1 && foundCommands[0].chatStyle.chatClickEvent.value == clickEvent.value) { + return + } + foundCommands.add(message) + } + } + + fun String.replaceAll(oldValue: String, newValue: String, ignoreCase: Boolean = false): String { + var text = this + while (true) { + val newText = text.replace(oldValue, newValue, ignoreCase = ignoreCase) + if (newText == text) { + return text + } + text = newText + } + } } |