Implemented Global Chat

Added global chat feature, so players can still maintain global communication while being in their own clan chat
An individual player can opt out of global chat by using the ::muteglobal command
Implemented automatic message splitting for clan and global chat
Implemented colour selection for global chat (prefix your message with hex colour code, e.g. //%690420 before the message)
This commit is contained in:
Ceikry 2023-03-01 00:02:12 +00:00 committed by Ryan
parent 124eeab893
commit 3445b792c8
5 changed files with 100 additions and 16 deletions

View file

@ -264,5 +264,8 @@ class ServerConstants {
@JvmField
var DRAGON_AXE_USE_OSRS_SPEC = false
@JvmField
var ENABLE_GLOBALCHAT = false
}
}

View file

@ -0,0 +1,40 @@
package core.game.system.communication
import core.api.Commands
import core.api.getAttribute
import core.api.sendMessage
import core.api.setAttribute
import core.game.system.command.Privilege
import core.game.world.repository.Repository
import core.tools.colorize
class GlobalChat : Commands {
override fun defineCommands() {
define("muteglobal", Privilege.STANDARD, "", "Toggles global chat on or off.") {player, _ ->
val original = getAttribute(player, ATTR_GLOBAL_MUTE, false)
setAttribute(player, ATTR_GLOBAL_MUTE, !original)
sendMessage(player, "Global chat is now ${if (original) "ON" else "OFF"}.")
return@define
}
}
companion object {
val ATTR_GLOBAL_MUTE = "/save:globalmute"
fun process(sender: String, message: String) {
val msgSD = prepare(sender, message, false)
val msgHD = prepare(sender, message, true)
for (player in Repository.players.filter { !getAttribute(it, ATTR_GLOBAL_MUTE, false) }) {
if (player.interfaceManager.isResizable)
sendMessage(player, msgHD)
else
sendMessage(player, msgSD)
}
}
private fun prepare(sender: String, message: String, isResizable: Boolean): String {
val baseColor = if (isResizable) "%G" else "%7512ff"
val bracketColor = if (isResizable) "%ffffff" else "%000000"
return colorize("$bracketColor[${baseColor}G$bracketColor] $sender: ${baseColor}$message")
}
}
}

View file

@ -133,6 +133,7 @@ object ServerConfigParser {
ServerConstants.DISCORD_MOD_WEBHOOK = data.getString("server.moderation_webhook", "")
ServerConstants.NOAUTH_DEFAULT_ADMIN = data.getBoolean("server.noauth_default_admin", false)
ServerConstants.DRAGON_AXE_USE_OSRS_SPEC = data.getBoolean("world.dragon_axe_use_osrs_spec", false)
ServerConstants.ENABLE_GLOBALCHAT = data.getBoolean("world.enable_globalchat", true)
}

View file

@ -47,6 +47,7 @@ import core.game.node.entity.player.info.LogType
import core.game.node.entity.player.info.PlayerMonitor
import core.tools.SystemLogger
import core.game.system.command.CommandSystem
import core.game.system.communication.GlobalChat
import core.game.world.GameWorld
import core.game.world.repository.Repository
import core.net.packet.`in`.Packet
@ -54,6 +55,7 @@ import core.net.packet.`in`.RunScript
import core.worker.ManagementEvents
import java.io.PrintWriter
import java.io.StringWriter
import java.lang.Math.min
import java.util.*
object PacketProcessor {
@ -198,13 +200,28 @@ object PacketProcessor {
if (pkt.player.details.isMuted)
pkt.player.sendMessage("You have been muted due to breaking a rule.")
else {
if (pkt.message.startsWith("/") && pkt.player.communication.clan != null) {
val builder = ClanMessage.newBuilder()
builder.sender = pkt.player.name
builder.clanName = pkt.player.communication.clan.owner.lowercase().replace(" ", "_")
builder.message = pkt.message.substring(1)
builder.rank = pkt.player.rights.ordinal
ManagementEvents.publish(builder.build())
if (ServerConstants.ENABLE_GLOBALCHAT && pkt.message.startsWith("//")) {
if (getAttribute(pkt.player, GlobalChat.ATTR_GLOBAL_MUTE, false))
return
val messages = splitChatMessage(pkt.message.substring(2), pkt.player.name.length + 3, false)
for (message in messages) {
if (message.isNotBlank())
GlobalChat.process(pkt.player.username, message)
}
return
}
else if (pkt.message.startsWith("/") && pkt.player.communication.clan != null) {
val messages = splitChatMessage(pkt.message.substring(1), pkt.player.communication.clan.name.length + pkt.player.name.length, pkt.player.details.rights.ordinal != 0)
for (message in messages) {
if (message.isBlank()) continue
val builder = ClanMessage.newBuilder()
builder.sender = pkt.player.name
builder.clanName = pkt.player.communication.clan.owner.lowercase().replace(" ", "_")
builder.message = message
builder.rank = pkt.player.rights.ordinal
ManagementEvents.publish(builder.build())
}
return
}
PlayerMonitor.logChat(pkt.player, "public", pkt.message)
@ -759,5 +776,24 @@ object PacketProcessor {
container.insert(slot, secondSlot, false)
}
container.refresh()
}
}
fun splitChatMessage(message: String, clanLength: Int, rankPresent: Boolean) : ArrayList<String> {
val messages = ArrayList<String>()
val effectiveCutoff = BASE_CHAT_CUTOFF - (clanLength + if (rankPresent) 9 else 0)
var counter = 0
for (token in message.split(" ")) {
if (counter + token.length > effectiveCutoff)
break
counter += token.length + 1
}
messages.add(message.substring(0, min(counter, message.length)))
if (counter < message.length)
messages.add(message.substring(counter, message.length))
return messages
}
const val BASE_CHAT_CUTOFF = 81
}

View file

@ -7,14 +7,18 @@ const val GREEN = "<col=66ff33>"
const val BLUE = "<col=3366ff>"
const val PURPLE = "<col=cc00ff>"
fun colorize(line: String): String{
val new = line.replace("%R", RED)
.replace("%O", ORANGE)
.replace("%Y", YELLOW)
.replace("%G", GREEN)
.replace("%B", BLUE)
.replace("%P", PURPLE).append("</col>") + " "
return new
private val pattern = Regex("%[0-9a-fA-F]{6}")
private val testData = arrayOf("This is a string with no colors.", "This %R is a string with one color.", "This %R %G %B is a string with multiple colors.", "This %ffffff is an arbitrary hex string.")
fun colorize(line: String): String {
return line.replace("%R", RED)
.replace("%O", ORANGE)
.replace("%Y", YELLOW)
.replace("%G", GREEN)
.replace("%B", BLUE)
.replace("%P", PURPLE)
.replace(pattern) { matchResult -> "<col=${matchResult.value.substring(1)}>" }
.append("</col>") + " "
}
fun colorize(line: String, hexColor: String): String{