From 0fdd3a0133b3d0f310e97046b0085a19e23586b1 Mon Sep 17 00:00:00 2001 From: Jakob Gillich Date: Mon, 24 Aug 2020 00:27:25 +0200 Subject: [PATCH] Add unprivileged-gm-commands config option Also replaced !kick with /worldkick (CMT_KICK) --- docker-compose.yml | 7 +- .../scala/net/psforever/server/Server.scala | 13 +- src/main/resources/application.conf | 6 +- .../psforever/actors/session/ChatActor.scala | 111 ++-- .../actors/session/SessionActor.scala | 9 +- .../scala/net/psforever/packet/PSPacket.scala | 23 + .../net/psforever/packet/game/ChatMsg.scala | 2 +- .../net/psforever/types/ChatMessageType.scala | 528 +++++++++--------- .../scala/net/psforever/util/Config.scala | 24 +- 9 files changed, 391 insertions(+), 332 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f7938773..8ae72124 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: "3" services: loginserver: - image: mozilla/sbt:8u232_1.3.8 + image: mozilla/sbt volumes: - .:/PSF-Loginserver:z working_dir: /PSF-Loginserver @@ -12,15 +12,12 @@ services: - 51002:51002/tcp command: > sh -c ' - if [ ! -f "config/worldserver.ini" ]; then - sed "s/Hostname = \"localhost\"/Hostname = \"db\"/g" config/worldserver.ini.dist > config/worldserver.ini - fi if [ ! -d "pscrypto-lib" ]; then wget https://github.com/psforever/PSCrypto/releases/download/v1.1/pscrypto-lib-1.1.zip unzip pscrypto-lib-1.1.zip rm pscrypto-lib-1.1.zip fi - sbt pslogin/run + sbt server/run ' adminer: image: adminer diff --git a/server/src/main/scala/net/psforever/server/Server.scala b/server/src/main/scala/net/psforever/server/Server.scala index 6c44a239..c1fdeae2 100644 --- a/server/src/main/scala/net/psforever/server/Server.scala +++ b/server/src/main/scala/net/psforever/server/Server.scala @@ -4,6 +4,7 @@ import java.net.InetAddress import java.nio.file.Paths import java.util.Locale +import akka.actor.ActorSystem import akka.actor.typed.scaladsl.adapter._ import akka.routing.RandomPool import akka.{actor => classic} @@ -86,7 +87,7 @@ object Server { } /** Start up the main actor system. This "system" is the home for all actors running on this server */ - implicit val system = classic.ActorSystem("PsLogin") + implicit val system: ActorSystem = classic.ActorSystem("PsLogin") Default(system) /** Create pipelines for the login and world servers @@ -109,12 +110,12 @@ object Server { SessionPipeline("world-session-", classic.Props[SessionActor]()) ) - val netSim: Option[NetworkSimulatorParameters] = if (Config.app.developer.netSim.enable) { + val netSim: Option[NetworkSimulatorParameters] = if (Config.app.development.netSim.enable) { val params = NetworkSimulatorParameters( - Config.app.developer.netSim.loss, - Config.app.developer.netSim.delay.toMillis, - Config.app.developer.netSim.reorderChance, - Config.app.developer.netSim.reorderTime.toMillis + Config.app.development.netSim.loss, + Config.app.development.netSim.delay.toMillis, + Config.app.development.netSim.reorderChance, + Config.app.development.netSim.reorderTime.toMillis ) logger.warn("NetSim is active") logger.warn(params.toString) diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index b307db80..19ef4851 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -90,7 +90,11 @@ network { } } -developer { +development { + # List of GM commands available to everyone + # Values are ChatMessageType members, for example: [CMT_ADDBATTLEEXPERIENCE, CMT_CAPTUREBASE] + unprivileged-gm-commands = [] + net-sim { # Enable artificial packet unreliability. Used for development testing. # Active equally on upstream and downstream packets. diff --git a/src/main/scala/net/psforever/actors/session/ChatActor.scala b/src/main/scala/net/psforever/actors/session/ChatActor.scala index 5b703dcf..4ecbe26f 100644 --- a/src/main/scala/net/psforever/actors/session/ChatActor.scala +++ b/src/main/scala/net/psforever/actors/session/ChatActor.scala @@ -14,7 +14,7 @@ import net.psforever.objects.zones.Zoning import net.psforever.packet.PacketCoding import net.psforever.packet.game.{ChatMsg, DeadState, RequestDestroyMessage, ZonePopulationUpdateMessage} import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID, Vector3} -import net.psforever.util.PointOfInterest +import net.psforever.util.{Config, PointOfInterest} import net.psforever.zones.Zones import net.psforever.services.chat.ChatService import net.psforever.services.chat.ChatService.ChatChannel @@ -123,8 +123,11 @@ class ChatActor( case Message(message) => log.info("Chat: " + message) + val gmCommandAllowed = + session.account.gm || Config.app.development.unprivilegedGmCommands.contains(message.messageType) + (message.messageType, message.recipient.trim, message.contents.trim) match { - case (CMT_FLY, recipient, contents) if session.account.gm => + case (CMT_FLY, recipient, contents) if gmCommandAllowed => val flying = contents match { case "on" => true case "off" => false @@ -148,7 +151,7 @@ class ChatActor( else 50 sessionActor ! SessionActor.SetConnectionState(connectionState) - case (CMT_SPEED, recipient, contents) if session.account.gm => + case (CMT_SPEED, recipient, contents) if gmCommandAllowed => val speed = try { contents.toFloat @@ -159,7 +162,7 @@ class ChatActor( sessionActor ! SessionActor.SetSpeed(speed) sessionActor ! SessionActor.SendResponse(message.copy(contents = f"$speed%.3f")) - case (CMT_TOGGLESPECTATORMODE, _, contents) if session.account.gm => + case (CMT_TOGGLESPECTATORMODE, _, contents) if gmCommandAllowed => val spectator = contents match { case "on" => true case "off" => false @@ -339,38 +342,6 @@ class ChatActor( ) } - case (_, _, contents) if session.account.gm && contents.startsWith("!kick") => - val input = contents.split("\\s+").drop(1) - if (input.length > 0) { - val numRegex = raw"(\d+)".r - val id = input(0) - val determination: Player => Boolean = id match { - case numRegex(_) => _.CharId == id.toLong - case _ => _.Name.equals(id) - } - session.zone.LivePlayers - .find(determination) - .orElse(session.zone.Corpses.find(determination)) match { - case Some(player) => - input.lift(1) match { - case Some(numRegex(time)) => - sessionActor ! SessionActor.Kick(player, Some(time.toLong)) - case _ => - sessionActor ! SessionActor.Kick(player) - } - case None => - sessionActor ! SessionActor.SendResponse( - ChatMsg( - CMT_GMOPEN, - message.wideContents, - "Server", - "Invalid player", - message.note - ) - ) - } - } - case (_, _, contents) if contents.startsWith("!ntu") && session.account.gm => session.zone.Buildings.values.foreach(building => building.Amenities.foreach(amenity => @@ -390,7 +361,7 @@ class ChatActor( // unknown ! commands are ignored } - case (CMT_CAPTUREBASE, _, contents) if session.account.gm => + case (CMT_CAPTUREBASE, _, contents) if gmCommandAllowed => val args = contents.split(" ").filter(_ != "") val (faction, factionPos) = args.zipWithIndex @@ -507,21 +478,21 @@ class ChatActor( } case (CMT_GMBROADCAST | CMT_GMBROADCAST_NC | CMT_GMBROADCAST_VS | CMT_GMBROADCAST_TR, _, _) - if session.account.gm => + if gmCommandAllowed => chatService ! ChatService.Message( session, message.copy(recipient = session.player.Name), ChatChannel.Default() ) - case (CMT_GMTELL, _, _) if session.account.gm => + case (CMT_GMTELL, _, _) if gmCommandAllowed => chatService ! ChatService.Message( session, message.copy(recipient = session.player.Name), ChatChannel.Default() ) - case (CMT_GMBROADCASTPOPUP, _, _) if session.account.gm => + case (CMT_GMBROADCASTPOPUP, _, _) if gmCommandAllowed => chatService ! ChatService.Message( session, message.copy(recipient = session.player.Name), @@ -583,7 +554,7 @@ class ChatActor( ChatChannel.Default() ) - case (CMT_COMMAND, _, _) if session.account.gm => + case (CMT_COMMAND, _, _) if gmCommandAllowed => chatService ! ChatService.Message( session, message.copy(recipient = session.player.Name), @@ -593,7 +564,7 @@ class ChatActor( case (CMT_NOTE, _, _) => chatService ! ChatService.Message(session, message, ChatChannel.Default()) - case (CMT_SILENCE, _, _) if session.account.gm => + case (CMT_SILENCE, _, _) if gmCommandAllowed => chatService ! ChatService.Message(session, message, ChatChannel.Default()) case (CMT_SQUAD, _, _) => @@ -627,7 +598,7 @@ class ChatActor( ChatMsg(ChatMessageType.CMT_WHO, true, "", "VS online : " + popVS + " on " + contName, None) ) - case (CMT_ZONE, _, contents) if session.account.gm => + case (CMT_ZONE, _, contents) if gmCommandAllowed => val buffer = contents.toLowerCase.split("\\s+") val (zone, gate, list) = (buffer.lift(0), buffer.lift(1)) match { case (Some("-list"), None) => @@ -664,7 +635,7 @@ class ChatActor( ) } - case (CMT_WARP, _, contents) if session.account.gm => + case (CMT_WARP, _, contents) if gmCommandAllowed => val buffer = contents.toLowerCase.split("\\s+") val (coordinates, waypoint) = (buffer.lift(0), buffer.lift(1), buffer.lift(2)) match { case (Some(x), Some(y), Some(z)) => (Some(x, y, z), None) @@ -693,7 +664,7 @@ class ChatActor( ) } - case (CMT_SETBATTLERANK, _, contents) if session.account.gm => + case (CMT_SETBATTLERANK, _, contents) if gmCommandAllowed => val buffer = contents.toLowerCase.split("\\s+") val (target, rank) = (buffer.lift(0), buffer.lift(1)) match { case (Some(target), Some(rank)) if target == session.avatar.name => @@ -721,7 +692,7 @@ class ChatActor( ) } - case (CMT_SETCOMMANDRANK, _, contents) if session.account.gm => + case (CMT_SETCOMMANDRANK, _, contents) if gmCommandAllowed => val buffer = contents.toLowerCase.split("\\s+") val (target, rank) = (buffer.lift(0), buffer.lift(1)) match { case (Some(target), Some(rank)) if target == session.avatar.name => @@ -749,7 +720,7 @@ class ChatActor( ) } - case (CMT_ADDBATTLEEXPERIENCE, _, contents) if session.account.gm => + case (CMT_ADDBATTLEEXPERIENCE, _, contents) if gmCommandAllowed => contents.toIntOption match { case Some(bep) => avatarActor ! AvatarActor.AwardBep(bep) case None => @@ -758,7 +729,7 @@ class ChatActor( ) } - case (CMT_ADDCOMMANDEXPERIENCE, _, contents) if session.account.gm => + case (CMT_ADDCOMMANDEXPERIENCE, _, contents) if gmCommandAllowed => contents.toIntOption match { case Some(cep) => avatarActor ! AvatarActor.AwardCep(cep) case None => @@ -817,7 +788,7 @@ class ChatActor( ) ) - case (CMT_ADDCERTIFICATION, _, contents) if session.account.gm => + case (CMT_ADDCERTIFICATION, _, contents) if gmCommandAllowed => val certs = contents.split(" ").filter(_ != "").map(name => Certification.values.find(_.name == name)) if (certs.nonEmpty) { if (certs.contains(None)) { @@ -850,6 +821,48 @@ class ChatActor( ) } + case (CMT_KICK, _, contents) if gmCommandAllowed => + val input = contents.split("\\s+").drop(1) + if (input.length > 0) { + val numRegex = raw"(\d+)".r + val id = input(0) + val determination: Player => Boolean = id match { + case numRegex(_) => _.CharId == id.toLong + case _ => _.Name.equals(id) + } + session.zone.LivePlayers + .find(determination) + .orElse(session.zone.Corpses.find(determination)) match { + case Some(player) => + input.lift(1) match { + case Some(numRegex(time)) => + sessionActor ! SessionActor.Kick(player, Some(time.toLong)) + case _ => + sessionActor ! SessionActor.Kick(player) + } + + sessionActor ! SessionActor.SendResponse( + ChatMsg( + CMT_GMOPEN, + message.wideContents, + "Server", + "@kick_o", + message.note + ) + ) + case None => + sessionActor ! SessionActor.SendResponse( + ChatMsg( + CMT_GMOPEN, + message.wideContents, + "Server", + "@kick_o", + message.note + ) + ) + } + } + case _ => log.info(s"unhandled chat message $message") } diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index cecc0009..80ac0e65 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -261,7 +261,7 @@ class SessionActor extends Actor with MDCContextAware { */ var upstreamMessageCount: Int = 0 var zoningType: Zoning.Method.Value = Zoning.Method.None - var zoningChatMessageType: ChatMessageType.Value = ChatMessageType.CMT_QUIT + var zoningChatMessageType: ChatMessageType = ChatMessageType.CMT_QUIT var zoningStatus: Zoning.Status.Value = Zoning.Status.None var zoningCounter: Int = 0 var instantActionFallbackDestination: Option[Zoning.InstantAction.Located] = None @@ -1736,12 +1736,13 @@ class SessionActor extends Actor with MDCContextAware { /** * The user no longer expects to perform a zoning event for this reason. - * @param msg the message to the user + * + * @param msg the message to the user * @param msgType the type of message, influencing how it is presented to the user; * normally, this message uses the same value as `zoningChatMessageType`s * defaults to `None` */ - def CancelZoningProcessWithReason(msg: String, msgType: Option[ChatMessageType.Value] = None): Unit = { + def CancelZoningProcessWithReason(msg: String, msgType: Option[ChatMessageType] = None): Unit = { if (zoningStatus > Zoning.Status.None) { sendResponse(ChatMsg(msgType.getOrElse(zoningChatMessageType), false, "", msg, None)) } @@ -9281,7 +9282,7 @@ class SessionActor extends Actor with MDCContextAware { } def KickedByAdministration(): Unit = { - sendResponse(DisconnectMessage("Your account has been logged out by a Customer Service Representative.")) + sendResponse(DisconnectMessage("@kick_w")) Thread.sleep(300) sendResponse(DropSession(session.id, "kick by GM")) } diff --git a/src/main/scala/net/psforever/packet/PSPacket.scala b/src/main/scala/net/psforever/packet/PSPacket.scala index 6b0bc0dc..36e116e0 100644 --- a/src/main/scala/net/psforever/packet/PSPacket.scala +++ b/src/main/scala/net/psforever/packet/PSPacket.scala @@ -3,6 +3,7 @@ package net.psforever.packet import java.nio.charset.Charset +import enumeratum.{Enum, EnumEntry} import enumeratum.values.{IntEnum, IntEnumEntry} import scodec.{Attempt, Codec, DecodeResult, Err} import scodec.bits._ @@ -153,6 +154,28 @@ object PacketHelpers { createIntEnumCodec(enum, storageCodec.xmap[Int](_.toInt, _.toLong)) } + /** Create a Codec for enumeratum's Enum type */ + def createEnumCodec[E <: EnumEntry](enum: Enum[E], storageCodec: Codec[Int]): Codec[E] = { + type Struct = Int :: HNil + val struct: Codec[Struct] = storageCodec.hlist + + def to(pkt: E): Struct = { + enum.indexOf(pkt) :: HNil + } + + def from(struct: Struct): Attempt[E] = + struct match { + case enumVal :: HNil => + enum.valuesToIndex.find(_._2 == enumVal) match { + case Some((v, _)) => Attempt.successful(v) + case None => + Attempt.failure(Err(s"Enum index '${enumVal}' not found in values '${enum.valuesToIndex.toString()}'")) + } + } + + struct.narrow[E](from, to) + } + /** Common codec for how PlanetSide stores string sizes * * When the first bit of the byte is set, the size can be between [0, 127]. diff --git a/src/main/scala/net/psforever/packet/game/ChatMsg.scala b/src/main/scala/net/psforever/packet/game/ChatMsg.scala index 4b61acbf..af7cee84 100644 --- a/src/main/scala/net/psforever/packet/game/ChatMsg.scala +++ b/src/main/scala/net/psforever/packet/game/ChatMsg.scala @@ -21,7 +21,7 @@ import scodec.codecs._ * @param note only used when the message is of note type */ final case class ChatMsg( - messageType: ChatMessageType.Value, + messageType: ChatMessageType, wideContents: Boolean, recipient: String, contents: String, diff --git a/src/main/scala/net/psforever/types/ChatMessageType.scala b/src/main/scala/net/psforever/types/ChatMessageType.scala index 603023e7..d1e1c11f 100644 --- a/src/main/scala/net/psforever/types/ChatMessageType.scala +++ b/src/main/scala/net/psforever/types/ChatMessageType.scala @@ -1,7 +1,8 @@ -// Copyright (c) 2017 PSForever package net.psforever.types +import enumeratum.{Enum, EnumEntry} import net.psforever.packet.PacketHelpers +import scodec.Codec import scodec.codecs._ /** @@ -18,264 +19,269 @@ import scodec.codecs._ * CMT_METAGAME, CMT_SPEEDHACK, CMT_DUMPBUILDINGTREE, CMT_CLIENT_BATCH * CMT_COMMAND_ZONE96, CMT_COMMAND_ZONE97, CMT_COMMAND_ZONE98, CMT_COMMAND_ZONE99 */ -object ChatMessageType extends Enumeration { - type Type = Value - val UNK_0, // ??? - CMT_ALLIANCE, // ??? unused - CMT_BATTLEGROUP, // /bg (not working???) - CMT_BROADCAST, // /broadcast OR /b - CMT_COMMAND, // /command OR /c - CMT_COMMAND_ALLZONES, // /comall - CMT_COMMAND_REPORT, // /sitrep OR /situationreport - CMT_COMMAND_SANCTUARY, // /comsanctuary OR /comsan - CMT_COMMAND_STATION, // ??? unused - CMT_COMMAND_CAVERN1, // /comsu OR /comsupai - CMT_COMMAND_CAVERN2, // /comhu OR /comhunhau - CMT_COMMAND_CAVERN3, // /comad OR /comadlivun - CMT_COMMAND_CAVERN4, // /comby OR /combyblos - CMT_COMMAND_CAVERN5, // /coman OR /comannwn - CMT_COMMAND_CAVERN6, // /comdr OR /comdrugaskan - CMT_COMMAND_ZONE1, // /comso OR /comsolsar - CMT_COMMAND_ZONE2, // /comho OR /comhossin - CMT_COMMAND_ZONE3, // /comcy OR /comcyssor - CMT_COMMAND_ZONE4, // /comis OR /comishundar - CMT_COMMAND_ZONE5, // /comfo OR /comforseral - CMT_COMMAND_ZONE6, // /comce OR /comceryshen - CMT_COMMAND_ZONE7, // /comes OR /comesamir - CMT_COMMAND_ZONE8, // /comos OR /comoshur - CMT_COMMAND_ZONE8_PRIME, // /compr OR /comoshurprime - CMT_COMMAND_ZONE9, // /comse OR /comsearhus - CMT_COMMAND_ZONE10, // /comam OR /comamerish - CMT_OPEN, // /local OR /l - CMT_OUTFIT, // /outfit OR /o - CMT_PLATOON, // /platoon OR /p - CMT_PLATOONLEADER, // /platoonleader OR /pl - CMT_SQUAD, // /squad OR /s - CMT_SQUADLEADER, // /sl - CMT_TELL, // /tell OR /t - U_CMT_BLACKOPS_CHAT, // ??? No slash command? - CMT_GMBROADCAST, // /gmbroadcast - CMT_GMBROADCAST_NC, // /ncbroadcast - CMT_GMBROADCAST_TR, // /trbroadcast - CMT_GMBROADCAST_VS, // /vsbroadcast - CMT_GMBROADCASTWORLD, // /worldbroadcast OR /wb - CMT_GMOPEN, // /gmlocal - CMT_GMTELL, // /gmtell (actually causes normal /tell 0x20 when not a gm???) - CMT_NOTE, // /note - CMT_GMBROADCASTPOPUP, // /gmpopup - U_CMT_GMTELLFROM, // Acknowledgement of /gmtell for sender - U_CMT_TELLFROM, // Acknowledgement of /tell for sender - UNK_45, // ??? empty - CMT_CULLWATERMARK, // ??? This actually causes the client to ping back to the server with some stringified numbers "80 120" (with the same 46 chatmsg causing infinite loop?) - may be incorrect decoding - CMT_INSTANTACTION, // /instantaction OR /ia - CMT_RECALL, // /recall - CMT_OUTFIT_RECALL, // /outfitrecall - CMT_SQUAD_REMATRIX, // ??? - CMT_OUTFITRENAME_USER, // /outfitrename - CMT_RENAME_USER, // /rename - CMT_REPORTUSER, // /report - CMT_VOICE, // quickchat (v-- commands) - CMT_WHO, // /who - CMT_WHO_CSR, // /whocsr OR /whogm - CMT_WHO_PLATOONLEADERS, // /whoplatoonleaders OR /whopl - CMT_WHO_SQUADLEADERS, // /whosquadleaders OR /whosl - CMT_WHO_TEAMS, // /whoteams OR /whoempires - CMT_WHO_CR, // /who cr<#> - CMT_QUIT, // /quit OR /q - CMT_HIDE_HELMET, // /hide_helmet OR /helmet - CMT_TOGGLE_HAT, // /hat - CMT_TOGGLE_SHADES, // /shades - CMT_TOGGLE_EARPIECE, // /earpiece - CMT_TOGGLE_GM, // /gmtoggle - CMT_ANONYMOUS, // /anon OR /anonymous - CMT_DESTROY, // /destroy - CMT_KICK, // /worldkick - CMT_KICK_BY_ID, // /worldkickid - UNK_71, // ??? empty (though the game elsewhere handles it similarly to 69!) - CMT_LOCKSERVER, // /lockserver - CMT_UNLOCKSERVER, // /unlockserver - CMT_CAPTUREBASE, // /capturebase - CMT_CREATE, // /create - CMT_HACK_DOORS, // /hackdoors - CMT_OUTFITCLAIM, // /outfitclaim - CMT_OUTFITUNCLAIM, // /outfitunclaim - CMT_SETBASERESOURCES, // /setbaseresources - U_CMT_SETHEALTH_TARGET, // /sethealth t - U_CMT_SETARMOR_TARGET, // /setarmor t - CMT_SETVEHICLERESOURCES, // /setvehicleresources - CMT_SUPER_CREATE, // /supercreate OR /sc - CMT_VORTEX_MODULE, // /vortex OR /vtx - U_CMT_RESPAWNAMS, // /respawnams ("Create AMS Resp") - CMT_ADDBATTLEEXPERIENCE, // /addbep - CMT_ADDCERTIFICATION, // /certadd - CMT_ADDCOMMANDEXPERIENCE, // /addcep - CMT_ADDIMPLANT, // /addimplant - CMT_ARMOR, // /armor - CMT_ENABLEIMPLANT, // /enableimplant - CMT_EXPANSIONS, // /expansions - CMT_FIRST_TIME_EVENTS, // /firsttime OR /fte - CMT_INVENTORYLAYOUT, // /inventory - CMT_REMOVECERTIFICATION, // /certrm - CMT_REMOVEIMPLANT, // /removeimplant - CMT_SAVE, // /save - CMT_SETBATTLEEXPERIENCE, // /setbep - CMT_SETBATTLERANK, // /setbr - CMT_SETCAPACITANCE, // /setcapacitance - CMT_SETCOMMANDEXPERIENCE, // /setcep - CMT_SETCOMMANDRANK, // /setcr - CMT_SETFAVORITE, // /setfavorite - CMT_SETHEALTH, // /sethealth - CMT_SETARMOR, // /setarmor - CMT_SETIMPLANTSLOTS, // /setimplantslots - CMT_SETSTAMINA, // /setstamina - CMT_SUICIDE, // /suicide - CMT_USEFAVORITE, // /favorite - CMT_TOGGLERESPAWNPENALTY, // /togglerespawnpenalty - CMT_SETAMMO, // /setammo - CMT_AWARD_QUALIFY, // /award_qualify - CMT_AWARD_PROGRESS, // /award_progress - CMT_AWARD_ADD, // /award_add - CMT_AWARD_REMOVE, // /award_remove - CMT_STAT_ADD, // /stat_add - CMT_BFR_SETCAVERNCAPS, // /bfr_setcaverncaps - CMT_BFR_SETCAVERNKILLS, // /bfr_setcavernkills - CMT_BFR_IMPRINT, // /bfr_imprint - CMT_BFR_DAMAGE, // /bfrdamage - CMT_BFR_DAMAGEWEAPON, // /bfrdamageweapon - CMT_RESETPURCHASETIMERS, // /resetpurchasetimers - CMT_EVENTPLAYTIME, // /eventplaytime - CMT_SETTIME, // /settime - CMT_SETTIMESPEED, // /settimespeed - CMT_SNOOP, // /snoop - CMT_SOULMARK, // /soulmark - CMT_FLY, // /fly - CMT_SPEED, // /speed - CMT_TOGGLESPECTATORMODE, // /spectator - CMT_INFO, // /info - CMT_SHOWZONES, // /showzones - CMT_SYNC, // /sync - CMT_SECURITY, // /security - CMT_FIND, // /find - CMT_OUTFITCONFIRM, // /outfitconfirm - CMT_OUTFITDELETE, // /outfitdelete - CMT_OUTFITRENAME_GM, // /outfitrenamegm - CMT_OUTFITLEADER, // /outfitleader - CMT_OUTFITPOINTS, // /outfitpoints - CMT_OUTFITPOINTS_CHARACTER, // /giveop - CMT_OUTFITCREDITS, // /outfitcredits - CMT_RENAME_GM, // /renamegm - CMT_SETGRIEF, // /setgrief - CMT_SILENCE, // /silence - CMT_SILENCE_OUTFIT, // /silenceoutfit - CMT_COMMAND_SILENCE, // /commandsilence - CMT_COMMAND_SILENCE_OUTFIT, // /commandsilenceoutfit - CMT_COMMAND_SILENCE_EMPIRE, // /commandsilenceempire - CMT_SUMMON, // /summon - CMT_AWARD, // /award - U_CMT_AWARD_ZONE, // /award - CMT_AWARD_REVOKE, // /award_revoke - U_CMT_AWARD_REVOKE_ZONE, // /award_revoke - CMT_RESET_CERTS, // /resetcerts - U_CMT_SETBATTLERANK_OTHER, // /setbr - U_CMT_SETCOMMANDRANK_OTHER, // /setcr - CMT_GIVE_XP, // /givexp - CMT_BLACKOPS, // /blackops - CMT_GRANT_BFR_IMPRINT, // /grant_bfr_imprint - CMT_WARP, // /warp - CMT_SETPOPULATIONCAP, // /popcap - U_CMT_SHUTDOWN, // /shutdown "Shutdown" - CMT_MEMORYLOG, // /memorylog - U_CMT_ZONEROTATE, // /zonerotate - CMT_SHIFTER_ENABLE, // /shifteron - CMT_SHIFTER_DISABLE, // /shifteroff - CMT_SHIFTER_CREATE, // /shiftercreate - CMT_SHIFTER_CLEAR, // /shifterclear - CMT_MODULE_SPAWN_STAGGER, // /modulespawnstagger OR /stagger - CMT_MODULE_SPAWN_POP, // /modulespawnpop OR /pop - CMT_PROPERTY_OVERRIDE, // /setprop - CMT_PROPERTY_OVERRIDE_ZONE, // /setpropzone - CMT_SET_EMPIRE_BENEFIT, // /setempirebenefit - CMT_REMOVE_EMPIRE_BENEFIT, // /removeempirebenefit - CMT_SET_DEFCON_LEVEL, // /setdefconlevel - GET_DEFCON_TIME, // /get_defcon_time - CMT_RELOAD_ACTOFGOD_INFO, // /reload_actofgod - CMT_SET_DEFCON_WEIGHT, // /setdefconweight - CMT_SET_DEFCON_EVENT_NAME, // /setdefconeventname - CMT_EARTHQUAKE, // /earthquake - CMT_METEOR_SHOWER, // /meteor_shower - CMT_SPAWN_MONOLITH, // /spawn_monolith - CMT_PKG, // /pkg - CMT_ZONECOMMAND, // /zcommand - CMT_ZONESTART, // /zstart - CMT_ZONESTOP, // /zstop - CMT_ZONELOCK, // /zlock - CMT_BOLOCK, // /bolock - CMT_TRAINING_ZONE, // /train - CMT_ZONE, // /zone - CMT_SHOWDAMAGE, // /showdamage - CMT_EMPIREINCENTIVES, // /empireincentives - CMT_MINE, // /mine - CMT_BATTLEPLANPUBLISH, // /publish - CMT_BATTLEPLANUNPUBLISH, // /unpublish - CMT_BATTLEPLANSUBSCRIBE, // /subscribe - CMT_BATTLEPLANUNSUBSCRIBE, // /unsubscribe - CMT_TEST_BLDG_MODULES, // /testmodule - CMT_SQUAD_TEST, // /squadtest - CMT_HOTSPOT, // /hotspot OR /hot - CMT_SHIFTER_SAVE, // /shiftersave - CMT_SHIFTER_LOAD, // /shifterload - CMT_LIST_ASSETS, // /listassets - CMT_CHECK_PROPERTIES, // /checkprops - CMT_PROPERTY_QUERY, // /queryprop - CMT_INACTIVITYTIMEOUT, // /inactivitytimeout - CMT_SHOW_XPSPLIT, // /xpsplit - CMT_XPDIST, // /xpdist - CMT_SHOWXPDIST, // /showxpdist - CMT_ENTITYREPORT, // /entityreport - CMT_START_MISSION, // /startmission - CMT_RESET_MISSION, // /resetmission - CMT_CANCEL_MISSION, // /cancelmission - CMT_COMPLETE_MISSION, // /completemission - CMT_GOTO_MISSION_STEP, // /gotomissionstep - CMT_SHOW_MISSION_TRIGGERS, // /showmissiontriggers - CMT_ADD_VANUMODULE, // /moduleadd - CMT_REMOVE_VANUMODULE, // /moduleremove OR /modulerm - CMT_DEBUG_MASSIVE, // /debugmassive - CMT_WARP_TO_NEXT_BILLBOARD, // ??? - UNK_222, // ??? "CTF Flag stolen" - UNK_223, // ??? "CTF Flag lost" - UNK_224, // ??? "Vehicle Dismount" - UNK_225, // ??? empty - UNK_226, // ??? empty - UNK_227, // ??? empty - UNK_228, // ??? empty - UNK_229, // ??? empty - UNK_230, // ??? "Vehicle Mount" - UNK_231, // ??? empty - UNK_232, // ??? empty - CMT_ALARM, // /alarm - CMT_APPEAL, // /appeal - CMT_BUGREPORT, // /bug - CMT_CHATLOG, // /log - CMT_CREATE_MACRO, // /macro - CMT_EMOTE, // /emote OR /em - CMT_FILTER, // /filter - CMT_FRIENDS, // /friends - CMT_IGNORE, // /ignore - CMT_HELP, // /help OR /gm - CMT_LOC, // /loc - CMT_REPLY, // /reply OR /r - CMT_TIME, // /time - CMT_TIMEDHELP, // /timedhelp - CMT_TOGGLE_STATS, // /stats - CMT_VERSION, // /version - CMT_INCENTIVES, // /incentives - CMT_HIDESPECTATOR, // /hidespectator - CMT_HUMBUG, // /humbug - CMT_SOUND_HORNS, // /horns - CMT_SQUADINVITE, // /invite OR /squadinvite - CMT_SQUADKICK, // /kick - CMT_SQUADACCEPTINVITATION // /accept OR /yes +sealed abstract class ChatMessageType extends EnumEntry {} + +object ChatMessageType extends Enum[ChatMessageType] { + + val values: IndexedSeq[ChatMessageType] = findValues + + case object UNK_0 extends ChatMessageType // ??? + case object CMT_ALLIANCE extends ChatMessageType // ??? unused + case object CMT_BATTLEGROUP extends ChatMessageType // /bg (not working???) + case object CMT_BROADCAST extends ChatMessageType // /broadcast OR /b + case object CMT_COMMAND extends ChatMessageType // /command OR /c + case object CMT_COMMAND_ALLZONES extends ChatMessageType // /comall + case object CMT_COMMAND_REPORT extends ChatMessageType // /sitrep OR /situationreport + case object CMT_COMMAND_SANCTUARY extends ChatMessageType // /comsanctuary OR /comsan + case object CMT_COMMAND_STATION extends ChatMessageType // ??? unused + case object CMT_COMMAND_CAVERN1 extends ChatMessageType // /comsu OR /comsupai + case object CMT_COMMAND_CAVERN2 extends ChatMessageType // /comhu OR /comhunhau + case object CMT_COMMAND_CAVERN3 extends ChatMessageType // /comad OR /comadlivun + case object CMT_COMMAND_CAVERN4 extends ChatMessageType // /comby OR /combyblos + case object CMT_COMMAND_CAVERN5 extends ChatMessageType // /coman OR /comannwn + case object CMT_COMMAND_CAVERN6 extends ChatMessageType // /comdr OR /comdrugaskan + case object CMT_COMMAND_ZONE1 extends ChatMessageType // /comso OR /comsolsar + case object CMT_COMMAND_ZONE2 extends ChatMessageType // /comho OR /comhossin + case object CMT_COMMAND_ZONE3 extends ChatMessageType // /comcy OR /comcyssor + case object CMT_COMMAND_ZONE4 extends ChatMessageType // /comis OR /comishundar + case object CMT_COMMAND_ZONE5 extends ChatMessageType // /comfo OR /comforseral + case object CMT_COMMAND_ZONE6 extends ChatMessageType // /comce OR /comceryshen + case object CMT_COMMAND_ZONE7 extends ChatMessageType // /comes OR /comesamir + case object CMT_COMMAND_ZONE8 extends ChatMessageType // /comos OR /comoshur + case object CMT_COMMAND_ZONE8_PRIME extends ChatMessageType // /compr OR /comoshurprime + case object CMT_COMMAND_ZONE9 extends ChatMessageType // /comse OR /comsearhus + case object CMT_COMMAND_ZONE10 extends ChatMessageType // /comam OR /comamerish + case object CMT_OPEN extends ChatMessageType // /local OR /l + case object CMT_OUTFIT extends ChatMessageType // /outfit OR /o + case object CMT_PLATOON extends ChatMessageType // /platoon OR /p + case object CMT_PLATOONLEADER extends ChatMessageType // /platoonleader OR /pl + case object CMT_SQUAD extends ChatMessageType // /squad OR /s + case object CMT_SQUADLEADER extends ChatMessageType // /sl + case object CMT_TELL extends ChatMessageType // /tell OR /t + case object U_CMT_BLACKOPS_CHAT extends ChatMessageType // ??? No slash command? + case object CMT_GMBROADCAST extends ChatMessageType // /gmbroadcast + case object CMT_GMBROADCAST_NC extends ChatMessageType // /ncbroadcast + case object CMT_GMBROADCAST_TR extends ChatMessageType // /trbroadcast + case object CMT_GMBROADCAST_VS extends ChatMessageType // /vsbroadcast + case object CMT_GMBROADCASTWORLD extends ChatMessageType // /worldbroadcast OR /wb + case object CMT_GMOPEN extends ChatMessageType // /gmlocal + case object CMT_GMTELL extends ChatMessageType // /gmtell (actually causes normal /tell 0x20 when not a gm???) + case object CMT_NOTE extends ChatMessageType // /note + case object CMT_GMBROADCASTPOPUP extends ChatMessageType // /gmpopup + case object U_CMT_GMTELLFROM extends ChatMessageType // Acknowledgement of /gmtell for sender + case object U_CMT_TELLFROM extends ChatMessageType // Acknowledgement of /tell for sender + case object UNK_45 extends ChatMessageType // ??? empty + case object CMT_CULLWATERMARK + extends ChatMessageType // ??? This actually causes the client to ping back to the server with some stringified numbers "80 120" (with the same 46 chatmsg causing infinite loop?) - may be incorrect decoding + case object CMT_INSTANTACTION extends ChatMessageType // /instantaction OR /ia + case object CMT_RECALL extends ChatMessageType // /recall + case object CMT_OUTFIT_RECALL extends ChatMessageType // /outfitrecall + case object CMT_SQUAD_REMATRIX extends ChatMessageType // ??? + case object CMT_OUTFITRENAME_USER extends ChatMessageType // /outfitrename + case object CMT_RENAME_USER extends ChatMessageType // /rename + case object CMT_REPORTUSER extends ChatMessageType // /report + case object CMT_VOICE extends ChatMessageType // quickchat (v-- commands) + case object CMT_WHO extends ChatMessageType // /who + case object CMT_WHO_CSR extends ChatMessageType // /whocsr OR /whogm + case object CMT_WHO_PLATOONLEADERS extends ChatMessageType // /whoplatoonleaders OR /whopl + case object CMT_WHO_SQUADLEADERS extends ChatMessageType // /whosquadleaders OR /whosl + case object CMT_WHO_TEAMS extends ChatMessageType // /whoteams OR /whoempires + case object CMT_WHO_CR extends ChatMessageType // /who cr<#> + case object CMT_QUIT extends ChatMessageType // /quit OR /q + case object CMT_HIDE_HELMET extends ChatMessageType // /hide_helmet OR /helmet + case object CMT_TOGGLE_HAT extends ChatMessageType // /hat + case object CMT_TOGGLE_SHADES extends ChatMessageType // /shades + case object CMT_TOGGLE_EARPIECE extends ChatMessageType // /earpiece + case object CMT_TOGGLE_GM extends ChatMessageType // /gmtoggle + case object CMT_ANONYMOUS extends ChatMessageType // /anon OR /anonymous + case object CMT_DESTROY extends ChatMessageType // /destroy + case object CMT_KICK extends ChatMessageType // /worldkick + case object CMT_KICK_BY_ID extends ChatMessageType // /worldkickid + case object UNK_71 extends ChatMessageType // ??? empty (though the game elsewhere handles it similarly to 69!) + case object CMT_LOCKSERVER extends ChatMessageType // /lockserver + case object CMT_UNLOCKSERVER extends ChatMessageType // /unlockserver + case object CMT_CAPTUREBASE extends ChatMessageType // /capturebase + case object CMT_CREATE extends ChatMessageType // /create + case object CMT_HACK_DOORS extends ChatMessageType // /hackdoors + case object CMT_OUTFITCLAIM extends ChatMessageType // /outfitclaim + case object CMT_OUTFITUNCLAIM extends ChatMessageType // /outfitunclaim + case object CMT_SETBASERESOURCES extends ChatMessageType // /setbaseresources + case object U_CMT_SETHEALTH_TARGET extends ChatMessageType // /sethealth t + case object U_CMT_SETARMOR_TARGET extends ChatMessageType // /setarmor t + case object CMT_SETVEHICLERESOURCES extends ChatMessageType // /setvehicleresources + case object CMT_SUPER_CREATE extends ChatMessageType // /supercreate OR /sc + case object CMT_VORTEX_MODULE extends ChatMessageType // /vortex OR /vtx + case object U_CMT_RESPAWNAMS extends ChatMessageType // /respawnams ("Create AMS Resp") + case object CMT_ADDBATTLEEXPERIENCE extends ChatMessageType // /addbep + case object CMT_ADDCERTIFICATION extends ChatMessageType // /certadd + case object CMT_ADDCOMMANDEXPERIENCE extends ChatMessageType // /addcep + case object CMT_ADDIMPLANT extends ChatMessageType // /addimplant + case object CMT_ARMOR extends ChatMessageType // /armor + case object CMT_ENABLEIMPLANT extends ChatMessageType // /enableimplant + case object CMT_EXPANSIONS extends ChatMessageType // /expansions + case object CMT_FIRST_TIME_EVENTS extends ChatMessageType // /firsttime OR /fte + case object CMT_INVENTORYLAYOUT extends ChatMessageType // /inventory + case object CMT_REMOVECERTIFICATION extends ChatMessageType // /certrm + case object CMT_REMOVEIMPLANT extends ChatMessageType // /removeimplant + case object CMT_SAVE extends ChatMessageType // /save + case object CMT_SETBATTLEEXPERIENCE extends ChatMessageType // /setbep + case object CMT_SETBATTLERANK extends ChatMessageType // /setbr + case object CMT_SETCAPACITANCE extends ChatMessageType // /setcapacitance + case object CMT_SETCOMMANDEXPERIENCE extends ChatMessageType // /setcep + case object CMT_SETCOMMANDRANK extends ChatMessageType // /setcr + case object CMT_SETFAVORITE extends ChatMessageType // /setfavorite + case object CMT_SETHEALTH extends ChatMessageType // /sethealth + case object CMT_SETARMOR extends ChatMessageType // /setarmor + case object CMT_SETIMPLANTSLOTS extends ChatMessageType // /setimplantslots + case object CMT_SETSTAMINA extends ChatMessageType // /setstamina + case object CMT_SUICIDE extends ChatMessageType // /suicide + case object CMT_USEFAVORITE extends ChatMessageType // /favorite + case object CMT_TOGGLERESPAWNPENALTY extends ChatMessageType // /togglerespawnpenalty + case object CMT_SETAMMO extends ChatMessageType // /setammo + case object CMT_AWARD_QUALIFY extends ChatMessageType // /award_qualify + case object CMT_AWARD_PROGRESS extends ChatMessageType // /award_progress + case object CMT_AWARD_ADD extends ChatMessageType // /award_add + case object CMT_AWARD_REMOVE extends ChatMessageType // /award_remove + case object CMT_STAT_ADD extends ChatMessageType // /stat_add + case object CMT_BFR_SETCAVERNCAPS extends ChatMessageType // /bfr_setcaverncaps + case object CMT_BFR_SETCAVERNKILLS extends ChatMessageType // /bfr_setcavernkills + case object CMT_BFR_IMPRINT extends ChatMessageType // /bfr_imprint + case object CMT_BFR_DAMAGE extends ChatMessageType // /bfrdamage + case object CMT_BFR_DAMAGEWEAPON extends ChatMessageType // /bfrdamageweapon + case object CMT_RESETPURCHASETIMERS extends ChatMessageType // /resetpurchasetimers + case object CMT_EVENTPLAYTIME extends ChatMessageType // /eventplaytime + case object CMT_SETTIME extends ChatMessageType // /settime + case object CMT_SETTIMESPEED extends ChatMessageType // /settimespeed + case object CMT_SNOOP extends ChatMessageType // /snoop + case object CMT_SOULMARK extends ChatMessageType // /soulmark + case object CMT_FLY extends ChatMessageType // /fly + case object CMT_SPEED extends ChatMessageType // /speed + case object CMT_TOGGLESPECTATORMODE extends ChatMessageType // /spectator + case object CMT_INFO extends ChatMessageType // /info + case object CMT_SHOWZONES extends ChatMessageType // /showzones + case object CMT_SYNC extends ChatMessageType // /sync + case object CMT_SECURITY extends ChatMessageType // /security + case object CMT_FIND extends ChatMessageType // /find + case object CMT_OUTFITCONFIRM extends ChatMessageType // /outfitconfirm + case object CMT_OUTFITDELETE extends ChatMessageType // /outfitdelete + case object CMT_OUTFITRENAME_GM extends ChatMessageType // /outfitrenamegm + case object CMT_OUTFITLEADER extends ChatMessageType // /outfitleader + case object CMT_OUTFITPOINTS extends ChatMessageType // /outfitpoints + case object CMT_OUTFITPOINTS_CHARACTER extends ChatMessageType // /giveop + case object CMT_OUTFITCREDITS extends ChatMessageType // /outfitcredits + case object CMT_RENAME_GM extends ChatMessageType // /renamegm + case object CMT_SETGRIEF extends ChatMessageType // /setgrief + case object CMT_SILENCE extends ChatMessageType // /silence + case object CMT_SILENCE_OUTFIT extends ChatMessageType // /silenceoutfit + case object CMT_COMMAND_SILENCE extends ChatMessageType // /commandsilence + case object CMT_COMMAND_SILENCE_OUTFIT extends ChatMessageType // /commandsilenceoutfit + case object CMT_COMMAND_SILENCE_EMPIRE extends ChatMessageType // /commandsilenceempire + case object CMT_SUMMON extends ChatMessageType // /summon + case object CMT_AWARD extends ChatMessageType // /award + case object U_CMT_AWARD_ZONE extends ChatMessageType // /award + case object CMT_AWARD_REVOKE extends ChatMessageType // /award_revoke + case object U_CMT_AWARD_REVOKE_ZONE extends ChatMessageType // /award_revoke + case object CMT_RESET_CERTS extends ChatMessageType // /resetcerts + case object U_CMT_SETBATTLERANK_OTHER extends ChatMessageType // /setbr + case object U_CMT_SETCOMMANDRANK_OTHER extends ChatMessageType // /setcr + case object CMT_GIVE_XP extends ChatMessageType // /givexp + case object CMT_BLACKOPS extends ChatMessageType // /blackops + case object CMT_GRANT_BFR_IMPRINT extends ChatMessageType // /grant_bfr_imprint + case object CMT_WARP extends ChatMessageType // /warp + case object CMT_SETPOPULATIONCAP extends ChatMessageType // /popcap + case object U_CMT_SHUTDOWN extends ChatMessageType // /shutdown "Shutdown" + case object CMT_MEMORYLOG extends ChatMessageType // /memorylog + case object U_CMT_ZONEROTATE extends ChatMessageType // /zonerotate + case object CMT_SHIFTER_ENABLE extends ChatMessageType // /shifteron + case object CMT_SHIFTER_DISABLE extends ChatMessageType // /shifteroff + case object CMT_SHIFTER_CREATE extends ChatMessageType // /shiftercreate + case object CMT_SHIFTER_CLEAR extends ChatMessageType // /shifterclear + case object CMT_MODULE_SPAWN_STAGGER extends ChatMessageType // /modulespawnstagger OR /stagger + case object CMT_MODULE_SPAWN_POP extends ChatMessageType // /modulespawnpop OR /pop + case object CMT_PROPERTY_OVERRIDE extends ChatMessageType // /setprop + case object CMT_PROPERTY_OVERRIDE_ZONE extends ChatMessageType // /setpropzone + case object CMT_SET_EMPIRE_BENEFIT extends ChatMessageType // /setempirebenefit + case object CMT_REMOVE_EMPIRE_BENEFIT extends ChatMessageType // /removeempirebenefit + case object CMT_SET_DEFCON_LEVEL extends ChatMessageType // /setdefconlevel + case object GET_DEFCON_TIME extends ChatMessageType // /get_defcon_time + case object CMT_RELOAD_ACTOFGOD_INFO extends ChatMessageType // /reload_actofgod + case object CMT_SET_DEFCON_WEIGHT extends ChatMessageType // /setdefconweight + case object CMT_SET_DEFCON_EVENT_NAME extends ChatMessageType // /setdefconeventname + case object CMT_EARTHQUAKE extends ChatMessageType // /earthquake + case object CMT_METEOR_SHOWER extends ChatMessageType // /meteor_shower + case object CMT_SPAWN_MONOLITH extends ChatMessageType // /spawn_monolith + case object CMT_PKG extends ChatMessageType // /pkg + case object CMT_ZONECOMMAND extends ChatMessageType // /zcommand + case object CMT_ZONESTART extends ChatMessageType // /zstart + case object CMT_ZONESTOP extends ChatMessageType // /zstop + case object CMT_ZONELOCK extends ChatMessageType // /zlock + case object CMT_BOLOCK extends ChatMessageType // /bolock + case object CMT_TRAINING_ZONE extends ChatMessageType // /train + case object CMT_ZONE extends ChatMessageType // /zone + case object CMT_SHOWDAMAGE extends ChatMessageType // /showdamage + case object CMT_EMPIREINCENTIVES extends ChatMessageType // /empireincentives + case object CMT_MINE extends ChatMessageType // /mine + case object CMT_BATTLEPLANPUBLISH extends ChatMessageType // /publish + case object CMT_BATTLEPLANUNPUBLISH extends ChatMessageType // /unpublish + case object CMT_BATTLEPLANSUBSCRIBE extends ChatMessageType // /subscribe + case object CMT_BATTLEPLANUNSUBSCRIBE extends ChatMessageType // /unsubscribe + case object CMT_TEST_BLDG_MODULES extends ChatMessageType // /testmodule + case object CMT_SQUAD_TEST extends ChatMessageType // /squadtest + case object CMT_HOTSPOT extends ChatMessageType // /hotspot OR /hot + case object CMT_SHIFTER_SAVE extends ChatMessageType // /shiftersave + case object CMT_SHIFTER_LOAD extends ChatMessageType // /shifterload + case object CMT_LIST_ASSETS extends ChatMessageType // /listassets + case object CMT_CHECK_PROPERTIES extends ChatMessageType // /checkprops + case object CMT_PROPERTY_QUERY extends ChatMessageType // /queryprop + case object CMT_INACTIVITYTIMEOUT extends ChatMessageType // /inactivitytimeout + case object CMT_SHOW_XPSPLIT extends ChatMessageType // /xpsplit + case object CMT_XPDIST extends ChatMessageType // /xpdist + case object CMT_SHOWXPDIST extends ChatMessageType // /showxpdist + case object CMT_ENTITYREPORT extends ChatMessageType // /entityreport + case object CMT_START_MISSION extends ChatMessageType // /startmission + case object CMT_RESET_MISSION extends ChatMessageType // /resetmission + case object CMT_CANCEL_MISSION extends ChatMessageType // /cancelmission + case object CMT_COMPLETE_MISSION extends ChatMessageType // /completemission + case object CMT_GOTO_MISSION_STEP extends ChatMessageType // /gotomissionstep + case object CMT_SHOW_MISSION_TRIGGERS extends ChatMessageType // /showmissiontriggers + case object CMT_ADD_VANUMODULE extends ChatMessageType // /moduleadd + case object CMT_REMOVE_VANUMODULE extends ChatMessageType // /moduleremove OR /modulerm + case object CMT_DEBUG_MASSIVE extends ChatMessageType // /debugmassive + case object CMT_WARP_TO_NEXT_BILLBOARD extends ChatMessageType // ??? + case object UNK_222 extends ChatMessageType // ??? "CTF Flag stolen" + case object UNK_223 extends ChatMessageType // ??? "CTF Flag lost" + case object UNK_224 extends ChatMessageType // ??? "Vehicle Dismount" + case object UNK_225 extends ChatMessageType // ??? empty + case object UNK_226 extends ChatMessageType // ??? empty + case object UNK_227 extends ChatMessageType // ??? empty + case object UNK_228 extends ChatMessageType // ??? empty + case object UNK_229 extends ChatMessageType // ??? empty + case object UNK_230 extends ChatMessageType // ??? "Vehicle Mount" + case object UNK_231 extends ChatMessageType // ??? empty + case object UNK_232 extends ChatMessageType // ??? empty + case object CMT_ALARM extends ChatMessageType // /alarm + case object CMT_APPEAL extends ChatMessageType // /appeal + case object CMT_BUGREPORT extends ChatMessageType // /bug + case object CMT_CHATLOG extends ChatMessageType // /log + case object CMT_CREATE_MACRO extends ChatMessageType // /macro + case object CMT_EMOTE extends ChatMessageType // /emote OR /em + case object CMT_FILTER extends ChatMessageType // /filter + case object CMT_FRIENDS extends ChatMessageType // /friends + case object CMT_IGNORE extends ChatMessageType // /ignore + case object CMT_HELP extends ChatMessageType // /help OR /gm + case object CMT_LOC extends ChatMessageType // /loc + case object CMT_REPLY extends ChatMessageType // /reply OR /r + case object CMT_TIME extends ChatMessageType // /time + case object CMT_TIMEDHELP extends ChatMessageType // /timedhelp + case object CMT_TOGGLE_STATS extends ChatMessageType // /stats + case object CMT_VERSION extends ChatMessageType // /version + case object CMT_INCENTIVES extends ChatMessageType // /incentives + case object CMT_HIDESPECTATOR extends ChatMessageType // /hidespectator + case object CMT_HUMBUG extends ChatMessageType // /humbug + case object CMT_SOUND_HORNS extends ChatMessageType // /horns + case object CMT_SQUADINVITE extends ChatMessageType // /invite OR /squadinvite + case object CMT_SQUADKICK extends ChatMessageType // /kick + case object CMT_SQUADACCEPTINVITATION extends ChatMessageType // /accept OR /yes /* TODO: Past this point, the types overflow 8 bits, so need a way to either map them for ChatMsg or just take them completely out @@ -342,9 +348,7 @@ object ChatMessageType extends Enumeration { */ - = Value - - implicit val codec = PacketHelpers.createEnumerationCodec(this, uint8L) + implicit val codec: Codec[ChatMessageType] = PacketHelpers.createEnumCodec(this, uint8L) } /* diff --git a/src/main/scala/net/psforever/util/Config.scala b/src/main/scala/net/psforever/util/Config.scala index b910f8d0..29e3068d 100644 --- a/src/main/scala/net/psforever/util/Config.scala +++ b/src/main/scala/net/psforever/util/Config.scala @@ -3,11 +3,14 @@ package net.psforever.util import java.nio.file.Paths import com.typesafe.config.{Config => TypesafeConfig} +import enumeratum.{Enum, EnumEntry} import enumeratum.values.{IntEnum, IntEnumEntry} import net.psforever.packet.game.ServerType +import net.psforever.types.ChatMessageType import pureconfig.ConfigConvert.viaNonEmptyStringOpt import pureconfig.ConfigReader.Result import pureconfig.{ConfigConvert, ConfigSource} + import scala.concurrent.duration._ import scala.reflect.ClassTag import pureconfig.generic.auto._ // intellij: this is not unused @@ -28,13 +31,25 @@ object Config { viaNonEmptyStringOpt[A]( v => enum.values.toList.collectFirst { - case (e: ServerType) if e.name == v => e.asInstanceOf[A] + case e: ServerType if e.name == v => e.asInstanceOf[A] }, _.value.toString ) + implicit def enumeratumConfigConvert[A <: EnumEntry](implicit + enum: Enum[A], + ct: ClassTag[A] + ): ConfigConvert[A] = + viaNonEmptyStringOpt[A]( + v => + enum.values.toList.collectFirst { + case e if e.toString.toLowerCase == v.toLowerCase => e.asInstanceOf[A] + }, + _.toString + ) + private val source = { - val configFile = Paths.get(directory, "psforever.conf").toFile() + val configFile = Paths.get(directory, "psforever.conf").toFile if (configFile.exists) ConfigSource.file(configFile).withFallback(ConfigSource.defaultApplication) else @@ -60,7 +75,7 @@ case class AppConfig( game: GameConfig, antiCheat: AntiCheatConfig, network: NetworkConfig, - developer: DeveloperConfig, + development: DevelopmentConfig, kamon: KamonConfig, sentry: SentryConfig ) @@ -109,7 +124,8 @@ case class GameConfig( instantActionAms: Boolean ) -case class DeveloperConfig( +case class DevelopmentConfig( + unprivilegedGmCommands: Seq[ChatMessageType], netSim: NetSimConfig )