From a2857f57db508e619120d749137afbafa5dafb12 Mon Sep 17 00:00:00 2001 From: Taylor Becker Date: Sat, 7 Jun 2025 22:04:30 -0400 Subject: [PATCH] GH-5: Chat component support --- CHANGELOG.md | 2 + README.md | 61 +++++++++++++++++-- .../simplemc/simpleannounce/SimpleAnnounce.kt | 6 +- .../config/BaseComponentDeserializer.kt | 23 +++++++ .../config/SimpleAnnounceConfig.kt | 15 ++--- .../simpleannounce/sender/BossBarSender.kt | 2 +- .../simpleannounce/sender/ChatSender.kt | 2 +- .../simpleannounce/sender/TitleSender.kt | 4 +- src/main/resources/config.yml | 33 ++++++++-- 9 files changed, 126 insertions(+), 22 deletions(-) create mode 100644 src/main/kotlin/org/simplemc/simpleannounce/config/BaseComponentDeserializer.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c2b5fb..4c053d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] ### Added +- GH-5: JSON Chat Component (JSON) support in messages (@tajobe) + - Uses legacy conversion for Boss and Title announcements, full component support for Chat - GH-4: Sound support (@tajobe) - GH-3: Title type announcement sender (@tajobe) - MIT license diff --git a/README.md b/README.md index 726c1f4..3913425 100755 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Messages can be sent server-wide or controlled by permissions after a delay and - ...additional options depending on announcement type - `Chat` type announcement: - `messages`(ChatMessage list): Message(s) to send - - `message`(string): message string + - `message`([Chat Component]): message component (plain text, or json, see examples) - `sound`(SoundConfig, optional): Override announcement SoundConfig - `Boss` type announcement: - `hold`(duration*): Time for boss bar to be on screen @@ -43,7 +43,7 @@ Messages can be sent server-wide or controlled by permissions after a delay and - `animate`(boolean): if bar should animate over hold time - `reverseAnimation`(boolean): if animation should be reversed - `messages`(BossBarMessage list): - - `message`(string): message string + - `message`([Chat Component]): message component (plain text, or json, see examples) - `sound`(SoundConfig, optional): Override announcement SoundConfig - ...boss bar config overrides per message eg hold, color, style, animate, etc... - `Title` type announcement: @@ -51,8 +51,8 @@ Messages can be sent server-wide or controlled by permissions after a delay and - `stay`(duration*): Time for title to stay on screen - `fadeOut`(duration*): Time it takes for title to fade out - `messages`(TitleMessage list): - - `title`(string): title string - - `subtitle`(string): subtitle string, appears below title slightly smaller + - `title`([Chat Component]): title component (plain text, or json, see examples) + - `subtitle`([Chat Component]): subtitle component (plain text, or json, see examples), appears below title slightly smaller - `sound`(SoundConfig, optional): Override announcement SoundConfig - ...title config overrides eg fadeIn, stay, fadeOut... - `config-version`: **Internal use for configuration migrations, do not edit** @@ -120,6 +120,59 @@ announcements: config-version: 1 ``` +#### Chat Components + +Message contents are parsed as [Chat Component]s. This means that in addition to the normal `message: some message`, you can use JSON or YAML-formatted components. + +```yaml + - type: Chat + repeat: 30s + messages: + - message: { + "extra": [ + { + "color": "gold", + "text": "This is a " + }, + { + "bold": true, + "color": "gold", + "clickEvent": { + "action": "open_url", + "value": "https://www.spigotmc.org/wiki/the-chat-component-api/" + }, + "hoverEvent": { + "action": "show_text", + "contents": "Chat Component API" + }, + "text": "TextComponent" + }, + { "text": " announcement!" } + ] + } +``` +or +```yaml + - type: Chat + repeat: 30s + messages: + - message: + extra: + - color: gold + text: "This is a " + - bold: true + color: gold + text: TextComponent + clickEvent: + action: open_url + value: "https://www.spigotmc.org/wiki/the-chat-component-api/" + hoverEvent: + action: show_text + "contents": "Chat Component API" + - text: " announcement!" +``` + [Sound]: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html [BarColor]: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarColor.html [BarStyle]: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/boss/BarStyle.html +[Chat Component]: https://www.spigotmc.org/wiki/the-chat-component-api/ diff --git a/src/main/kotlin/org/simplemc/simpleannounce/SimpleAnnounce.kt b/src/main/kotlin/org/simplemc/simpleannounce/SimpleAnnounce.kt index 7b59152..3f0d8c8 100644 --- a/src/main/kotlin/org/simplemc/simpleannounce/SimpleAnnounce.kt +++ b/src/main/kotlin/org/simplemc/simpleannounce/SimpleAnnounce.kt @@ -5,11 +5,14 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.module.SimpleModule import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator import com.fasterxml.jackson.dataformat.yaml.YAMLMapper +import com.fasterxml.jackson.module.kotlin.addDeserializer import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import net.md_5.bungee.api.chat.BaseComponent import org.bukkit.command.Command import org.bukkit.command.CommandSender import org.bukkit.plugin.java.JavaPlugin +import org.simplemc.simpleannounce.config.BaseComponentDeserializer import org.simplemc.simpleannounce.config.DurationDeserializer import org.simplemc.simpleannounce.config.DurationSerializer import org.simplemc.simpleannounce.config.SimpleAnnounceConfig @@ -27,7 +30,8 @@ class SimpleAnnounce : JavaPlugin() { private const val RELOAD_COMMAND = "simpleannouncereload" private val durationModule = SimpleModule() - .addDeserializer(Duration::class.java, DurationDeserializer()) + .addDeserializer(Duration::class, DurationDeserializer()) + .addDeserializer(BaseComponent::class, BaseComponentDeserializer()) .addSerializer(DurationSerializer()) } diff --git a/src/main/kotlin/org/simplemc/simpleannounce/config/BaseComponentDeserializer.kt b/src/main/kotlin/org/simplemc/simpleannounce/config/BaseComponentDeserializer.kt new file mode 100644 index 0000000..0adfcaa --- /dev/null +++ b/src/main/kotlin/org/simplemc/simpleannounce/config/BaseComponentDeserializer.kt @@ -0,0 +1,23 @@ +package org.simplemc.simpleannounce.config + +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.JsonDeserializer +import com.fasterxml.jackson.databind.JsonNode +import net.md_5.bungee.api.chat.BaseComponent +import net.md_5.bungee.chat.ComponentSerializer + +class BaseComponentDeserializer : JsonDeserializer() { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): BaseComponent? { + val json = p.readValueAsTree().toString() + return try { + ComponentSerializer.deserialize(json) + } catch (_: IllegalArgumentException) { + throw ctxt.weirdKeyException( + BaseComponent::class.java, + json, + "Couldn't parse TextComponent", + ) + } + } +} diff --git a/src/main/kotlin/org/simplemc/simpleannounce/config/SimpleAnnounceConfig.kt b/src/main/kotlin/org/simplemc/simpleannounce/config/SimpleAnnounceConfig.kt index 1c83bc1..424ab55 100644 --- a/src/main/kotlin/org/simplemc/simpleannounce/config/SimpleAnnounceConfig.kt +++ b/src/main/kotlin/org/simplemc/simpleannounce/config/SimpleAnnounceConfig.kt @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonAlias import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonTypeInfo import com.fasterxml.jackson.annotation.JsonUnwrapped +import net.md_5.bungee.api.chat.BaseComponent import org.bukkit.Sound import org.bukkit.boss.BarColor import org.bukkit.boss.BarStyle @@ -68,7 +69,7 @@ data class SimpleAnnounceConfig( override val excludesPermissions: List = emptyList(), @field:JsonAlias("message") override val messages: List, ) : AnnouncementConfig() { - data class ChatMessage(val message: String, override val sound: SoundConfig? = null) : Message + data class ChatMessage(val message: BaseComponent, override val sound: SoundConfig? = null) : Message } data class Boss( @@ -82,14 +83,10 @@ data class SimpleAnnounceConfig( @field:JsonUnwrapped val barConfig: BarConfig = BarConfig(), ) : AnnouncementConfig() { data class BossBarMessage( - val message: String, + val message: BaseComponent, override val sound: SoundConfig? = null, @field:JsonUnwrapped val barConfig: BarConfig? = null, - ) : Message { - init { - require(message.length <= 64) { "Boss Bar text must be <= 64 characters" } - } - } + ) : Message data class BarConfig( val hold: Duration = 5.seconds, @@ -118,8 +115,8 @@ data class SimpleAnnounceConfig( @field:JsonUnwrapped val titleConfig: TitleConfig = TitleConfig(), ) : AnnouncementConfig() { data class TitleMessage( - val title: String, - val subtitle: String? = null, + val title: BaseComponent, + val subtitle: BaseComponent? = null, override val sound: SoundConfig? = null, @field:JsonUnwrapped val titleConfig: TitleConfig? = null, ) : Message diff --git a/src/main/kotlin/org/simplemc/simpleannounce/sender/BossBarSender.kt b/src/main/kotlin/org/simplemc/simpleannounce/sender/BossBarSender.kt index f81d790..6d2e4be 100644 --- a/src/main/kotlin/org/simplemc/simpleannounce/sender/BossBarSender.kt +++ b/src/main/kotlin/org/simplemc/simpleannounce/sender/BossBarSender.kt @@ -15,7 +15,7 @@ class BossBarSender( val barConfig = message.barConfig ?: announcement.barConfig // create the bar - val bar = Bukkit.createBossBar(message.message, barConfig.color, barConfig.style) + val bar = Bukkit.createBossBar(message.message.toLegacyText(), barConfig.color, barConfig.style) bar.progress = if (barConfig.reverseAnimation) 1.0 else 0.0 // show bar to players diff --git a/src/main/kotlin/org/simplemc/simpleannounce/sender/ChatSender.kt b/src/main/kotlin/org/simplemc/simpleannounce/sender/ChatSender.kt index 8ba1c94..201072f 100644 --- a/src/main/kotlin/org/simplemc/simpleannounce/sender/ChatSender.kt +++ b/src/main/kotlin/org/simplemc/simpleannounce/sender/ChatSender.kt @@ -9,6 +9,6 @@ class ChatSender( ) : AnnouncementSender(plugin, announcement) { override fun run() { val message = getNextMessage() - send(message) { it.sendMessage(message.message) } + send(message) { it.spigot().sendMessage(message.message) } } } diff --git a/src/main/kotlin/org/simplemc/simpleannounce/sender/TitleSender.kt b/src/main/kotlin/org/simplemc/simpleannounce/sender/TitleSender.kt index 0b74b8f..2197ce4 100644 --- a/src/main/kotlin/org/simplemc/simpleannounce/sender/TitleSender.kt +++ b/src/main/kotlin/org/simplemc/simpleannounce/sender/TitleSender.kt @@ -13,8 +13,8 @@ class TitleSender( send(message) { it.sendTitle( - message.title, - message.subtitle, + message.title.toLegacyText(), + message.subtitle?.toLegacyText(), titleConfig.fadeInTicks, titleConfig.stayTicks, titleConfig.fadeOutTicks, diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a239db7..b49c4bd 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -31,7 +31,7 @@ # Chat type: # messages(ChatMessage list): -# - message(string): +# - message(Chat Component): # sound(SoundConfig, optional): # # Boss type: @@ -42,7 +42,7 @@ # animate(boolean): # reverseAnimation(boolean): # messages(BossBarMessage list): -# - message(string): +# - message(Chat Component): # sound(SoundConfig, optional): # # @@ -52,8 +52,8 @@ # stay(duration):