From 76430e680447333bea22d7f87888481b565a2622 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Mon, 4 Dec 2023 23:08:36 -0500 Subject: [PATCH 01/11] Rewrite to avoid many async ChannelData writes, try to clean up overall structure to encourage this goal --- .../com/mineinabyss/chatty/ChattyChannel.kt | 62 +++++ .../com/mineinabyss/chatty/ChattyCommands.kt | 247 +++++++++--------- .../com/mineinabyss/chatty/ChattyConfig.kt | 23 -- .../chatty/components/ChannelData.kt | 21 +- .../mineinabyss/chatty/helpers/ChatHelpers.kt | 47 +--- .../chatty/listeners/ChatListener.kt | 85 +++--- .../chatty/listeners/ChattyProxyListener.kt | 53 ++-- .../chatty/listeners/DiscordListener.kt | 25 +- .../chatty/listeners/PlayerListener.kt | 10 +- .../chatty/placeholders/Placeholders.kt | 41 +-- .../chatty/queries/SpyingPlayers.kt | 13 + .../com/mineinabyss/chatty/tags/ChattyTags.kt | 6 +- gradle.properties | 2 +- 13 files changed, 341 insertions(+), 294 deletions(-) create mode 100644 chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt create mode 100644 chatty-paper/src/main/kotlin/com/mineinabyss/chatty/queries/SpyingPlayers.kt diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt new file mode 100644 index 0000000..a61a299 --- /dev/null +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt @@ -0,0 +1,62 @@ +package com.mineinabyss.chatty + +import com.mineinabyss.chatty.components.ChannelType +import com.mineinabyss.chatty.components.SpyOnChannels +import com.mineinabyss.chatty.queries.SpyingPlayers +import com.mineinabyss.geary.papermc.tracking.entities.toGeary +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import net.kyori.adventure.audience.Audience +import net.kyori.adventure.text.format.NamedTextColor +import net.kyori.adventure.text.format.TextColor +import org.bukkit.Bukkit +import org.bukkit.entity.Player + +@Serializable +data class ChattyChannel( + val channelType: ChannelType, + val permission: String = "", + val logToConsole: Boolean = true, + val simpleConsoleMessages: Boolean = false, + val proxy: Boolean = false, + val discordsrv: Boolean = true, + val isDefaultChannel: Boolean = false, + val isStaffChannel: Boolean = false, + val format: String = "", + @SerialName("messageColor") val _messageColor: String = "white", + val channelRadius: Int = 0, + val channelAliases: List = listOf(), +) { + val key by lazy { chatty.config.channels.entries.first { it.value == this }.key } + val messageColor: TextColor + get() = TextColor.fromHexString(_messageColor) ?: NamedTextColor.NAMES.value(_messageColor) + ?: NamedTextColor.WHITE + + + fun getAudience(player: Player): Collection { + val onlinePlayers by lazy { Bukkit.getOnlinePlayers() } + val audiences = mutableSetOf() + + when (channelType) { + ChannelType.GLOBAL -> audiences.addAll(onlinePlayers) + ChannelType.RADIUS -> { + if (channelRadius <= 0) audiences.addAll(onlinePlayers) + else audiences.addAll(player.world.players.filter { p -> + player.location.distanceSquared(p.location) <= (channelRadius * channelRadius) + }) + } + + ChannelType.PERMISSION -> audiences.addAll(onlinePlayers.filter { p -> p.hasPermission(permission) }) + // Intended for Guilds etc., want to consider finding a non-permission way for this + ChannelType.PRIVATE -> audiences.add(player) + } + + // Add spying players + val spies = SpyingPlayers().run { + toList { query -> query.player.takeIf { query.spying.channels.contains(key) } }.filterNotNull() + } + audiences.addAll(spies) + + return audiences + } +} diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt index 03ccca8..52ff99b 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt @@ -9,7 +9,6 @@ import com.mineinabyss.chatty.helpers.* import com.mineinabyss.geary.papermc.tracking.entities.toGeary import com.mineinabyss.idofront.commands.arguments.stringArg import com.mineinabyss.idofront.commands.execution.IdofrontCommandExecutor -import com.mineinabyss.idofront.commands.extensions.actions.ensureSenderIsPlayer import com.mineinabyss.idofront.commands.extensions.actions.playerAction import com.mineinabyss.idofront.entities.toPlayer import com.mineinabyss.idofront.events.call @@ -23,8 +22,6 @@ import org.bukkit.command.Command import org.bukkit.command.CommandSender import org.bukkit.command.TabCompleter import org.bukkit.entity.Player -import kotlin.collections.component1 -import kotlin.collections.component2 import kotlin.collections.set class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { @@ -35,46 +32,23 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { chatty.plugin.createChattyContext() sender.sendConsoleMessage("Chatty has been reloaded!") } - // chatty.config.reload() is a thing but does not regen or remove stuff so -// chatty.config.reload() -// chatty.messages.reload() -// chatty.emoteFixer.reload() - } - ("message" / "msg")(desc = "Private message another player") { - ensureSenderIsPlayer() - val player by stringArg() - action { - (sender as? Player)?.handleSendingPrivateMessage( - player.toPlayer() ?: return@action, - arguments, - false - ) - } - } - ("reply" / "r")(desc = "Reply to your previous private message") { - ensureSenderIsPlayer() - action { - val player = sender as? Player ?: return@action - player.chattyData.lastMessager?.toPlayer()?.let { player.handleSendingPrivateMessage(it, arguments, true) } - ?: player.sendFormattedMessage(chatty.messages.privateMessages.emptyReply) - } } "ping"(desc = "Commands related to the chat-ping feature.") { "toggle"(desc = "Toggle the ping sound.") { - ensureSenderIsPlayer() - action { - val player = sender as? Player ?: return@action - player.toGeary().setPersisting(player.chattyData.apply { ChannelData(channelId, lastChannelUsed, !disablePingSound, pingSound, lastMessager) }) + playerAction { + val gearyPlayer = player.toGeary() + val oldData = gearyPlayer.get() ?: return@playerAction + gearyPlayer.setPersisting(oldData.copy(disablePingSound = !oldData.disablePingSound)) player.sendFormattedMessage(chatty.messages.ping.toggledPingSound) } } "sound"(desc = "Change your pingsound") { val soundName by stringArg() - ensureSenderIsPlayer() - action { - val player = sender as? Player ?: return@action + playerAction { + val gearyPlayer = player.toGeary() + val oldData = gearyPlayer.get() ?: return@playerAction if (soundName in getAlternativePingSounds) { - player.toGeary().setPersisting(player.chattyData.apply { ChannelData(channelId, lastChannelUsed, !disablePingSound, soundName, lastMessager) }) + gearyPlayer.setPersisting(oldData.copy(pingSound = soundName)) player.sendFormattedMessage(chatty.messages.ping.changedPingSound) } else player.sendFormattedMessage(chatty.messages.ping.invalidPingSound) } @@ -87,21 +61,19 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { } } ("nickname" / "nick") { - action { + playerAction { val nickMessage = chatty.messages.nicknames val nick = arguments.toSentence() - val player = sender as? Player - val bypassFormatPerm = player?.hasPermission(ChattyPermissions.NICKNAME_OTHERS) == true + val bypassFormatPerm = player.hasPermission(ChattyPermissions.NICKNAME_OTHERS) when { - player is Player && !player.hasPermission(ChattyPermissions.NICKNAME) -> + !player.hasPermission(ChattyPermissions.NICKNAME) -> player.sendFormattedMessage(nickMessage.selfDenied) arguments.isEmpty() -> { // Removes players displayname or sends error if sender is console - player?.chattyNickname = null - player?.sendFormattedMessage(nickMessage.selfEmpty) - ?: sender.sendConsoleMessage(nickMessage.consoleNicknameSelf) + player.chattyNickname = null + player.sendFormattedMessage(nickMessage.selfEmpty) } arguments.first().startsWith(chatty.config.nicknames.nickNameOtherPrefix) -> { @@ -109,34 +81,34 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { val otherNick = nick.removePlayerToNickFromString() when { - player?.hasPermission(ChattyPermissions.NICKNAME_OTHERS) == false -> + !player.hasPermission(ChattyPermissions.NICKNAME_OTHERS) -> player.sendFormattedMessage(nickMessage.otherDenied, otherPlayer) otherPlayer == null || otherPlayer !in Bukkit.getOnlinePlayers() -> - player?.sendFormattedMessage(nickMessage.invalidPlayer, otherPlayer) + player.sendFormattedMessage(nickMessage.invalidPlayer, otherPlayer) otherNick.isEmpty() -> { otherPlayer.chattyNickname = null otherPlayer.sendFormattedMessage(nickMessage.selfEmpty) - player?.sendFormattedMessage(nickMessage.otherEmpty, otherPlayer) + player.sendFormattedMessage(nickMessage.otherEmpty, otherPlayer) } !bypassFormatPerm && !otherNick.verifyNickLength() -> - player?.sendFormattedMessage(nickMessage.tooLong) + player.sendFormattedMessage(nickMessage.tooLong) otherNick.isNotEmpty() -> { otherPlayer.chattyNickname = otherNick - player?.sendFormattedMessage(nickMessage.otherSuccess, otherPlayer) + player.sendFormattedMessage(nickMessage.otherSuccess, otherPlayer) } } } else -> { if (!bypassFormatPerm && !nick.verifyNickLength()) { - player?.sendFormattedMessage(nickMessage.tooLong) + player.sendFormattedMessage(nickMessage.tooLong) } else { - player?.chattyNickname = nick - player?.sendFormattedMessage(nickMessage.selfSuccess) + player.chattyNickname = nick + player.sendFormattedMessage(nickMessage.selfSuccess) } } } @@ -144,97 +116,79 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { } "commandspy" { playerAction { - (sender as? Player)?.toGeary()?.let { - if (it.has()) { - it.remove() - player.sendFormattedMessage(chatty.messages.spying.commandSpyOff) - } else { - it.getOrSetPersisting { CommandSpy() } - player.sendFormattedMessage(chatty.messages.spying.commandSpyOn) - } + val gearyPlayer = player.toGeary() + if (gearyPlayer.has()) { + gearyPlayer.remove() + player.sendFormattedMessage(chatty.messages.spying.commandSpyOff) + } else { + gearyPlayer.getOrSetPersisting { CommandSpy() } + player.sendFormattedMessage(chatty.messages.spying.commandSpyOn) } } } "spy" { - val channel by stringArg() - ensureSenderIsPlayer() - action { - val player = sender as? Player ?: return@action + val channelName by stringArg() + playerAction { + val channel = chatty.config.channels[channelName] ?: run { + player.sendFormattedMessage(chatty.messages.channels.noChannelWithName) + return@playerAction + } val spy = player.toGeary().getOrSetPersisting { SpyOnChannels() } when { - channel !in chatty.config.channels.keys -> - player.sendFormattedMessage(chatty.messages.channels.noChannelWithName) - - getChannelFromId(channel)?.channelType == ChannelType.GLOBAL -> + channel.channelType == ChannelType.GLOBAL -> player.sendFormattedMessage(chatty.messages.spying.cannotSpyOnChannel) - !player.hasPermission(getChannelFromId(channel)?.permission.toString()) -> + !player.hasPermission(channel.permission) -> player.sendFormattedMessage(chatty.messages.spying.cannotSpyOnChannel) - channel in spy.channels -> { + channel.key in spy.channels -> { player.sendFormattedMessage(chatty.messages.spying.stopSpyingOnChannel) - spy.channels.remove(channel) + spy.channels.remove(channel.key) } else -> { - spy.channels.add(channel) + spy.channels.add(channel.key) player.sendFormattedMessage(chatty.messages.spying.startSpyingOnChannel) } } } } - getAllChannelNames().forEach { channelName -> - channelName { - ensureSenderIsPlayer() - action { - val player = sender as? Player ?: return@action - player.swapChannelCommand(channelName) - } - } - } - chatty.config.channels.forEach { (channelId, channel) -> - channel.channelAliases.forEach { alias -> - alias { - ensureSenderIsPlayer() - action { - val player = sender as? Player ?: return@action - player.swapChannelCommand(channelId) + chatty.config.channels.values + .flatMap { it.channelAliases + it.key } + .forEach { channelName -> + channelName { + playerAction { + player.swapChannelCommand(chatty.config.channels[channelName]) } } } - } } ("global" / "g") { - ensureSenderIsPlayer() - action { - (sender as? Player)?.shortcutCommand(getGlobalChat(), arguments) + playerAction { + player.shortcutCommand(getGlobalChat(), arguments) } } ("local" / "l") { - ensureSenderIsPlayer() - action { - (sender as? Player)?.shortcutCommand(getRadiusChannel(), arguments) + playerAction { + player.shortcutCommand(getRadiusChannel(), arguments) } } ("admin" / "a") { - ensureSenderIsPlayer() - action { - (sender as? Player)?.shortcutCommand(getAdminChannel(), arguments) + playerAction { + player.shortcutCommand(getAdminChannel(), arguments) } } ("message" / "msg")(desc = "Private message another player") { - ensureSenderIsPlayer() - val player by stringArg() - action { - (sender as? Player)?.handleSendingPrivateMessage(player.toPlayer() ?: return@action, arguments, false) + val otherPlayer by stringArg() + playerAction { + player.handleSendingPrivateMessage(otherPlayer.toPlayer() ?: return@playerAction, arguments, false) } } ("reply" / "r")(desc = "Reply to your previous private message") { - ensureSenderIsPlayer() - action { - val player = sender as? Player ?: return@action - player.chattyData.lastMessager?.toPlayer()?.let { player.handleSendingPrivateMessage(it, arguments, true) } + playerAction { + player.toGeary().get()?.lastMessager?.toPlayer() + ?.let { player.handleSendingPrivateMessage(it, arguments, true) } ?: player.sendFormattedMessage(chatty.messages.privateMessages.emptyReply) } } @@ -250,44 +204,61 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { val otherPrefix = chatty.config.nicknames.nickNameOtherPrefix return if (command.name == "chatty") { when (args.size) { - 1 -> listOf("message", "ping", "reload", "channels", "nickname", "spy", "commandspy").filter { s -> s.startsWith(args[0]) } + 1 -> listOf( + "message", + "ping", + "reload", + "channels", + "nickname", + "spy", + "commandspy" + ).filter { s -> s.startsWith(args[0]) } + 2 -> when (args[0]) { "ping" -> listOf("toggle", "sound").filter { s -> s.startsWith(args[1]) } "message", "msg" -> onlinePlayers.filter { s -> s.startsWith(args[1], true) } "spy" -> - chatty.config.channels.keys.toList().filter { s -> - s.startsWith(args[1], true) && getChannelFromId(s)?.channelType != ChannelType.GLOBAL - } + chatty.config.channels.entries.filter { s -> + s.key.startsWith(args[1], true) && s.value.channelType != ChannelType.GLOBAL + }.map { it.key } + else -> emptyList() } + 3 -> when { args[1] == "sound" -> getAlternativePingSounds.filter { s -> s.startsWith(args[2], true) } args[1].startsWith(otherPrefix) -> onlinePlayers.filter { s -> s.replace(otherPrefix.toString(), "").startsWith(args[2], true) } + else -> emptyList() } + else -> emptyList() } } else emptyList() } private fun Player.shortcutCommand( - channel: Map.Entry?, + channel: Map.Entry?, arguments: List ) { + val chattyData = toGeary().get() ?: return val currentChannel = chattyData.channelId when { channel == null -> sendFormattedMessage(chatty.messages.channels.noChannelWithName) channel.value.permission.isNotBlank() && !hasPermission(channel.value.permission) -> sendFormattedMessage(chatty.messages.channels.missingChannelPermission) - arguments.isEmpty() -> swapChannelCommand(channel.key) + arguments.isEmpty() -> swapChannelCommand(channel.value) else -> { - toGeary().setPersisting(chattyData.copy(channelId = channel.key, lastChannelUsed = channel.key)) + toGeary().setPersisting(chattyData.copy(channelId = channel.key, lastChannelUsedId = channel.key)) chatty.plugin.launch(chatty.plugin.asyncDispatcher) { GenericChattyDecorateEvent(this@shortcutCommand, arguments.toSentence().miniMsg()).call { - GenericChattyChatEvent(this@shortcutCommand, (this as AsyncChatDecorateEvent).result()).callEvent() + GenericChattyChatEvent( + this@shortcutCommand, + (this as AsyncChatDecorateEvent).result() + ).callEvent() } } toGeary().setPersisting(chattyData.copy(channelId = currentChannel)) @@ -296,23 +267,24 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { } private val replyMap = mutableMapOf() - private fun handleReplyTimer(player: Player): Job { - if (player in replyMap) return replyMap[player]!! + private fun handleReplyTimer(player: Player, chattyData: ChannelData): Job { + replyMap[player]?.let { return it } replyMap[player]?.cancel() - return chatty.plugin.launch(chatty.plugin.asyncDispatcher) { + return chatty.plugin.launch { delay(chatty.config.privateMessages.messageReplyTime) replyMap[player]?.cancel() replyMap.remove(player) - player.toGeary().setPersisting(player.chattyData.copy(lastMessager = null)) + player.toGeary().setPersisting(chattyData.copy(lastMessager = null)) } } - private fun Player.handleSendingPrivateMessage(player: Player, arguments: List, isReply: Boolean = false) { + private fun Player.handleSendingPrivateMessage(other: Player, arguments: List, isReply: Boolean = false) { + val chattyData = toGeary().get() ?: return when { !chatty.config.privateMessages.enabled -> sendFormattedMessage(chatty.messages.privateMessages.disabled) - isReply && this.chattyData.lastMessager == null -> + isReply && chattyData.lastMessager == null -> sendFormattedMessage(chatty.messages.privateMessages.emptyReply) !isReply && arguments.first().toPlayer() == null -> @@ -320,17 +292,21 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { else -> { val msg = if (isReply) arguments.toSentence() else arguments.removeFirstArgumentOfStringList() - if (msg.isEmpty() || this == player) return + if (msg.isEmpty() || this == other) return - replyMap[player] = handleReplyTimer(player) + replyMap[other] = handleReplyTimer(other, chattyData) - this.sendFormattedPrivateMessage(chatty.config.privateMessages.messageSendFormat, msg, player) - player.sendFormattedPrivateMessage(chatty.config.privateMessages.messageReceiveFormat, msg, this) - player.toGeary().setPersisting(player.chattyData.copy(lastMessager = uniqueId)) + this.sendFormattedPrivateMessage(chatty.config.privateMessages.messageSendFormat, msg, other) + other.sendFormattedPrivateMessage(chatty.config.privateMessages.messageReceiveFormat, msg, this) + val gearyOther = other.toGeary() + val otherChannelData = gearyOther.get() + if (otherChannelData != null) { + gearyOther.setPersisting(otherChannelData.copy(lastMessager = uniqueId)) + } if (chatty.config.privateMessages.messageSendSound.isNotEmpty()) - this.playSound(player.location, chatty.config.privateMessages.messageSendSound, 1f, 1f) + this.playSound(other.location, chatty.config.privateMessages.messageSendSound, 1f, 1f) if (chatty.config.privateMessages.messageReceivedSound.isNotEmpty()) - player.playSound(player.location, chatty.config.privateMessages.messageReceivedSound, 1f, 1f) + other.playSound(other.location, chatty.config.privateMessages.messageReceivedSound, 1f, 1f) } } } @@ -339,10 +315,31 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { this.sendMessage(translatePlaceholders((optionalPlayer ?: this), message).parseTags(this, true)) private fun Player.sendFormattedPrivateMessage(messageFormat: String, message: String, receiver: Player) = - this.sendMessage((translatePlaceholders(receiver, messageFormat).serialize() + message).parseTags(receiver, true)) + this.sendMessage( + (translatePlaceholders(receiver, messageFormat).serialize() + message) + .parseTags(receiver, true) + ) private fun CommandSender.sendConsoleMessage(message: String) = this.sendMessage(message.parseTags(null, true)) private fun List.removeFirstArgumentOfStringList(): String = this.filter { it != this.first() }.toSentence() + + + private fun Player.swapChannelCommand(newChannel: ChattyChannel?) { + when { + newChannel == null -> + sendFormattedMessage(chatty.messages.channels.noChannelWithName) + + newChannel.permission.isNotBlank() && !hasPermission(newChannel.permission) -> + sendFormattedMessage(chatty.messages.channels.missingChannelPermission) + + else -> { + val chattyData = toGeary().get() ?: return + toGeary().setPersisting(chattyData.copy(channelId = newChannel.key, lastChannelUsedId = newChannel.key)) + sendFormattedMessage(chatty.messages.channels.channelChanged) + } + } + } + } diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyConfig.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyConfig.kt index 4f55315..08eb59a 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyConfig.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyConfig.kt @@ -2,10 +2,7 @@ package com.mineinabyss.chatty import com.mineinabyss.chatty.components.ChannelType import com.mineinabyss.idofront.serialization.DurationSerializer -import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import net.kyori.adventure.text.format.NamedTextColor -import net.kyori.adventure.text.format.TextColor import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes @@ -72,26 +69,6 @@ data class ChattyConfig( val sendProxyMessagesToDiscord: Boolean = true, ) - @Serializable - data class ChattyChannel( - val channelType: ChannelType, - val permission: String = "", - val logToConsole: Boolean = true, - val simpleConsoleMessages: Boolean = false, - val proxy: Boolean = false, - val discordsrv: Boolean = true, - val isDefaultChannel: Boolean = false, - val isStaffChannel: Boolean = false, - val format: String = "", - @SerialName("messageColor") val _messageColor: String = "white", - val channelRadius: Int = 0, - val channelAliases: List = listOf(), - ) { - val messageColor: TextColor - get() = TextColor.fromHexString(_messageColor) ?: NamedTextColor.NAMES.value(_messageColor) - ?: NamedTextColor.WHITE - } - @Serializable data class Ping( val enabledChannels: List = listOf(), diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/components/ChannelData.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/components/ChannelData.kt index 959eeba..f7c442c 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/components/ChannelData.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/components/ChannelData.kt @@ -1,24 +1,35 @@ package com.mineinabyss.chatty.components +import com.mineinabyss.chatty.ChattyChannel +import com.mineinabyss.chatty.chatty import com.mineinabyss.chatty.helpers.getDefaultChat -import com.mineinabyss.geary.papermc.tracking.entities.toGeary import com.mineinabyss.idofront.serialization.UUIDSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.bukkit.entity.Player import java.util.* @Serializable @SerialName("chatty:chatty_data") data class ChannelData( val channelId: String = getDefaultChat().key, - val lastChannelUsed: String = channelId, + @SerialName("lastChannelUsed") + val lastChannelUsedId: String = channelId, val disablePingSound: Boolean = false, val pingSound: String? = null, val lastMessager: @Serializable(UUIDSerializer::class) UUID? = null, -) +) { + val channel: ChattyChannel? get() = chatty.config.channels[channelId] + val lastChannelUsed: ChattyChannel? get() = chatty.config.channels[lastChannelUsedId] + + fun withChannelVerified(): ChannelData { + if (channelId !in chatty.config.channels) + return copy(channelId = getDefaultChat().key) + return this + } +} + +//val Player.chattyData get() = toGeary().getOrSetPersisting { ChannelData() } -val Player.chattyData get() = toGeary().getOrSetPersisting { ChannelData() } enum class ChannelType { GLOBAL, RADIUS, diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/helpers/ChatHelpers.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/helpers/ChatHelpers.kt index 660c651..b26b5cb 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/helpers/ChatHelpers.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/helpers/ChatHelpers.kt @@ -4,8 +4,8 @@ import com.combimagnetron.imageloader.Avatar import com.combimagnetron.imageloader.Image.ColorType import com.combimagnetron.imageloader.ImageUtils import com.mineinabyss.chatty.chatty +import com.mineinabyss.chatty.components.ChannelData import com.mineinabyss.chatty.components.ChannelType -import com.mineinabyss.chatty.components.chattyData import com.mineinabyss.chatty.components.chattyNickname import com.mineinabyss.chatty.placeholders.chattyPlaceholderTags import com.mineinabyss.geary.papermc.tracking.entities.toGeary @@ -45,10 +45,9 @@ fun String.checkForPlayerPings(channelId: String): Player? { } } -fun Component.handlePlayerPings(player: Player, pingedPlayer: Player) { - getChannelFromId(player.chattyData.channelId) ?: return +fun Component.handlePlayerPings(player: Player, pingedPlayer: Player, pingedChannelData: ChannelData) { val ping = chatty.config.ping - val pingSound = pingedPlayer.chattyData.pingSound ?: ping.defaultPingSound + val pingSound = pingedChannelData.pingSound ?: ping.defaultPingSound val clickToReply = if (ping.clickToReply) ".toSentence() = this.joinToString(" ") fun String.toPlayer() = Bukkit.getPlayer(this) -fun Player.swapChannelCommand(channelId: String) { - val newChannel = getChannelFromId(channelId) - when { - newChannel == null -> - sendFormattedMessage(chatty.messages.channels.noChannelWithName) - - newChannel.permission.isNotBlank() && !hasPermission(newChannel.permission) -> - sendFormattedMessage(chatty.messages.channels.missingChannelPermission) - - else -> { - toGeary().setPersisting(chattyData.copy(channelId = channelId, lastChannelUsed = channelId)) - sendFormattedMessage(chatty.messages.channels.channelChanged) - } - } -} - fun Player.sendFormattedMessage(message: String) = this.sendMessage(translatePlaceholders(this, message).parseTags(player, true)) fun formattedResult(player: Player, message: Component): Component { - player.verifyPlayerChannel() - val channel = player.getChannelFromPlayer() ?: return message + val channelData = player.toGeary().get()?.withChannelVerified() + val channel = channelData?.channel ?: return message val parsedFormat = translatePlaceholders(player, channel.format).parseTags(player, true) val parsedMessage = Component.text("").color(channel.messageColor).append(message.parseTags(player, false)) return parsedFormat.append(parsedMessage) } - -fun T.copyWithEdit(block: T.() -> T): T { - return block() -} diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChatListener.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChatListener.kt index 0c43033..dfcf0b7 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChatListener.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChatListener.kt @@ -1,18 +1,20 @@ package com.mineinabyss.chatty.listeners -import com.mineinabyss.chatty.ChattyConfig +import com.github.shynixn.mccoroutine.bukkit.launch +import com.mineinabyss.chatty.ChattyChannel import com.mineinabyss.chatty.chatty import com.mineinabyss.chatty.chattyProxyChannel import com.mineinabyss.chatty.components.* import com.mineinabyss.chatty.helpers.* -import com.mineinabyss.geary.papermc.tracking.entities.toGeary +import com.mineinabyss.geary.datatypes.family.family +import com.mineinabyss.geary.papermc.tracking.entities.toGearyOrNull +import com.mineinabyss.geary.systems.accessors.Pointer +import com.mineinabyss.geary.systems.query.GearyQuery import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize -import io.papermc.paper.chat.ChatRenderer import io.papermc.paper.event.player.AsyncChatCommandDecorateEvent import io.papermc.paper.event.player.AsyncChatDecorateEvent import io.papermc.paper.event.player.AsyncChatEvent -import net.kyori.adventure.audience.Audience import net.kyori.adventure.text.Component import net.kyori.adventure.text.minimessage.MiniMessage import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer @@ -22,17 +24,23 @@ import org.bukkit.event.EventHandler import org.bukkit.event.EventPriority import org.bukkit.event.Listener import org.bukkit.event.player.PlayerCommandPreprocessEvent -import kotlin.math.sqrt @Suppress("UnstableApiUsage") class ChatListener : Listener { val plainText = PlainTextComponentSerializer.plainText() + val commandSpyQuery = CommandSpyQuery() + + class CommandSpyQuery : GearyQuery() { + val Pointer.player by get() + val Pointer.commandSpy by family { has() } + } @EventHandler fun PlayerCommandPreprocessEvent.onPlayerCommand() { - Bukkit.getOnlinePlayers().filter { it.uniqueId != player.uniqueId && it.toGeary().has() }.forEach { p -> - p.sendFormattedMessage(chatty.config.chat.commandSpyFormat, message, optionalPlayer = player) - } + commandSpyQuery.run { toList { it.player } } + .forEach { p -> + p.sendFormattedMessage(chatty.config.chat.commandSpyFormat, message, optionalPlayer = player) + } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) @@ -47,17 +55,20 @@ class ChatListener : Listener { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) fun AsyncChatEvent.onPlayerChat() { - player.verifyPlayerChannel() - val channelId = player.chattyData.channelId - val channel = getChannelFromId(channelId) ?: return + val ogChannelData = player.toGearyOrNull()?.get() ?: return + val channelData = ogChannelData.withChannelVerified() + val channelId = channelData.channelId + val channel = channelData.channel ?: return if (viewers().isNotEmpty()) viewers().clear() - viewers() += setAudienceForChannelType(player) + viewers() += channel.getAudience(player) val pingedPlayer = originalMessage().serialize().checkForPlayerPings(channelId) if (pingedPlayer != null && pingedPlayer != player && pingedPlayer in viewers()) { - message().handlePlayerPings(player, pingedPlayer) viewers() -= setOf(pingedPlayer, player) + val pingedChannelData = pingedPlayer.toGearyOrNull()?.get() + if (pingedChannelData != null) + message().handlePlayerPings(player, pingedPlayer, pingedChannelData) } if (channel.proxy) { @@ -89,44 +100,16 @@ class ChatListener : Listener { } else renderer { _, _, _, _ -> return@renderer message() } } - private fun setAudienceForChannelType(player: Player): Set { - val onlinePlayers = Bukkit.getOnlinePlayers() - val channel = getChannelFromId(player.chattyData.channelId) ?: return emptySet() - val audiences = mutableSetOf() - - when (channel.channelType) { - ChannelType.GLOBAL -> audiences.addAll(onlinePlayers) - ChannelType.RADIUS -> { - if (channel.channelRadius <= 0) audiences.addAll(onlinePlayers) - else audiences.addAll(onlinePlayers.filter { p -> - player.world == p.world && sqrt(player.location.distanceSquared(p.location)) <= channel.channelRadius - }) - } - - ChannelType.PERMISSION -> - audiences.addAll(onlinePlayers.filter { p -> p.hasPermission(channel.permission) }) - // Intended for Guilds etc., want to consider finding a non-permission way for this - ChannelType.PRIVATE -> audiences.add(player) - } - - audiences.addAll(onlinePlayers.filter { p -> - p !in audiences && p.toGeary().get()?.channels?.contains(player.chattyData.channelId) == true - }) - - return audiences - } - private fun Player.sendFormattedMessage(vararg message: String, optionalPlayer: Player? = null) = - this.sendMessage(translatePlaceholders((optionalPlayer ?: this), message.joinToString(" ")).parseTags(optionalPlayer ?: this, true)) - - private fun Component.stripMessageFormat(player: Player, channel: ChattyConfig.ChattyChannel) = + this.sendMessage( + translatePlaceholders((optionalPlayer ?: this), message.joinToString(" ")).parseTags( + optionalPlayer ?: this, + true + ) + ) + + private fun Component.stripMessageFormat(player: Player, channel: ChattyChannel) = plainText.serialize(this) - .replace(plainText.serialize(translatePlaceholders(player, channel.format).parseTags(player, true)), "").miniMsg().parseTags(player, false) -} - -object RendererExtension : ChatRenderer { - override fun render(source: Player, sourceDisplayName: Component, message: Component, viewer: Audience): Component { - - return message - } + .replace(plainText.serialize(translatePlaceholders(player, channel.format).parseTags(player, true)), "") + .miniMsg().parseTags(player, false) } diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt index 5753375..6453273 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt @@ -1,14 +1,13 @@ package com.mineinabyss.chatty.listeners +import com.mineinabyss.chatty.ChattyChannel import com.mineinabyss.chatty.chatty import com.mineinabyss.chatty.chattyProxyChannel +import com.mineinabyss.chatty.components.ChannelData import com.mineinabyss.chatty.components.ChannelType -import com.mineinabyss.chatty.components.SpyOnChannels -import com.mineinabyss.chatty.components.chattyData import com.mineinabyss.chatty.helpers.ZERO_WIDTH -import com.mineinabyss.chatty.helpers.getChannelFromId -import com.mineinabyss.chatty.helpers.getChannelFromPlayer import com.mineinabyss.chatty.helpers.toPlayer +import com.mineinabyss.chatty.queries.SpyingPlayers import com.mineinabyss.geary.papermc.tracking.entities.toGeary import com.mineinabyss.idofront.textcomponents.miniMsg import github.scarsz.discordsrv.Debug @@ -33,12 +32,13 @@ class ChattyProxyListener : PluginMessageListener { val senderName = decoded.substringBefore(ZERO_WIDTH) val channelId = decoded.substringAfter(ZERO_WIDTH).split(ZERO_WIDTH).first() val channelFormat = decoded.substringAfter(channelId + ZERO_WIDTH).split(ZERO_WIDTH).first() - val channel = getChannelFromId(channelId) + val channel = chatty.config.channels[channelId] val proxyMessage = decoded.substringAfterLast(ZERO_WIDTH) val onlinePlayers = Bukkit.getOnlinePlayers().filter { it.server == Bukkit.getServer() } - val canSpy = onlinePlayers.filter { - it.toGeary().get()?.channels?.contains(player.chattyData.channelId) == true + val canSpy = SpyingPlayers().run { + toList { query -> query.player.takeIf { query.spying.channels.contains(channelId) } } + .filterNotNull() } // If the channel is not found, it is discord @@ -50,46 +50,67 @@ class ChattyProxyListener : PluginMessageListener { ChannelType.GLOBAL -> onlinePlayers ChannelType.RADIUS -> canSpy ChannelType.PERMISSION -> onlinePlayers.filter { it.hasPermission(channel.permission) || it in canSpy } - ChannelType.PRIVATE -> onlinePlayers.filter { it.getChannelFromPlayer() == channel || it in canSpy } + ChannelType.PRIVATE -> onlinePlayers.filter { + it.toGeary().get()?.channel == channel || it in canSpy + } }.forEach { it.sendMessage(proxyMessage.miniMsg()) } } - if (!chatty.config.proxy.sendProxyMessagesToDiscord || - channel?.discordsrv != true || !chatty.isDiscordSRVLoaded - ) return + if (chatty.config.proxy.sendProxyMessagesToDiscord + && channel?.discordsrv == true + && chatty.isDiscordSRVLoaded + ) { + sendToDiscord(proxyMessage, senderName, channel, channelFormat) + } + + } + fun sendToDiscord(proxyMessage: String, senderName: String, channel: ChattyChannel, channelFormat: String) { val reserializer = DiscordSRV.config().getBoolean("Experiment_MCDiscordReserializer_ToDiscord") - val discordChannel = DiscordSRV.getPlugin().getDestinationTextChannelForGameChannelName(chatty.config.proxy.discordSrvChannelID) + val discordChannel = DiscordSRV.getPlugin() + .getDestinationTextChannelForGameChannelName(chatty.config.proxy.discordSrvChannelID) when { discordChannel == null -> { - DiscordSRV.debug(Debug.MINECRAFT_TO_DISCORD, - "Failed to find Discord channel to forward message from game channel $channel") + DiscordSRV.debug( + Debug.MINECRAFT_TO_DISCORD, + "Failed to find Discord channel to forward message from game channel $channel" + ) } + !DiscordUtil.checkPermission(discordChannel.guild, Permission.MANAGE_WEBHOOKS) -> DiscordSRV.error("Couldn't deliver chat message as webhook because the bot lacks the \"Manage Webhooks\" permission.") + else -> { val discordMessage = proxyMessage.replaceFirst(channelFormat, "") .apply { PlaceholderUtil.replacePlaceholdersToDiscord(this) } .apply { if (!reserializer) MessageUtil.strip(this) } - .apply { if (translateMentions) DiscordUtil.convertMentionsFromNames(this, DiscordSRV.getPlugin().mainGuild) } + .apply { + if (translateMentions) DiscordUtil.convertMentionsFromNames( + this, + DiscordSRV.getPlugin().mainGuild + ) + } val whUsername = DiscordSRV.config().getString("Experiment_WebhookChatMessageUsernameFormat") .replace("(%displayname%)|(%username%)".toRegex(), senderName) .let { MessageUtil.strip(PlaceholderUtil.replacePlaceholders(it)) } - WebhookUtil.deliverMessage(discordChannel, whUsername, + WebhookUtil.deliverMessage( + discordChannel, whUsername, DiscordSRV.getAvatarUrl(senderName, senderName.toPlayer()?.uniqueId), discordMessage.translateEmoteIDsToComponent(), MessageEmbed(null, null, null, null, null, 10, null, null, null, null, null, null, null) ) } } + } private val translateMentions = if (!chatty.isDiscordSRVLoaded) false else DiscordSRV.config().getBoolean("DiscordChatChannelTranslateMentions") + private fun String.translateEmoteIDsToComponent(): String { var translated = this chatty.emotefixer.emotes.entries.forEach { (emoteId, replacement) -> diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/DiscordListener.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/DiscordListener.kt index 37d5ec3..39ce7e0 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/DiscordListener.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/DiscordListener.kt @@ -1,13 +1,12 @@ package com.mineinabyss.chatty.listeners -import com.mineinabyss.chatty.ChattyConfig +import com.mineinabyss.chatty.ChattyChannel import com.mineinabyss.chatty.chatty import com.mineinabyss.chatty.chattyProxyChannel -import com.mineinabyss.chatty.components.chattyData -import com.mineinabyss.chatty.helpers.getChannelFromId -import com.mineinabyss.chatty.helpers.getChannelFromPlayer +import com.mineinabyss.chatty.components.ChannelData import com.mineinabyss.chatty.helpers.parseTags import com.mineinabyss.chatty.helpers.translatePlaceholders +import com.mineinabyss.geary.papermc.tracking.entities.toGeary import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize import github.scarsz.discordsrv.api.ListenerPriority @@ -36,24 +35,30 @@ class DiscordListener { fun DiscordGuildMessagePostProcessEvent.sendDiscordToProxy() { minecraftMessage = (minecraftMessage.serialize() .substringBefore(message.contentRaw) + mm.stripTags(message.contentStripped)).miniMsg() - Bukkit.getServer().sendPluginMessage(chatty.plugin, chattyProxyChannel, minecraftMessage.serialize().toByteArray()) + Bukkit.getServer() + .sendPluginMessage(chatty.plugin, chattyProxyChannel, minecraftMessage.serialize().toByteArray()) } @Subscribe(priority = ListenerPriority.NORMAL) fun GameChatMessagePreProcessEvent.onChat() { - val channel = getChannelFromId(player.chattyData.channelId) ?: return - val lastUsedChannel = getChannelFromId(player.chattyData.lastChannelUsed) ?: return + val data = player.toGeary().get() ?: return + val channel = data.channel ?: return + val lastUsedChannel = data.lastChannelUsed ?: return when { isCancelled -> return !channel.discordsrv || (channel != lastUsedChannel && !lastUsedChannel.discordsrv) -> isCancelled = true - else -> messageComponent = messageComponent.stripFormat(player, player.getChannelFromPlayer() ?: return) + else -> messageComponent = messageComponent.stripFormat(player, channel) } } // Parse the DSRV Component through the Chatty normal MM instance to format tags, then serialize/deserialize it back to DSRV Component - private fun Component.stripFormat(player: Player, channel: ChattyConfig.ChattyChannel) = - plainText.serialize(this).replace(plainText.serialize(translatePlaceholders(player, channel.format).parseTags(player, true).serialize().miniMsg()), "").miniMsg() + private fun Component.stripFormat(player: Player, channel: ChattyChannel) = + plainText.serialize(this).replace( + plainText.serialize( + translatePlaceholders(player, channel.format).parseTags(player, true).serialize().miniMsg() + ), "" + ).miniMsg() @Subscribe fun DeathMessagePreProcessEvent.onDeath() { diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/PlayerListener.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/PlayerListener.kt index 658e986..de92e6d 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/PlayerListener.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/PlayerListener.kt @@ -3,10 +3,7 @@ package com.mineinabyss.chatty.listeners import com.mineinabyss.chatty.chatty import com.mineinabyss.chatty.components.ChannelData import com.mineinabyss.chatty.components.HideJoinLeave -import com.mineinabyss.chatty.helpers.parseTags -import com.mineinabyss.chatty.helpers.refreshSkinInCaches -import com.mineinabyss.chatty.helpers.translatePlaceholders -import com.mineinabyss.chatty.helpers.verifyPlayerChannel +import com.mineinabyss.chatty.helpers.* import com.mineinabyss.geary.papermc.tracking.entities.toGeary import com.mineinabyss.idofront.textcomponents.serialize import org.bukkit.event.EventHandler @@ -29,8 +26,9 @@ class PlayerListener : Listener { @EventHandler(priority = EventPriority.NORMAL) fun PlayerJoinEvent.onJoin() { - player.verifyPlayerChannel() - if (chatty.config.join.enabled && !player.toGeary().has()) + val gearyPlayer = player.toGeary() + gearyPlayer.getOrSetPersisting { ChannelData() } + if (chatty.config.join.enabled && !gearyPlayer.has()) joinMessage(translatePlaceholders(player, chatty.messages.joinLeave.joinMessage)) } diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/placeholders/Placeholders.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/placeholders/Placeholders.kt index cfae12e..5630e1b 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/placeholders/Placeholders.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/placeholders/Placeholders.kt @@ -1,11 +1,14 @@ package com.mineinabyss.chatty.placeholders import com.mineinabyss.chatty.chatty +import com.mineinabyss.chatty.components.ChannelData import com.mineinabyss.chatty.components.SpyOnChannels -import com.mineinabyss.chatty.components.chattyData import com.mineinabyss.chatty.components.chattyNickname -import com.mineinabyss.chatty.helpers.* +import com.mineinabyss.chatty.helpers.getAllChannelNames +import com.mineinabyss.chatty.helpers.translateFullPlayerSkinComponent +import com.mineinabyss.chatty.helpers.translatePlayerHeadComponent import com.mineinabyss.geary.papermc.tracking.entities.toGeary +import com.mineinabyss.geary.papermc.tracking.entities.toGearyOrNull import com.mineinabyss.idofront.font.Space import com.mineinabyss.idofront.textcomponents.miniMsg import com.mineinabyss.idofront.textcomponents.serialize @@ -13,16 +16,17 @@ import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver import org.bukkit.entity.Player -fun chattyPlaceholders(player: Player?, string: String? = null) : Map { - val channel = player?.getChannelFromPlayer() - val shift = if (string == null) 0 else try { - Integer.parseInt(string.substringAfter("shift_", "0")) - } catch (e: NumberFormatException) { 0 } +fun chattyPlaceholders(player: Player?, string: String? = null): Map { + val channelData = player?.toGearyOrNull()?.get() + val channel = channelData?.channel + val shift = string?.substringAfter("shift_", "0")?.toIntOrNull() ?: 0 return mapOf( "all_channels" to getAllChannelNames().joinToString(", "), - "player_available_channels" to getAllChannelNames().filter { player?.hasPermission(getChannelFromId(it)?.permission.toString()) != false }.joinToString(", "), - "player_channel" to player?.chattyData?.channelId.toString(), + "player_available_channels" to chatty.config.channels.values.filter { + player?.hasPermission(it.permission) ?: false + }.joinToString(", "), + "player_channel" to channelData?.channelId.toString(), "player_channel_permission" to channel?.permission.toString(), "player_channel_isdefault" to channel?.isDefaultChannel.toString(), "player_channel_type" to channel?.channelType.toString(), @@ -39,8 +43,8 @@ fun chattyPlaceholders(player: Player?, string: String? = null) : Map - Placeholder.component("chatty_${p.key}", p.value.miniMsg()) - }.forEach { tagResolver.resolver(it) } +val Player?.chattyPlaceholderTags: TagResolver + get() { + val tagResolver = TagResolver.builder() + chattyPlaceholders(this).map { p -> + Placeholder.component("chatty_${p.key}", p.value.miniMsg()) + }.forEach { tagResolver.resolver(it) } - return tagResolver.build() -} + return tagResolver.build() + } diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/queries/SpyingPlayers.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/queries/SpyingPlayers.kt new file mode 100644 index 0000000..5782fe1 --- /dev/null +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/queries/SpyingPlayers.kt @@ -0,0 +1,13 @@ +package com.mineinabyss.chatty.queries + +import com.mineinabyss.chatty.components.CommandSpy +import com.mineinabyss.chatty.components.SpyOnChannels +import com.mineinabyss.geary.datatypes.family.family +import com.mineinabyss.geary.systems.accessors.Pointer +import com.mineinabyss.geary.systems.query.GearyQuery +import org.bukkit.entity.Player + +class SpyingPlayers: GearyQuery() { + val Pointer.player by get() + val Pointer.spying by get() +} diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/tags/ChattyTags.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/tags/ChattyTags.kt index ed5e28a..1d2704c 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/tags/ChattyTags.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/tags/ChattyTags.kt @@ -14,9 +14,9 @@ import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver object ChattyTags { - private val SHIFT = "shift" - private val HEAD = "head" - private val SKIN = "skin" + private const val SHIFT = "shift" + private const val HEAD = "head" + private const val SKIN = "skin" val SHIFT_RESOLVER: TagResolver = SerializableResolver.claimingComponent( SHIFT, { args: ArgumentQueue, ctx: Context -> create(args, ctx, SHIFT) }, diff --git a/gradle.properties b/gradle.properties index b1c5805..35e1c4c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=com.mineinabyss version=0.7 -idofrontVersion=0.20.6 +idofrontVersion=0.20.14 velocityVersion=3.2.0 coroutinesVersion=1.6.4 From a18fcf75fbbcdca4479dd562eecadb7dc9c13e76 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Mon, 4 Dec 2023 23:58:14 -0500 Subject: [PATCH 02/11] Register some components before first async use --- .../main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt index 15f5cb4..84b5c50 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt @@ -1,5 +1,8 @@ package com.mineinabyss.chatty +import com.mineinabyss.chatty.components.ChannelData +import com.mineinabyss.chatty.components.ChattyNickname +import com.mineinabyss.chatty.components.CommandSpy import com.mineinabyss.chatty.helpers.DiscordEmoteFixer import com.mineinabyss.chatty.listeners.ChatListener import com.mineinabyss.chatty.listeners.ChattyProxyListener @@ -7,6 +10,7 @@ import com.mineinabyss.chatty.listeners.DiscordListener import com.mineinabyss.chatty.listeners.PlayerListener import com.mineinabyss.chatty.placeholders.PlaceholderAPIHook import com.mineinabyss.geary.autoscan.autoscan +import com.mineinabyss.geary.helpers.componentId import com.mineinabyss.geary.modules.geary import com.mineinabyss.idofront.config.config import com.mineinabyss.idofront.di.DI @@ -40,6 +44,10 @@ class ChattyPlugin : JavaPlugin() { if (chatty.isDiscordSRVLoaded) DiscordSRV.api.subscribe(DiscordListener()) + + // register components we'll use async now since they'll error otherwise + componentId() + componentId() } fun createChattyContext() { From 20722d481b50a2d4207e5cd907cb527bfa0f2f0f Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 00:16:42 -0500 Subject: [PATCH 03/11] Revert msg, r to ensureSenderIsPlayer --- .../kotlin/com/mineinabyss/chatty/ChattyCommands.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt index 52ff99b..6c76fdc 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt @@ -9,6 +9,7 @@ import com.mineinabyss.chatty.helpers.* import com.mineinabyss.geary.papermc.tracking.entities.toGeary import com.mineinabyss.idofront.commands.arguments.stringArg import com.mineinabyss.idofront.commands.execution.IdofrontCommandExecutor +import com.mineinabyss.idofront.commands.extensions.actions.ensureSenderIsPlayer import com.mineinabyss.idofront.commands.extensions.actions.playerAction import com.mineinabyss.idofront.entities.toPlayer import com.mineinabyss.idofront.events.call @@ -180,13 +181,16 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { } } ("message" / "msg")(desc = "Private message another player") { - val otherPlayer by stringArg() - playerAction { - player.handleSendingPrivateMessage(otherPlayer.toPlayer() ?: return@playerAction, arguments, false) + ensureSenderIsPlayer() + val player by stringArg() + action { + (sender as? Player)?.handleSendingPrivateMessage(player.toPlayer() ?: return@action, arguments, false) } } ("reply" / "r")(desc = "Reply to your previous private message") { - playerAction { + ensureSenderIsPlayer() + action { + val player = sender as? Player ?: return@action player.toGeary().get()?.lastMessager?.toPlayer() ?.let { player.handleSendingPrivateMessage(it, arguments, true) } ?: player.sendFormattedMessage(chatty.messages.privateMessages.emptyReply) From d57f78ea630cda29132963bd37383ccb374ad926 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 00:37:29 -0500 Subject: [PATCH 04/11] Fix tab completion on /msg --- .../com/mineinabyss/chatty/ChattyCommands.kt | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt index 6c76fdc..4893299 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt @@ -206,41 +206,44 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { ): List { val onlinePlayers = Bukkit.getOnlinePlayers().map { it.name } val otherPrefix = chatty.config.nicknames.nickNameOtherPrefix - return if (command.name == "chatty") { - when (args.size) { - 1 -> listOf( - "message", - "ping", - "reload", - "channels", - "nickname", - "spy", - "commandspy" - ).filter { s -> s.startsWith(args[0]) } - - 2 -> when (args[0]) { - "ping" -> listOf("toggle", "sound").filter { s -> s.startsWith(args[1]) } - "message", "msg" -> onlinePlayers.filter { s -> s.startsWith(args[1], true) } - "spy" -> - chatty.config.channels.entries.filter { s -> - s.key.startsWith(args[1], true) && s.value.channelType != ChannelType.GLOBAL - }.map { it.key } + return when (command.name) { + "chatty" -> { + when (args.size) { + 1 -> listOf( + "message", + "ping", + "reload", + "channels", + "nickname", + "spy", + "commandspy" + ).filter { s -> s.startsWith(args[0]) } + + 2 -> when (args[0]) { + "ping" -> listOf("toggle", "sound").filter { s -> s.startsWith(args[1]) } + "spy" -> + chatty.config.channels.entries.filter { s -> + s.key.startsWith(args[1], true) && s.value.channelType != ChannelType.GLOBAL + }.map { it.key } + + else -> emptyList() + } - else -> emptyList() - } + 3 -> when { + args[1] == "sound" -> getAlternativePingSounds.filter { s -> s.startsWith(args[2], true) } + args[1].startsWith(otherPrefix) -> onlinePlayers.filter { s -> + s.replace(otherPrefix.toString(), "").startsWith(args[2], true) + } - 3 -> when { - args[1] == "sound" -> getAlternativePingSounds.filter { s -> s.startsWith(args[2], true) } - args[1].startsWith(otherPrefix) -> onlinePlayers.filter { s -> - s.replace(otherPrefix.toString(), "").startsWith(args[2], true) + else -> emptyList() } else -> emptyList() } - - else -> emptyList() } - } else emptyList() + "message", "msg" -> onlinePlayers.filter { s -> s.startsWith(args[0], true) }.take(25) + else -> emptyList() + } } private fun Player.shortcutCommand( From dd034af30a85449ba14ca2ee85d4815f35de11b3 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 00:43:56 -0500 Subject: [PATCH 05/11] Fix spying players query created async --- .../src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt | 2 +- .../src/main/kotlin/com/mineinabyss/chatty/ChattyContext.kt | 2 ++ .../src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt | 4 ++++ .../com/mineinabyss/chatty/listeners/ChattyProxyListener.kt | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt index a61a299..55cb1a7 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt @@ -52,7 +52,7 @@ data class ChattyChannel( } // Add spying players - val spies = SpyingPlayers().run { + val spies = chatty.spyingPlayers.run { toList { query -> query.player.takeIf { query.spying.channels.contains(key) } }.filterNotNull() } audiences.addAll(spies) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyContext.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyContext.kt index c8cda80..bfe9c34 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyContext.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyContext.kt @@ -1,6 +1,7 @@ package com.mineinabyss.chatty import com.mineinabyss.chatty.helpers.DiscordEmoteFixer +import com.mineinabyss.chatty.queries.SpyingPlayers import com.mineinabyss.idofront.config.IdofrontConfig import com.mineinabyss.idofront.di.DI import org.bukkit.Bukkit @@ -14,4 +15,5 @@ interface ChattyContext { val emotefixer: DiscordEmoteFixer val isPlaceholderApiLoaded: Boolean val isDiscordSRVLoaded: Boolean + val spyingPlayers: SpyingPlayers } diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt index 84b5c50..ae6aaf7 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt @@ -9,6 +9,7 @@ import com.mineinabyss.chatty.listeners.ChattyProxyListener import com.mineinabyss.chatty.listeners.DiscordListener import com.mineinabyss.chatty.listeners.PlayerListener import com.mineinabyss.chatty.placeholders.PlaceholderAPIHook +import com.mineinabyss.chatty.queries.SpyingPlayers import com.mineinabyss.geary.autoscan.autoscan import com.mineinabyss.geary.helpers.componentId import com.mineinabyss.geary.modules.geary @@ -59,6 +60,9 @@ class ChattyPlugin : JavaPlugin() { override val emotefixer: DiscordEmoteFixer by config("emotefixer", dataFolder.toPath(), DiscordEmoteFixer()) override val isPlaceholderApiLoaded: Boolean = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI") override val isDiscordSRVLoaded: Boolean = Bukkit.getPluginManager().isPluginEnabled("DiscordSRV") + override val spyingPlayers: SpyingPlayers = SpyingPlayers().apply { + registerIfNotRegistered() + } } DI.add(chattyContext) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt index 6453273..c2a06ce 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt @@ -36,7 +36,7 @@ class ChattyProxyListener : PluginMessageListener { val proxyMessage = decoded.substringAfterLast(ZERO_WIDTH) val onlinePlayers = Bukkit.getOnlinePlayers().filter { it.server == Bukkit.getServer() } - val canSpy = SpyingPlayers().run { + val canSpy = chatty.spyingPlayers.run { toList { query -> query.player.takeIf { query.spying.channels.contains(channelId) } } .filterNotNull() } From 6bb8bc856ea11ae3f915de3d66c182ee335a40bc Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 00:45:14 -0500 Subject: [PATCH 06/11] Move componentId registration up to onLoad --- .../main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt index ae6aaf7..b494011 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyPlugin.kt @@ -27,6 +27,10 @@ class ChattyPlugin : JavaPlugin() { all() } } + + // register components we'll use async now since they'll error otherwise + componentId() + componentId() } override fun onEnable() { @@ -39,16 +43,11 @@ class ChattyPlugin : JavaPlugin() { ChattyCommands() listeners(ChatListener(), PlayerListener()) - if (chatty.isPlaceholderApiLoaded) PlaceholderAPIHook().register() if (chatty.isDiscordSRVLoaded) DiscordSRV.api.subscribe(DiscordListener()) - - // register components we'll use async now since they'll error otherwise - componentId() - componentId() } fun createChattyContext() { From 5f5edbc4746c4a809c7f8e08dd6844030afbe515 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 11:50:43 -0500 Subject: [PATCH 07/11] Resolve review requests --- .../com/mineinabyss/chatty/ChattyChannel.kt | 8 +++++--- .../chatty/components/ChannelData.kt | 1 - .../chatty/listeners/ChatListener.kt | 4 ++-- .../chatty/listeners/ChattyProxyListener.kt | 18 +++++++++--------- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt index 55cb1a7..011af53 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt @@ -4,12 +4,14 @@ import com.mineinabyss.chatty.components.ChannelType import com.mineinabyss.chatty.components.SpyOnChannels import com.mineinabyss.chatty.queries.SpyingPlayers import com.mineinabyss.geary.papermc.tracking.entities.toGeary +import com.mineinabyss.idofront.serialization.ColorSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.kyori.adventure.audience.Audience import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextColor import org.bukkit.Bukkit +import org.bukkit.Color import org.bukkit.entity.Player @Serializable @@ -23,14 +25,14 @@ data class ChattyChannel( val isDefaultChannel: Boolean = false, val isStaffChannel: Boolean = false, val format: String = "", - @SerialName("messageColor") val _messageColor: String = "white", + @Serializable(with=ColorSerializer::class) + @SerialName("messageColor") val _messageColor: Color = Color.WHITE, val channelRadius: Int = 0, val channelAliases: List = listOf(), ) { val key by lazy { chatty.config.channels.entries.first { it.value == this }.key } val messageColor: TextColor - get() = TextColor.fromHexString(_messageColor) ?: NamedTextColor.NAMES.value(_messageColor) - ?: NamedTextColor.WHITE + get() = TextColor.color(_messageColor.asRGB()) fun getAudience(player: Player): Collection { diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/components/ChannelData.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/components/ChannelData.kt index f7c442c..60d9b2c 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/components/ChannelData.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/components/ChannelData.kt @@ -12,7 +12,6 @@ import java.util.* @SerialName("chatty:chatty_data") data class ChannelData( val channelId: String = getDefaultChat().key, - @SerialName("lastChannelUsed") val lastChannelUsedId: String = channelId, val disablePingSound: Boolean = false, val pingSound: String? = null, diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChatListener.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChatListener.kt index dfcf0b7..818f651 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChatListener.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChatListener.kt @@ -66,9 +66,9 @@ class ChatListener : Listener { val pingedPlayer = originalMessage().serialize().checkForPlayerPings(channelId) if (pingedPlayer != null && pingedPlayer != player && pingedPlayer in viewers()) { viewers() -= setOf(pingedPlayer, player) - val pingedChannelData = pingedPlayer.toGearyOrNull()?.get() - if (pingedChannelData != null) + pingedPlayer.toGearyOrNull()?.get()?.let { pingedChannelData -> message().handlePlayerPings(player, pingedPlayer, pingedChannelData) + } } if (channel.proxy) { diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt index c2a06ce..96cf3ec 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/listeners/ChattyProxyListener.kt @@ -51,7 +51,7 @@ class ChattyProxyListener : PluginMessageListener { ChannelType.RADIUS -> canSpy ChannelType.PERMISSION -> onlinePlayers.filter { it.hasPermission(channel.permission) || it in canSpy } ChannelType.PRIVATE -> onlinePlayers.filter { - it.toGeary().get()?.channel == channel || it in canSpy + it.toGeary().get()?.withChannelVerified()?.channel == channel || it in canSpy } }.forEach { it.sendMessage(proxyMessage.miniMsg()) } } @@ -83,14 +83,14 @@ class ChattyProxyListener : PluginMessageListener { DiscordSRV.error("Couldn't deliver chat message as webhook because the bot lacks the \"Manage Webhooks\" permission.") else -> { - val discordMessage = proxyMessage.replaceFirst(channelFormat, "") - .apply { PlaceholderUtil.replacePlaceholdersToDiscord(this) } - .apply { if (!reserializer) MessageUtil.strip(this) } - .apply { - if (translateMentions) DiscordUtil.convertMentionsFromNames( - this, - DiscordSRV.getPlugin().mainGuild - ) + val discordMessage = proxyMessage + .replaceFirst(channelFormat, "") + .run { PlaceholderUtil.replacePlaceholdersToDiscord(this) } + .run { if (!reserializer) MessageUtil.strip(this) else this } + .run { + if (translateMentions) + DiscordUtil.convertMentionsFromNames(this,DiscordSRV.getPlugin().mainGuild) + else this } val whUsername = DiscordSRV.config().getString("Experiment_WebhookChatMessageUsernameFormat") From 669139825bdf95102fc7e399030d80120490972a Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 12:13:41 -0500 Subject: [PATCH 08/11] Revert messageColor changes --- .../main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt index 011af53..55cb1a7 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyChannel.kt @@ -4,14 +4,12 @@ import com.mineinabyss.chatty.components.ChannelType import com.mineinabyss.chatty.components.SpyOnChannels import com.mineinabyss.chatty.queries.SpyingPlayers import com.mineinabyss.geary.papermc.tracking.entities.toGeary -import com.mineinabyss.idofront.serialization.ColorSerializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.kyori.adventure.audience.Audience import net.kyori.adventure.text.format.NamedTextColor import net.kyori.adventure.text.format.TextColor import org.bukkit.Bukkit -import org.bukkit.Color import org.bukkit.entity.Player @Serializable @@ -25,14 +23,14 @@ data class ChattyChannel( val isDefaultChannel: Boolean = false, val isStaffChannel: Boolean = false, val format: String = "", - @Serializable(with=ColorSerializer::class) - @SerialName("messageColor") val _messageColor: Color = Color.WHITE, + @SerialName("messageColor") val _messageColor: String = "white", val channelRadius: Int = 0, val channelAliases: List = listOf(), ) { val key by lazy { chatty.config.channels.entries.first { it.value == this }.key } val messageColor: TextColor - get() = TextColor.color(_messageColor.asRGB()) + get() = TextColor.fromHexString(_messageColor) ?: NamedTextColor.NAMES.value(_messageColor) + ?: NamedTextColor.WHITE fun getAudience(player: Player): Collection { From 7a9320be599d39f85005d1316bb79e629dc2f755 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 12:51:40 -0500 Subject: [PATCH 09/11] Dont tab complete name after first time --- .../com/mineinabyss/chatty/ChattyCommands.kt | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt index 4893299..9082952 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt @@ -166,18 +166,21 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { } } ("global" / "g") { - playerAction { - player.shortcutCommand(getGlobalChat(), arguments) + ensureSenderIsPlayer() + action { + (sender as? Player)?.shortcutCommand(getGlobalChat(), arguments) } } ("local" / "l") { - playerAction { - player.shortcutCommand(getRadiusChannel(), arguments) + ensureSenderIsPlayer() + action { + (sender as? Player)?.shortcutCommand(getRadiusChannel(), arguments) } } ("admin" / "a") { - playerAction { - player.shortcutCommand(getAdminChannel(), arguments) + ensureSenderIsPlayer() + action { + (sender as? Player)?.shortcutCommand(getAdminChannel(), arguments) } } ("message" / "msg")(desc = "Private message another player") { @@ -241,7 +244,11 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { else -> emptyList() } } - "message", "msg" -> onlinePlayers.filter { s -> s.startsWith(args[0], true) }.take(25) + "message", "msg" -> + when (args.size) { + 0, 1 -> onlinePlayers.filter { s -> s.startsWith(args[0], true) }.take(25) + else -> emptyList() + } else -> emptyList() } } From 85f88a52d33834573f043830452aa892f77d7073 Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 13:01:39 -0500 Subject: [PATCH 10/11] Dont launch async event for commands like /l (channel gets reverted back too fast) --- .../main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt index 9082952..c879e90 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt @@ -266,8 +266,9 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { arguments.isEmpty() -> swapChannelCommand(channel.value) else -> { - toGeary().setPersisting(chattyData.copy(channelId = channel.key, lastChannelUsedId = channel.key)) - chatty.plugin.launch(chatty.plugin.asyncDispatcher) { + val gearyPlayer = toGeary() + gearyPlayer.setPersisting(chattyData.copy(channelId = channel.key, lastChannelUsedId = channel.key)) + runCatching { GenericChattyDecorateEvent(this@shortcutCommand, arguments.toSentence().miniMsg()).call { GenericChattyChatEvent( this@shortcutCommand, @@ -275,7 +276,7 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { ).callEvent() } } - toGeary().setPersisting(chattyData.copy(channelId = currentChannel)) + gearyPlayer.setPersisting(chattyData.copy(channelId = currentChannel)) } } } From cfd266f176b8073c7a964e31b84a11bb39038b7f Mon Sep 17 00:00:00 2001 From: Danielle Voznyy Date: Tue, 5 Dec 2023 13:10:40 -0500 Subject: [PATCH 11/11] Revert to launching async dispatcher, but swap back after event is called --- .../kotlin/com/mineinabyss/chatty/ChattyCommands.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt index c879e90..0f612c6 100644 --- a/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt +++ b/chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt @@ -4,9 +4,11 @@ package com.mineinabyss.chatty import com.github.shynixn.mccoroutine.bukkit.asyncDispatcher import com.github.shynixn.mccoroutine.bukkit.launch +import com.github.shynixn.mccoroutine.bukkit.minecraftDispatcher import com.mineinabyss.chatty.components.* import com.mineinabyss.chatty.helpers.* import com.mineinabyss.geary.papermc.tracking.entities.toGeary +import com.mineinabyss.geary.papermc.tracking.entities.toGearyOrNull import com.mineinabyss.idofront.commands.arguments.stringArg import com.mineinabyss.idofront.commands.execution.IdofrontCommandExecutor import com.mineinabyss.idofront.commands.extensions.actions.ensureSenderIsPlayer @@ -18,6 +20,7 @@ import com.mineinabyss.idofront.textcomponents.serialize import io.papermc.paper.event.player.AsyncChatDecorateEvent import kotlinx.coroutines.Job import kotlinx.coroutines.delay +import kotlinx.coroutines.withContext import org.bukkit.Bukkit import org.bukkit.command.Command import org.bukkit.command.CommandSender @@ -266,17 +269,19 @@ class ChattyCommands : IdofrontCommandExecutor(), TabCompleter { arguments.isEmpty() -> swapChannelCommand(channel.value) else -> { - val gearyPlayer = toGeary() - gearyPlayer.setPersisting(chattyData.copy(channelId = channel.key, lastChannelUsedId = channel.key)) - runCatching { + toGeary().setPersisting(chattyData.copy(channelId = channel.key, lastChannelUsedId = channel.key)) + chatty.plugin.launch(chatty.plugin.asyncDispatcher) { GenericChattyDecorateEvent(this@shortcutCommand, arguments.toSentence().miniMsg()).call { GenericChattyChatEvent( this@shortcutCommand, (this as AsyncChatDecorateEvent).result() ).callEvent() } + withContext(chatty.plugin.minecraftDispatcher) { + // chance that player logged out by now + toGearyOrNull()?.setPersisting(chattyData.copy(channelId = currentChannel)) + } } - gearyPlayer.setPersisting(chattyData.copy(channelId = currentChannel)) } } }