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