Skip to content

Commit

Permalink
Rewrite to avoid many async ChannelData writes, try to clean up overa…
Browse files Browse the repository at this point in the history
…ll structure to encourage this goal
  • Loading branch information
0ffz committed Dec 5, 2023
1 parent 16a1935 commit 76430e6
Show file tree
Hide file tree
Showing 13 changed files with 341 additions and 294 deletions.
Original file line number Diff line number Diff line change
@@ -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<String> = 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<Audience> {
val onlinePlayers by lazy { Bukkit.getOnlinePlayers() }
val audiences = mutableSetOf<Audience>()

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
}
}
247 changes: 122 additions & 125 deletions chatty-paper/src/main/kotlin/com/mineinabyss/chatty/ChattyCommands.kt

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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<String> = listOf(),
) {
val messageColor: TextColor
get() = TextColor.fromHexString(_messageColor) ?: NamedTextColor.NAMES.value(_messageColor)
?: NamedTextColor.WHITE
}

@Serializable
data class Ping(
val enabledChannels: List<String> = listOf(),
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) "<insert:@${
player.chattyNickname?.let { MiniMessage.miniMessage().stripTags(it) }
Expand All @@ -61,7 +60,7 @@ fun Component.handlePlayerPings(player: Player, pingedPlayer: Player) {
.build()
)

if (!pingedPlayer.chattyData.disablePingSound)
if (!pingedChannelData.disablePingSound)
pingedPlayer.playSound(pingedPlayer.location, pingSound, SoundCategory.VOICE, ping.pingVolume, ping.pingPitch)
pingedPlayer.sendMessage(pingMessage)

Expand Down Expand Up @@ -113,16 +112,12 @@ fun getDefaultChat() =
?: getGlobalChat()
?: throw IllegalStateException("No Default or Global channel found")

fun getChannelFromId(channelId: String) =
chatty.config.channels.entries.firstOrNull { it.key == channelId }?.value
// TODO change to data.channel
//fun getChannelFromId(channelId: String) =
// chatty.config.channels[channelId]

fun Player.getChannelFromPlayer() =
chatty.config.channels.entries.firstOrNull { it.key == this.chattyData.channelId }?.value

fun Player.verifyPlayerChannel() {
if (chattyData.channelId !in chatty.config.channels)
toGeary().setPersisting(chattyData.copy(channelId = getDefaultChat().key))
}
//fun Player.getChannelFromPlayer() =
// chatty.config.channels.entries.firstOrNull { it.key == this.chattyData.channelId }?.value

fun getAllChannelNames() = chatty.config.channels.keys.toList()

Expand Down Expand Up @@ -194,34 +189,14 @@ fun List<String>.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<ChannelData>()?.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> T.copyWithEdit(block: T.() -> T): T {
return block()
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<Player>()
val Pointer.commandSpy by family { has<CommandSpy>() }
}

@EventHandler
fun PlayerCommandPreprocessEvent.onPlayerCommand() {
Bukkit.getOnlinePlayers().filter { it.uniqueId != player.uniqueId && it.toGeary().has<CommandSpy>() }.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)
Expand All @@ -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<ChannelData>() ?: 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<ChannelData>()
if (pingedChannelData != null)
message().handlePlayerPings(player, pingedPlayer, pingedChannelData)
}

if (channel.proxy) {
Expand Down Expand Up @@ -89,44 +100,16 @@ class ChatListener : Listener {
} else renderer { _, _, _, _ -> return@renderer message() }
}

private fun setAudienceForChannelType(player: Player): Set<Audience> {
val onlinePlayers = Bukkit.getOnlinePlayers()
val channel = getChannelFromId(player.chattyData.channelId) ?: return emptySet()
val audiences = mutableSetOf<Audience>()

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<SpyOnChannels>()?.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)
}
Loading

0 comments on commit 76430e6

Please sign in to comment.