diff --git a/Server/src/main/core/ServerConstants.kt b/Server/src/main/core/ServerConstants.kt index 5823be465..d060ff29a 100644 --- a/Server/src/main/core/ServerConstants.kt +++ b/Server/src/main/core/ServerConstants.kt @@ -264,5 +264,8 @@ class ServerConstants { @JvmField var DRAGON_AXE_USE_OSRS_SPEC = false + + @JvmField + var ENABLE_GLOBALCHAT = false } } diff --git a/Server/src/main/core/game/system/communication/GlobalChat.kt b/Server/src/main/core/game/system/communication/GlobalChat.kt new file mode 100644 index 000000000..98e60229a --- /dev/null +++ b/Server/src/main/core/game/system/communication/GlobalChat.kt @@ -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") + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/system/config/ServerConfigParser.kt b/Server/src/main/core/game/system/config/ServerConfigParser.kt index a486db759..413e55cf7 100644 --- a/Server/src/main/core/game/system/config/ServerConfigParser.kt +++ b/Server/src/main/core/game/system/config/ServerConfigParser.kt @@ -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) } diff --git a/Server/src/main/core/net/packet/PacketProcessor.kt b/Server/src/main/core/net/packet/PacketProcessor.kt index 59d67c9b3..7fb86cc21 100644 --- a/Server/src/main/core/net/packet/PacketProcessor.kt +++ b/Server/src/main/core/net/packet/PacketProcessor.kt @@ -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 { + val messages = ArrayList() + + 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 } \ No newline at end of file diff --git a/Server/src/main/core/tools/Globals.kt b/Server/src/main/core/tools/Globals.kt index ed2f85f40..cb070f762 100644 --- a/Server/src/main/core/tools/Globals.kt +++ b/Server/src/main/core/tools/Globals.kt @@ -7,14 +7,18 @@ const val GREEN = "" const val BLUE = "" const val PURPLE = "" -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("") + " " - 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 -> "" } + .append("") + " " } fun colorize(line: String, hexColor: String): String{