diff options
| author | Sho Sakuma <me@m1sk9.dev> | 2026-09-28 23:00:29 +0900 |
|---|---|---|
| committer | Sho Sakuma <me@m1sk9.dev> | 2026-09-28 23:00:29 +0900 |
| commit | af2feee95e7f6ebaef5466402789917ae65c0796 (patch) | |
| tree | 1a4bcd9c9ea3a32ddfb861ce541ca0877ef3aa88 | |
| parent | e725de11e80abd9d96784c7f08a09893c852fef0 (diff) | |
| download | LunaticChat-af2feee95e7f6ebaef5466402789917ae65c0796.tar.gz LunaticChat-af2feee95e7f6ebaef5466402789917ae65c0796.tar.bz2 LunaticChat-af2feee95e7f6ebaef5466402789917ae65c0796.zip | |
feat(paper): add world, display_name, channel_id and role chat placeholders
Operators asked for more of the sender's context in chat formats than the
name alone. {world} covers direct messages and channel chat; the channel
details and the sender's display name and role only exist for channel
chat, so only that format accepts them.
A direct message from another server renders {world} empty: the relay does
not carry the sender's world, and adding it would need a protocol bump and
a coordinated Velocity release for one placeholder. The renderer now
accepts underscores so the snake_case names match as written.
Co-Authored-By: Claude <noreply@anthropic.com>
15 files changed, 178 insertions, 26 deletions
diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/ChannelMessageHandler.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/ChannelMessageHandler.kt index d75b8ef..b9a8239 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/ChannelMessageHandler.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/ChannelMessageHandler.kt @@ -1,6 +1,8 @@ package dev.m1sk9.lunaticChat.paper.chat.handler +import dev.m1sk9.lunaticChat.engine.chat.channel.ChannelContext import dev.m1sk9.lunaticChat.engine.chat.channel.ChannelMessageLogEntry +import dev.m1sk9.lunaticChat.engine.chat.channel.ChannelRole import dev.m1sk9.lunaticChat.engine.debug.DebugCategory import dev.m1sk9.lunaticChat.engine.debug.DebugLogger import dev.m1sk9.lunaticChat.paper.chat.channel.ChannelManager @@ -13,6 +15,7 @@ import dev.m1sk9.lunaticChat.paper.i18n.LanguageManager import dev.m1sk9.lunaticChat.paper.i18n.channelMessage import dev.m1sk9.lunaticChat.paper.settings.PlayerSettingsManager import net.kyori.adventure.text.Component +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer import org.bukkit.Bukkit import org.bukkit.entity.Player @@ -35,7 +38,7 @@ class ChannelMessageHandler( val senderSettings = settingsManager?.getSettings(playerId) - val formattedMessage = formatChannelMessage(player.name, context.channel.name, message) + val formattedMessage = formatChannelMessage(player, context, message) // Play notification sound to sender if enabled if (senderSettings?.channelMessageNotificationEnabled == true) { @@ -87,8 +90,26 @@ class ChannelMessageHandler( } private fun formatChannelMessage( - senderName: String, - channelName: String, + sender: Player, + context: ChannelContext, message: String, - ): Component = messageFormats.current.channelMessage(senderName, channelName, message) + ): Component = + messageFormats.current.channelMessage( + sender = sender.name, + channel = context.channel.name, + channelId = context.channel.id, + displayName = LegacyComponentSerializer.legacySection().serialize(sender.displayName()), + message = message, + world = sender.world.name, + role = roleLabel(context.members.firstOrNull { it.playerId == sender.uniqueId }?.role), + ) + + private fun roleLabel(role: ChannelRole?): String = + languageManager.getMessage( + when (role) { + ChannelRole.OWNER -> "channel.role.owner" + ChannelRole.MODERATOR -> "channel.role.moderator" + ChannelRole.MEMBER, null -> "channel.role.member" + }, + ) } diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/DirectMessageHandler.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/DirectMessageHandler.kt index aa4f0d8..af3aa3f 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/DirectMessageHandler.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/DirectMessageHandler.kt @@ -142,9 +142,10 @@ class DirectMessageHandler( val formats = messageFormats.current - notifySpies(formats, sender.name, recipient.name, message) + notifySpies(formats, sender.name, recipient.name, message, sender.world.name) - val userMessage = formatMessage(formats, sender.name, recipient.name, displayMessage, replyTo = sender.name) + val userMessage = + formatMessage(formats, sender.name, recipient.name, displayMessage, sender.world.name, replyTo = sender.name) sender.apply { sendMessage(userMessage) takeIf { senderSettings?.directMessageNotificationEnabled == true } @@ -180,10 +181,10 @@ class DirectMessageHandler( val formats = messageFormats.current val recipientDisplay = "$targetName@$targetServerName" - notifySpies(formats, sender.name, recipientDisplay, message) + notifySpies(formats, sender.name, recipientDisplay, message, sender.world.name) val userMessage = - formatMessage(formats, sender.name, recipientDisplay, displayMessage, replyTo = recipientDisplay) + formatMessage(formats, sender.name, recipientDisplay, displayMessage, sender.world.name, replyTo = recipientDisplay) sender.apply { sendMessage(userMessage) takeIf { senderSettings?.directMessageNotificationEnabled == true } @@ -208,7 +209,8 @@ class DirectMessageHandler( val senderDisplay = "$senderName@$sourceServerName" val userMessage = - formatMessage(formats, senderDisplay, recipient.name, message, replyTo = senderDisplay) + // The relay does not carry the sender's world, so {world} renders empty for a remote sender. + formatMessage(formats, senderDisplay, recipient.name, message, world = "", replyTo = senderDisplay) recipient.apply { sendMessage(userMessage) takeIf { recipientSettings?.directMessageNotificationEnabled == true } @@ -233,12 +235,13 @@ class DirectMessageHandler( senderName: String, recipientName: String, rawMessage: String, + world: String, ) { SpyPermissionManager.notifySpies( noticeText = { languageManager.getMessage("general.spyMessage") }, exclude = { it.name == senderName || it.name == recipientName }, ) { - formatMessage(formats, senderName, recipientName, rawMessage, replyTo = senderName) + formatMessage(formats, senderName, recipientName, rawMessage, world, replyTo = senderName) } } @@ -247,8 +250,9 @@ class DirectMessageHandler( senderName: String, recipientName: String, message: String, + world: String, replyTo: String, ) = formats - .directMessage(senderName, recipientName, message) + .directMessage(senderName, recipientName, message, world) .clickEvent(ClickEvent.suggestCommand("/tell $replyTo ")) } diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatFormat.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatFormat.kt index 1ce872b..85e6b52 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatFormat.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatFormat.kt @@ -15,25 +15,35 @@ fun MessageFormatConfig.directMessage( sender: String, recipient: String, message: String, + world: String, ): Component = directMessageFormat.render( mapOf( ChatPlaceholder.SENDER to sender, ChatPlaceholder.RECIPIENT to recipient, ChatPlaceholder.MESSAGE to message, + ChatPlaceholder.WORLD to world, ), ) fun MessageFormatConfig.channelMessage( sender: String, channel: String, + channelId: String, + displayName: String, message: String, + world: String, + role: String, ): Component = channelMessageFormat.render( mapOf( ChatPlaceholder.SENDER to sender, ChatPlaceholder.CHANNEL to channel, + ChatPlaceholder.CHANNEL_ID to channelId, + ChatPlaceholder.DISPLAY_NAME to displayName, ChatPlaceholder.MESSAGE to message, + ChatPlaceholder.WORLD to world, + ChatPlaceholder.ROLE to role, ), ) @@ -50,7 +60,7 @@ fun MessageFormatConfig.crossServerGlobalChat( ), ) -private val PLACEHOLDER = Regex("""\{([A-Za-z]+)}""") +private val PLACEHOLDER = Regex("""\{([A-Za-z_]+)}""") // One pass over the format rather than one replace per placeholder, so a value that itself // contains "{message}" (a channel named that way, say) is inserted literally instead of being diff --git a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatPlaceholder.kt b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatPlaceholder.kt index b0b8034..1edb6d2 100644 --- a/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatPlaceholder.kt +++ b/platform-paper/src/main/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatPlaceholder.kt @@ -14,7 +14,11 @@ enum class ChatPlaceholder( RECIPIENT("recipient"), MESSAGE("message"), CHANNEL("channel"), + CHANNEL_ID("channel_id"), + DISPLAY_NAME("display_name"), SERVER("server"), + WORLD("world"), + ROLE("role"), ; companion object { diff --git a/platform-paper/src/main/resources/config.yml b/platform-paper/src/main/resources/config.yml index 4ca17b9..6f9a9d9 100644 --- a/platform-paper/src/main/resources/config.yml +++ b/platform-paper/src/main/resources/config.yml @@ -107,6 +107,10 @@ features: # {message} - The content of the message # {channel} - The name of the chat channel (only for channel chat) # {server} - The name of the server (only for Velocity cross-server chat) +# {world} - The world the sender is in (direct messages and channel chat; empty for a direct message from another server) +# {display_name} - The display name of the sender (only for channel chat) +# {channel_id} - The ID of the chat channel (only for channel chat) +# {role} - The sender's role in the channel: Owner, Moderator or Member (only for channel chat) # ---------------------------------------------- # These are the only settings /lc reload applies without a restart. diff --git a/platform-paper/src/main/resources/languages/en.yml b/platform-paper/src/main/resources/languages/en.yml index 7d1925e..8fd7144 100644 --- a/platform-paper/src/main/resources/languages/en.yml +++ b/platform-paper/src/main/resources/languages/en.yml @@ -235,6 +235,10 @@ channel: cannotTransferToSelf: "You cannot transfer ownership to yourself" receivedOwnership: "You are now the owner of {channel} (previously owned by {previousOwner})" error: "Failed to transfer ownership" + role: + owner: "Owner" + moderator: "Moderator" + member: "Member" general: playerOnlyCommand: "This command can only be executed by players." diff --git a/platform-paper/src/main/resources/languages/ja.yml b/platform-paper/src/main/resources/languages/ja.yml index 0350ad5..321a043 100644 --- a/platform-paper/src/main/resources/languages/ja.yml +++ b/platform-paper/src/main/resources/languages/ja.yml @@ -235,6 +235,10 @@ channel: cannotTransferToSelf: "自分自身にオーナー権限を譲渡することはできません" receivedOwnership: "チャンネル {channel} のオーナーになりました (前のオーナー: {previousOwner})" error: "オーナー権限の譲渡に失敗しました" + role: + owner: "オーナー" + moderator: "モデレーター" + member: "メンバー" general: playerOnlyCommand: "このコマンドはプレイヤーのみが実行できます" diff --git a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/TestUtils.kt b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/TestUtils.kt index 5b1a9a0..b38cbb4 100644 --- a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/TestUtils.kt +++ b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/TestUtils.kt @@ -17,6 +17,8 @@ import dev.m1sk9.lunaticChat.paper.config.key.VelocityIntegrationConfig import dev.m1sk9.lunaticChat.paper.i18n.Language import dev.m1sk9.lunaticChat.paper.storage.AsyncScheduler import io.mockk.mockk +import net.kyori.adventure.text.Component +import org.bukkit.World import org.bukkit.entity.Player import org.bukkit.plugin.java.JavaPlugin import java.util.UUID @@ -183,11 +185,17 @@ object TestUtils { uuid: UUID = UUID.randomUUID(), name: String = "TestPlayer", isOnline: Boolean = true, + displayName: Component = Component.text(name), + worldName: String = "world", ): Player { val player = mockk<Player>(relaxed = true) + val world = mockk<World>(relaxed = true) + io.mockk.every { world.name } returns worldName io.mockk.every { player.uniqueId } returns uuid io.mockk.every { player.name } returns name io.mockk.every { player.isOnline } returns isOnline + io.mockk.every { player.displayName() } returns displayName + io.mockk.every { player.world } returns world return player } diff --git a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/ChannelMessageHandlerTest.kt b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/ChannelMessageHandlerTest.kt index 26e2cc6..24f2897 100644 --- a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/ChannelMessageHandlerTest.kt +++ b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/ChannelMessageHandlerTest.kt @@ -2,6 +2,7 @@ package dev.m1sk9.lunaticChat.paper.chat.handler import dev.m1sk9.lunaticChat.engine.chat.channel.ChannelContext import dev.m1sk9.lunaticChat.engine.chat.channel.ChannelMessageLogEntry +import dev.m1sk9.lunaticChat.engine.chat.channel.ChannelRole import dev.m1sk9.lunaticChat.engine.debug.DebugLogger import dev.m1sk9.lunaticChat.paper.TestUtils import dev.m1sk9.lunaticChat.paper.chat.channel.ChannelManager @@ -18,6 +19,7 @@ import io.mockk.unmockkStatic import io.mockk.verify import net.kyori.adventure.sound.Sound import net.kyori.adventure.text.Component +import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer import org.bukkit.Bukkit import java.util.UUID @@ -97,6 +99,35 @@ class ChannelMessageHandlerTest { } @Test + fun `the channel format renders the sender's display name, world and role and the channel ID`() { + val owner = + TestUtils.createMockPlayer( + uuid = senderId, + name = "Alice", + displayName = Component.text("Queen", NamedTextColor.RED), + worldName = "world_nether", + ) + every { Bukkit.getPlayer(senderId) } returns owner + every { channelManager.getPlayerChannelContext(senderId) } returns + ChannelContext( + channel = channel, + members = + listOf( + TestUtils.createTestChannelMember(channelId = channel.id, playerId = senderId, role = ChannelRole.OWNER), + TestUtils.createTestChannelMember(channelId = channel.id, playerId = memberId), + ), + ) + every { languageManager.getMessage("channel.role.owner") } returns "Owner" + messageFormats.replace(MessageFormatConfig(channelMessageFormat = "{channel_id}|{display_name}|{world}|{role}")) + val delivered = slot<Component>() + + handler().sendChannelMessage(owner, "hello") + + verify { member.sendMessage(capture(delivered)) } + assertEquals("ch-1|§cQueen|world_nether|Owner", LegacyComponentSerializer.legacySection().serialize(delivered.captured)) + } + + @Test fun `a member who went offline receives nothing`() { val offline = TestUtils.createMockPlayer(uuid = memberId, name = "Bob", isOnline = false) every { Bukkit.getPlayer(memberId) } returns offline diff --git a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/DirectMessageHandlerTest.kt b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/DirectMessageHandlerTest.kt index 0246549..5c1e9ee 100644 --- a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/DirectMessageHandlerTest.kt +++ b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/chat/handler/DirectMessageHandlerTest.kt @@ -113,6 +113,29 @@ class DirectMessageHandlerTest { } @Test + fun `the direct message format renders the sender's world`() { + val formats = TestUtils.createTestConfiguration().messageFormat.copy(directMessageFormat = "{sender}@{world}: {message}") + val handler = createHandler(configuration = TestUtils.createTestConfiguration().copy(messageFormat = formats)) + val sender = TestUtils.createMockPlayer(name = "Alice", worldName = "world_the_end") + val recipient = TestUtils.createMockPlayer(name = "Bob") + + runBlocking { handler.sendDirectMessage(sender, recipient, "hi") } + + assertEquals("Alice@world_the_end: hi", recipient.receivedMessage().legacy()) + } + + @Test + fun `a direct message from another server renders the sender's world empty`() { + val formats = TestUtils.createTestConfiguration().messageFormat.copy(directMessageFormat = "{sender}[{world}]: {message}") + val handler = createHandler(configuration = TestUtils.createTestConfiguration().copy(messageFormat = formats)) + val recipient = TestUtils.createMockPlayer(name = "Bob") + + handler.handleIncomingCrossServerMessage(recipient, "Alice", "lobby", "hi") + + assertEquals("Alice@lobby[]: hi", recipient.receivedMessage().legacy()) + } + + @Test fun `handleIncomingCrossServerMessage shows the recipient the sender qualified by server`() { val handler = createHandler() val recipient = TestUtils.createMockPlayer(name = "Bob") diff --git a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatFormatTest.kt b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatFormatTest.kt index 0d23395..c977fd1 100644 --- a/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatFormatTest.kt +++ b/platform-paper/src/test/kotlin/dev/m1sk9/lunaticChat/paper/i18n/ChatFormatTest.kt @@ -4,6 +4,7 @@ import dev.m1sk9.lunaticChat.paper.config.key.MessageFormatConfig import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer import kotlin.reflect.full.memberProperties import kotlin.test.Test import kotlin.test.assertEquals @@ -12,25 +13,28 @@ import kotlin.test.assertTrue class ChatFormatTest { private val defaults = MessageFormatConfig() - private val placeholderPattern = Regex("""\{([A-Za-z]+)}""") + private val placeholderPattern = Regex("""\{([A-Za-z_]+)}""") private fun Component.legacy(): String = LegacyComponentSerializer.legacySection().serialize(this) private fun MessageFormatConfig.renderAll(): List<String> = listOf( - directMessage("Alice", "Bob", "hi"), - channelMessage("Alice", "general", "hi"), + directMessage("Alice", "Bob", "hi", "world"), + channelMessage("Alice", "general", "general", "Queen", "hi", "world", "Owner"), crossServerGlobalChat("lobby", "Alice", "hi"), ).map { it.legacy() } @Test fun `the default direct message format renders sender, recipient and message`() { - assertEquals("§7[§eAlice §7>> §eBob§7] §fhi", defaults.directMessage("Alice", "Bob", "hi").legacy()) + assertEquals("§7[§eAlice §7>> §eBob§7] §fhi", defaults.directMessage("Alice", "Bob", "hi", "world").legacy()) } @Test fun `the default channel message format renders channel, sender and message`() { - assertEquals("§7[§b#general§7] §eAlice: §fhi", defaults.channelMessage("Alice", "general", "hi").legacy()) + assertEquals( + "§7[§b#general§7] §eAlice: §fhi", + defaults.channelMessage("Alice", "general", "general", "Queen", "hi", "world", "Owner").legacy(), + ) } @Test @@ -39,29 +43,56 @@ class ChatFormatTest { } @Test + fun `the direct message format renders the sender's world`() { + val formats = MessageFormatConfig(directMessageFormat = "{sender} ({world}): {message}") + + assertEquals("Alice (world_nether): hi", formats.directMessage("Alice", "Bob", "hi", "world_nether").legacy()) + } + + @Test + fun `the channel format renders channel ID, display name, world and role`() { + val formats = MessageFormatConfig(channelMessageFormat = "{channel_id} {display_name} {world} {role}") + + assertEquals( + "general-1 Queen world_nether Owner", + formats.channelMessage("Alice", "General", "general-1", "Queen", "hi", "world_nether", "Owner").legacy(), + ) + } + + @Test + fun `section sign codes in a display name become styles`() { + val formats = MessageFormatConfig(channelMessageFormat = "{display_name}") + + val rendered = formats.channelMessage("Alice", "general", "general", "§cQueen", "hi", "world", "Owner") + + assertEquals("Queen", PlainTextComponentSerializer.plainText().serialize(rendered)) + assertEquals(NamedTextColor.RED, rendered.color()) + } + + @Test fun `unknown placeholders and ones the format does not accept are left as written`() { val formats = MessageFormatConfig(directMessageFormat = "{foo} {channel} {message}") - assertEquals("{foo} {channel} hi", formats.directMessage("Alice", "Bob", "hi").legacy()) + assertEquals("{foo} {channel} hi", formats.directMessage("Alice", "Bob", "hi", "world").legacy()) } @Test fun `a value containing a placeholder is inserted literally`() { val formats = MessageFormatConfig(channelMessageFormat = "<{channel}> {message}") - assertEquals("<{message}> hi", formats.channelMessage("Alice", "{message}", "hi").legacy()) + assertEquals("<{message}> hi", formats.channelMessage("Alice", "{message}", "general", "Queen", "hi", "world", "Owner").legacy()) } @Test fun `dollar signs and backslashes in a value are inserted literally`() { val formats = MessageFormatConfig(directMessageFormat = "{message}") - assertEquals("$1 \\ {sender}", formats.directMessage("Alice", "Bob", "$1 \\ {sender}").legacy()) + assertEquals("$1 \\ {sender}", formats.directMessage("Alice", "Bob", "$1 \\ {sender}", "world").legacy()) } @Test fun `section sign codes become styles rather than text`() { - val rendered = defaults.directMessage("Alice", "Bob", "hi") + val rendered = defaults.directMessage("Alice", "Bob", "hi", "world") assertTrue(rendered.children().isNotEmpty()) assertEquals(NamedTextColor.GRAY, rendered.children().first().color()) @@ -102,6 +133,6 @@ class ChatFormatTest { val keys = ChatPlaceholder.entries.map { it.key } assertEquals(keys.size, keys.toSet().size) - keys.forEach { assertTrue(Regex("[A-Za-z]+").matches(it), "$it cannot be matched by the renderer") } + keys.forEach { assertTrue(Regex("[A-Za-z_]+").matches(it), "$it cannot be matched by the renderer") } } } diff --git a/website/src/docs/configuration.md b/website/src/docs/configuration.md index 4b46b55..35e7599 100644 --- a/website/src/docs/configuration.md +++ b/website/src/docs/configuration.md @@ -172,8 +172,8 @@ proxy logs for everyone else. | Key | Default | Available Placeholders | |-----|---------|----------------------| -| `directMessageFormat` | `§7[§e{sender} §7>> §e{recipient}§7] §f{message}` | `{sender}`, `{recipient}`, `{message}` | -| `channelMessageFormat` | `§7[§b#{channel}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{channel}` | +| `directMessageFormat` | `§7[§e{sender} §7>> §e{recipient}§7] §f{message}` | `{sender}`, `{recipient}`, `{message}`, `{world}` | +| `channelMessageFormat` | `§7[§b#{channel}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{channel}`, `{channel_id}`, `{display_name}`, `{world}`, `{role}` | | `crossServerGlobalChatFormat` | `§7[§6{server}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{server}` | ## Data Files diff --git a/website/src/docs/reference/message-format.md b/website/src/docs/reference/message-format.md index 68fee84..b0976fa 100644 --- a/website/src/docs/reference/message-format.md +++ b/website/src/docs/reference/message-format.md @@ -17,6 +17,10 @@ These are the only settings `/lc reload` <Badge type="tip" text="v1.4.0~" /> app | `{message}` | Message content | All | | `{channel}` | Channel name | `channelMessageFormat` | | `{server}` | Server name | `crossServerGlobalChatFormat` | +| `{world}` <Badge type="tip" text="v1.5.0~" /> | World the sender is in. Empty for a direct message from another server | `directMessageFormat`, `channelMessageFormat` | +| `{display_name}` <Badge type="tip" text="v1.5.0~" /> | Display name of the sender, including colors set by other plugins | `channelMessageFormat` | +| `{channel_id}` <Badge type="tip" text="v1.5.0~" /> | Channel ID | `channelMessageFormat` | +| `{role}` <Badge type="tip" text="v1.5.0~" /> | Sender's role in the channel (Owner / Moderator / Member) | `channelMessageFormat` | ## Format List diff --git a/website/src/ja/docs/configuration.md b/website/src/ja/docs/configuration.md index 59d0c73..a5c211a 100644 --- a/website/src/ja/docs/configuration.md +++ b/website/src/ja/docs/configuration.md @@ -167,8 +167,8 @@ LUNATICCHAT_DEBUG=velocity,protocol | キー | デフォルト | 利用可能なプレースホルダー | |------|------------|--------------------------| -| `directMessageFormat` | `§7[§e{sender} §7>> §e{recipient}§7] §f{message}` | `{sender}`, `{recipient}`, `{message}` | -| `channelMessageFormat` | `§7[§b#{channel}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{channel}` | +| `directMessageFormat` | `§7[§e{sender} §7>> §e{recipient}§7] §f{message}` | `{sender}`, `{recipient}`, `{message}`, `{world}` | +| `channelMessageFormat` | `§7[§b#{channel}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{channel}`, `{channel_id}`, `{display_name}`, `{world}`, `{role}` | | `crossServerGlobalChatFormat` | `§7[§6{server}§7] §e{sender}: §f{message}` | `{sender}`, `{message}`, `{server}` | ## データファイル diff --git a/website/src/ja/docs/reference/message-format.md b/website/src/ja/docs/reference/message-format.md index 3eddd1a..79c6745 100644 --- a/website/src/ja/docs/reference/message-format.md +++ b/website/src/ja/docs/reference/message-format.md @@ -17,6 +17,10 @@ layout: doc | `{message}` | メッセージの内容 | すべて | | `{channel}` | チャンネル名 | `channelMessageFormat` | | `{server}` | サーバー名 | `crossServerGlobalChatFormat` | +| `{world}` <Badge type="tip" text="v1.5.0~" /> | 送信者がいるワールド名.別サーバーから届いたダイレクトメッセージでは空になります | `directMessageFormat`, `channelMessageFormat` | +| `{display_name}` <Badge type="tip" text="v1.5.0~" /> | 送信者の表示名.他のプラグインが設定した色も含みます | `channelMessageFormat` | +| `{channel_id}` <Badge type="tip" text="v1.5.0~" /> | チャンネル ID | `channelMessageFormat` | +| `{role}` <Badge type="tip" text="v1.5.0~" /> | チャンネル内での送信者の役割 (オーナー / モデレーター / メンバー) | `channelMessageFormat` | ## フォーマット一覧 |
