diff --git a/build.gradle.kts b/build.gradle.kts index a25aa83..770eab0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,10 @@ import java.io.BufferedReader plugins { - id("com.gradleup.shadow") version "8.3.6" // Import shadow API. - java // Tell gradle this is a java project. - eclipse // Import eclipse plugin for IDE integration. kotlin("jvm") version "2.1.21" // Import kotlin jvm plugin for kotlin/java integration. + id("com.gradleup.shadow") version "8.3.6" // Import shadow API. + id("com.diffplug.spotless") version "7.0.4" + eclipse // Import eclipse plugin for IDE integration. } val commitHash = Runtime @@ -74,6 +74,7 @@ kotlin { } tasks.build { + dependsOn(tasks.spotlessApply) dependsOn(tasks.shadowJar) } @@ -114,3 +115,11 @@ java { vendor = JvmVendorSpec.GRAAL_VM } } + +spotless { + kotlin { + ktfmt().kotlinlangStyle().configure { + it.setMaxWidth(120) + } + } +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/BlocklistManager.kt b/src/main/kotlin/nl/skbotnl/chatog/BlocklistManager.kt index 622c4f6..174321b 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/BlocklistManager.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/BlocklistManager.kt @@ -1,9 +1,9 @@ package nl.skbotnl.chatog -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import java.net.URI import java.util.concurrent.TimeUnit +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch object BlocklistManager { private var blockList = mutableListOf() @@ -24,22 +24,21 @@ object BlocklistManager { } private fun refresh() { - URI("https://raw.githubusercontent.com/hagezi/dns-blocklists/main/domains/multi.txt").toURL().openStream() + URI("https://raw.githubusercontent.com/hagezi/dns-blocklists/main/domains/multi.txt") + .toURL() + .openStream() .use { input -> input.bufferedReader().use { bufferedReader -> - bufferedReader.lines().skip(11).forEach { - blockList += it - } + bufferedReader.lines().skip(11).forEach { blockList += it } } } } private val urlRegex = Regex("^(https?|ftp|file)://([-a-zA-Z0-9+&@#/%?=~_|!:,.;]*?[^/]*)") + fun checkUrl(url: String): Boolean { var baseUrl: String? = null - urlRegex.findAll(url).iterator().forEach { urlMatch -> - baseUrl = urlMatch.groups[2]?.value - } + urlRegex.findAll(url).iterator().forEach { urlMatch -> baseUrl = urlMatch.groups[2]?.value } if (baseUrl == null) { return false } @@ -51,4 +50,4 @@ object BlocklistManager { } return false } -} \ No newline at end of file +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt b/src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt index 3464e79..e6be7da 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt @@ -1,12 +1,12 @@ package nl.skbotnl.chatog import com.earth2me.essentials.Essentials +import java.util.* import kotlinx.coroutines.* import net.milkbowl.vault.chat.Chat import nl.skbotnl.chatog.commands.* import org.bukkit.Bukkit import org.bukkit.plugin.java.JavaPlugin -import java.util.* class ChatOG : JavaPlugin() { @OptIn(DelicateCoroutinesApi::class) @@ -59,9 +59,10 @@ class ChatOG : JavaPlugin() { Bukkit.getPluginManager().disablePlugin(this) return } - translator = if (Config.openAIEnabled) { - OpenAI() - } else null + translator = + if (Config.openAIEnabled) { + OpenAI() + } else null languageDatabase = LanguageDatabase() if (languageDatabase.testConnection()) { @@ -71,9 +72,7 @@ class ChatOG : JavaPlugin() { } BlocklistManager.load() - scope.launch { - EmojiConverter.load() - } + scope.launch { EmojiConverter.load() } val rsp = server.servicesManager.getRegistration(Chat::class.java) chat = rsp!!.provider @@ -87,9 +86,7 @@ class ChatOG : JavaPlugin() { this.getCommand("p")?.setExecutor(PremiumChat()) if (Config.discordEnabled) { - scope.launch { - DiscordBridge.main() - } + scope.launch { DiscordBridge.main() } } } @@ -103,8 +100,6 @@ class ChatOG : JavaPlugin() { scope.cancel() - runBlocking { - scope.coroutineContext[Job]?.join() - } + runBlocking { scope.coroutineContext[Job]?.join() } } } diff --git a/src/main/kotlin/nl/skbotnl/chatog/ChatSystemHelper.kt b/src/main/kotlin/nl/skbotnl/chatog/ChatSystemHelper.kt index eda40d9..3eaf9f2 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/ChatSystemHelper.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/ChatSystemHelper.kt @@ -1,125 +1,121 @@ -package nl.skbotnl.chatog - -import kotlinx.coroutines.DelicateCoroutinesApi -import kotlinx.coroutines.launch -import me.clip.placeholderapi.PlaceholderAPI -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.JoinConfiguration -import net.kyori.adventure.text.TextComponent -import net.kyori.adventure.text.event.ClickEvent -import net.kyori.adventure.text.event.HoverEvent -import net.trueog.utilitiesog.UtilitiesOG -import nl.skbotnl.chatog.Helper.legacyToMm -import nl.skbotnl.chatog.Helper.removeColor -import nl.skbotnl.chatog.commands.TranslateMessage -import org.bukkit.Bukkit -import org.bukkit.entity.Player -import java.util.* - -@OptIn(DelicateCoroutinesApi::class) -object ChatSystemHelper { - object ChatType { - const val STAFFCHAT = "staffchat" - const val PREMIUMCHAT = "premiumchat" - } - - var inChat: MutableMap = HashMap() - - fun sendMessageInStaffChat(player: Player, text: String) { - var chatString = "${ChatOG.chat.getPlayerPrefix(player)}${player.name}" - - if (PlaceholderAPI.setPlaceholders(player, "%simpleclans_clan_color_tag%") != "") { - chatString = PlaceholderAPI.setPlaceholders(player, "&8[%simpleclans_clan_color_tag%&8] $chatString") - } - chatString = "&cSTAFF | $chatString" - - if (Config.staffDiscordEnabled) { - val discordMessageString = Helper.convertEmojis(text) - - ChatOG.scope.launch { - DiscordBridge.sendStaffMessage(discordMessageString, removeColor(chatString), player.uniqueId) - } - } - - val messageComponents = Helper.convertLinks(text, player) - - val messageComponent = - Component.join(JoinConfiguration.separator(Component.text(" ")), messageComponents) as TextComponent - - val chatComponent = UtilitiesOG.trueogColorize(legacyToMm("$chatString${ChatOG.chat.getPlayerSuffix(player)}")) - - var textComponent = - Component.join(JoinConfiguration.noSeparators(), chatComponent, messageComponent) - textComponent = textComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to translate this message") - ) - ) - - val randomUUID = UUID.randomUUID() - textComponent = textComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.RUN_COMMAND, - "/translatemessage $randomUUID 1" - ) - ) - - TranslateMessage.chatMessages[randomUUID] = TranslateMessage.SentChatMessage(text, player) - - for (p in Bukkit.getOnlinePlayers()) { - if (p.hasPermission("chat-og.staff")) { - p.sendMessage(textComponent) - } - } - } - - fun sendMessageInPremiumChat(player: Player, text: String) { - var chatString = "${ChatOG.chat.getPlayerPrefix(player)}${player.name}" - - if (PlaceholderAPI.setPlaceholders(player, "%simpleclans_clan_color_tag%") != "") { - chatString = PlaceholderAPI.setPlaceholders(player, "&8[%simpleclans_clan_color_tag%&8] $chatString") - } - chatString = "&aPREMIUM | $chatString" - - if (Config.premiumDiscordEnabled) { - val discordMessageString = Helper.convertEmojis(text) - - ChatOG.scope.launch { - DiscordBridge.sendPremiumMessage(discordMessageString, removeColor(chatString), player.uniqueId) - } - } - - val messageComponents = Helper.convertLinks(text, player) - - val messageComponent = - Component.join(JoinConfiguration.separator(Component.text(" ")), messageComponents) as TextComponent - - val chatComponent = UtilitiesOG.trueogColorize(legacyToMm("$chatString${ChatOG.chat.getPlayerSuffix(player)}")) - - var textComponent = - Component.join(JoinConfiguration.noSeparators(), chatComponent, messageComponent) - textComponent = textComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to translate this message") - ) - ) - - val randomUUID = UUID.randomUUID() - textComponent = textComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.RUN_COMMAND, - "/translatemessage $randomUUID 1" - ) - ) - - TranslateMessage.chatMessages[randomUUID] = TranslateMessage.SentChatMessage(text, player) - - for (p in Bukkit.getOnlinePlayers()) { - if (p.hasPermission("chat-og.premium")) { - p.sendMessage(textComponent) - } - } - } -} +package nl.skbotnl.chatog + +import java.util.* +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.launch +import me.clip.placeholderapi.PlaceholderAPI +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.JoinConfiguration +import net.kyori.adventure.text.TextComponent +import net.kyori.adventure.text.event.ClickEvent +import net.kyori.adventure.text.event.HoverEvent +import net.trueog.utilitiesog.UtilitiesOG +import nl.skbotnl.chatog.Helper.legacyToMm +import nl.skbotnl.chatog.Helper.removeColor +import nl.skbotnl.chatog.commands.TranslateMessage +import org.bukkit.Bukkit +import org.bukkit.entity.Player + +@OptIn(DelicateCoroutinesApi::class) +object ChatSystemHelper { + object ChatType { + const val STAFFCHAT = "staffchat" + const val PREMIUMCHAT = "premiumchat" + } + + var inChat: MutableMap = HashMap() + + fun sendMessageInStaffChat(player: Player, text: String) { + var chatString = "${ChatOG.chat.getPlayerPrefix(player)}${player.name}" + + if (PlaceholderAPI.setPlaceholders(player, "%simpleclans_clan_color_tag%") != "") { + chatString = PlaceholderAPI.setPlaceholders(player, "&8[%simpleclans_clan_color_tag%&8] $chatString") + } + chatString = "&cSTAFF | $chatString" + + if (Config.staffDiscordEnabled) { + val discordMessageString = Helper.convertEmojis(text) + + ChatOG.scope.launch { + DiscordBridge.sendStaffMessage(discordMessageString, removeColor(chatString), player.uniqueId) + } + } + + val messageComponents = Helper.convertLinks(text, player) + + val messageComponent = + Component.join(JoinConfiguration.separator(Component.text(" ")), messageComponents) as TextComponent + + val chatComponent = UtilitiesOG.trueogColorize(legacyToMm("$chatString${ChatOG.chat.getPlayerSuffix(player)}")) + + var textComponent = Component.join(JoinConfiguration.noSeparators(), chatComponent, messageComponent) + textComponent = + textComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to translate this message"), + ) + ) + + val randomUUID = UUID.randomUUID() + textComponent = + textComponent.clickEvent( + ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/translatemessage $randomUUID 1") + ) + + TranslateMessage.chatMessages[randomUUID] = TranslateMessage.SentChatMessage(text, player) + + for (p in Bukkit.getOnlinePlayers()) { + if (p.hasPermission("chat-og.staff")) { + p.sendMessage(textComponent) + } + } + } + + fun sendMessageInPremiumChat(player: Player, text: String) { + var chatString = "${ChatOG.chat.getPlayerPrefix(player)}${player.name}" + + if (PlaceholderAPI.setPlaceholders(player, "%simpleclans_clan_color_tag%") != "") { + chatString = PlaceholderAPI.setPlaceholders(player, "&8[%simpleclans_clan_color_tag%&8] $chatString") + } + chatString = "&aPREMIUM | $chatString" + + if (Config.premiumDiscordEnabled) { + val discordMessageString = Helper.convertEmojis(text) + + ChatOG.scope.launch { + DiscordBridge.sendPremiumMessage(discordMessageString, removeColor(chatString), player.uniqueId) + } + } + + val messageComponents = Helper.convertLinks(text, player) + + val messageComponent = + Component.join(JoinConfiguration.separator(Component.text(" ")), messageComponents) as TextComponent + + val chatComponent = UtilitiesOG.trueogColorize(legacyToMm("$chatString${ChatOG.chat.getPlayerSuffix(player)}")) + + var textComponent = Component.join(JoinConfiguration.noSeparators(), chatComponent, messageComponent) + textComponent = + textComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to translate this message"), + ) + ) + + val randomUUID = UUID.randomUUID() + textComponent = + textComponent.clickEvent( + ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/translatemessage $randomUUID 1") + ) + + TranslateMessage.chatMessages[randomUUID] = TranslateMessage.SentChatMessage(text, player) + + for (p in Bukkit.getOnlinePlayers()) { + if (p.hasPermission("chat-og.premium")) { + p.sendMessage(textComponent) + } + } + } +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/Config.kt b/src/main/kotlin/nl/skbotnl/chatog/Config.kt index f505d42..eb490e7 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/Config.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/Config.kt @@ -1,8 +1,8 @@ package nl.skbotnl.chatog +import java.io.File import net.kyori.adventure.text.format.NamedTextColor import org.bukkit.configuration.file.YamlConfiguration -import java.io.File object Config { lateinit var prefix: String @@ -33,16 +33,13 @@ object Config { data class RGBColor(val r: Int, val g: Int, val b: Int) - /** - * @return True if failed - */ + /** @return True if failed */ fun load(): Boolean { val file = File(ChatOG.plugin.dataFolder, "config.yml") if (!file.exists()) { ChatOG.plugin.saveDefaultConfig() } val config = YamlConfiguration.loadConfiguration(file) - config.save(file) try { prefix = config.get("prefix") as String @@ -80,11 +77,12 @@ object Config { return true } - openAIModel = try { - config.get("model") as String - } catch (_: Exception) { - "" - } + openAIModel = + try { + config.get("model") as String + } catch (_: Exception) { + "" + } } try { @@ -183,7 +181,6 @@ object Config { } } - try { webhook = config.get("webhook") as String } catch (_: Exception) { @@ -215,55 +212,59 @@ object Config { return false } - val messageColors = mapOf( - Pair("BLACK", NamedTextColor.BLACK), - Pair("DARK_BLUE", NamedTextColor.DARK_BLUE), - Pair("DARK_GREEN", NamedTextColor.DARK_GREEN), - Pair("DARK_AQUA", NamedTextColor.DARK_AQUA), - Pair("DARK_RED", NamedTextColor.DARK_RED), - Pair("DARK_PURPLE", NamedTextColor.DARK_PURPLE), - Pair("GOLD", NamedTextColor.GOLD), - Pair("GRAY", NamedTextColor.GRAY), - Pair("DARK_GRAY", NamedTextColor.DARK_GRAY), - Pair("BLUE", NamedTextColor.BLUE), - Pair("GREEN", NamedTextColor.GREEN), - Pair("AQUA", NamedTextColor.AQUA), - Pair("RED", NamedTextColor.RED), - Pair("LIGHT_PURPLE", NamedTextColor.LIGHT_PURPLE), - Pair("YELLOW", NamedTextColor.YELLOW), - Pair("WHITE", NamedTextColor.WHITE), - ) + val messageColors = + mapOf( + Pair("BLACK", NamedTextColor.BLACK), + Pair("DARK_BLUE", NamedTextColor.DARK_BLUE), + Pair("DARK_GREEN", NamedTextColor.DARK_GREEN), + Pair("DARK_AQUA", NamedTextColor.DARK_AQUA), + Pair("DARK_RED", NamedTextColor.DARK_RED), + Pair("DARK_PURPLE", NamedTextColor.DARK_PURPLE), + Pair("GOLD", NamedTextColor.GOLD), + Pair("GRAY", NamedTextColor.GRAY), + Pair("DARK_GRAY", NamedTextColor.DARK_GRAY), + Pair("BLUE", NamedTextColor.BLUE), + Pair("GREEN", NamedTextColor.GREEN), + Pair("AQUA", NamedTextColor.AQUA), + Pair("RED", NamedTextColor.RED), + Pair("LIGHT_PURPLE", NamedTextColor.LIGHT_PURPLE), + Pair("YELLOW", NamedTextColor.YELLOW), + Pair("WHITE", NamedTextColor.WHITE), + ) roles.forEach { val messageColorList = config.getStringList("roles.$it.message_color") - roleMessageColor[it] = if (messageColorList.isEmpty()) { - try { - config.get("roles.$it.message_color") as String - } catch (_: Exception) { - return@forEach - } - - if (!messageColors.contains(messageColorList[0].uppercase())) { - ChatOG.plugin.logger.severe("The message color for \"$it\" (\"${messageColorList[0]}\") is invalid.") - return@forEach - } - - messageColors[messageColorList[0].uppercase()]!! - } else { - if (messageColorList.size != 3) { - ChatOG.plugin.logger.severe("The message color for \"$it\" is not a color or an RGB value.") - return@forEach - } - - messageColorList.forEach colorForEach@{ colorInList -> + roleMessageColor[it] = + if (messageColorList.isEmpty()) { try { - colorInList.toUByte() + config.get("roles.$it.message_color") as String } catch (_: Exception) { - ChatOG.plugin.logger.severe("The RGB value for \"$it\" is invalid.") return@forEach } + + if (!messageColors.contains(messageColorList[0].uppercase())) { + ChatOG.plugin.logger.severe( + "The message color for \"$it\" (\"${messageColorList[0]}\") is invalid." + ) + return@forEach + } + + messageColors[messageColorList[0].uppercase()]!! + } else { + if (messageColorList.size != 3) { + ChatOG.plugin.logger.severe("The message color for \"$it\" is not a color or an RGB value.") + return@forEach + } + + messageColorList.forEach colorForEach@{ colorInList -> + try { + colorInList.toUByte() + } catch (_: Exception) { + ChatOG.plugin.logger.severe("The RGB value for \"$it\" is invalid.") + return@forEach + } + } + RGBColor(messageColorList[0].toInt(), messageColorList[1].toInt(), messageColorList[2].toInt()) } - RGBColor(messageColorList[0].toInt(), messageColorList[1].toInt(), messageColorList[2].toInt()) - } } return false diff --git a/src/main/kotlin/nl/skbotnl/chatog/DiscordBridge.kt b/src/main/kotlin/nl/skbotnl/chatog/DiscordBridge.kt index 32c1de8..fbef174 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/DiscordBridge.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/DiscordBridge.kt @@ -9,6 +9,7 @@ import dev.minn.jda.ktx.generics.getChannel import dev.minn.jda.ktx.jdabuilder.cache import dev.minn.jda.ktx.jdabuilder.intents import dev.minn.jda.ktx.jdabuilder.light +import java.util.* import net.dv8tion.jda.api.JDA import net.dv8tion.jda.api.entities.Activity import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel @@ -32,7 +33,6 @@ import nl.skbotnl.chatog.Helper.removeColor import nl.skbotnl.chatog.Helper.stripGroupMentions import nl.skbotnl.chatog.commands.TranslateMessage import org.bukkit.Bukkit -import java.util.* object DiscordBridge { var jda: JDA? = null @@ -60,17 +60,19 @@ object DiscordBridge { ChatOG.plugin.logger.warning("Config option \"premiumWebhook\" is invalid") } - jda = light(Config.botToken, enableCoroutines = true) { - intents += listOf(GatewayIntent.GUILD_MEMBERS, GatewayIntent.MESSAGE_CONTENT) - cache += listOf(CacheFlag.EMOJI) - setMemberCachePolicy(MemberCachePolicy.ALL) - } + jda = + light(Config.botToken, enableCoroutines = true) { + intents += listOf(GatewayIntent.GUILD_MEMBERS, GatewayIntent.MESSAGE_CONTENT) + cache += listOf(CacheFlag.EMOJI) + setMemberCachePolicy(MemberCachePolicy.ALL) + } jda?.presence?.setPresence(Activity.playing(Config.status), false) jda?.listener { sendMessageWithBot(Config.serverHasStartedMessage) - jda?.getGuildById(Config.guildId)?.upsertCommand(Config.listCommandName, "List all online players.") + jda?.getGuildById(Config.guildId) + ?.upsertCommand(Config.listCommandName, "List all online players.") ?.queue() } @@ -82,15 +84,17 @@ object DiscordBridge { it.hook.sendMessage("There are no players online.").queue() return@listener } - it.hook.sendMessage( - "${ + it.hook + .sendMessage( + "${ Config.listCommandText .replace("%onlineplayers%", Bukkit.getOnlinePlayers().count().toString()) .replace("%maxplayers%", Bukkit.getMaxPlayers().toString()) }\n${ Bukkit.getOnlinePlayers().joinToString(separator = ", ") { player -> player.name } }" - ).queue() + ) + .queue() } catch (e: Exception) { ChatOG.plugin.logger.warning("Could not respond to /list interaction") } @@ -98,7 +102,11 @@ object DiscordBridge { } jda?.listener { - if (it.channel.id != Config.channelId && (if (Config.staffDiscordEnabled) it.channel.id != Config.staffChannelId else true) && (if (Config.premiumDiscordEnabled) it.channel.id != Config.premiumChannelId else true)) { + if ( + it.channel.id != Config.channelId && + (if (Config.staffDiscordEnabled) it.channel.id != Config.staffChannelId else true) && + (if (Config.premiumDiscordEnabled) it.channel.id != Config.premiumChannelId else true) + ) { return@listener } @@ -111,11 +119,12 @@ object DiscordBridge { val user = it.author val member = it.member ?: return@listener val color = member.color - val textColor: TextColor = if (color == null) { - TextColor.color(153, 170, 181) - } else { - TextColor.color(color.rgb) - } + val textColor: TextColor = + if (color == null) { + TextColor.color(153, 170, 181) + } else { + TextColor.color(color.rgb) + } val roles = member.roles val roleIds = roles.map { role -> role.id } @@ -123,52 +132,55 @@ object DiscordBridge { val topRole = roles.maxBy { role -> role.positionRaw } val discordComponent = Component.text("Discord: ").color(TextColor.color(88, 101, 242)) - val userComponent: TextComponent = if (color == null) { - Component.text("@${user.name}").color(NamedTextColor.GRAY) - } else { - Component.text("[#${topRole.name}] @${user.name}").color(textColor) - } + val userComponent: TextComponent = + if (color == null) { + Component.text("@${user.name}").color(NamedTextColor.GRAY) + } else { + Component.text("[#${topRole.name}] @${user.name}").color(textColor) + } - val messageColor = if (Config.roles.isEmpty()) { - NamedTextColor.GRAY - } else { - val roleId = - message.guild.getRoleById(Config.roles.filter { role -> topRole.id == message.guild.getRoleById(role)?.id }[0])?.id - if (roleId != null) { - val roleColor = Config.roleMessageColor[roleId] + val messageColor = + if (Config.roles.isEmpty()) { + NamedTextColor.GRAY + } else { + val roleId = + message.guild + .getRoleById( + Config.roles.filter { role -> topRole.id == message.guild.getRoleById(role)?.id }[0] + ) + ?.id + if (roleId != null) { + val roleColor = Config.roleMessageColor[roleId] - if (roleColor is Config.RGBColor) { - TextColor.color(roleColor.r, roleColor.g, roleColor.b) - } else { - roleColor as NamedTextColor - } - } else NamedTextColor.GRAY - } + if (roleColor is Config.RGBColor) { + TextColor.color(roleColor.r, roleColor.g, roleColor.b) + } else { + roleColor as NamedTextColor + } + } else NamedTextColor.GRAY + } val messageComponents = mutableListOf(Component.text(" >").color(messageColor)) val attachmentComponents = mutableListOf() - if (message.stickers.size != 0) attachmentComponents += Component.text("[Sticker: ${message.stickers[0].name}]") - .color(messageColor) + if (message.stickers.size != 0) + attachmentComponents += Component.text("[Sticker: ${message.stickers[0].name}]").color(messageColor) if (message.attachments.isNotEmpty()) { message.attachments.forEach { attachment -> var linkComponent = Component.text(attachment.url).color(TextColor.color(34, 100, 255)) - linkComponent = linkComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to open link") + linkComponent = + linkComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to open link"), + ) ) - ) - linkComponent = linkComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.OPEN_URL, - attachment.url - ) - ) + linkComponent = + linkComponent.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, attachment.url)) attachmentComponents += linkComponent } @@ -187,7 +199,7 @@ object DiscordBridge { "${Config.prefix}: @${user.name} has posted a disallowed link: ${ word.replace( ".", - "[dot]" + "[dot]", ) }." ) @@ -199,29 +211,29 @@ object DiscordBridge { var linkComponent = Component.text(url.groups[2]!!.value).color(TextColor.color(34, 100, 255)) - linkComponent = linkComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to open link") + linkComponent = + linkComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to open link"), + ) ) - ) - linkComponent = linkComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.OPEN_URL, - url.groups[2]!!.value + linkComponent = + linkComponent.clickEvent( + ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, url.groups[2]!!.value) ) - ) val beforeComponent = Component.text(url.groups[1]?.value ?: "").color(messageColor) val afterComponent = Component.text(url.groups[4]?.value ?: "").color(messageColor) - val fullComponent = Component.join( - JoinConfiguration.noSeparators(), - beforeComponent, - linkComponent, - afterComponent - ) + val fullComponent = + Component.join( + JoinConfiguration.noSeparators(), + beforeComponent, + linkComponent, + afterComponent, + ) messageComponents += fullComponent } continue @@ -229,25 +241,29 @@ object DiscordBridge { var messageText: Component = Component.text(word) if (Config.colorCodeRoles.any { colorCodeRole -> colorCodeRole in roleIds }) { - messageText = if (messageComponents.isNotEmpty()) { - val lastContent = (messageComponents.last() as TextComponent).content() - if (Helper.getColorSection(lastContent) != "" && Helper.getFirstColorSection(word) == "") { - UtilitiesOG.trueogColorize(legacyToMm(Helper.getColorSection(lastContent) + word)) + messageText = + if (messageComponents.isNotEmpty()) { + val lastContent = (messageComponents.last() as TextComponent).content() + if ( + Helper.getColorSection(lastContent) != "" && Helper.getFirstColorSection(word) == "" + ) { + UtilitiesOG.trueogColorize(legacyToMm(Helper.getColorSection(lastContent) + word)) + } else { + UtilitiesOG.trueogColorize(legacyToMm(word)) + } } else { UtilitiesOG.trueogColorize(legacyToMm(word)) } - } else { - UtilitiesOG.trueogColorize(legacyToMm(word)) - } } messageComponents += messageText.color(messageColor) } } - val contentComponent = Component.join( - JoinConfiguration.separator(Component.text(" ")), - messageComponents + attachmentComponents - ) + val contentComponent = + Component.join( + JoinConfiguration.separator(Component.text(" ")), + messageComponents + attachmentComponents, + ) var replyComponent = Component.text("") @@ -255,61 +271,63 @@ object DiscordBridge { val replyMessage = message.messageReference!!.message if (replyMessage != null) { replyComponent = - Component.text("[Reply to: ${if (!replyMessage.isWebhookMessage) "@" else ""}${replyMessage.author.name}] ") + Component.text( + "[Reply to: ${if (!replyMessage.isWebhookMessage) "@" else ""}${replyMessage.author.name}] " + ) .color(NamedTextColor.GREEN) } } - var messageComponent = when (it.channel.id) { - Config.staffChannelId -> { - val staffComponent = Component.text("STAFF | ").color(NamedTextColor.RED) - Component.join( - JoinConfiguration.noSeparators(), - discordComponent, - staffComponent, - replyComponent, - userComponent, - contentComponent - ) + var messageComponent = + when (it.channel.id) { + Config.staffChannelId -> { + val staffComponent = Component.text("STAFF | ").color(NamedTextColor.RED) + Component.join( + JoinConfiguration.noSeparators(), + discordComponent, + staffComponent, + replyComponent, + userComponent, + contentComponent, + ) + } + + Config.premiumChannelId -> { + val premiumComponent = Component.text("PREMIUM | ").color(NamedTextColor.GREEN) + Component.join( + JoinConfiguration.noSeparators(), + discordComponent, + premiumComponent, + replyComponent, + userComponent, + contentComponent, + ) + } + + else -> { + Component.join( + JoinConfiguration.noSeparators(), + discordComponent, + replyComponent, + userComponent, + contentComponent, + ) + } } - Config.premiumChannelId -> { - val premiumComponent = Component.text("PREMIUM | ").color(NamedTextColor.GREEN) - Component.join( - JoinConfiguration.noSeparators(), - discordComponent, - premiumComponent, - replyComponent, - userComponent, - contentComponent + messageComponent = + messageComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to translate this message"), ) - } - - else -> { - Component.join( - JoinConfiguration.noSeparators(), - discordComponent, - replyComponent, - userComponent, - contentComponent - ) - } - } - - messageComponent = messageComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to translate this message") ) - ) val randomUUID = UUID.randomUUID() - messageComponent = messageComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.RUN_COMMAND, - "/translatemessage $randomUUID 2" + messageComponent = + messageComponent.clickEvent( + ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/translatemessage $randomUUID 2") ) - ) when (it.channel.id) { Config.staffChannelId -> { @@ -335,12 +353,13 @@ object DiscordBridge { } } - TranslateMessage.customMessages[randomUUID] = TranslateMessage.SentCustomMessage( - message.contentDisplay, - member.effectiveName, - Component.join(JoinConfiguration.noSeparators(), discordComponent, userComponent), - Component.text(" > ").color(messageColor) - ) + TranslateMessage.customMessages[randomUUID] = + TranslateMessage.SentCustomMessage( + message.contentDisplay, + member.effectiveName, + Component.join(JoinConfiguration.noSeparators(), discordComponent, userComponent), + Component.text(" > ").color(messageColor), + ) } } @@ -363,9 +382,10 @@ object DiscordBridge { return } - val webhookMessage = WebhookMessageBuilder() - .setUsername(removeColor(player)) - .setContent(stripGroupMentions(convertMentions(message))) + val webhookMessage = + WebhookMessageBuilder() + .setUsername(removeColor(player)) + .setContent(stripGroupMentions(convertMentions(message))) if (uuid != null) { webhookMessage.setAvatarUrl("https://minotar.net/helm/$uuid.png") } @@ -381,9 +401,10 @@ object DiscordBridge { return } - val webhookMessage = WebhookMessageBuilder() - .setUsername(removeColor(player)) - .setContent(stripGroupMentions((convertMentions(message)))) + val webhookMessage = + WebhookMessageBuilder() + .setUsername(removeColor(player)) + .setContent(stripGroupMentions((convertMentions(message)))) if (uuid != null) { webhookMessage.setAvatarUrl("https://minotar.net/helm/$uuid.png") } @@ -399,9 +420,10 @@ object DiscordBridge { return } - val webhookMessage = WebhookMessageBuilder() - .setUsername(removeColor(player)) - .setContent(stripGroupMentions((convertMentions(message)))) + val webhookMessage = + WebhookMessageBuilder() + .setUsername(removeColor(player)) + .setContent(stripGroupMentions((convertMentions(message)))) if (uuid != null) { webhookMessage.setAvatarUrl("https://minotar.net/helm/$uuid.png") } @@ -422,9 +444,8 @@ object DiscordBridge { iconUrl = "https://minotar.net/helm/$uuid.png" } - val webhookMessage = WebhookEmbedBuilder() - .setColor(color) - .setAuthor(WebhookEmbed.EmbedAuthor(message, iconUrl, null)) + val webhookMessage = + WebhookEmbedBuilder().setColor(color).setAuthor(WebhookEmbed.EmbedAuthor(message, iconUrl, null)) webhook?.send(webhookMessage.build()) } diff --git a/src/main/kotlin/nl/skbotnl/chatog/EmojiConverter.kt b/src/main/kotlin/nl/skbotnl/chatog/EmojiConverter.kt index 452b56e..4bc8e00 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/EmojiConverter.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/EmojiConverter.kt @@ -3,9 +3,10 @@ package nl.skbotnl.chatog import com.google.gson.JsonParser object EmojiConverter { - private val emojiRegex = Regex( - "[#*0-9]\\uFE0F?\\u20E3|[\\xA9\\xAE\\u203C\\u2049\\u2122\\u2139\\u2194-\\u2199\\u21A9\\u21AA\\u231A\\u231B\\u2328\\u23CF\\u23ED-\\u23EF\\u23F1\\u23F2\\u23F8-\\u23FA\\u24C2\\u25AA\\u25AB\\u25B6\\u25C0\\u25FB\\u25FC\\u25FE\\u2600-\\u2604\\u260E\\u2611\\u2614\\u2615\\u2618\\u2620\\u2622\\u2623\\u2626\\u262A\\u262E\\u262F\\u2638-\\u263A\\u2640\\u2642\\u2648-\\u2653\\u265F\\u2660\\u2663\\u2665\\u2666\\u2668\\u267B\\u267E\\u267F\\u2692\\u2694-\\u2697\\u2699\\u269B\\u269C\\u26A0\\u26A7\\u26AA\\u26B0\\u26B1\\u26BD\\u26BE\\u26C4\\u26C8\\u26CF\\u26D1\\u26E9\\u26F0-\\u26F5\\u26F7\\u26F8\\u26FA\\u2702\\u2708\\u2709\\u270F\\u2712\\u2714\\u2716\\u271D\\u2721\\u2733\\u2734\\u2744\\u2747\\u2757\\u2763\\u27A1\\u2934\\u2935\\u2B05-\\u2B07\\u2B1B\\u2B1C\\u2B55\\u3030\\u303D\\u3297\\u3299\\x{1F004}\\x{1F170}\\x{1F171}\\x{1F17E}\\x{1F17F}\\x{1F202}\\x{1F237}\\x{1F321}\\x{1F324}-\\x{1F32C}\\x{1F336}\\x{1F37D}\\x{1F396}\\x{1F397}\\x{1F399}-\\x{1F39B}\\x{1F39E}\\x{1F39F}\\x{1F3CD}\\x{1F3CE}\\x{1F3D4}-\\x{1F3DF}\\x{1F3F5}\\x{1F3F7}\\x{1F43F}\\x{1F4FD}\\x{1F549}\\x{1F54A}\\x{1F56F}\\x{1F570}\\x{1F573}\\x{1F576}-\\x{1F579}\\x{1F587}\\x{1F58A}-\\x{1F58D}\\x{1F5A5}\\x{1F5A8}\\x{1F5B1}\\x{1F5B2}\\x{1F5BC}\\x{1F5C2}-\\x{1F5C4}\\x{1F5D1}-\\x{1F5D3}\\x{1F5DC}-\\x{1F5DE}\\x{1F5E1}\\x{1F5E3}\\x{1F5E8}\\x{1F5EF}\\x{1F5F3}\\x{1F5FA}\\x{1F6CB}\\x{1F6CD}-\\x{1F6CF}\\x{1F6E0}-\\x{1F6E5}\\x{1F6E9}\\x{1F6F0}\\x{1F6F3}]\\uFE0F?|[\\u261D\\u270C\\u270D\\x{1F574}\\x{1F590}][\\uFE0F\\x{1F3FB}-\\x{1F3FF}]?|[\\u26F9\\x{1F3CB}\\x{1F3CC}\\x{1F575}][\\uFE0F\\x{1F3FB}-\\x{1F3FF}]?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\u270A\\u270B\\x{1F385}\\x{1F3C2}\\x{1F3C7}\\x{1F442}\\x{1F443}\\x{1F446}-\\x{1F450}\\x{1F466}\\x{1F467}\\x{1F46B}-\\x{1F46D}\\x{1F472}\\x{1F474}-\\x{1F476}\\x{1F478}\\x{1F47C}\\x{1F483}\\x{1F485}\\x{1F48F}\\x{1F491}\\x{1F4AA}\\x{1F57A}\\x{1F595}\\x{1F596}\\x{1F64C}\\x{1F64F}\\x{1F6C0}\\x{1F6CC}\\x{1F90C}\\x{1F90F}\\x{1F918}-\\x{1F91F}\\x{1F930}-\\x{1F934}\\x{1F936}\\x{1F977}\\x{1F9B5}\\x{1F9B6}\\x{1F9BB}\\x{1F9D2}\\x{1F9D3}\\x{1F9D5}\\x{1FAC3}-\\x{1FAC5}\\x{1FAF0}\\x{1FAF2}-\\x{1FAF8}][\\x{1F3FB}-\\x{1F3FF}]?|[\\x{1F3C3}\\x{1F6B6}\\x{1F9CE}][\\x{1F3FB}-\\x{1F3FF}]?(?:\\u200D(?:[\\u2640\\u2642]\\uFE0F?(?:\\u200D\\u27A1\\uFE0F?)?|\\u27A1\\uFE0F?))?|[\\x{1F3C4}\\x{1F3CA}\\x{1F46E}\\x{1F470}\\x{1F471}\\x{1F473}\\x{1F477}\\x{1F481}\\x{1F482}\\x{1F486}\\x{1F487}\\x{1F645}-\\x{1F647}\\x{1F64B}\\x{1F64D}\\x{1F64E}\\x{1F6A3}\\x{1F6B4}\\x{1F6B5}\\x{1F926}\\x{1F935}\\x{1F937}-\\x{1F939}\\x{1F93D}\\x{1F93E}\\x{1F9B8}\\x{1F9B9}\\x{1F9CD}\\x{1F9CF}\\x{1F9D4}\\x{1F9D6}-\\x{1F9DD}][\\x{1F3FB}-\\x{1F3FF}]?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\x{1F46F}\\x{1F9DE}\\x{1F9DF}](?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\u23E9-\\u23EC\\u23F0\\u23F3\\u25FD\\u2693\\u26A1\\u26AB\\u26C5\\u26CE\\u26D4\\u26EA\\u26FD\\u2705\\u2728\\u274C\\u274E\\u2753-\\u2755\\u2795-\\u2797\\u27B0\\u27BF\\u2B50\\x{1F0CF}\\x{1F18E}\\x{1F191}-\\x{1F19A}\\x{1F201}\\x{1F21A}\\x{1F22F}\\x{1F232}-\\x{1F236}\\x{1F238}-\\x{1F23A}\\x{1F250}\\x{1F251}\\x{1F300}-\\x{1F320}\\x{1F32D}-\\x{1F335}\\x{1F337}-\\x{1F343}\\x{1F345}-\\x{1F34A}\\x{1F34C}-\\x{1F37C}\\x{1F37E}-\\x{1F384}\\x{1F386}-\\x{1F393}\\x{1F3A0}-\\x{1F3C1}\\x{1F3C5}\\x{1F3C6}\\x{1F3C8}\\x{1F3C9}\\x{1F3CF}-\\x{1F3D3}\\x{1F3E0}-\\x{1F3F0}\\x{1F3F8}-\\x{1F407}\\x{1F409}-\\x{1F414}\\x{1F416}-\\x{1F425}\\x{1F427}-\\x{1F43A}\\x{1F43C}-\\x{1F43E}\\x{1F440}\\x{1F444}\\x{1F445}\\x{1F451}-\\x{1F465}\\x{1F46A}\\x{1F479}-\\x{1F47B}\\x{1F47D}-\\x{1F480}\\x{1F484}\\x{1F488}-\\x{1F48E}\\x{1F490}\\x{1F492}-\\x{1F4A9}\\x{1F4AB}-\\x{1F4FC}\\x{1F4FF}-\\x{1F53D}\\x{1F54B}-\\x{1F54E}\\x{1F550}-\\x{1F567}\\x{1F5A4}\\x{1F5FB}-\\x{1F62D}\\x{1F62F}-\\x{1F634}\\x{1F637}-\\x{1F641}\\x{1F643}\\x{1F644}\\x{1F648}-\\x{1F64A}\\x{1F680}-\\x{1F6A2}\\x{1F6A4}-\\x{1F6B3}\\x{1F6B7}-\\x{1F6BF}\\x{1F6C1}-\\x{1F6C5}\\x{1F6D0}-\\x{1F6D2}\\x{1F6D5}-\\x{1F6D7}\\x{1F6DC}-\\x{1F6DF}\\x{1F6EB}\\x{1F6EC}\\x{1F6F4}-\\x{1F6FC}\\x{1F7E0}-\\x{1F7EB}\\x{1F7F0}\\x{1F90D}\\x{1F90E}\\x{1F910}-\\x{1F917}\\x{1F920}-\\x{1F925}\\x{1F927}-\\x{1F92F}\\x{1F93A}\\x{1F93F}-\\x{1F945}\\x{1F947}-\\x{1F976}\\x{1F978}-\\x{1F9B4}\\x{1F9B7}\\x{1F9BA}\\x{1F9BC}-\\x{1F9CC}\\x{1F9D0}\\x{1F9E0}-\\x{1F9FF}\\x{1FA70}-\\x{1FA7C}\\x{1FA80}-\\x{1FA89}\\x{1FA8F}-\\x{1FAC2}\\x{1FAC6}\\x{1FACE}-\\x{1FADC}\\x{1FADF}-\\x{1FAE9}]|\\u26D3\\uFE0F?(?:\\u200D\\x{1F4A5})?|\\u2764\\uFE0F?(?:\\u200D[\\x{1F525}\\x{1FA79}])?|\\x{1F1E6}[\\x{1F1E8}-\\x{1F1EC}\\x{1F1EE}\\x{1F1F1}\\x{1F1F2}\\x{1F1F4}\\x{1F1F6}-\\x{1F1FA}\\x{1F1FC}\\x{1F1FD}\\x{1F1FF}]|\\x{1F1E7}[\\x{1F1E6}\\x{1F1E7}\\x{1F1E9}-\\x{1F1EF}\\x{1F1F1}-\\x{1F1F4}\\x{1F1F6}-\\x{1F1F9}\\x{1F1FB}\\x{1F1FC}\\x{1F1FE}\\x{1F1FF}]|\\x{1F1E8}[\\x{1F1E6}\\x{1F1E8}\\x{1F1E9}\\x{1F1EB}-\\x{1F1EE}\\x{1F1F0}-\\x{1F1F7}\\x{1F1FA}-\\x{1F1FF}]|\\x{1F1E9}[\\x{1F1EA}\\x{1F1EC}\\x{1F1EF}\\x{1F1F0}\\x{1F1F2}\\x{1F1F4}\\x{1F1FF}]|\\x{1F1EA}[\\x{1F1E6}\\x{1F1E8}\\x{1F1EA}\\x{1F1EC}\\x{1F1ED}\\x{1F1F7}-\\x{1F1FA}]|\\x{1F1EB}[\\x{1F1EE}-\\x{1F1F0}\\x{1F1F2}\\x{1F1F4}\\x{1F1F7}]|\\x{1F1EC}[\\x{1F1E6}\\x{1F1E7}\\x{1F1E9}-\\x{1F1EE}\\x{1F1F1}-\\x{1F1F3}\\x{1F1F5}-\\x{1F1FA}\\x{1F1FC}\\x{1F1FE}]|\\x{1F1ED}[\\x{1F1F0}\\x{1F1F2}\\x{1F1F3}\\x{1F1F7}\\x{1F1F9}\\x{1F1FA}]|\\x{1F1EE}[\\x{1F1E8}-\\x{1F1EA}\\x{1F1F1}-\\x{1F1F4}\\x{1F1F6}-\\x{1F1F9}]|\\x{1F1EF}[\\x{1F1EA}\\x{1F1F2}\\x{1F1F4}\\x{1F1F5}]|\\x{1F1F0}[\\x{1F1EA}\\x{1F1EC}-\\x{1F1EE}\\x{1F1F2}\\x{1F1F3}\\x{1F1F5}\\x{1F1F7}\\x{1F1FC}\\x{1F1FE}\\x{1F1FF}]|\\x{1F1F1}[\\x{1F1E6}-\\x{1F1E8}\\x{1F1EE}\\x{1F1F0}\\x{1F1F7}-\\x{1F1FB}\\x{1F1FE}]|\\x{1F1F2}[\\x{1F1E6}\\x{1F1E8}-\\x{1F1ED}\\x{1F1F0}-\\x{1F1FF}]|\\x{1F1F3}[\\x{1F1E6}\\x{1F1E8}\\x{1F1EA}-\\x{1F1EC}\\x{1F1EE}\\x{1F1F1}\\x{1F1F4}\\x{1F1F5}\\x{1F1F7}\\x{1F1FA}\\x{1F1FF}]|\\x{1F1F4}\\x{1F1F2}|\\x{1F1F5}[\\x{1F1E6}\\x{1F1EA}-\\x{1F1ED}\\x{1F1F0}-\\x{1F1F3}\\x{1F1F7}-\\x{1F1F9}\\x{1F1FC}\\x{1F1FE}]|\\x{1F1F6}\\x{1F1E6}|\\x{1F1F7}[\\x{1F1EA}\\x{1F1F4}\\x{1F1F8}\\x{1F1FA}\\x{1F1FC}]|\\x{1F1F8}[\\x{1F1E6}-\\x{1F1EA}\\x{1F1EC}-\\x{1F1F4}\\x{1F1F7}-\\x{1F1F9}\\x{1F1FB}\\x{1F1FD}-\\x{1F1FF}]|\\x{1F1F9}[\\x{1F1E6}\\x{1F1E8}\\x{1F1E9}\\x{1F1EB}-\\x{1F1ED}\\x{1F1EF}-\\x{1F1F4}\\x{1F1F7}\\x{1F1F9}\\x{1F1FB}\\x{1F1FC}\\x{1F1FF}]|\\x{1F1FA}[\\x{1F1E6}\\x{1F1EC}\\x{1F1F2}\\x{1F1F3}\\x{1F1F8}\\x{1F1FE}\\x{1F1FF}]|\\x{1F1FB}[\\x{1F1E6}\\x{1F1E8}\\x{1F1EA}\\x{1F1EC}\\x{1F1EE}\\x{1F1F3}\\x{1F1FA}]|\\x{1F1FC}[\\x{1F1EB}\\x{1F1F8}]|\\x{1F1FD}\\x{1F1F0}|\\x{1F1FE}[\\x{1F1EA}\\x{1F1F9}]|\\x{1F1FF}[\\x{1F1E6}\\x{1F1F2}\\x{1F1FC}]|\\x{1F344}(?:\\u200D\\x{1F7EB})?|\\x{1F34B}(?:\\u200D\\x{1F7E9})?|\\x{1F3F3}\\uFE0F?(?:\\u200D(?:\\u26A7\\uFE0F?|\\x{1F308}))?|\\x{1F3F4}(?:\\u200D\\u2620\\uFE0F?|\\x{E0067}\\x{E0062}(?:\\x{E0065}\\x{E006E}\\x{E0067}|\\x{E0073}\\x{E0063}\\x{E0074}|\\x{E0077}\\x{E006C}\\x{E0073})\\x{E007F})?|\\x{1F408}(?:\\u200D\\u2B1B)?|\\x{1F415}(?:\\u200D\\x{1F9BA})?|\\x{1F426}(?:\\u200D[\\u2B1B\\x{1F525}])?|\\x{1F43B}(?:\\u200D\\u2744\\uFE0F?)?|\\x{1F441}\\uFE0F?(?:\\u200D\\x{1F5E8}\\uFE0F?)?|\\x{1F468}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F468}\\x{1F469}]\\u200D(?:\\x{1F466}(?:\\u200D\\x{1F466})?|\\x{1F467}(?:\\u200D[\\x{1F466}\\x{1F467}])?)|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}|\\x{1F466}(?:\\u200D\\x{1F466})?|\\x{1F467}(?:\\u200D[\\x{1F466}\\x{1F467}])?)|\\x{1F3FB}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FC}-\\x{1F3FF}]))?|\\x{1F3FC}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FB}\\x{1F3FD}-\\x{1F3FF}]))?|\\x{1F3FD}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FB}\\x{1F3FC}\\x{1F3FE}\\x{1F3FF}]))?|\\x{1F3FE}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FB}-\\x{1F3FD}\\x{1F3FF}]))?|\\x{1F3FF}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FB}-\\x{1F3FE}]))?)?|\\x{1F469}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?[\\x{1F468}\\x{1F469}]|\\x{1F466}(?:\\u200D\\x{1F466})?|\\x{1F467}(?:\\u200D[\\x{1F466}\\x{1F467}])?|\\x{1F469}\\u200D(?:\\x{1F466}(?:\\u200D\\x{1F466})?|\\x{1F467}(?:\\u200D[\\x{1F466}\\x{1F467}])?))|\\x{1F3FB}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FC}-\\x{1F3FF}]))?|\\x{1F3FC}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FB}\\x{1F3FD}-\\x{1F3FF}]))?|\\x{1F3FD}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FB}\\x{1F3FC}\\x{1F3FE}\\x{1F3FF}]))?|\\x{1F3FE}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FB}-\\x{1F3FD}\\x{1F3FF}]))?|\\x{1F3FF}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FB}-\\x{1F3FE}]))?)?|\\x{1F62E}(?:\\u200D\\x{1F4A8})?|\\x{1F635}(?:\\u200D\\x{1F4AB})?|\\x{1F636}(?:\\u200D\\x{1F32B}\\uFE0F?)?|\\x{1F642}(?:\\u200D[\\u2194\\u2195]\\uFE0F?)?|\\x{1F93C}(?:[\\x{1F3FB}-\\x{1F3FF}]|\\u200D[\\u2640\\u2642]\\uFE0F?)?|\\x{1F9D1}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\x{1F91D}\\u200D\\x{1F9D1}|\\x{1F9D1}\\u200D\\x{1F9D2}(?:\\u200D\\x{1F9D2})?|\\x{1F9D2}(?:\\u200D\\x{1F9D2})?)|\\x{1F3FB}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FC}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?|\\x{1F3FC}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FB}\\x{1F3FD}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?|\\x{1F3FD}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FB}\\x{1F3FC}\\x{1F3FE}\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?|\\x{1F3FE}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FD}\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?|\\x{1F3FF}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FE}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?)?|\\x{1FAF1}(?:\\x{1F3FB}(?:\\u200D\\x{1FAF2}[\\x{1F3FC}-\\x{1F3FF}])?|\\x{1F3FC}(?:\\u200D\\x{1FAF2}[\\x{1F3FB}\\x{1F3FD}-\\x{1F3FF}])?|\\x{1F3FD}(?:\\u200D\\x{1FAF2}[\\x{1F3FB}\\x{1F3FC}\\x{1F3FE}\\x{1F3FF}])?|\\x{1F3FE}(?:\\u200D\\x{1FAF2}[\\x{1F3FB}-\\x{1F3FD}\\x{1F3FF}])?|\\x{1F3FF}(?:\\u200D\\x{1FAF2}[\\x{1F3FB}-\\x{1F3FE}])?)?" - ) + private val emojiRegex = + Regex( + "[#*0-9]\\uFE0F?\\u20E3|[\\xA9\\xAE\\u203C\\u2049\\u2122\\u2139\\u2194-\\u2199\\u21A9\\u21AA\\u231A\\u231B\\u2328\\u23CF\\u23ED-\\u23EF\\u23F1\\u23F2\\u23F8-\\u23FA\\u24C2\\u25AA\\u25AB\\u25B6\\u25C0\\u25FB\\u25FC\\u25FE\\u2600-\\u2604\\u260E\\u2611\\u2614\\u2615\\u2618\\u2620\\u2622\\u2623\\u2626\\u262A\\u262E\\u262F\\u2638-\\u263A\\u2640\\u2642\\u2648-\\u2653\\u265F\\u2660\\u2663\\u2665\\u2666\\u2668\\u267B\\u267E\\u267F\\u2692\\u2694-\\u2697\\u2699\\u269B\\u269C\\u26A0\\u26A7\\u26AA\\u26B0\\u26B1\\u26BD\\u26BE\\u26C4\\u26C8\\u26CF\\u26D1\\u26E9\\u26F0-\\u26F5\\u26F7\\u26F8\\u26FA\\u2702\\u2708\\u2709\\u270F\\u2712\\u2714\\u2716\\u271D\\u2721\\u2733\\u2734\\u2744\\u2747\\u2757\\u2763\\u27A1\\u2934\\u2935\\u2B05-\\u2B07\\u2B1B\\u2B1C\\u2B55\\u3030\\u303D\\u3297\\u3299\\x{1F004}\\x{1F170}\\x{1F171}\\x{1F17E}\\x{1F17F}\\x{1F202}\\x{1F237}\\x{1F321}\\x{1F324}-\\x{1F32C}\\x{1F336}\\x{1F37D}\\x{1F396}\\x{1F397}\\x{1F399}-\\x{1F39B}\\x{1F39E}\\x{1F39F}\\x{1F3CD}\\x{1F3CE}\\x{1F3D4}-\\x{1F3DF}\\x{1F3F5}\\x{1F3F7}\\x{1F43F}\\x{1F4FD}\\x{1F549}\\x{1F54A}\\x{1F56F}\\x{1F570}\\x{1F573}\\x{1F576}-\\x{1F579}\\x{1F587}\\x{1F58A}-\\x{1F58D}\\x{1F5A5}\\x{1F5A8}\\x{1F5B1}\\x{1F5B2}\\x{1F5BC}\\x{1F5C2}-\\x{1F5C4}\\x{1F5D1}-\\x{1F5D3}\\x{1F5DC}-\\x{1F5DE}\\x{1F5E1}\\x{1F5E3}\\x{1F5E8}\\x{1F5EF}\\x{1F5F3}\\x{1F5FA}\\x{1F6CB}\\x{1F6CD}-\\x{1F6CF}\\x{1F6E0}-\\x{1F6E5}\\x{1F6E9}\\x{1F6F0}\\x{1F6F3}]\\uFE0F?|[\\u261D\\u270C\\u270D\\x{1F574}\\x{1F590}][\\uFE0F\\x{1F3FB}-\\x{1F3FF}]?|[\\u26F9\\x{1F3CB}\\x{1F3CC}\\x{1F575}][\\uFE0F\\x{1F3FB}-\\x{1F3FF}]?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\u270A\\u270B\\x{1F385}\\x{1F3C2}\\x{1F3C7}\\x{1F442}\\x{1F443}\\x{1F446}-\\x{1F450}\\x{1F466}\\x{1F467}\\x{1F46B}-\\x{1F46D}\\x{1F472}\\x{1F474}-\\x{1F476}\\x{1F478}\\x{1F47C}\\x{1F483}\\x{1F485}\\x{1F48F}\\x{1F491}\\x{1F4AA}\\x{1F57A}\\x{1F595}\\x{1F596}\\x{1F64C}\\x{1F64F}\\x{1F6C0}\\x{1F6CC}\\x{1F90C}\\x{1F90F}\\x{1F918}-\\x{1F91F}\\x{1F930}-\\x{1F934}\\x{1F936}\\x{1F977}\\x{1F9B5}\\x{1F9B6}\\x{1F9BB}\\x{1F9D2}\\x{1F9D3}\\x{1F9D5}\\x{1FAC3}-\\x{1FAC5}\\x{1FAF0}\\x{1FAF2}-\\x{1FAF8}][\\x{1F3FB}-\\x{1F3FF}]?|[\\x{1F3C3}\\x{1F6B6}\\x{1F9CE}][\\x{1F3FB}-\\x{1F3FF}]?(?:\\u200D(?:[\\u2640\\u2642]\\uFE0F?(?:\\u200D\\u27A1\\uFE0F?)?|\\u27A1\\uFE0F?))?|[\\x{1F3C4}\\x{1F3CA}\\x{1F46E}\\x{1F470}\\x{1F471}\\x{1F473}\\x{1F477}\\x{1F481}\\x{1F482}\\x{1F486}\\x{1F487}\\x{1F645}-\\x{1F647}\\x{1F64B}\\x{1F64D}\\x{1F64E}\\x{1F6A3}\\x{1F6B4}\\x{1F6B5}\\x{1F926}\\x{1F935}\\x{1F937}-\\x{1F939}\\x{1F93D}\\x{1F93E}\\x{1F9B8}\\x{1F9B9}\\x{1F9CD}\\x{1F9CF}\\x{1F9D4}\\x{1F9D6}-\\x{1F9DD}][\\x{1F3FB}-\\x{1F3FF}]?(?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\x{1F46F}\\x{1F9DE}\\x{1F9DF}](?:\\u200D[\\u2640\\u2642]\\uFE0F?)?|[\\u23E9-\\u23EC\\u23F0\\u23F3\\u25FD\\u2693\\u26A1\\u26AB\\u26C5\\u26CE\\u26D4\\u26EA\\u26FD\\u2705\\u2728\\u274C\\u274E\\u2753-\\u2755\\u2795-\\u2797\\u27B0\\u27BF\\u2B50\\x{1F0CF}\\x{1F18E}\\x{1F191}-\\x{1F19A}\\x{1F201}\\x{1F21A}\\x{1F22F}\\x{1F232}-\\x{1F236}\\x{1F238}-\\x{1F23A}\\x{1F250}\\x{1F251}\\x{1F300}-\\x{1F320}\\x{1F32D}-\\x{1F335}\\x{1F337}-\\x{1F343}\\x{1F345}-\\x{1F34A}\\x{1F34C}-\\x{1F37C}\\x{1F37E}-\\x{1F384}\\x{1F386}-\\x{1F393}\\x{1F3A0}-\\x{1F3C1}\\x{1F3C5}\\x{1F3C6}\\x{1F3C8}\\x{1F3C9}\\x{1F3CF}-\\x{1F3D3}\\x{1F3E0}-\\x{1F3F0}\\x{1F3F8}-\\x{1F407}\\x{1F409}-\\x{1F414}\\x{1F416}-\\x{1F425}\\x{1F427}-\\x{1F43A}\\x{1F43C}-\\x{1F43E}\\x{1F440}\\x{1F444}\\x{1F445}\\x{1F451}-\\x{1F465}\\x{1F46A}\\x{1F479}-\\x{1F47B}\\x{1F47D}-\\x{1F480}\\x{1F484}\\x{1F488}-\\x{1F48E}\\x{1F490}\\x{1F492}-\\x{1F4A9}\\x{1F4AB}-\\x{1F4FC}\\x{1F4FF}-\\x{1F53D}\\x{1F54B}-\\x{1F54E}\\x{1F550}-\\x{1F567}\\x{1F5A4}\\x{1F5FB}-\\x{1F62D}\\x{1F62F}-\\x{1F634}\\x{1F637}-\\x{1F641}\\x{1F643}\\x{1F644}\\x{1F648}-\\x{1F64A}\\x{1F680}-\\x{1F6A2}\\x{1F6A4}-\\x{1F6B3}\\x{1F6B7}-\\x{1F6BF}\\x{1F6C1}-\\x{1F6C5}\\x{1F6D0}-\\x{1F6D2}\\x{1F6D5}-\\x{1F6D7}\\x{1F6DC}-\\x{1F6DF}\\x{1F6EB}\\x{1F6EC}\\x{1F6F4}-\\x{1F6FC}\\x{1F7E0}-\\x{1F7EB}\\x{1F7F0}\\x{1F90D}\\x{1F90E}\\x{1F910}-\\x{1F917}\\x{1F920}-\\x{1F925}\\x{1F927}-\\x{1F92F}\\x{1F93A}\\x{1F93F}-\\x{1F945}\\x{1F947}-\\x{1F976}\\x{1F978}-\\x{1F9B4}\\x{1F9B7}\\x{1F9BA}\\x{1F9BC}-\\x{1F9CC}\\x{1F9D0}\\x{1F9E0}-\\x{1F9FF}\\x{1FA70}-\\x{1FA7C}\\x{1FA80}-\\x{1FA89}\\x{1FA8F}-\\x{1FAC2}\\x{1FAC6}\\x{1FACE}-\\x{1FADC}\\x{1FADF}-\\x{1FAE9}]|\\u26D3\\uFE0F?(?:\\u200D\\x{1F4A5})?|\\u2764\\uFE0F?(?:\\u200D[\\x{1F525}\\x{1FA79}])?|\\x{1F1E6}[\\x{1F1E8}-\\x{1F1EC}\\x{1F1EE}\\x{1F1F1}\\x{1F1F2}\\x{1F1F4}\\x{1F1F6}-\\x{1F1FA}\\x{1F1FC}\\x{1F1FD}\\x{1F1FF}]|\\x{1F1E7}[\\x{1F1E6}\\x{1F1E7}\\x{1F1E9}-\\x{1F1EF}\\x{1F1F1}-\\x{1F1F4}\\x{1F1F6}-\\x{1F1F9}\\x{1F1FB}\\x{1F1FC}\\x{1F1FE}\\x{1F1FF}]|\\x{1F1E8}[\\x{1F1E6}\\x{1F1E8}\\x{1F1E9}\\x{1F1EB}-\\x{1F1EE}\\x{1F1F0}-\\x{1F1F7}\\x{1F1FA}-\\x{1F1FF}]|\\x{1F1E9}[\\x{1F1EA}\\x{1F1EC}\\x{1F1EF}\\x{1F1F0}\\x{1F1F2}\\x{1F1F4}\\x{1F1FF}]|\\x{1F1EA}[\\x{1F1E6}\\x{1F1E8}\\x{1F1EA}\\x{1F1EC}\\x{1F1ED}\\x{1F1F7}-\\x{1F1FA}]|\\x{1F1EB}[\\x{1F1EE}-\\x{1F1F0}\\x{1F1F2}\\x{1F1F4}\\x{1F1F7}]|\\x{1F1EC}[\\x{1F1E6}\\x{1F1E7}\\x{1F1E9}-\\x{1F1EE}\\x{1F1F1}-\\x{1F1F3}\\x{1F1F5}-\\x{1F1FA}\\x{1F1FC}\\x{1F1FE}]|\\x{1F1ED}[\\x{1F1F0}\\x{1F1F2}\\x{1F1F3}\\x{1F1F7}\\x{1F1F9}\\x{1F1FA}]|\\x{1F1EE}[\\x{1F1E8}-\\x{1F1EA}\\x{1F1F1}-\\x{1F1F4}\\x{1F1F6}-\\x{1F1F9}]|\\x{1F1EF}[\\x{1F1EA}\\x{1F1F2}\\x{1F1F4}\\x{1F1F5}]|\\x{1F1F0}[\\x{1F1EA}\\x{1F1EC}-\\x{1F1EE}\\x{1F1F2}\\x{1F1F3}\\x{1F1F5}\\x{1F1F7}\\x{1F1FC}\\x{1F1FE}\\x{1F1FF}]|\\x{1F1F1}[\\x{1F1E6}-\\x{1F1E8}\\x{1F1EE}\\x{1F1F0}\\x{1F1F7}-\\x{1F1FB}\\x{1F1FE}]|\\x{1F1F2}[\\x{1F1E6}\\x{1F1E8}-\\x{1F1ED}\\x{1F1F0}-\\x{1F1FF}]|\\x{1F1F3}[\\x{1F1E6}\\x{1F1E8}\\x{1F1EA}-\\x{1F1EC}\\x{1F1EE}\\x{1F1F1}\\x{1F1F4}\\x{1F1F5}\\x{1F1F7}\\x{1F1FA}\\x{1F1FF}]|\\x{1F1F4}\\x{1F1F2}|\\x{1F1F5}[\\x{1F1E6}\\x{1F1EA}-\\x{1F1ED}\\x{1F1F0}-\\x{1F1F3}\\x{1F1F7}-\\x{1F1F9}\\x{1F1FC}\\x{1F1FE}]|\\x{1F1F6}\\x{1F1E6}|\\x{1F1F7}[\\x{1F1EA}\\x{1F1F4}\\x{1F1F8}\\x{1F1FA}\\x{1F1FC}]|\\x{1F1F8}[\\x{1F1E6}-\\x{1F1EA}\\x{1F1EC}-\\x{1F1F4}\\x{1F1F7}-\\x{1F1F9}\\x{1F1FB}\\x{1F1FD}-\\x{1F1FF}]|\\x{1F1F9}[\\x{1F1E6}\\x{1F1E8}\\x{1F1E9}\\x{1F1EB}-\\x{1F1ED}\\x{1F1EF}-\\x{1F1F4}\\x{1F1F7}\\x{1F1F9}\\x{1F1FB}\\x{1F1FC}\\x{1F1FF}]|\\x{1F1FA}[\\x{1F1E6}\\x{1F1EC}\\x{1F1F2}\\x{1F1F3}\\x{1F1F8}\\x{1F1FE}\\x{1F1FF}]|\\x{1F1FB}[\\x{1F1E6}\\x{1F1E8}\\x{1F1EA}\\x{1F1EC}\\x{1F1EE}\\x{1F1F3}\\x{1F1FA}]|\\x{1F1FC}[\\x{1F1EB}\\x{1F1F8}]|\\x{1F1FD}\\x{1F1F0}|\\x{1F1FE}[\\x{1F1EA}\\x{1F1F9}]|\\x{1F1FF}[\\x{1F1E6}\\x{1F1F2}\\x{1F1FC}]|\\x{1F344}(?:\\u200D\\x{1F7EB})?|\\x{1F34B}(?:\\u200D\\x{1F7E9})?|\\x{1F3F3}\\uFE0F?(?:\\u200D(?:\\u26A7\\uFE0F?|\\x{1F308}))?|\\x{1F3F4}(?:\\u200D\\u2620\\uFE0F?|\\x{E0067}\\x{E0062}(?:\\x{E0065}\\x{E006E}\\x{E0067}|\\x{E0073}\\x{E0063}\\x{E0074}|\\x{E0077}\\x{E006C}\\x{E0073})\\x{E007F})?|\\x{1F408}(?:\\u200D\\u2B1B)?|\\x{1F415}(?:\\u200D\\x{1F9BA})?|\\x{1F426}(?:\\u200D[\\u2B1B\\x{1F525}])?|\\x{1F43B}(?:\\u200D\\u2744\\uFE0F?)?|\\x{1F441}\\uFE0F?(?:\\u200D\\x{1F5E8}\\uFE0F?)?|\\x{1F468}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F468}\\x{1F469}]\\u200D(?:\\x{1F466}(?:\\u200D\\x{1F466})?|\\x{1F467}(?:\\u200D[\\x{1F466}\\x{1F467}])?)|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}|\\x{1F466}(?:\\u200D\\x{1F466})?|\\x{1F467}(?:\\u200D[\\x{1F466}\\x{1F467}])?)|\\x{1F3FB}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FC}-\\x{1F3FF}]))?|\\x{1F3FC}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FB}\\x{1F3FD}-\\x{1F3FF}]))?|\\x{1F3FD}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FB}\\x{1F3FC}\\x{1F3FE}\\x{1F3FF}]))?|\\x{1F3FE}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FB}-\\x{1F3FD}\\x{1F3FF}]))?|\\x{1F3FF}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F468}[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F468}[\\x{1F3FB}-\\x{1F3FE}]))?)?|\\x{1F469}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?[\\x{1F468}\\x{1F469}]|\\x{1F466}(?:\\u200D\\x{1F466})?|\\x{1F467}(?:\\u200D[\\x{1F466}\\x{1F467}])?|\\x{1F469}\\u200D(?:\\x{1F466}(?:\\u200D\\x{1F466})?|\\x{1F467}(?:\\u200D[\\x{1F466}\\x{1F467}])?))|\\x{1F3FB}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FC}-\\x{1F3FF}]))?|\\x{1F3FC}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FB}\\x{1F3FD}-\\x{1F3FF}]))?|\\x{1F3FD}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FB}\\x{1F3FC}\\x{1F3FE}\\x{1F3FF}]))?|\\x{1F3FE}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FB}-\\x{1F3FD}\\x{1F3FF}]))?|\\x{1F3FF}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:[\\x{1F468}\\x{1F469}]|\\x{1F48B}\\u200D[\\x{1F468}\\x{1F469}])[\\x{1F3FB}-\\x{1F3FF}]|\\x{1F91D}\\u200D[\\x{1F468}\\x{1F469}][\\x{1F3FB}-\\x{1F3FE}]))?)?|\\x{1F62E}(?:\\u200D\\x{1F4A8})?|\\x{1F635}(?:\\u200D\\x{1F4AB})?|\\x{1F636}(?:\\u200D\\x{1F32B}\\uFE0F?)?|\\x{1F642}(?:\\u200D[\\u2194\\u2195]\\uFE0F?)?|\\x{1F93C}(?:[\\x{1F3FB}-\\x{1F3FF}]|\\u200D[\\u2640\\u2642]\\uFE0F?)?|\\x{1F9D1}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\x{1F91D}\\u200D\\x{1F9D1}|\\x{1F9D1}\\u200D\\x{1F9D2}(?:\\u200D\\x{1F9D2})?|\\x{1F9D2}(?:\\u200D\\x{1F9D2})?)|\\x{1F3FB}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FC}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?|\\x{1F3FC}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FB}\\x{1F3FD}-\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?|\\x{1F3FD}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FB}\\x{1F3FC}\\x{1F3FE}\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?|\\x{1F3FE}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FD}\\x{1F3FF}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?|\\x{1F3FF}(?:\\u200D(?:[\\u2695\\u2696\\u2708]\\uFE0F?|[\\x{1F9AF}\\x{1F9BC}\\x{1F9BD}](?:\\u200D\\u27A1\\uFE0F?)?|[\\x{1F33E}\\x{1F373}\\x{1F37C}\\x{1F384}\\x{1F393}\\x{1F3A4}\\x{1F3A8}\\x{1F3EB}\\x{1F3ED}\\x{1F4BB}\\x{1F4BC}\\x{1F527}\\x{1F52C}\\x{1F680}\\x{1F692}\\x{1F9B0}-\\x{1F9B3}]|\\u2764\\uFE0F?\\u200D(?:\\x{1F48B}\\u200D)?\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FE}]|\\x{1F91D}\\u200D\\x{1F9D1}[\\x{1F3FB}-\\x{1F3FF}]))?)?|\\x{1FAF1}(?:\\x{1F3FB}(?:\\u200D\\x{1FAF2}[\\x{1F3FC}-\\x{1F3FF}])?|\\x{1F3FC}(?:\\u200D\\x{1FAF2}[\\x{1F3FB}\\x{1F3FD}-\\x{1F3FF}])?|\\x{1F3FD}(?:\\u200D\\x{1FAF2}[\\x{1F3FB}\\x{1F3FC}\\x{1F3FE}\\x{1F3FF}])?|\\x{1F3FE}(?:\\u200D\\x{1FAF2}[\\x{1F3FB}-\\x{1F3FD}\\x{1F3FF}])?|\\x{1F3FF}(?:\\u200D\\x{1FAF2}[\\x{1F3FB}-\\x{1F3FE}])?)?" + ) private var emojiMap: HashMap = hashMapOf() fun load() { @@ -25,9 +26,7 @@ object EmojiConverter { fun replaceEmojisWithNames(text: String): String { var tempText = text - emojiRegex.findAll(text).iterator().forEach { - tempText = tempText.replace(it.value, ":${getName(it.value)}:") - } + emojiRegex.findAll(text).iterator().forEach { tempText = tempText.replace(it.value, ":${getName(it.value)}:") } return tempText } -} \ No newline at end of file +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/Events.kt b/src/main/kotlin/nl/skbotnl/chatog/Events.kt index 28bcb85..ff3dfa1 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/Events.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/Events.kt @@ -2,6 +2,7 @@ package nl.skbotnl.chatog import io.papermc.paper.advancement.AdvancementDisplay.Frame.* import io.papermc.paper.event.player.AsyncChatEvent +import java.util.* import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.launch import me.clip.placeholderapi.PlaceholderAPI @@ -28,7 +29,6 @@ import org.bukkit.event.entity.PlayerDeathEvent import org.bukkit.event.player.* import org.bukkit.event.server.BroadcastMessageEvent import xyz.jpenilla.announcerplus.listener.JoinQuitListener -import java.util.* @OptIn(DelicateCoroutinesApi::class) class Events : Listener { @@ -46,17 +46,16 @@ class Events : Listener { var chatString = "${ChatOG.chat.getPlayerPrefix(event.player)} ${event.player.name}" if (PlaceholderAPI.setPlaceholders(event.player, "%simpleclans_clan_color_tag%") != "") { - chatString = PlaceholderAPI.setPlaceholders( - event.player, - "&8[%simpleclans_clan_color_tag%&8] $chatString" - ) + chatString = PlaceholderAPI.setPlaceholders(event.player, "&8[%simpleclans_clan_color_tag%&8] $chatString") } ChatOG.scope.launch { DiscordBridge.sendEmbed( "${removeColor(chatString)} has joined the game. ${ Bukkit.getOnlinePlayers().count() - } player(s) online.", event.player.uniqueId, 0x00FF00 + } player(s) online.", + event.player.uniqueId, + 0x00FF00, ) } } @@ -73,17 +72,16 @@ class Events : Listener { var chatString = "${ChatOG.chat.getPlayerPrefix(event.player)} ${event.player.name}" if (PlaceholderAPI.setPlaceholders(event.player, "%simpleclans_clan_color_tag%") != "") { - chatString = PlaceholderAPI.setPlaceholders( - event.player, - "&8[%simpleclans_clan_color_tag%&8] $chatString" - ) + chatString = PlaceholderAPI.setPlaceholders(event.player, "&8[%simpleclans_clan_color_tag%&8] $chatString") } ChatOG.scope.launch { DiscordBridge.sendEmbed( "${removeColor(chatString)} has left the game. ${ Bukkit.getOnlinePlayers().count() - 1 - } player(s) online.", event.player.uniqueId, 0xFF0000 + } player(s) online.", + event.player.uniqueId, + 0xFF0000, ) } } @@ -100,10 +98,7 @@ class Events : Listener { var chatString = "${ChatOG.chat.getPlayerPrefix(event.player)} ${event.player.name}" if (PlaceholderAPI.setPlaceholders(event.player, "%simpleclans_clan_color_tag%") != "") { - chatString = PlaceholderAPI.setPlaceholders( - event.player, - "&8[%simpleclans_clan_color_tag%&8] $chatString" - ) + chatString = PlaceholderAPI.setPlaceholders(event.player, "&8[%simpleclans_clan_color_tag%&8] $chatString") } val reason = PlainTextComponentSerializer.plainText().serialize(event.reason()) @@ -112,7 +107,9 @@ class Events : Listener { DiscordBridge.sendEmbed( "${removeColor(chatString)} was kicked with reason: \"${reason}\". ${ Bukkit.getOnlinePlayers().count() - 1 - } player(s) online.", event.player.uniqueId, 0xFF0000 + } player(s) online.", + event.player.uniqueId, + 0xFF0000, ) } } @@ -129,30 +126,24 @@ class Events : Listener { var chatString = "${ChatOG.chat.getPlayerPrefix(event.player)} ${event.player.name}" if (PlaceholderAPI.setPlaceholders(event.player, "%simpleclans_clan_color_tag%") != "") { - chatString = PlaceholderAPI.setPlaceholders( - event.player, - "&8[%simpleclans_clan_color_tag%&8] $chatString" - ) + chatString = PlaceholderAPI.setPlaceholders(event.player, "&8[%simpleclans_clan_color_tag%&8] $chatString") } val advancementTitleKey = event.advancement.display?.title() ?: return val advancementTitle = PlainTextComponentSerializer.plainText().serialize(advancementTitleKey) - val advancementMessage = when (event.advancement.display?.frame()) { - GOAL -> "has reached the goal [$advancementTitle]" - TASK -> "has made the advancement [$advancementTitle]" - CHALLENGE -> "has completed the challenge [$advancementTitle]" - else -> { - return + val advancementMessage = + when (event.advancement.display?.frame()) { + GOAL -> "has reached the goal [$advancementTitle]" + TASK -> "has made the advancement [$advancementTitle]" + CHALLENGE -> "has completed the challenge [$advancementTitle]" + else -> { + return + } } - } ChatOG.scope.launch { - DiscordBridge.sendEmbed( - "${removeColor(chatString)} $advancementMessage.", - event.player.uniqueId, - 0xFFFF00 - ) + DiscordBridge.sendEmbed("${removeColor(chatString)} $advancementMessage.", event.player.uniqueId, 0xFFFF00) } } @@ -170,9 +161,7 @@ class Events : Listener { return } - ChatOG.scope.launch { - DiscordBridge.sendMessage(content, "[Server] Broadcast", null) - } + ChatOG.scope.launch { DiscordBridge.sendMessage(content, "[Server] Broadcast", null) } } @EventHandler @@ -194,15 +183,12 @@ class Events : Listener { var chatString = "${ChatOG.chat.getPlayerPrefix(event.player)} ${event.player.name}" if (PlaceholderAPI.setPlaceholders(event.player, "%simpleclans_clan_color_tag%") != "") { - chatString = - PlaceholderAPI.setPlaceholders(event.player, "&8[%simpleclans_clan_color_tag%&8] $chatString") + chatString = PlaceholderAPI.setPlaceholders(event.player, "&8[%simpleclans_clan_color_tag%&8] $chatString") } val discordMessageString = Helper.convertEmojis(oldTextComponent.content()) - ChatOG.scope.launch { - DiscordBridge.sendMessage(discordMessageString, chatString, event.player.uniqueId) - } + ChatOG.scope.launch { DiscordBridge.sendMessage(discordMessageString, chatString, event.player.uniqueId) } val messageComponents = Helper.convertLinks(oldTextComponent.content(), event.player) @@ -212,26 +198,22 @@ class Events : Listener { val chatComponent = UtilitiesOG.trueogColorize(legacyToMm("$chatString${ChatOG.chat.getPlayerSuffix(event.player)}")) - var textComponent = - Component.join(JoinConfiguration.noSeparators(), chatComponent, messageComponent) - textComponent = textComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to translate this message") + var textComponent = Component.join(JoinConfiguration.noSeparators(), chatComponent, messageComponent) + textComponent = + textComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to translate this message"), + ) ) - ) val randomUUID = UUID.randomUUID() - textComponent = textComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.RUN_COMMAND, - "/translatemessage $randomUUID 1" + textComponent = + textComponent.clickEvent( + ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/translatemessage $randomUUID 1") ) - ) - event.viewers().forEach { - it.sendMessage(textComponent) - } + event.viewers().forEach { it.sendMessage(textComponent) } TranslateMessage.chatMessages[randomUUID] = TranslateMessage.SentChatMessage(oldTextComponent.content(), event.player) @@ -241,12 +223,22 @@ class Events : Listener { fun onCommandPreprocess(event: PlayerCommandPreprocessEvent) { val checkSplit = event.message.split(" ", limit = 2)[0] - if (!(checkSplit == "/msg" || checkSplit == "/whisper" || checkSplit == "/pm" || checkSplit == "/reply" || checkSplit == "/r")) { + if ( + !(checkSplit == "/msg" || + checkSplit == "/whisper" || + checkSplit == "/pm" || + checkSplit == "/reply" || + checkSplit == "/r") + ) { if (checkSplit == "/s") { event.isCancelled = true if (!event.player.hasPermission("chat-og.staff")) { - event.player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You do not have permission to run this command.")) + event.player.sendMessage( + UtilitiesOG.trueogColorize( + "${Config.prefix}: You do not have permission to run this command." + ) + ) return } @@ -256,11 +248,15 @@ class Events : Listener { if (ChatSystemHelper.inChat[event.player.uniqueId] == ChatType.STAFFCHAT) { ChatSystemHelper.inChat[event.player.uniqueId] = "" - event.player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in normal chat.")) + event.player.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in normal chat.") + ) return } ChatSystemHelper.inChat[event.player.uniqueId] = ChatType.STAFFCHAT - event.player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in staff chat.")) + event.player.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in staff chat.") + ) return } @@ -270,11 +266,12 @@ class Events : Listener { } event.isCancelled = true - val messageSplit: List = if (checkSplit == "/r" || checkSplit == "/reply") { - event.message.split(" ", ignoreCase = true, limit = 2) - } else { - event.message.split(" ", ignoreCase = true, limit = 3) - } + val messageSplit: List = + if (checkSplit == "/r" || checkSplit == "/reply") { + event.message.split(" ", ignoreCase = true, limit = 2) + } else { + event.message.split(" ", ignoreCase = true, limit = 3) + } if (messageSplit.count() < 3 && !(checkSplit == "/r" || checkSplit == "/reply")) { event.player.sendMessage(UtilitiesOG.trueogColorize("${messageSplit[0]} ")) @@ -292,7 +289,9 @@ class Events : Listener { message = messageSplit[1] if (!lastMessaged.containsKey(event.player.uniqueId)) { - event.player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You haven't messaged anyone yet.")) + event.player.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: You haven't messaged anyone yet.") + ) return } @@ -304,62 +303,62 @@ class Events : Listener { } if (player == null) { - event.player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: That player doesn't exist or isn't online.")) + event.player.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: That player doesn't exist or isn't online.") + ) return } val randomUUID = UUID.randomUUID() - TranslateMessage.pmMessages[randomUUID] = TranslateMessage.SentPMMessage( - message, - event.player.uniqueId, - player.uniqueId - ) + TranslateMessage.pmMessages[randomUUID] = + TranslateMessage.SentPMMessage(message, event.player.uniqueId, player.uniqueId) - val colourMessage = if (event.player.hasPermission("chat-og.color")) { - UtilitiesOG.trueogColorize(legacyToMm(message)) - } else { - Component.text(message) - } + val colourMessage = + if (event.player.hasPermission("chat-og.color")) { + UtilitiesOG.trueogColorize(legacyToMm(message)) + } else { + Component.text(message) + } val toSenderPrefix = "[me -> ${player.name}]" - var toSenderTextComponent = Component.join( - JoinConfiguration.separator(Component.text(" ")), - UtilitiesOG.trueogColorize(toSenderPrefix), - colourMessage - ) - toSenderTextComponent = toSenderTextComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to translate this message") + var toSenderTextComponent = + Component.join( + JoinConfiguration.separator(Component.text(" ")), + UtilitiesOG.trueogColorize(toSenderPrefix), + colourMessage, ) - ) - toSenderTextComponent = toSenderTextComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.RUN_COMMAND, - "/translatemessage $randomUUID 3" + toSenderTextComponent = + toSenderTextComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to translate this message"), + ) + ) + toSenderTextComponent = + toSenderTextComponent.clickEvent( + ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/translatemessage $randomUUID 3") ) - ) event.player.sendMessage(toSenderTextComponent) val toPrefix = "[${event.player.name} -> me]" - var toTextComponent = Component.join( - JoinConfiguration.separator(Component.text(" ")), - UtilitiesOG.trueogColorize(toPrefix), - colourMessage - ) - toTextComponent = toTextComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to translate this message") + var toTextComponent = + Component.join( + JoinConfiguration.separator(Component.text(" ")), + UtilitiesOG.trueogColorize(toPrefix), + colourMessage, ) - ) - toTextComponent = toTextComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.RUN_COMMAND, - "/translatemessage $randomUUID 3" + toTextComponent = + toTextComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to translate this message"), + ) + ) + toTextComponent = + toTextComponent.clickEvent( + ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/translatemessage $randomUUID 3") ) - ) player.sendMessage(toTextComponent) lastMessaged[event.player.uniqueId] = player.uniqueId @@ -382,7 +381,7 @@ class Events : Listener { DiscordBridge.sendEmbed( removeColor((event.deathMessage() as TextComponent).content()), event.player.uniqueId, - 0xFF0000 + 0xFF0000, ) } return @@ -391,8 +390,7 @@ class Events : Listener { var nameString = "${ChatOG.chat.getPlayerPrefix(event.player)} ${event.player.name}" if (PlaceholderAPI.setPlaceholders(event.player, "%simpleclans_clan_color_tag%") != "") { - nameString = - PlaceholderAPI.setPlaceholders(event.player, "&8[%simpleclans_clan_color_tag%&8] $nameString") + nameString = PlaceholderAPI.setPlaceholders(event.player, "&8[%simpleclans_clan_color_tag%&8] $nameString") } val nameComponent = UtilitiesOG.trueogColorize(legacyToMm(nameString)) @@ -416,22 +414,20 @@ class Events : Listener { @EventHandler fun onVanish(event: VanishStatusChangeEvent) { if (event.value) { - val playerQuitEvent = PlayerQuitEvent( - event.affected.base, - Component.translatable( - "multiplayer.player.left", - NamedTextColor.YELLOW, - event.affected.base.displayName() - ), - PlayerQuitEvent.QuitReason.DISCONNECTED - ) + val playerQuitEvent = + PlayerQuitEvent( + event.affected.base, + Component.translatable( + "multiplayer.player.left", + NamedTextColor.YELLOW, + event.affected.base.displayName(), + ), + PlayerQuitEvent.QuitReason.DISCONNECTED, + ) JoinQuitListener().onQuit(playerQuitEvent) onQuit(playerQuitEvent) } else { - val playerJoinEvent = PlayerJoinEvent( - event.affected.base, - Component.text("") - ) + val playerJoinEvent = PlayerJoinEvent(event.affected.base, Component.text("")) JoinQuitListener().onJoin(playerJoinEvent) onJoin(playerJoinEvent) } diff --git a/src/main/kotlin/nl/skbotnl/chatog/Helper.kt b/src/main/kotlin/nl/skbotnl/chatog/Helper.kt index c67fa92..44ec281 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/Helper.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/Helper.kt @@ -1,6 +1,7 @@ package nl.skbotnl.chatog import dev.minn.jda.ktx.coroutines.await +import java.util.* import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji import net.kyori.adventure.text.Component import net.kyori.adventure.text.JoinConfiguration @@ -11,7 +12,6 @@ import net.kyori.adventure.text.format.TextColor import net.trueog.utilitiesog.UtilitiesOG import org.bukkit.Bukkit import org.bukkit.entity.Player -import java.util.* object Helper { private var translateTimeout: MutableMap = HashMap() @@ -31,24 +31,31 @@ object Helper { } fun legacyToMm(text: String): String { - return text.replace("[§&]4".toRegex(), "").replace("[§&]c".toRegex(), "") - .replace("[§&]6".toRegex(), "").replace("[§&]e".toRegex(), "") - .replace("[§&]2".toRegex(), "").replace("[§&]a".toRegex(), "") - .replace("[§&]b".toRegex(), "").replace("[§&]3".toRegex(), "") - .replace("[§&]1".toRegex(), "").replace("[§&]9".toRegex(), "") + return text + .replace("[§&]4".toRegex(), "") + .replace("[§&]c".toRegex(), "") + .replace("[§&]6".toRegex(), "") + .replace("[§&]e".toRegex(), "") + .replace("[§&]2".toRegex(), "") + .replace("[§&]a".toRegex(), "") + .replace("[§&]b".toRegex(), "") + .replace("[§&]3".toRegex(), "") + .replace("[§&]1".toRegex(), "") + .replace("[§&]9".toRegex(), "") .replace("[§&]d".toRegex(), "") - .replace("[§&]5".toRegex(), "").replace("[§&]f".toRegex(), "") + .replace("[§&]5".toRegex(), "") + .replace("[§&]f".toRegex(), "") .replace("[§&]7".toRegex(), "") - .replace("[§&]8".toRegex(), "").replace("[§&]0".toRegex(), "") + .replace("[§&]8".toRegex(), "") + .replace("[§&]0".toRegex(), "") .replace("[§&]r".toRegex(), "") } private val colorRegex = Regex("[§&]?[§&]([0-9a-fk-orA-FK-OR])") + fun removeColor(text: String): String { var tempText = text - colorRegex.findAll(text).iterator().forEach { - tempText = tempText.replace(it.value, "") - } + colorRegex.findAll(text).iterator().forEach { tempText = tempText.replace(it.value, "") } return tempText } @@ -76,6 +83,7 @@ object Helper { } private val getColorRegex = Regex("(&)?&([0-9a-fk-orA-FK-OR])") + private fun getColor(text: String): String { val it = getColorRegex.findAll(text).iterator() @@ -88,6 +96,7 @@ object Helper { } private val getHandle = Regex("@([a-z0-9_.]{2,32})") + suspend fun convertMentions(text: String): String { val guild = DiscordBridge.jda?.getGuildById(Config.guildId) if (guild == null) { @@ -122,7 +131,11 @@ object Helper { if (urlIter.hasNext()) { urlIter.forEach { link -> if (BlocklistManager.checkUrl(word)) { - player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: WARNING: You are not allowed to post links like that here.")) + player.sendMessage( + UtilitiesOG.trueogColorize( + "${Config.prefix}: WARNING: You are not allowed to post links like that here." + ) + ) for (onlinePlayer in Bukkit.getOnlinePlayers()) { if (onlinePlayer.hasPermission("group.moderator")) { onlinePlayer.sendMessage( @@ -130,7 +143,7 @@ object Helper { "${Config.prefix}: ${player.name} has posted a disallowed link: ${ word.replace( ".", - "[dot]" + "[dot]", ) }." ) @@ -141,19 +154,18 @@ object Helper { } var linkComponent = Component.text(link.groups[2]!!.value).color(TextColor.color(34, 100, 255)) - linkComponent = linkComponent.hoverEvent( - HoverEvent.hoverEvent( - HoverEvent.Action.SHOW_TEXT, - UtilitiesOG.trueogColorize("Click to open link") + linkComponent = + linkComponent.hoverEvent( + HoverEvent.hoverEvent( + HoverEvent.Action.SHOW_TEXT, + UtilitiesOG.trueogColorize("Click to open link"), + ) ) - ) - linkComponent = linkComponent.clickEvent( - ClickEvent.clickEvent( - ClickEvent.Action.OPEN_URL, - link.groups[2]!!.value + linkComponent = + linkComponent.clickEvent( + ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, link.groups[2]!!.value) ) - ) val beforeComponent = UtilitiesOG.trueogColorize(legacyToMm(chatColor) + (link.groups[1]?.value ?: "")) @@ -167,24 +179,25 @@ object Helper { } return@forEach } - val wordComponent = if (player.hasPermission("chat-og.color")) { - if (messageComponents.isNotEmpty()) { - val lastContent = (messageComponents.last() as TextComponent).content() - if (getColorSection(lastContent) != "" && getFirstColorSection(word) == "") { - UtilitiesOG.trueogColorize(legacyToMm(getColorSection(lastContent) + word)) + val wordComponent = + if (player.hasPermission("chat-og.color")) { + if (messageComponents.isNotEmpty()) { + val lastContent = (messageComponents.last() as TextComponent).content() + if (getColorSection(lastContent) != "" && getFirstColorSection(word) == "") { + UtilitiesOG.trueogColorize(legacyToMm(getColorSection(lastContent) + word)) + } else { + UtilitiesOG.trueogColorize(legacyToMm(chatColor + word)) + } } else { UtilitiesOG.trueogColorize(legacyToMm(chatColor + word)) } } else { - UtilitiesOG.trueogColorize(legacyToMm(chatColor + word)) + Component.join( + JoinConfiguration.noSeparators(), + UtilitiesOG.trueogColorize(legacyToMm(chatColor)), + Component.text(word), + ) } - } else { - Component.join( - JoinConfiguration.noSeparators(), - UtilitiesOG.trueogColorize(legacyToMm(chatColor)), - Component.text(word) - ) - } messageComponents += wordComponent } @@ -204,14 +217,19 @@ object Helper { } if (guildEmojis != null) { - emojiRegex.findAll(text).iterator().asSequence().distinctBy { it.value }.forEach { - guildEmojis.forEach { emoji -> - if (emoji.name == it.groupValues[1]) { - val replaceWith = "<${if (emoji.isAnimated) "a" else ""}:${it.groupValues[1]}:${emoji.id}>" - discordMessageString = discordMessageString.replace(it.value, replaceWith) + emojiRegex + .findAll(text) + .iterator() + .asSequence() + .distinctBy { it.value } + .forEach { + guildEmojis.forEach { emoji -> + if (emoji.name == it.groupValues[1]) { + val replaceWith = "<${if (emoji.isAnimated) "a" else ""}:${it.groupValues[1]}:${emoji.id}>" + discordMessageString = discordMessageString.replace(it.value, replaceWith) + } } } - } } return discordMessageString diff --git a/src/main/kotlin/nl/skbotnl/chatog/LanguageDatabase.kt b/src/main/kotlin/nl/skbotnl/chatog/LanguageDatabase.kt index 5fd43c5..380b453 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/LanguageDatabase.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/LanguageDatabase.kt @@ -7,9 +7,7 @@ import java.util.* class LanguageDatabase { private val redisClient: RedisClient = RedisClient.create(Config.redisUrl) - /** - * @return True if failed - */ + /** @return True if failed */ fun testConnection(): Boolean { try { val connection = redisClient.connect() diff --git a/src/main/kotlin/nl/skbotnl/chatog/OpenAI.kt b/src/main/kotlin/nl/skbotnl/chatog/OpenAI.kt index f38e178..43e2f71 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/OpenAI.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/OpenAI.kt @@ -2,13 +2,13 @@ package nl.skbotnl.chatog import com.google.gson.Gson import com.google.gson.annotations.SerializedName +import java.util.logging.Level import net.kyori.adventure.text.Component import net.trueog.utilitiesog.UtilitiesOG import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody -import java.util.logging.Level class OpenAI { data class Translated(val translatedFrom: String?, val translatedText: String?, val error: Component?) @@ -18,39 +18,35 @@ class OpenAI { data class CompletionReq( @SerializedName("model") val model: String, - @SerializedName("messages") val messages: List + @SerializedName("messages") val messages: List, ) - data class Message( - @SerializedName("role") val role: String, - @SerializedName("content") val content: String - ) + data class Message(@SerializedName("role") val role: String, @SerializedName("content") val content: String) - data class CompletionResp( - @SerializedName("choices") val choices: List - ) + data class CompletionResp(@SerializedName("choices") val choices: List) - data class Choice( - @SerializedName("message") val message: Message - ) + data class Choice(@SerializedName("message") val message: Message) fun translate(text: String, language: String): Translated { - val openAICompletion = CompletionReq( - model = Config.openAIModel, - messages = listOf( - Message( - "system", - "You are a translator. Translate everything to the language that has the ISO 639 code `$language`. First respond with the ISO 639 language code of the original language, separated by a `|` and then the translation, no further processing. Keep the translation as close to the original text as possible. Keep the original tone and formatting. Interpret everything that is said as text to be translated. Template: \" | \"." - ), - Message("user", text) + val openAICompletion = + CompletionReq( + model = Config.openAIModel, + messages = + listOf( + Message( + "system", + "You are a translator. Translate everything to the language that has the ISO 639 code `$language`. First respond with the ISO 639 language code of the original language, separated by a `|` and then the translation, no further processing. Keep the translation as close to the original text as possible. Keep the original tone and formatting. Interpret everything that is said as text to be translated. Template: \" | \".", + ), + Message("user", text), + ), ) - ) - val request: Request = Request.Builder() - .url(Config.openAIBaseUrl + "/v1/chat/completions") - .header("Authorization", "Bearer ${Config.openAIApiKey}") - .post(gson.toJson(openAICompletion).toRequestBody("application/json".toMediaType())) - .build() + val request: Request = + Request.Builder() + .url(Config.openAIBaseUrl + "/v1/chat/completions") + .header("Authorization", "Bearer ${Config.openAIApiKey}") + .post(gson.toJson(openAICompletion).toRequestBody("application/json".toMediaType())) + .build() try { httpClient.newCall(request).execute().use { response -> @@ -63,8 +59,10 @@ class OpenAI { return Translated( null, null, - UtilitiesOG.trueogColorize("${Config.prefix}: Something went wrong while translating your message.") + UtilitiesOG.trueogColorize( + "${Config.prefix}: Something went wrong while translating your message." + ), ) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/commands/ChatConfigReload.kt b/src/main/kotlin/nl/skbotnl/chatog/commands/ChatConfigReload.kt index 2124869..2ca5ea9 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/commands/ChatConfigReload.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/commands/ChatConfigReload.kt @@ -1,44 +1,48 @@ -package nl.skbotnl.chatog.commands - -import club.minnced.discord.webhook.WebhookClient -import net.dv8tion.jda.api.entities.Activity -import net.trueog.utilitiesog.UtilitiesOG -import nl.skbotnl.chatog.ChatOG -import nl.skbotnl.chatog.Config -import nl.skbotnl.chatog.DiscordBridge -import nl.skbotnl.chatog.LanguageDatabase -import org.bukkit.Bukkit -import org.bukkit.command.Command -import org.bukkit.command.CommandExecutor -import org.bukkit.command.CommandSender - -class ChatConfigReload : CommandExecutor { - override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { - if (Config.load()) { - sender.sendMessage(UtilitiesOG.trueogColorize("Failed to reload the config. Check the console for more information.")) - Bukkit.getPluginManager().disablePlugin(ChatOG.plugin) - return true - } - - ChatOG.languageDatabase = LanguageDatabase() - if (ChatOG.languageDatabase.testConnection()) { - ChatOG.plugin.logger.severe("Could not connect to Redis") - Bukkit.getPluginManager().disablePlugin(ChatOG.plugin) - return true - } - - if (Config.discordEnabled) { - DiscordBridge.webhook = WebhookClient.withUrl(Config.webhook) - if (Config.staffDiscordEnabled) { - DiscordBridge.staffWebhook = WebhookClient.withUrl(Config.staffWebhook) - } - if (Config.premiumDiscordEnabled) { - DiscordBridge.premiumWebhook = WebhookClient.withUrl(Config.premiumWebhook) - } - DiscordBridge.jda?.presence?.setPresence(Activity.playing(Config.status), false) - } - - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Successfully reloaded the config.")) - return true - } -} +package nl.skbotnl.chatog.commands + +import club.minnced.discord.webhook.WebhookClient +import net.dv8tion.jda.api.entities.Activity +import net.trueog.utilitiesog.UtilitiesOG +import nl.skbotnl.chatog.ChatOG +import nl.skbotnl.chatog.Config +import nl.skbotnl.chatog.DiscordBridge +import nl.skbotnl.chatog.LanguageDatabase +import org.bukkit.Bukkit +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender + +class ChatConfigReload : CommandExecutor { + override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { + if (Config.load()) { + sender.sendMessage( + UtilitiesOG.trueogColorize("Failed to reload the config. Check the console for more information.") + ) + Bukkit.getPluginManager().disablePlugin(ChatOG.plugin) + return true + } + + ChatOG.languageDatabase = LanguageDatabase() + if (ChatOG.languageDatabase.testConnection()) { + ChatOG.plugin.logger.severe("Could not connect to Redis") + Bukkit.getPluginManager().disablePlugin(ChatOG.plugin) + return true + } + + if (Config.discordEnabled) { + DiscordBridge.webhook = WebhookClient.withUrl(Config.webhook) + if (Config.staffDiscordEnabled) { + DiscordBridge.staffWebhook = WebhookClient.withUrl(Config.staffWebhook) + } + if (Config.premiumDiscordEnabled) { + DiscordBridge.premiumWebhook = WebhookClient.withUrl(Config.premiumWebhook) + } + DiscordBridge.jda?.presence?.setPresence(Activity.playing(Config.status), false) + } + + sender.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: Successfully reloaded the config.") + ) + return true + } +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/commands/PremiumChat.kt b/src/main/kotlin/nl/skbotnl/chatog/commands/PremiumChat.kt index 8b54eb7..df8f905 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/commands/PremiumChat.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/commands/PremiumChat.kt @@ -1,38 +1,46 @@ -package nl.skbotnl.chatog.commands - -import net.trueog.utilitiesog.UtilitiesOG -import nl.skbotnl.chatog.ChatSystemHelper -import nl.skbotnl.chatog.ChatSystemHelper.ChatType -import nl.skbotnl.chatog.Config -import org.bukkit.command.Command -import org.bukkit.command.CommandExecutor -import org.bukkit.command.CommandSender -import org.bukkit.entity.Player - -class PremiumChat : CommandExecutor { - override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { - if (sender !is Player) { - sender.sendMessage("You can only execute this command as a player.") - return true - } - if (!sender.hasPermission("chat-og.premium")) { - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You do not have permission to run this command.")) - return true - } - if (args == null || args.isEmpty()) { - if (ChatSystemHelper.inChat[sender.uniqueId] == ChatType.PREMIUMCHAT) { - ChatSystemHelper.inChat[sender.uniqueId] = "" - - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in normal chat.")) - return true - } - ChatSystemHelper.inChat[sender.uniqueId] = ChatType.PREMIUMCHAT - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in premium chat.")) - return true - } - - ChatSystemHelper.sendMessageInPremiumChat(sender, args.joinToString(separator = " ")) - - return true - } -} +package nl.skbotnl.chatog.commands + +import net.trueog.utilitiesog.UtilitiesOG +import nl.skbotnl.chatog.ChatSystemHelper +import nl.skbotnl.chatog.ChatSystemHelper.ChatType +import nl.skbotnl.chatog.Config +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player + +class PremiumChat : CommandExecutor { + override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { + if (sender !is Player) { + sender.sendMessage("You can only execute this command as a player.") + return true + } + if (!sender.hasPermission("chat-og.premium")) { + sender.sendMessage( + UtilitiesOG.trueogColorize( + "${Config.prefix}: You do not have permission to run this command." + ) + ) + return true + } + if (args == null || args.isEmpty()) { + if (ChatSystemHelper.inChat[sender.uniqueId] == ChatType.PREMIUMCHAT) { + ChatSystemHelper.inChat[sender.uniqueId] = "" + + sender.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in normal chat.") + ) + return true + } + ChatSystemHelper.inChat[sender.uniqueId] = ChatType.PREMIUMCHAT + sender.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in premium chat.") + ) + return true + } + + ChatSystemHelper.sendMessageInPremiumChat(sender, args.joinToString(separator = " ")) + + return true + } +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/commands/StaffChat.kt b/src/main/kotlin/nl/skbotnl/chatog/commands/StaffChat.kt index 7de598d..e683b3b 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/commands/StaffChat.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/commands/StaffChat.kt @@ -1,38 +1,46 @@ -package nl.skbotnl.chatog.commands - -import net.trueog.utilitiesog.UtilitiesOG -import nl.skbotnl.chatog.ChatSystemHelper -import nl.skbotnl.chatog.ChatSystemHelper.ChatType -import nl.skbotnl.chatog.Config -import org.bukkit.command.Command -import org.bukkit.command.CommandExecutor -import org.bukkit.command.CommandSender -import org.bukkit.entity.Player - -class StaffChat : CommandExecutor { - override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { - if (sender !is Player) { - sender.sendMessage("You can only execute this command as a player") - return true - } - if (!sender.hasPermission("chat-og.staff")) { - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You do not have permission to run this command.")) - return true - } - if (args == null || args.isEmpty()) { - if (ChatSystemHelper.inChat[sender.uniqueId] == ChatType.STAFFCHAT) { - ChatSystemHelper.inChat[sender.uniqueId] = "" - - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in normal chat.")) - return true - } - ChatSystemHelper.inChat[sender.uniqueId] = ChatType.STAFFCHAT - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in staff chat.")) - return true - } - - ChatSystemHelper.sendMessageInStaffChat(sender, args.joinToString(separator = " ")) - - return true - } -} +package nl.skbotnl.chatog.commands + +import net.trueog.utilitiesog.UtilitiesOG +import nl.skbotnl.chatog.ChatSystemHelper +import nl.skbotnl.chatog.ChatSystemHelper.ChatType +import nl.skbotnl.chatog.Config +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player + +class StaffChat : CommandExecutor { + override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { + if (sender !is Player) { + sender.sendMessage("You can only execute this command as a player") + return true + } + if (!sender.hasPermission("chat-og.staff")) { + sender.sendMessage( + UtilitiesOG.trueogColorize( + "${Config.prefix}: You do not have permission to run this command." + ) + ) + return true + } + if (args == null || args.isEmpty()) { + if (ChatSystemHelper.inChat[sender.uniqueId] == ChatType.STAFFCHAT) { + ChatSystemHelper.inChat[sender.uniqueId] = "" + + sender.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in normal chat.") + ) + return true + } + ChatSystemHelper.inChat[sender.uniqueId] = ChatType.STAFFCHAT + sender.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: You are now talking in staff chat.") + ) + return true + } + + ChatSystemHelper.sendMessageInStaffChat(sender, args.joinToString(separator = " ")) + + return true + } +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateMessage.kt b/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateMessage.kt index 4dba08a..d5195fa 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateMessage.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateMessage.kt @@ -1,192 +1,210 @@ -package nl.skbotnl.chatog.commands - -import kotlinx.coroutines.DelicateCoroutinesApi -import me.clip.placeholderapi.PlaceholderAPI -import net.kyori.adventure.text.Component -import net.kyori.adventure.text.JoinConfiguration -import net.kyori.adventure.text.format.NamedTextColor -import net.trueog.utilitiesog.UtilitiesOG -import nl.skbotnl.chatog.ChatOG -import nl.skbotnl.chatog.Config -import nl.skbotnl.chatog.Helper -import nl.skbotnl.chatog.Helper.legacyToMm -import org.bukkit.Bukkit -import org.bukkit.command.Command -import org.bukkit.command.CommandExecutor -import org.bukkit.command.CommandSender -import org.bukkit.entity.Player -import java.util.* - -class TranslateMessage : CommandExecutor { - interface ISentMessage { - val message: String - } - - data class SentChatMessage(override val message: String, val player: Player) : ISentMessage - data class SentCustomMessage( - override val message: String, - val username: String, - val prefix: Component, - val suffix: Component - ) : - ISentMessage - - data class SentPMMessage(override val message: String, val sender: UUID, val receiver: UUID) : ISentMessage - - companion object { - val chatMessages: MutableMap = HashMap() - val customMessages: MutableMap = HashMap() - val pmMessages: MutableMap = HashMap() - } - - @OptIn(DelicateCoroutinesApi::class) - override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { - if (sender !is Player) { - return false - } - if (args == null) { - return false - } - if (args.isEmpty()) { - return false - } - if (args.count() < 2) { - return false - } - val player: Player = sender - - if (Helper.getTranslateTimeout(player.uniqueId) != 0L) { - player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You're doing that too fast.")) - return true - } - - val uuid: UUID? - - try { - uuid = UUID.fromString(args[0]) - } catch (_: IllegalArgumentException) { - player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: That is not a valid UUID.")) - return true - } - - val messageType: Int - try { - messageType = args[1].toInt() - } catch (_: NumberFormatException) { - player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Invalid message type.")) - return true - } - - val sentMessage: ISentMessage? = when (messageType) { - 1 -> chatMessages[uuid] - 2 -> customMessages[uuid] - 3 -> pmMessages[uuid] - else -> { - return false - } - } - - if (sentMessage == null) { - player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Could not find that message.")) - return true - } - - if (ChatOG.translator == null) { - player.sendMessage( - UtilitiesOG.trueogColorize("${Config.prefix}: The translator is disabled.") - ) - return true - } - - val language = ChatOG.languageDatabase.getPlayerLanguage(player.uniqueId) - - if (language == null) { - player.sendMessage( - UtilitiesOG.trueogColorize("${Config.prefix}: Something went wrong while trying to get your preferred language.") - ) - return true - } - - player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Translating message (this can take some time)...")) - - val translated = ChatOG.translator!!.translate(sentMessage.message, language) - - if (translated.error != null) { - player.sendMessage(translated.error) - return true - } - - if (translated.translatedText == null) { - player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Could not translate that message.")) - return true - } - - lateinit var translateMessage: Component - - when (messageType) { - 1 -> { - val sentChatMessage = sentMessage as SentChatMessage - var playerString = - "${ChatOG.chat.getPlayerPrefix(sentChatMessage.player)}${sentChatMessage.player.name}${ - ChatOG.chat.getPlayerSuffix(sentChatMessage.player) - }" - if (PlaceholderAPI.setPlaceholders(sentMessage.player, "%simpleclans_clan_color_tag%") != "") { - playerString = PlaceholderAPI.setPlaceholders( - sentMessage.player, - "&8[%simpleclans_clan_color_tag%&8] $playerString" - ) - } - val playerComponent = - UtilitiesOG.trueogColorize(legacyToMm("[${translated.translatedFrom} -> $language (Can be inaccurate)] $playerString")) - - // Don't convert color in translated messages - translateMessage = Component.join( - JoinConfiguration.noSeparators(), - playerComponent, - Component.text(translated.translatedText) - ) - } - - 2 -> { - val sentCustomMessage = sentMessage as SentCustomMessage - - val translatedComponent = - Component.text("[${translated.translatedFrom} -> $language (Can be inaccurate)] ") - .color(NamedTextColor.LIGHT_PURPLE) - - translateMessage = Component.join( - JoinConfiguration.noSeparators(), - translatedComponent, - sentCustomMessage.prefix, - Component.text(sentCustomMessage.username), - sentCustomMessage.suffix, - Component.text(translated.translatedText) - ) - } - - 3 -> { - val sentPMMessage = sentMessage as SentPMMessage - - val translatedComponent = - Component.text("[${translated.translatedFrom} -> $language (Can be inaccurate)] ") - .color(NamedTextColor.LIGHT_PURPLE) - - val pmComponent = if (player.uniqueId == sentPMMessage.sender) { - UtilitiesOG.trueogColorize("[me -> ${Bukkit.getPlayer(sentPMMessage.receiver)!!.name}] ") - } else { - UtilitiesOG.trueogColorize("[${Bukkit.getPlayer(sentPMMessage.sender)!!.name} -> me] ") - } - - translateMessage = Component.join( - JoinConfiguration.noSeparators(), - translatedComponent, - pmComponent, - Component.text(translated.translatedText) - ) - } - } - player.sendMessage(translateMessage) - - return true - } -} +package nl.skbotnl.chatog.commands + +import java.util.* +import kotlinx.coroutines.DelicateCoroutinesApi +import me.clip.placeholderapi.PlaceholderAPI +import net.kyori.adventure.text.Component +import net.kyori.adventure.text.JoinConfiguration +import net.kyori.adventure.text.format.NamedTextColor +import net.trueog.utilitiesog.UtilitiesOG +import nl.skbotnl.chatog.ChatOG +import nl.skbotnl.chatog.Config +import nl.skbotnl.chatog.Helper +import nl.skbotnl.chatog.Helper.legacyToMm +import org.bukkit.Bukkit +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player + +class TranslateMessage : CommandExecutor { + interface ISentMessage { + val message: String + } + + data class SentChatMessage(override val message: String, val player: Player) : ISentMessage + + data class SentCustomMessage( + override val message: String, + val username: String, + val prefix: Component, + val suffix: Component, + ) : ISentMessage + + data class SentPMMessage(override val message: String, val sender: UUID, val receiver: UUID) : ISentMessage + + companion object { + val chatMessages: MutableMap = HashMap() + val customMessages: MutableMap = HashMap() + val pmMessages: MutableMap = HashMap() + } + + @OptIn(DelicateCoroutinesApi::class) + override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { + if (sender !is Player) { + return false + } + if (args == null) { + return false + } + if (args.isEmpty()) { + return false + } + if (args.count() < 2) { + return false + } + val player: Player = sender + + if (Helper.getTranslateTimeout(player.uniqueId) != 0L) { + player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: You're doing that too fast.")) + return true + } + + val uuid: UUID? + + try { + uuid = UUID.fromString(args[0]) + } catch (_: IllegalArgumentException) { + player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: That is not a valid UUID.")) + return true + } + + val messageType: Int + try { + messageType = args[1].toInt() + } catch (_: NumberFormatException) { + player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Invalid message type.")) + return true + } + + val sentMessage: ISentMessage? = + when (messageType) { + 1 -> chatMessages[uuid] + 2 -> customMessages[uuid] + 3 -> pmMessages[uuid] + else -> { + return false + } + } + + if (sentMessage == null) { + player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Could not find that message.")) + return true + } + + if (ChatOG.translator == null) { + player.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: The translator is disabled.")) + return true + } + + val language = ChatOG.languageDatabase.getPlayerLanguage(player.uniqueId) + + if (language == null) { + player.sendMessage( + UtilitiesOG.trueogColorize( + "${Config.prefix}: Something went wrong while trying to get your preferred language." + ) + ) + return true + } + + player.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: Translating message (this can take some time)...") + ) + + val translated = ChatOG.translator!!.translate(sentMessage.message, language) + + if (translated.error != null) { + player.sendMessage(translated.error) + return true + } + + if (translated.translatedText == null) { + player.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: Could not translate that message.") + ) + return true + } + + lateinit var translateMessage: Component + + when (messageType) { + 1 -> { + val sentChatMessage = sentMessage as SentChatMessage + var playerString = + "${ChatOG.chat.getPlayerPrefix(sentChatMessage.player)}${sentChatMessage.player.name}${ + ChatOG.chat.getPlayerSuffix(sentChatMessage.player) + }" + if (PlaceholderAPI.setPlaceholders(sentMessage.player, "%simpleclans_clan_color_tag%") != "") { + playerString = + PlaceholderAPI.setPlaceholders( + sentMessage.player, + "&8[%simpleclans_clan_color_tag%&8] $playerString", + ) + } + val playerComponent = + UtilitiesOG.trueogColorize( + legacyToMm( + "[${translated.translatedFrom} -> $language (Can be inaccurate)] $playerString" + ) + ) + + // Don't convert color in translated messages + translateMessage = + Component.join( + JoinConfiguration.noSeparators(), + playerComponent, + Component.text(translated.translatedText), + ) + } + + 2 -> { + val sentCustomMessage = sentMessage as SentCustomMessage + + val translatedComponent = + Component.text("[${translated.translatedFrom} -> $language (Can be inaccurate)] ") + .color(NamedTextColor.LIGHT_PURPLE) + + translateMessage = + Component.join( + JoinConfiguration.noSeparators(), + translatedComponent, + sentCustomMessage.prefix, + Component.text(sentCustomMessage.username), + sentCustomMessage.suffix, + Component.text(translated.translatedText), + ) + } + + 3 -> { + val sentPMMessage = sentMessage as SentPMMessage + + val translatedComponent = + Component.text("[${translated.translatedFrom} -> $language (Can be inaccurate)] ") + .color(NamedTextColor.LIGHT_PURPLE) + + val pmComponent = + if (player.uniqueId == sentPMMessage.sender) { + UtilitiesOG.trueogColorize( + "[me -> ${Bukkit.getPlayer(sentPMMessage.receiver)!!.name}] " + ) + } else { + UtilitiesOG.trueogColorize( + "[${Bukkit.getPlayer(sentPMMessage.sender)!!.name} -> me] " + ) + } + + translateMessage = + Component.join( + JoinConfiguration.noSeparators(), + translatedComponent, + pmComponent, + Component.text(translated.translatedText), + ) + } + } + player.sendMessage(translateMessage) + + return true + } +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateSettings.kt b/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateSettings.kt index 79b8c03..523d9b9 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateSettings.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateSettings.kt @@ -1,85 +1,88 @@ -package nl.skbotnl.chatog.commands - -import kotlinx.coroutines.DelicateCoroutinesApi -import net.trueog.utilitiesog.UtilitiesOG -import nl.skbotnl.chatog.ChatOG -import nl.skbotnl.chatog.Config -import org.bukkit.command.Command -import org.bukkit.command.CommandExecutor -import org.bukkit.command.CommandSender -import org.bukkit.entity.Player - -class TranslateSettings : CommandExecutor { - companion object { - val languagesList = listOf( - "ar", - "az", - "bg", - "bn", - "ca", - "cs", - "da", - "de", - "el", - "en", - "eo", - "es", - "et", - "fa", - "fi", - "fr", - "ga", - "he", - "hi", - "hu", - "id", - "it", - "ja", - "ko", - "lt", - "lv", - "ms", - "nb", - "nl", - "pl", - "pt", - "ro", - "ru", - "sk", - "sl", - "sq", - "sv", - "th", - "tl", - "tr", - "uk", - "zh", - "zt" - ) - } - - @OptIn(DelicateCoroutinesApi::class) - override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { - if (sender !is Player) { - return false - } - if (args == null) { - return false - } - if (args.isEmpty()) { - return false - } - - val language = args[0] - - if (languagesList.indexOf(language) == -1) { - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Invalid language.")) - return true - } - - ChatOG.languageDatabase.setPlayerLanguage(sender.uniqueId, language) - sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Set language to: $language.")) - - return true - } -} +package nl.skbotnl.chatog.commands + +import kotlinx.coroutines.DelicateCoroutinesApi +import net.trueog.utilitiesog.UtilitiesOG +import nl.skbotnl.chatog.ChatOG +import nl.skbotnl.chatog.Config +import org.bukkit.command.Command +import org.bukkit.command.CommandExecutor +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player + +class TranslateSettings : CommandExecutor { + companion object { + val languagesList = + listOf( + "ar", + "az", + "bg", + "bn", + "ca", + "cs", + "da", + "de", + "el", + "en", + "eo", + "es", + "et", + "fa", + "fi", + "fr", + "ga", + "he", + "hi", + "hu", + "id", + "it", + "ja", + "ko", + "lt", + "lv", + "ms", + "nb", + "nl", + "pl", + "pt", + "ro", + "ru", + "sk", + "sl", + "sq", + "sv", + "th", + "tl", + "tr", + "uk", + "zh", + "zt", + ) + } + + @OptIn(DelicateCoroutinesApi::class) + override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean { + if (sender !is Player) { + return false + } + if (args == null) { + return false + } + if (args.isEmpty()) { + return false + } + + val language = args[0] + + if (languagesList.indexOf(language) == -1) { + sender.sendMessage(UtilitiesOG.trueogColorize("${Config.prefix}: Invalid language.")) + return true + } + + ChatOG.languageDatabase.setPlayerLanguage(sender.uniqueId, language) + sender.sendMessage( + UtilitiesOG.trueogColorize("${Config.prefix}: Set language to: $language.") + ) + + return true + } +} diff --git a/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateSettingsTabCompleter.kt b/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateSettingsTabCompleter.kt index 9a9281b..5f7f2d2 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateSettingsTabCompleter.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/commands/TranslateSettingsTabCompleter.kt @@ -1,17 +1,16 @@ -package nl.skbotnl.chatog.commands - -import org.bukkit.command.Command -import org.bukkit.command.CommandSender -import org.bukkit.command.TabCompleter - -class TranslateSettingsTabCompleter : TabCompleter { - override fun onTabComplete( - sender: CommandSender, - command: Command, - label: String, - args: Array? - ): MutableList { - return TranslateSettings.languagesList.toMutableList() - } - -} \ No newline at end of file +package nl.skbotnl.chatog.commands + +import org.bukkit.command.Command +import org.bukkit.command.CommandSender +import org.bukkit.command.TabCompleter + +class TranslateSettingsTabCompleter : TabCompleter { + override fun onTabComplete( + sender: CommandSender, + command: Command, + label: String, + args: Array?, + ): MutableList { + return TranslateSettings.languagesList.toMutableList() + } +}