diff --git a/common/src/main/scala/net/psforever/packet/game/ChatMsg.scala b/common/src/main/scala/net/psforever/packet/game/ChatMsg.scala index 6e244ebb..e6dbba75 100644 --- a/common/src/main/scala/net/psforever/packet/game/ChatMsg.scala +++ b/common/src/main/scala/net/psforever/packet/game/ChatMsg.scala @@ -11,18 +11,28 @@ import scodec.codecs._ * Instructs client to display and/or process a chat message/command when sent server to client. * Instructs server to route and/or process a chat message/command when sent client to server. * - * @param messagetype the type of the chat message (CMT) - * @param has_wide_contents whether the contents contains wide characters or not + * @param messageType the type of the chat message (CMT) + * @param wideContents whether the contents contains wide characters or not. This is + * required because Java/Scala have one String type with a charset + * of UTF-16. Therefore, there is no way at runtime to determine the + * charset of String. * @param recipient identifies the recipient of the message, such as in a tell (occasionally used as "sender" instead i.e. /note) * @param contents the textual contents of the message - * @param note_contents only present when the message is of note type + * @param note only used when the message is of note type */ -final case class ChatMsg(messagetype : ChatMessageType.Value, - has_wide_contents : Boolean, +final case class ChatMsg(messageType : ChatMessageType.Value, + wideContents : Boolean, recipient : String, contents : String, - note_contents : Option[String]) + note : Option[String]) extends PlanetSideGamePacket { + + // Prevent usage of the Note field unless the message is of type note + if(messageType == ChatMessageType.CMT_NOTE) + assert(note.isDefined, "Note contents required") + else + assert(note.isEmpty, "Note contents found, but message type isnt Note") + type Packet = ChatMsg def opcode = GamePacketOpcode.ChatMsg def encode = ChatMsg.encode(this) @@ -31,10 +41,13 @@ final case class ChatMsg(messagetype : ChatMessageType.Value, object ChatMsg extends Marshallable[ChatMsg] { implicit val codec : Codec[ChatMsg] = ( ("messagetype" | ChatMessageType.codec) >>:~ { messagetype_value => - (("has_wide_contents" | bool) >>:~ { has_wide_contents_value => + (("has_wide_contents" | bool) >>:~ { isWide => ("recipient" | PacketHelpers.encodedWideStringAligned(7)) :: - newcodecs.binary_choice(has_wide_contents_value, ("contents" | PacketHelpers.encodedWideString), ("contents" | PacketHelpers.encodedString)) + newcodecs.binary_choice(isWide, + "contents" | PacketHelpers.encodedWideString, + "contents" | PacketHelpers.encodedString) }) :+ - conditional(messagetype_value == ChatMessageType.CMT_NOTE, ("note_contents" | PacketHelpers.encodedWideString)) + conditional(messagetype_value == ChatMessageType.CMT_NOTE, + "note_contents" | PacketHelpers.encodedWideString) }).as[ChatMsg] } diff --git a/common/src/main/scala/net/psforever/packet/game/LoginRespMessage.scala b/common/src/main/scala/net/psforever/packet/game/LoginRespMessage.scala index f85c63d1..ec157357 100644 --- a/common/src/main/scala/net/psforever/packet/game/LoginRespMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/LoginRespMessage.scala @@ -26,7 +26,9 @@ object LoginRespMessage extends Marshallable[LoginRespMessage] { ("station_error" | uint32L) :: ("subscription_status" | uint32L) :: ("unknown" | uint32L) :: - ("username" | PacketHelpers.encodedString) :: ( - ("privilege" | uint32L) flatZip { priv => bool } xmap[Long]({case (a, _) => a}, priv => (priv, (priv & 1) == 1))) + ("username" | PacketHelpers.encodedString) :: + ("privilege" | uint32L) + .flatZip(priv => bool) + .xmap[Long]({case (a, _) => a}, priv => (priv, (priv & 1) == 1)) ).as[LoginRespMessage] } \ No newline at end of file diff --git a/common/src/test/scala/CryptoInterfaceTest.scala b/common/src/test/scala/CryptoInterfaceTest.scala index 57377e13..7b75ea05 100644 --- a/common/src/test/scala/CryptoInterfaceTest.scala +++ b/common/src/test/scala/CryptoInterfaceTest.scala @@ -5,7 +5,7 @@ import net.psforever.crypto.CryptoInterface import net.psforever.crypto.CryptoInterface.CryptoDHState import scodec.bits._ -class CryptoInterfaceTest extends Specification { +class CryptoInterfaceTest extends Specification { args(stopOnFail = true) "Crypto interface" should { "correctly initialize" in { CryptoInterface.initialize() diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 5924decc..8d35c76b 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -206,6 +206,15 @@ class GamePacketTest extends Specification { pkt_tell mustEqual string_tell } + + "allow and disallow note" in { + ChatMsg(ChatMessageType.CMT_ARMOR, + false, + "DontCare", "DontCare", Some("Should be here")) must throwA[AssertionError] + ChatMsg(ChatMessageType.CMT_NOTE, + false, + "DontCare", "DontCare", None) must throwA[AssertionError] + } } "ChangeFireModeMessage" should {