From 37237cb50447fe4334c71b50274fa542d60e1b45 Mon Sep 17 00:00:00 2001 From: NotAlexNoyle Date: Wed, 6 May 2026 16:10:11 -0400 Subject: [PATCH 1/6] Port placeholders to MiniPlaceholders Port all PlaceholderAPI usage to MiniPlaceholders / Utilities-OG APIs. Fix Unions-OG union colors breaking the MC -> Discord link. Drop the per-Discord-role suffix configuration. Player suffixes shown in messages now come exclusively from each player's individual LuckPerms suffix. Fix LuckPerms spacing so exactly one space appears between the player name and any prefix/suffix. Configure Color Code Roles. --- CHANGELOG.md | 9 ++- build.gradle.kts | 3 + src/main/kotlin/nl/skbotnl/chatog/Events.kt | 15 ++-- .../skbotnl/chatog/chatsystem/ChatSystem.kt | 5 +- .../chatog/config/discord/DiscordConfig.kt | 5 +- .../config/discord/DiscordSuffixConfig.kt | 6 -- .../skbotnl/chatog/discord/DiscordBridge.kt | 11 +-- .../translation/command/TranslateMessage.kt | 9 +-- .../kotlin/nl/skbotnl/chatog/util/ChatUtil.kt | 56 ++++++++++---- .../nl/skbotnl/chatog/util/PlayerAffix.kt | 52 ++++++++++++- src/main/resources/config.yml | 74 ++++++++++++------- 11 files changed, 166 insertions(+), 79 deletions(-) delete mode 100644 src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordSuffixConfig.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 562a687..3978f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,11 @@ NotAlexNoyle 05/06/26: -- Drop PlaceholderAPI dependency. Resolve Unions-OG union color tags - through MiniPlaceholders via Utilities-OG. -- Forward more types of exceptions to the server console. -- Tighten LuckPerms prefix/suffix spacing and trim handling. +- Port all uses of PlaceholderAPI to MiniPlaceholders / Utilities-OG APIs. +- Fix Unions-OG Union colors breaking MC -> Discord link. +- Drop the per-Discord-role suffix configuration. Player suffixes shown in messages now come exclusively from each player's individual LuckPerms suffix. +- Fix LuckPerms spacing so exactly one space appears between the player name and any prefix/suffix. +- Configure Color Code Roles. NotAlexNoyle 05/04/26: diff --git a/build.gradle.kts b/build.gradle.kts index 7c9855f..2649c76 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -58,6 +58,9 @@ dependencies { compileOnlyApi(project(":libs:Utilities-OG")) // Import TrueOG Network Utilities-OG Java API (from source). compileOnlyApi(project(":libs:Vanish-OG")) // Import TrueOG Network Vanish-OG Java API (from source). compileOnly("net.luckperms:api:5.5") // Import LuckPerms API. + compileOnly( + "io.github.miniplaceholders:miniplaceholders-api:2.2.3" + ) // Import MiniPlaceholders API for direct tag access. implementation("tools.jackson.core:jackson-databind:3.1.1") implementation("tools.jackson.dataformat:jackson-dataformat-yaml:3.1.1") diff --git a/src/main/kotlin/nl/skbotnl/chatog/Events.kt b/src/main/kotlin/nl/skbotnl/chatog/Events.kt index d0634be..453af59 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/Events.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/Events.kt @@ -42,7 +42,7 @@ internal class Events : Listener { return } - val playerPartString = ChatUtil.getPlayerPartString(event.player) + val playerPartString = ChatUtil.getDiscordPlayerPartString(event.player) scope.launch { discordBridgeLock.read { @@ -66,7 +66,7 @@ internal class Events : Listener { return } - val playerPartString = ChatUtil.getPlayerPartString(event.player) + val playerPartString = ChatUtil.getDiscordPlayerPartString(event.player) scope.launch { discordBridgeLock.read { @@ -90,7 +90,7 @@ internal class Events : Listener { return } - val playerPartString = ChatUtil.getPlayerPartString(event.player) + val playerPartString = ChatUtil.getDiscordPlayerPartString(event.player) val reason = PlainTextComponentSerializer.plainText().serialize(event.reason()) @@ -116,7 +116,7 @@ internal class Events : Listener { return } - val playerPartString = ChatUtil.getPlayerPartString(event.player) + val playerPartString = ChatUtil.getDiscordPlayerPartString(event.player) val advancementTitleKey = event.advancement.display?.title() ?: return val advancementTitle = PlainTextComponentSerializer.plainText().serialize(advancementTitleKey) @@ -190,10 +190,9 @@ internal class Events : Listener { var nameString = "${PlayerAffix.getPrefix(event.player.uniqueId)}${event.player.name}" - val unionColorTag = - PlainTextComponentSerializer.plainText() - .serialize(UtilitiesOG.trueogExpand("", event.player)) - if (unionColorTag.isNotEmpty() && unionColorTag != "&8None") { + val unionColorTag = ChatUtil.fetchUnionColorTag(event.player) + val unionPlain = ChatUtil.stripFormatting(unionColorTag) + if (unionPlain.isNotEmpty() && unionPlain != "None") { nameString = "&8[$unionColorTag&8] $nameString" } val nameComponent = UtilitiesOG.trueogColorize(legacyToMm(nameString)) diff --git a/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt b/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt index b5df718..2127efe 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt @@ -23,7 +23,10 @@ internal abstract class ChatSystem { var playerPartString = ChatUtil.getPlayerPartString(player) playerPartString = listOfNotNull(prefix, playerPartString).joinToString(" | ") - sendDiscordMessage(text, playerPartString, player.uniqueId) + val discordPlayerPartString = + listOfNotNull(prefix, ChatUtil.getDiscordPlayerPartString(player)).joinToString(" | ") + + sendDiscordMessage(text, discordPlayerPartString, player.uniqueId) val messageComponent = ChatUtil.processText(text, player) ?: return diff --git a/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt b/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt index 14959a5..838aa97 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt @@ -1,10 +1,12 @@ package nl.skbotnl.chatog.config.discord import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonSetter import com.fasterxml.jackson.annotation.Nulls +@JsonIgnoreProperties(ignoreUnknown = true) data class DiscordConfig @JsonCreator constructor( @@ -23,7 +25,4 @@ constructor( @param:JsonProperty("useColorCodeRoles") val useColorCodeRoles: Boolean, @param:JsonProperty("colorCodeRoles") @field:JsonSetter(nulls = Nulls.AS_EMPTY) val colorCodeRoles: List, @param:JsonProperty("roles") @field:JsonSetter(nulls = Nulls.AS_EMPTY) val roles: Map, - @param:JsonProperty("roleSuffixes") - @field:JsonSetter(nulls = Nulls.AS_EMPTY) - val roleSuffixes: Map, ) diff --git a/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordSuffixConfig.kt b/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordSuffixConfig.kt deleted file mode 100644 index 4162114..0000000 --- a/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordSuffixConfig.kt +++ /dev/null @@ -1,6 +0,0 @@ -package nl.skbotnl.chatog.config.discord - -import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonProperty - -data class DiscordSuffixConfig @JsonCreator constructor(@param:JsonProperty("suffix") val suffix: String) diff --git a/src/main/kotlin/nl/skbotnl/chatog/discord/DiscordBridge.kt b/src/main/kotlin/nl/skbotnl/chatog/discord/DiscordBridge.kt index da403ef..701cb8a 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/discord/DiscordBridge.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/discord/DiscordBridge.kt @@ -187,12 +187,7 @@ internal class DiscordBridge private constructor() { ?: NamedTextColor.GRAY } - val suffix = - if (config.discord.roleSuffixes.isEmpty()) { - "> " - } else { - sortedRoles.firstNotNullOfOrNull { r -> config.discord.roleSuffixes[r.id] }?.suffix ?: "> " - } + val suffix = " > " val messageComponents = mutableListOf(UtilitiesOG.trueogColorize(suffix)) @@ -368,7 +363,7 @@ internal class DiscordBridge private constructor() { message.contentDisplay, member.effectiveName, Component.join(JoinConfiguration.noSeparators(), discordComponent, userComponent), - Component.text("$suffix "), + Component.text(suffix), ) } return discordBridge @@ -398,7 +393,7 @@ internal class DiscordBridge private constructor() { suspend fun sendMessage(message: String, player: Player) { val webhookMessage = WebhookMessageBuilder() - .setUsername(UtilitiesOG.stripFormatting(ChatUtil.getPlayerPartString(player))) + .setUsername(UtilitiesOG.stripFormatting(ChatUtil.getDiscordPlayerPartString(player))) .setContent(UtilitiesOG.stripFormatting(ChatUtil.stripGroupMentions(ChatUtil.convertMentions(message)))) .setAvatarUrl("https://minotar.net/helm/${player.uniqueId}.png") diff --git a/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt b/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt index af243fe..8e861a3 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt @@ -4,7 +4,6 @@ import java.util.* import net.kyori.adventure.text.Component import net.kyori.adventure.text.JoinConfiguration import net.kyori.adventure.text.format.NamedTextColor -import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer import net.trueog.utilitiesog.UtilitiesOG import nl.skbotnl.chatog.ChatOG.Companion.config import nl.skbotnl.chatog.ChatOG.Companion.languageDatabase @@ -142,10 +141,9 @@ internal class TranslateMessage : CommandExecutor { "${PlayerAffix.getPrefix(sentChatMessage.player.uniqueId)}${sentChatMessage.player.name}${ PlayerAffix.getSuffix(sentChatMessage.player.uniqueId) }" - val unionColorTag = - PlainTextComponentSerializer.plainText() - .serialize(UtilitiesOG.trueogExpand("", sentMessage.player)) - if (unionColorTag.isNotEmpty() && unionColorTag != "&8None") { + val unionColorTag = ChatUtil.fetchUnionColorTag(sentMessage.player) + val unionPlain = ChatUtil.stripFormatting(unionColorTag) + if (unionPlain.isNotEmpty() && unionPlain != "None") { playerString = "&8[$unionColorTag&8] $playerString" } val playerComponent = @@ -155,7 +153,6 @@ internal class TranslateMessage : CommandExecutor { ) ) - // Don't convert color in translated messages translateMessage = Component.join( JoinConfiguration.noSeparators(), diff --git a/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt b/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt index a9d8435..459f388 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt @@ -1,6 +1,7 @@ package nl.skbotnl.chatog.util import dev.minn.jda.ktx.coroutines.await +import io.github.miniplaceholders.api.MiniPlaceholders import java.util.* import kotlin.concurrent.read import net.kyori.adventure.text.Component @@ -9,6 +10,7 @@ import net.kyori.adventure.text.event.HoverEvent import net.kyori.adventure.text.format.TextColor import net.kyori.adventure.text.minimessage.Context import net.kyori.adventure.text.minimessage.MiniMessage +import net.kyori.adventure.text.minimessage.tag.PreProcess import net.kyori.adventure.text.minimessage.tag.Tag import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver @@ -25,19 +27,45 @@ import org.bukkit.Sound import org.bukkit.entity.Player internal object ChatUtil { - fun getPlayerPartString(player: Player): String { - var playerPart = "${PlayerAffix.getPrefix(player.uniqueId)}${player.name}" + fun getPlayerPartString(player: Player, includeSuffix: Boolean = false): String { + var playerPart = + "${PlayerAffix.getPrefix(player.uniqueId)}${player.name}${if (includeSuffix) PlayerAffix.getSuffix(player.uniqueId) else ""}" - val unionColorTag = - PlainTextComponentSerializer.plainText() - .serialize(UtilitiesOG.trueogExpand("", player)) - if (unionColorTag.isNotEmpty() && unionColorTag != "&8None") { + val unionColorTag = fetchUnionColorTag(player) + val unionPlain = stripFormatting(unionColorTag) + if (unionPlain.isNotEmpty() && unionPlain != "None") { playerPart = legacyToMm("&8[$unionColorTag&8] ") + playerPart } return playerPart } + fun getDiscordPlayerPartString(player: Player): String { + return getPlayerPartString(player, includeSuffix = true) + } + + fun fetchUnionColorTag(player: Player): String { + var captured = "" + val original = MiniPlaceholders.getAudiencePlaceholders(player) + val capturingResolver = + object : TagResolver { + override fun resolve(name: String, arguments: ArgumentQueue, ctx: Context): Tag? { + val tag = original.resolve(name, arguments, ctx) ?: return null + if (tag is PreProcess) { + captured = tag.value().replace('§', '&') + return Tag.preProcessParsed("") + } + return tag + } + + override fun has(name: String): Boolean = original.has(name) + } + val resolver = + TagResolver.builder().resolver(MiniPlaceholders.getGlobalPlaceholders()).resolver(capturingResolver).build() + MiniMessage.miniMessage().deserialize("", resolver) + return captured + } + val mentionRegex = Regex("@([A-Za-z0-9_]{3,16})") fun dingForMentions(dontDingFor: UUID, component: Component) { @@ -102,6 +130,10 @@ internal object ChatUtil { return legacyRegex.replace(text) { legacyToMmMap[it.groupValues[1].lowercase()] ?: it.value } } + fun stripFormatting(text: String): String { + return MiniMessage.miniMessage().stripTags(legacyRegex.replace(text, "")) + } + private val getHandle = Regex("@([a-z0-9_.]{2,32})") suspend fun convertMentions(text: String): String { @@ -170,8 +202,10 @@ internal object ChatUtil { private fun processText(text: String, player: Player?, username: String?, color: Boolean): Component? { val words: MutableList = mutableListOf() + val canUseFormatting = player?.hasPermission("chat-og.color") == true || color + val textToProcess = if (canUseFormatting) legacyToMm(text) else stripFormatting(text) - legacyToMm(text).split(" ").forEach { word -> + textToProcess.split(" ").forEach { word -> val url = urlRegex.find(word) if (url != null) { @@ -206,14 +240,10 @@ internal object ChatUtil { } } - return if (player?.hasPermission("chat-og.color") == true) { + return if (canUseFormatting) { colorMm.deserialize(words.joinToString(" ")) } else { - if (color) { - colorMm.deserialize(words.joinToString(" ")) - } else { - noColorMm.deserialize(words.joinToString(" ")) - } + noColorMm.deserialize(words.joinToString(" ")) } } diff --git a/src/main/kotlin/nl/skbotnl/chatog/util/PlayerAffix.kt b/src/main/kotlin/nl/skbotnl/chatog/util/PlayerAffix.kt index 4c770be..012d819 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/util/PlayerAffix.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/util/PlayerAffix.kt @@ -6,13 +6,57 @@ import nl.skbotnl.chatog.util.ChatUtil.legacyToMm internal object PlayerAffix { fun getPrefix(uuid: UUID): String { - val prefix = getMetaData(uuid).prefix ?: return "" - return legacyToMm(prefix).trimEnd() + " " + val raw = getMetaData(uuid).prefix ?: return "" + val cleaned = stripOuterSpaces(legacyToMm(raw)) + if (ChatUtil.stripFormatting(cleaned).isEmpty()) return "" + return "$cleaned " } fun getSuffix(uuid: UUID): String { - val suffix = getMetaData(uuid).suffix ?: return "" - return " " + legacyToMm(suffix).trim() + val raw = getMetaData(uuid).suffix ?: return "" + val cleaned = stripOuterSpaces(legacyToMm(raw)) + if (ChatUtil.stripFormatting(cleaned).isEmpty()) return "" + return " $cleaned" + } + + private fun stripOuterSpaces(mm: String): String = stripTrailingSpaces(stripLeadingSpaces(mm)) + + private fun stripLeadingSpaces(mm: String): String { + val keptTags = StringBuilder() + var i = 0 + while (i < mm.length) { + val c = mm[i] + when { + c.isWhitespace() -> i++ + c == '<' -> { + val close = mm.indexOf('>', i) + if (close < 0) break + keptTags.append(mm, i, close + 1) + i = close + 1 + } + else -> return keptTags.toString() + mm.substring(i) + } + } + return keptTags.toString() + } + + private fun stripTrailingSpaces(mm: String): String { + val keptTags = StringBuilder() + var end = mm.length + while (end > 0) { + val c = mm[end - 1] + when { + c.isWhitespace() -> end-- + c == '>' -> { + val open = mm.lastIndexOf('<', end - 1) + if (open < 0) break + keptTags.insert(0, mm.substring(open, end)) + end = open + } + else -> return mm.substring(0, end) + keptTags.toString() + } + } + return keptTags.toString() } private fun getMetaData(uuid: UUID) = diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 2be98c6..f09f14f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -64,31 +64,53 @@ discord: listCommandText: "There are %onlineplayers% out of maximum 200 players online." # Color code roles - # TODO: Configure these roles. - useColorCodeRoles: false - # Configure which roles can use color codes with Discord -> Minecraft - # For example: - # - # colorCodeRoles: [1234567891274567890, 0987654321983654321] + # When true, only Discord users with one of the colorCodeRoles below can use + # Utilities-OG ColorCodeMap Bukkit codes (&c, &l, &*) or MiniMessage tags + # in Discord -> Minecraft chat. All others have their input stripped of + # formatting before it is rendered in-game. + useColorCodeRoles: true - # Configure the text color (after the username (Discord -> Minecraft)) for certain roles - # For example: - # - # roles: - # 1234567891239567890: - # messageColor: red - # - # message_color can be one of the following: black, dark_blue, dark_green, dark_aqua, dark_red, dark_purple, gold, gray, dark_gray, blue, green, aqua, red, light_purple, yellow, white - # - # You can also use RGB for the color: - # - # roles: - # 1234567891234567890: - # messageColor: [255, 255, 255] + # Discord role IDs allowed to use color codes from Discord. + colorCodeRoles: + - "897300356395073546" # OG-Pro + - "934876475285467247" # OG Master + - "897299946926125167" # Tester (same level as OG Master) + - "897299018407890945" # YouTube + - "1391741516204081162" # Technical Contributor + - "1096297706034569287" # Helper + - "897776965849858101" # Builder + - "916661431850639420" # MVP + - "1080912883694719047" # Developer + - "897297817574440970" # Moderator + - "897296878490763344" # Admin - # Configure the suffix for roles (has to include the space). color codes are allowed. - # For example: - - # roleSuffixes: - # 1234567891234527890: - # suffix: ": " + # Default Minecraft chat color applied to a Discord -> Minecraft message when + # the sender did not type their own color code. If a user has multiple + # configured roles the entry for their highest-positioned role wins. + roles: + "897657230575431710": # Member + messageColor: gray + "897300768619659314": # OG + messageColor: white + "897300356395073546": # OG-Pro + messageColor: white + "934876475285467247": # OG Master + messageColor: white + "897299946926125167": # Tester + messageColor: white + "897299018407890945": # YouTube + messageColor: white + "1391741516204081162": # Technical Contributor + messageColor: white + "1096297706034569287": # Helper + messageColor: white + "897776965849858101": # Builder + messageColor: white + "916661431850639420": # MVP + messageColor: white + "1080912883694719047": # Developer + messageColor: white + "897297817574440970": # Moderator + messageColor: white + "897296878490763344": # Admin + messageColor: white -- 2.47.3 From c0441ee52c8fd45599de4bc4cc04f58be8477ac1 Mon Sep 17 00:00:00 2001 From: NotAlexNoyle Date: Wed, 6 May 2026 16:33:45 -0400 Subject: [PATCH 2/6] Remove roleSuffixes config file crash patch --- .../kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt b/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt index 838aa97..314e256 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonSetter import com.fasterxml.jackson.annotation.Nulls -@JsonIgnoreProperties(ignoreUnknown = true) data class DiscordConfig @JsonCreator constructor( -- 2.47.3 From d687c1e619656719b55a630a77e23c60f2eed99d Mon Sep 17 00:00:00 2001 From: Sven Date: Wed, 6 May 2026 23:53:55 +0200 Subject: [PATCH 3/6] Remove Essentials dependency --- build.gradle.kts | 1 - src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt | 2 -- src/main/resources/plugin.yml | 3 +-- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 2649c76..a20eefe 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -51,7 +51,6 @@ repositories { /* ---------------------- Java project deps ---------------------------- */ dependencies { compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") // Declare Purpur API version to be packaged. - compileOnly("net.essentialsx:EssentialsX:2.21.0") // Import EssentialsX API (internally deprecated). compileOnly( files("libs/AnnouncerPlus-1.4.1.jar") ) // Import AnnouncerPlus API (binary-compatible with AnnouncerPlus-OG API). diff --git a/src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt b/src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt index daf0705..bc5e44d 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/ChatOG.kt @@ -1,6 +1,5 @@ package nl.skbotnl.chatog -import com.earth2me.essentials.Essentials import java.util.* import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.read @@ -51,7 +50,6 @@ internal class ChatOG : JavaPlugin() { var translator: OpenAITranslator? = null var discordBridge: DiscordBridge? = null val discordBridgeLock = ReentrantReadWriteLock() - var essentials = Bukkit.getServer().pluginManager.getPlugin("Essentials-OG") as Essentials var lastMessagedMap: MutableMap = HashMap() fun isConfigInitialized() = ::config.isInitialized diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 7fdd172..b00711b 100755 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -7,8 +7,7 @@ depend: - LuckPerms - AnnouncerPlus - Utilities-OG -softdepend: - - Essentials-OG + - Vanish-OG commands: translatemessage: description: Internal command for translating messages -- 2.47.3 From 22dd63f456218613ef1b6b13a9f2f81b3138f755 Mon Sep 17 00:00:00 2001 From: Sven Date: Thu, 7 May 2026 00:04:50 +0200 Subject: [PATCH 4/6] Clean up PlayerUtils (before PlayerAffix) and add support for configurable message colors using LuckPerms --- src/main/kotlin/nl/skbotnl/chatog/Events.kt | 4 +- .../skbotnl/chatog/chatsystem/ChatSystem.kt | 7 +- .../chatog/config/discord/DiscordConfig.kt | 1 - .../translation/command/TranslateMessage.kt | 7 +- .../kotlin/nl/skbotnl/chatog/util/ChatUtil.kt | 2 +- .../nl/skbotnl/chatog/util/PlayerAffix.kt | 67 ------------------- .../nl/skbotnl/chatog/util/PlayerUtils.kt | 24 +++++++ 7 files changed, 35 insertions(+), 77 deletions(-) delete mode 100644 src/main/kotlin/nl/skbotnl/chatog/util/PlayerAffix.kt create mode 100644 src/main/kotlin/nl/skbotnl/chatog/util/PlayerUtils.kt diff --git a/src/main/kotlin/nl/skbotnl/chatog/Events.kt b/src/main/kotlin/nl/skbotnl/chatog/Events.kt index 453af59..3b223c5 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/Events.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/Events.kt @@ -19,8 +19,8 @@ import nl.skbotnl.chatog.ChatOG.Companion.discordBridgeLock import nl.skbotnl.chatog.ChatOG.Companion.scope import nl.skbotnl.chatog.util.ChatUtil import nl.skbotnl.chatog.util.ChatUtil.legacyToMm -import nl.skbotnl.chatog.util.PlayerAffix import nl.skbotnl.chatog.util.PlayerExtensions.chatSystem +import nl.skbotnl.chatog.util.PlayerUtils import org.bukkit.Bukkit import org.bukkit.event.EventHandler import org.bukkit.event.Listener @@ -188,7 +188,7 @@ internal class Events : Listener { return } - var nameString = "${PlayerAffix.getPrefix(event.player.uniqueId)}${event.player.name}" + var nameString = "${PlayerUtils.getPrefix(event.player.uniqueId)}${event.player.name}" val unionColorTag = ChatUtil.fetchUnionColorTag(event.player) val unionPlain = ChatUtil.stripFormatting(unionColorTag) diff --git a/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt b/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt index 2127efe..3336934 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt @@ -9,7 +9,7 @@ import net.kyori.adventure.text.event.HoverEvent import net.trueog.utilitiesog.UtilitiesOG import nl.skbotnl.chatog.translation.command.TranslateMessage import nl.skbotnl.chatog.util.ChatUtil -import nl.skbotnl.chatog.util.PlayerAffix +import nl.skbotnl.chatog.util.PlayerUtils import org.bukkit.entity.Player internal abstract class ChatSystem { @@ -28,11 +28,12 @@ internal abstract class ChatSystem { sendDiscordMessage(text, discordPlayerPartString, player.uniqueId) - val messageComponent = ChatUtil.processText(text, player) ?: return + val messageComponent = + ChatUtil.processText(text, player)?.color(PlayerUtils.getMessageColor(player.uniqueId)) ?: return val chatComponent = UtilitiesOG.trueogColorize( - ChatUtil.legacyToMm("$playerPartString${PlayerAffix.getSuffix(player.uniqueId)} &7> ") + ChatUtil.legacyToMm("$playerPartString${PlayerUtils.getSuffix(player.uniqueId)} &7> ") ) var textComponent = Component.join(JoinConfiguration.noSeparators(), chatComponent, messageComponent) diff --git a/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt b/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt index 314e256..5959fd5 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/config/discord/DiscordConfig.kt @@ -1,7 +1,6 @@ package nl.skbotnl.chatog.config.discord import com.fasterxml.jackson.annotation.JsonCreator -import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonSetter import com.fasterxml.jackson.annotation.Nulls diff --git a/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt b/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt index 8e861a3..4ce017c 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt @@ -10,7 +10,7 @@ import nl.skbotnl.chatog.ChatOG.Companion.languageDatabase import nl.skbotnl.chatog.ChatOG.Companion.translator import nl.skbotnl.chatog.util.ChatUtil import nl.skbotnl.chatog.util.ChatUtil.legacyToMm -import nl.skbotnl.chatog.util.PlayerAffix +import nl.skbotnl.chatog.util.PlayerUtils import org.bukkit.Bukkit import org.bukkit.command.Command import org.bukkit.command.CommandExecutor @@ -137,9 +137,10 @@ internal class TranslateMessage : CommandExecutor { when (messageType) { 1 -> { val sentChatMessage = sentMessage as SentChatMessage + // TODO: Should use ChatUtil.getPlayerPartString var playerString = - "${PlayerAffix.getPrefix(sentChatMessage.player.uniqueId)}${sentChatMessage.player.name}${ - PlayerAffix.getSuffix(sentChatMessage.player.uniqueId) + "${PlayerUtils.getPrefix(sentChatMessage.player.uniqueId)}${sentChatMessage.player.name}${ + PlayerUtils.getSuffix(sentChatMessage.player.uniqueId) }" val unionColorTag = ChatUtil.fetchUnionColorTag(sentMessage.player) val unionPlain = ChatUtil.stripFormatting(unionColorTag) diff --git a/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt b/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt index 459f388..c2188df 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt @@ -29,7 +29,7 @@ import org.bukkit.entity.Player internal object ChatUtil { fun getPlayerPartString(player: Player, includeSuffix: Boolean = false): String { var playerPart = - "${PlayerAffix.getPrefix(player.uniqueId)}${player.name}${if (includeSuffix) PlayerAffix.getSuffix(player.uniqueId) else ""}" + "${PlayerUtils.getPrefix(player.uniqueId)}${player.name}${if (includeSuffix) PlayerUtils.getSuffix(player.uniqueId) else ""}" val unionColorTag = fetchUnionColorTag(player) val unionPlain = stripFormatting(unionColorTag) diff --git a/src/main/kotlin/nl/skbotnl/chatog/util/PlayerAffix.kt b/src/main/kotlin/nl/skbotnl/chatog/util/PlayerAffix.kt deleted file mode 100644 index 012d819..0000000 --- a/src/main/kotlin/nl/skbotnl/chatog/util/PlayerAffix.kt +++ /dev/null @@ -1,67 +0,0 @@ -package nl.skbotnl.chatog.util - -import java.util.* -import nl.skbotnl.chatog.ChatOG.Companion.luckPerms -import nl.skbotnl.chatog.util.ChatUtil.legacyToMm - -internal object PlayerAffix { - fun getPrefix(uuid: UUID): String { - val raw = getMetaData(uuid).prefix ?: return "" - val cleaned = stripOuterSpaces(legacyToMm(raw)) - if (ChatUtil.stripFormatting(cleaned).isEmpty()) return "" - return "$cleaned " - } - - fun getSuffix(uuid: UUID): String { - val raw = getMetaData(uuid).suffix ?: return "" - val cleaned = stripOuterSpaces(legacyToMm(raw)) - if (ChatUtil.stripFormatting(cleaned).isEmpty()) return "" - return " $cleaned" - } - - private fun stripOuterSpaces(mm: String): String = stripTrailingSpaces(stripLeadingSpaces(mm)) - - private fun stripLeadingSpaces(mm: String): String { - val keptTags = StringBuilder() - var i = 0 - while (i < mm.length) { - val c = mm[i] - when { - c.isWhitespace() -> i++ - c == '<' -> { - val close = mm.indexOf('>', i) - if (close < 0) break - keptTags.append(mm, i, close + 1) - i = close + 1 - } - else -> return keptTags.toString() + mm.substring(i) - } - } - return keptTags.toString() - } - - private fun stripTrailingSpaces(mm: String): String { - val keptTags = StringBuilder() - var end = mm.length - while (end > 0) { - val c = mm[end - 1] - when { - c.isWhitespace() -> end-- - c == '>' -> { - val open = mm.lastIndexOf('<', end - 1) - if (open < 0) break - keptTags.insert(0, mm.substring(open, end)) - end = open - } - else -> return mm.substring(0, end) + keptTags.toString() - } - } - return keptTags.toString() - } - - private fun getMetaData(uuid: UUID) = - with(luckPerms.userManager.getUser(uuid) ?: luckPerms.userManager.loadUser(uuid).join()) { - val queryOptions = luckPerms.contextManager.getQueryOptions(this).orElse(queryOptions) - cachedData.getMetaData(queryOptions) - } -} diff --git a/src/main/kotlin/nl/skbotnl/chatog/util/PlayerUtils.kt b/src/main/kotlin/nl/skbotnl/chatog/util/PlayerUtils.kt new file mode 100644 index 0000000..d62d726 --- /dev/null +++ b/src/main/kotlin/nl/skbotnl/chatog/util/PlayerUtils.kt @@ -0,0 +1,24 @@ +package nl.skbotnl.chatog.util + +import java.util.* +import net.kyori.adventure.text.format.NamedTextColor +import net.kyori.adventure.text.format.TextColor +import nl.skbotnl.chatog.ChatOG.Companion.luckPerms + +internal object PlayerUtils { + fun getPrefix(uuid: UUID): String { + val prefix = getMetaData(uuid).prefix?.trim() ?: return "" + return if (prefix.endsWith(' ')) prefix else "$prefix " + } + + fun getSuffix(uuid: UUID) = getMetaData(uuid).suffix?.trim() ?: "" + + fun getMessageColor(uuid: UUID): TextColor { + return getMetaData(uuid).getMetaValue("chat-og.messageColor")?.lowercase()?.let { + NamedTextColor.NAMES.value(it) + } ?: NamedTextColor.GRAY + } + + private fun getMetaData(uuid: UUID) = + with(luckPerms.userManager.getUser(uuid) ?: luckPerms.userManager.loadUser(uuid).join()) { cachedData.metaData } +} -- 2.47.3 From d33dd27274885b52e4dc0edf978376a2811b112d Mon Sep 17 00:00:00 2001 From: Sven Date: Fri, 8 May 2026 11:55:59 +0200 Subject: [PATCH 5/6] Clean up simpleclans_clan_color_tag expansion --- src/main/kotlin/nl/skbotnl/chatog/Events.kt | 16 ++++----- .../skbotnl/chatog/chatsystem/ChatSystem.kt | 2 +- .../skbotnl/chatog/discord/DiscordBridge.kt | 2 +- .../translation/command/TranslateMessage.kt | 8 ++--- .../kotlin/nl/skbotnl/chatog/util/ChatUtil.kt | 36 +++---------------- 5 files changed, 18 insertions(+), 46 deletions(-) diff --git a/src/main/kotlin/nl/skbotnl/chatog/Events.kt b/src/main/kotlin/nl/skbotnl/chatog/Events.kt index 3b223c5..158ff0e 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/Events.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/Events.kt @@ -42,7 +42,7 @@ internal class Events : Listener { return } - val playerPartString = ChatUtil.getDiscordPlayerPartString(event.player) + val playerPartString = ChatUtil.getPlayerPartString(event.player, includeSuffix = true) scope.launch { discordBridgeLock.read { @@ -66,7 +66,7 @@ internal class Events : Listener { return } - val playerPartString = ChatUtil.getDiscordPlayerPartString(event.player) + val playerPartString = ChatUtil.getPlayerPartString(event.player, includeSuffix = true) scope.launch { discordBridgeLock.read { @@ -90,7 +90,7 @@ internal class Events : Listener { return } - val playerPartString = ChatUtil.getDiscordPlayerPartString(event.player) + val playerPartString = ChatUtil.getPlayerPartString(event.player, includeSuffix = true) val reason = PlainTextComponentSerializer.plainText().serialize(event.reason()) @@ -116,7 +116,7 @@ internal class Events : Listener { return } - val playerPartString = ChatUtil.getDiscordPlayerPartString(event.player) + val playerPartString = ChatUtil.getPlayerPartString(event.player, includeSuffix = true) val advancementTitleKey = event.advancement.display?.title() ?: return val advancementTitle = PlainTextComponentSerializer.plainText().serialize(advancementTitleKey) @@ -190,10 +190,10 @@ internal class Events : Listener { var nameString = "${PlayerUtils.getPrefix(event.player.uniqueId)}${event.player.name}" - val unionColorTag = ChatUtil.fetchUnionColorTag(event.player) - val unionPlain = ChatUtil.stripFormatting(unionColorTag) - if (unionPlain.isNotEmpty() && unionPlain != "None") { - nameString = "&8[$unionColorTag&8] $nameString" + val unionTag = UtilitiesOG.trueogExpand("", event.player) + val unionPlainTag = UtilitiesOG.stripFormatting(unionTag) + if (unionPlainTag.isNotEmpty() && unionPlainTag != "None") { + nameString = "&8[$unionTag&8] $nameString" } val nameComponent = UtilitiesOG.trueogColorize(legacyToMm(nameString)) diff --git a/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt b/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt index 3336934..e0c990b 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/chatsystem/ChatSystem.kt @@ -24,7 +24,7 @@ internal abstract class ChatSystem { playerPartString = listOfNotNull(prefix, playerPartString).joinToString(" | ") val discordPlayerPartString = - listOfNotNull(prefix, ChatUtil.getDiscordPlayerPartString(player)).joinToString(" | ") + listOfNotNull(prefix, ChatUtil.getPlayerPartString(player, includeSuffix = true)).joinToString(" | ") sendDiscordMessage(text, discordPlayerPartString, player.uniqueId) diff --git a/src/main/kotlin/nl/skbotnl/chatog/discord/DiscordBridge.kt b/src/main/kotlin/nl/skbotnl/chatog/discord/DiscordBridge.kt index 701cb8a..34e2848 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/discord/DiscordBridge.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/discord/DiscordBridge.kt @@ -393,7 +393,7 @@ internal class DiscordBridge private constructor() { suspend fun sendMessage(message: String, player: Player) { val webhookMessage = WebhookMessageBuilder() - .setUsername(UtilitiesOG.stripFormatting(ChatUtil.getDiscordPlayerPartString(player))) + .setUsername(UtilitiesOG.stripFormatting(ChatUtil.getPlayerPartString(player, includeSuffix = true))) .setContent(UtilitiesOG.stripFormatting(ChatUtil.stripGroupMentions(ChatUtil.convertMentions(message)))) .setAvatarUrl("https://minotar.net/helm/${player.uniqueId}.png") diff --git a/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt b/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt index 4ce017c..ca6dab5 100755 --- a/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/translation/command/TranslateMessage.kt @@ -142,10 +142,10 @@ internal class TranslateMessage : CommandExecutor { "${PlayerUtils.getPrefix(sentChatMessage.player.uniqueId)}${sentChatMessage.player.name}${ PlayerUtils.getSuffix(sentChatMessage.player.uniqueId) }" - val unionColorTag = ChatUtil.fetchUnionColorTag(sentMessage.player) - val unionPlain = ChatUtil.stripFormatting(unionColorTag) - if (unionPlain.isNotEmpty() && unionPlain != "None") { - playerString = "&8[$unionColorTag&8] $playerString" + val unionTag = UtilitiesOG.trueogExpand("", player) + val unionPlainTag = UtilitiesOG.stripFormatting(unionTag) + if (unionPlainTag.isNotEmpty() && unionPlainTag != "None") { + playerString = "&8[$unionTag&8] $playerString" } val playerComponent = UtilitiesOG.trueogColorize( diff --git a/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt b/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt index c2188df..838260f 100644 --- a/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt +++ b/src/main/kotlin/nl/skbotnl/chatog/util/ChatUtil.kt @@ -1,7 +1,6 @@ package nl.skbotnl.chatog.util import dev.minn.jda.ktx.coroutines.await -import io.github.miniplaceholders.api.MiniPlaceholders import java.util.* import kotlin.concurrent.read import net.kyori.adventure.text.Component @@ -10,7 +9,6 @@ import net.kyori.adventure.text.event.HoverEvent import net.kyori.adventure.text.format.TextColor import net.kyori.adventure.text.minimessage.Context import net.kyori.adventure.text.minimessage.MiniMessage -import net.kyori.adventure.text.minimessage.tag.PreProcess import net.kyori.adventure.text.minimessage.tag.Tag import net.kyori.adventure.text.minimessage.tag.resolver.ArgumentQueue import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver @@ -31,41 +29,15 @@ internal object ChatUtil { var playerPart = "${PlayerUtils.getPrefix(player.uniqueId)}${player.name}${if (includeSuffix) PlayerUtils.getSuffix(player.uniqueId) else ""}" - val unionColorTag = fetchUnionColorTag(player) - val unionPlain = stripFormatting(unionColorTag) - if (unionPlain.isNotEmpty() && unionPlain != "None") { - playerPart = legacyToMm("&8[$unionColorTag&8] ") + playerPart + val unionTag = UtilitiesOG.trueogExpand("", player) + val unionPlainTag = UtilitiesOG.stripFormatting(unionTag) + if (unionPlainTag.isNotEmpty() && unionPlainTag != "None") { + playerPart = legacyToMm("&8[$unionTag&8] ") + playerPart } return playerPart } - fun getDiscordPlayerPartString(player: Player): String { - return getPlayerPartString(player, includeSuffix = true) - } - - fun fetchUnionColorTag(player: Player): String { - var captured = "" - val original = MiniPlaceholders.getAudiencePlaceholders(player) - val capturingResolver = - object : TagResolver { - override fun resolve(name: String, arguments: ArgumentQueue, ctx: Context): Tag? { - val tag = original.resolve(name, arguments, ctx) ?: return null - if (tag is PreProcess) { - captured = tag.value().replace('§', '&') - return Tag.preProcessParsed("") - } - return tag - } - - override fun has(name: String): Boolean = original.has(name) - } - val resolver = - TagResolver.builder().resolver(MiniPlaceholders.getGlobalPlaceholders()).resolver(capturingResolver).build() - MiniMessage.miniMessage().deserialize("", resolver) - return captured - } - val mentionRegex = Regex("@([A-Za-z0-9_]{3,16})") fun dingForMentions(dontDingFor: UUID, component: Component) { -- 2.47.3 From b627e1787e0b81c8b7f33df98b48e6820258c0df Mon Sep 17 00:00:00 2001 From: NotAlexNoyle Date: Sun, 10 May 2026 14:20:13 -0400 Subject: [PATCH 6/6] Update Utilities-OG --- libs/Utilities-OG | 2 +- libs/Vanish-OG | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/Utilities-OG b/libs/Utilities-OG index cfb722c..3e26fb1 160000 --- a/libs/Utilities-OG +++ b/libs/Utilities-OG @@ -1 +1 @@ -Subproject commit cfb722c3946b07952467b769a7dd313a6ca6a7e8 +Subproject commit 3e26fb1a84cd46754a57fc1e67d90fcc82d11ad5 diff --git a/libs/Vanish-OG b/libs/Vanish-OG index eb4f80f..3fcdfee 160000 --- a/libs/Vanish-OG +++ b/libs/Vanish-OG @@ -1 +1 @@ -Subproject commit eb4f80f46778f8bc70bb4c99d5189e5ef6bfc058 +Subproject commit 3fcdfee824c875c397af9793e276b197a03b5d3d -- 2.47.3