diff --git a/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala b/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala index 8ef3a3dc..6bf99d1d 100644 --- a/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala @@ -6,15 +6,76 @@ import scodec.{Attempt, Codec, Err} import scodec.codecs._ import shapeless.{::, HNil} +/** + * Manage composition and details of a player's current squad, or the currently-viewed squad.
+ *
+ * The `action` code indicates the format of the remainder data in the packet. + * The following formats are translated; their purposes are listed:
+ *   `(None)`
+ *     `3 ` - Save Squad Definition + *     `8 ` - List Squad + *     `26` - Reset All + *     `35` - Cancel Squad Search + *     `41` - Cancel Find + *   `Boolean`
+ *     `28` - Auto-approve Requests for Invitation
+ *     `29` - UNKNOWN
+ *     `30` - UNKNOWN
+ *     `31` - Location Follows Squad Lead
+ *   `Int`
+ *     `10` - Select this Role for Yourself
+ *     `11` - UNKNOWN
+ *     `20` - (Squad leader) Change Squad Zone
+ *     `21` - (Squad leader) Close Squad Member Position
+ *     `22` - (Squad leader) Add Squad Member Position
+ *     `33` - UNKNOWN
+ *     `40` - Find LFS Soldiers that Meet the Requirements for this Role
+ *   `Long`
+ *     `13` - UNKNOWN
+ *     `14` - UNKNOWN
+ *     `15` - UNKNOWN
+ *     `37` - UNKNOWN
+ *   `String`
+ *     `7 ` - UNKNOWN
+ *     `19` - (Squad leader) Change Squad Purpose
+ *   `Int :: Long`
+ *     `12` - UNKNOWN
+ *     `25` - (Squad leader) Change Squad Member Requirements - Weapons
+ *     `38` - UNKNOWN
+ *   `Int :: String`
+ *     `23` - (Squad leader) Change Squad Member Requirements - Role
+ *     `24` - (Squad leader) Change Squad Member Requirements - Detailed Orders
+ *   `Long :: Long`
+ *     `36` - UNKNOWN
+ *   `String :: Long :: Int :: Int`
+ *     `34` - Search for Squads with a Particular Role
+ *
+ * Exploration:
+ * Some notes regarding the full list of action codes follows after this packet. + * Asides from codes whose behaviors are unknown, some codes also have unknown data format. + * No information for codes 1, 5, 9, 27, or 35 has been found yet. + * @param action the purpose of this packet; + * also decides the content of the parameter fields + * @param unk1 na + * @param unk2 na + * @param string_opt the optional `String` parameter + * @param int1_opt the first optional `Int` parameter; + * will not necessarily conform to a single bit length + * @param int2_opt the second optional `Int` parameter + * @param long1_opt the first optional `Long` parameter; + * will not necessarily conform to a single bit length + * @param long2_opt the second optional `Long` parameter + * @param bool_opt the optional `Boolean` parameter + */ final case class SquadDefinitionActionMessage(action : Int, + unk1 : Int, unk2 : Int, - unk3 : Int, - unk4 : Option[String], - unk5 : Option[Int], - unk6 : Option[Int], - unk7 : Option[Long], - unk8 : Option[Long], - unk9 : Option[Boolean]) + string_opt : Option[String], + int1_opt : Option[Int], + int2_opt : Option[Int], + long1_opt : Option[Long], + long2_opt : Option[Long], + bool_opt : Option[Boolean]) extends PlanetSideGamePacket { type Packet = SquadDefinitionActionMessage def opcode = GamePacketOpcode.SquadDefinitionActionMessage @@ -22,8 +83,31 @@ final case class SquadDefinitionActionMessage(action : Int, } object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMessage] { + /** + * Common pattern for the parameters, with enough fields to support all possible outputs. + * All fields are `Option`al purposefully. + */ private type allPattern = Option[String] :: Option[Int] :: Option[Int] :: Option[Long] :: Option[Long] :: Option[Boolean] :: HNil + /** + * `Codec` for reading nothing from the remainder of the stream data. + * @return a filled-out `allPattern` if successful + */ + def noneCodec : Codec[allPattern] = ignore(0).xmap[allPattern] ( + { + case () => + None :: None :: None :: None :: None :: None :: HNil + }, + { + case _ :: _ :: _ :: _ :: _ :: _ :: HNil => + () + } + ) + + /** + * `Codec` for reading a single `Boolean` from remaining stream data. + * @return a filled-out `allPattern` if successful + */ def boolCodec : Codec[allPattern] = bool.hlist.exmap[allPattern] ( { case n :: HNil => @@ -37,6 +121,12 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe } ) + /** + * `Codec` for reading a single `Int` from remaining stream data. + * Multiple bit lengths can be processed from this reading. + * @param icodec the `Codec[Int]` read by this method + * @return a filled-out `allPattern` if successful + */ def intCodec(icodec : Codec[Int]) : Codec[allPattern] = icodec.hlist.exmap[allPattern] ( { case n :: HNil => @@ -50,6 +140,10 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe } ) + /** + * `Codec` for reading a single `Long` from remaining stream data. + * @return a filled-out `allPattern` if successful + */ def longCodec : Codec[allPattern] = uint32L.hlist.exmap[allPattern] ( { case n :: HNil => @@ -63,6 +157,11 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe } ) + /** + * `Codec` for reading a `String` from remaining stream data. + * All `String`s processed by this reading are wide character and are padded by six. + * @return a filled-out `allPattern` if successful + */ def stringCodec : Codec[allPattern] = PacketHelpers.encodedWideStringAligned(6).hlist.exmap[allPattern] ( { case a :: HNil => @@ -76,6 +175,12 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe } ) + /** + * `Codec` for reading an `Int` followed by a `Long` from remaining stream data. + * Multiple bit lengths can be processed for the `Long1` value from this reading. + * @param lcodec the `Codec[Long]` read by this method + * @return a filled-out `allPattern` if successful + */ def intLongCodec(lcodec : Codec[Long]) : Codec[allPattern] = ( uint4L :: lcodec @@ -94,6 +199,11 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe } ) + /** + * `Codec` for reading an `Int` followed by a `String` from remaining stream data. + * All `String`s processed by this reading are wide character and are padded by two. + * @return a filled-out `allPattern` if successful + */ def intStringCodec : Codec[allPattern] = ( uint4L :: PacketHelpers.encodedWideStringAligned(2) @@ -112,6 +222,10 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe } ) + /** + * `Codec` for reading two `Long`s from remaining stream data. + * @return a filled-out `allPattern` if successful + */ def longLongCodec : Codec[allPattern] = ( ulongL(46) :: uint32L @@ -128,6 +242,11 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe } ) + /** + * `Codec` for reading a `String`, a `Long`, and two `Int`s from remaining stream data. + * All `String`s processed by this reading are wide character and are padded by six. + * @return a filled-out `allPattern` if successful + */ def complexCodec : Codec[allPattern] = ( PacketHelpers.encodedWideStringAligned(6) :: ulongL(46) :: @@ -151,7 +270,17 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe ) import scala.annotation.switch - def select_codec(action : Int) : Codec[allPattern] = (action : @switch) match { + + /** + * Select the `Codec` to translate bit data in this packet with an `allPattern` format. + * @param action the purpose of this packet; + * also decides the content of the parameter fields + * @return an `allPattern` `Codec` that parses the appropriate data + */ + def selectCodec(action : Int) : Codec[allPattern] = (action : @switch) match { + case 3 | 8 | 26 | 35 | 41 => //TODO double check these + noneCodec + case 28 | 29 | 30 | 31 => boolCodec @@ -183,7 +312,7 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe complexCodec case _ => - //TODO for debugging purposes only + //TODO for debugging purposes only; normal failure condition below bits.hlist.exmap[allPattern] ( { case x :: HNil => @@ -199,52 +328,44 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe // ignore(0).exmap[allPattern] ( // { // case () => -// Attempt.failure(Err(s"can not match a codec pattern for decoding $test")) +// Attempt.failure(Err(s"can not match a codec pattern for decoding $action")) // }, // { -// case _ => -// Attempt.failure(Err(s"can not match a codec pattern for encoding $test")) +// case _ :: _ :: _ :: _ :: _ :: _ :: HNil => +// Attempt.failure(Err(s"can not match a codec pattern for encoding $action")) // } // ) } implicit val codec : Codec[SquadDefinitionActionMessage] = ( ("action" | uintL(6)) >>:~ { action => - ("unk2" | uint16L) :: - ("unk3" | uint4L) :: - select_codec(action) -// conditional(unk1 == 7, "unk4" | PacketHelpers.encodedWideStringAligned(6)) :: -// conditional((unk1 > 9 && unk1 < 13) || (unk1 > 20 && unk1 < 26) || unk1 == 38 || unk1 == 40, "unk5" | uint4L) :: -// conditional(unk1 == 23 || unk1 == 34, "unk6" | PacketHelpers.encodedWideStringAligned(4)) :: -// conditional(unk1 == 25 || unk1 == 34 || unk1 == 36, "unk7" | ulongL(46)) :: -// conditional(unk1 == 19, "unk8" | PacketHelpers.encodedWideStringAligned(2)) :: //goto LABEL_49 -// conditional(unk1 == 20 || unk1 == 34, "unk9" | uint16L) :: //goto LABEL_48 -// conditional(unk1 == 24, "unkA" | PacketHelpers.encodedWideString) :: //goto LABEL_49 -// conditional((unk1 > 11 && unk1 < 16) || (unk1 > 35 && unk1 < 39), "unkB" | uint32L) :: //goto LABEL_49 -// //LABEL_48 -// conditional(unk1 > 27 && unk1 < 32, "unkC" | bool) :: //goto LABEL_49 -// conditional(unk1 == 33, "unkD" | uintL(3)) :: -// //LABEL_49 -// conditional(unk1 == 34, "unkE" | uintL(3)) + ("unk1" | uint16L) :: + ("unk2" | uint4L) :: + selectCodec(action) } ).as[SquadDefinitionActionMessage] } /* -("change" specifically indicates the perspective is from the SL; "update for squad member" actions may be different) +("change" specifically indicates the perspective is from the SL; "update" indicates squad members other than the oen who made the change ("[#]" indicates the mode is detected but not properly parsed; the length of the combined fields may follow -[0] - clicking on a squad listed in the "Find Squad" tab / cancel squad search -[3] - save sqad favorite (6 bits) -[4] - load a squad definition favorite (6 bits) -7 - -[8] - list squad (6 bits) +[0] - clicking on a squad listed in the "Find Squad" tab / cancel squad search (6 bits/pad?) +[2] - ? (6 bits/pad?) +[3] - save squad favorite (6 bits/pad?) +[4] - load a squad definition favorite (6 bits/pad?) +[6] - ? (6 bits/pad?) +7 - ? +[8] - list squad (6 bits/pad?) 10 - select this role for yourself -11 - -12 - -13 - -14 - -15 - +11 - ? +12 - ? +13 - ? +14 - ? +15 - ? +[16] - ? (6 bits/pad?) +[17] - ? (6 bits/pad?) +[18] - ? (6 bits/pad?) 19 - change purpose 20 - change zone 21 - change/close squad member position @@ -252,41 +373,20 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe 23 - change squad member req role 24 - change squad member req detailed orders 25 - change squad member req weapons -[26] - reset all (6 bits) +[26] - reset all (6 bits/pad?) 28 - auto-approve requests for invitation 29 - 30 - 31 - location follows squad lead +[32] - ? (6 bits/pad?) 33 - 34 - search for squads with a particular role 36 - 37 - 38 - +[39] - ? (?) 40 - find LFS soldiers that meet the requirements for this role [41] - cancel search for LFS soldiers (6 bits) - -28 - 1u (Boolean) -29 - iu (Boolean) -30 - 1u (Boolean) -31 - 1u (Boolean) -33 - 3u (Int) -10 - 4u (Int) -11 - 4u (Int) -21 - 4u (Int) -22 - 4u (Int) -40 - 4u (Int) -20 - 16u (Int) -13 - 32u (Long) -14 - 32u (Long) -15 - 32u (Long) -37 - 32u (Long) -7 - String(6) (String) -19 - String(6) (String) -12 - 4u + 32u (Int :: Long) -38 - 4u + 32u (Int :: Long) -25 - 4u + 46u (Int :: Long) -23 - 4u + String(2) (Int :: String) -24 - 4u + String(2) (Int :: String) -36 - 46u + 32u (Long :: Long) -34 - String(6) + 46u + 16u + 3u (String :: Long :: Int :: Int) - */ \ No newline at end of file +[42] - ? (6 bits/pad?) +[43] - ? (6 bits/pad?) +*/ diff --git a/common/src/test/scala/GamePacketTest.scala b/common/src/test/scala/GamePacketTest.scala index 9da598c2..eb833722 100644 --- a/common/src/test/scala/GamePacketTest.scala +++ b/common/src/test/scala/GamePacketTest.scala @@ -2266,4 +2266,567 @@ class GamePacketTest extends Specification { } } } + + "SquadDefinitionActionMessage" should { + //local test data; note that the second field - unk1 - is always blank for now, but that probably changes + val string_03 = hex"E7 0c 0000c0" //index: 3 + val string_08 = hex"E7 20 000000" + val string_10 = hex"E7 28 000004" //index: 1 + val string_19 = hex"E7 4c 0000218041002d005400650061006d00" //"A-Team" + val string_20 = hex"E7 50 0000004000" + val string_21 = hex"E7 54 000008" //index: 2 + val string_22 = hex"E7 58 000008" //index: 2 + val string_23 = hex"E7 5c 0000061842004c00550046004f005200" //"BLUFOR", index: 1 + val string_24 = hex"E7 60 000006386b0069006c006c002000620061006400200064007500640065007300" //"kill bad dudes", index: 1 + val string_25 = hex"E7 64 000004400000800000" //"Anti-Vehicular" (former), "Infiltration Suit" (latter), index: 1 + val string_26 = hex"E7 68 000000" + val string_28 = hex"E7 70 000020" //On + val string_31 = hex"E7 7c 000020" //On + val string_34a = hex"E7 88 00002180420061006400610073007300000000000000040000" //"Badass", Solsar, Any matching position + val string_34b = hex"E7 88 00002180420061006400610073007300000000000000080000" //"Badass", Hossin, Any matching position + val string_34c = hex"E7 88 00002180420061006400610073007300000000000000080080" //"Badass", Hossin, Any position + val string_34d = hex"E7 88 00002180420061006400610073007300100000200000080100" //"Badass", Hossin, Some("Anti-Vehicular", "Infiltration Suit") + val string_34e = hex"E7 88 00002180420061006400610073007300100000200000080180" //"Badass", Hossin, All("Anti-Vehicular", "Infiltration Suit") + val string_35 = hex"E7 8c 000000" + val string_40 = hex"E7 a0 000004" //index: 1 + val string_41 = hex"E7 a4 000000" + + "decode (03)" in { + PacketCoding.DecodePacket(string_03).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 3 + unk1 mustEqual 0 + unk2 mustEqual 3 + str.isDefined mustEqual false + int1.isDefined mustEqual false + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (08)" in { + PacketCoding.DecodePacket(string_08).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 8 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual false + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (10)" in { + PacketCoding.DecodePacket(string_10).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 10 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual true + int1.get mustEqual 1 + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (19)" in { + PacketCoding.DecodePacket(string_19).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 19 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual true + str.get mustEqual "A-Team" + int1.isDefined mustEqual false + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (20)" in { + PacketCoding.DecodePacket(string_20).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 20 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual true + int1.get mustEqual 1 + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (21)" in { + PacketCoding.DecodePacket(string_21).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 21 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual true + int1.get mustEqual 2 + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (22)" in { + PacketCoding.DecodePacket(string_22).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 22 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual true + int1.get mustEqual 2 + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (23)" in { + PacketCoding.DecodePacket(string_23).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 23 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual true + str.get mustEqual "BLUFOR" + int1.isDefined mustEqual true + int1.get mustEqual 1 + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (24)" in { + PacketCoding.DecodePacket(string_24).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 24 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual true + str.get mustEqual "kill bad dudes" + int1.isDefined mustEqual true + int1.get mustEqual 1 + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (25)" in { + PacketCoding.DecodePacket(string_25).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 25 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual true + int1.get mustEqual 1 + int2.isDefined mustEqual false + long1.isDefined mustEqual true + long1.get mustEqual 536870928L + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (26)" in { + PacketCoding.DecodePacket(string_26).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 26 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual false + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (28)" in { + PacketCoding.DecodePacket(string_28).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 28 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual false + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual true + bool.get mustEqual true + case default => + ko + } + } + + "decode (31)" in { + PacketCoding.DecodePacket(string_31).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 31 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual false + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual true + bool.get mustEqual true + case default => + ko + } + } + + "decode (34a)" in { + PacketCoding.DecodePacket(string_34a).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 34 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual true + str.get mustEqual "Badass" + int1.isDefined mustEqual true + int1.get mustEqual 1 + int2.isDefined mustEqual true + int2.get mustEqual 0 + long1.isDefined mustEqual true + long1.get mustEqual 0 + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (34b)" in { + PacketCoding.DecodePacket(string_34b).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 34 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual true + str.get mustEqual "Badass" + int1.isDefined mustEqual true + int1.get mustEqual 2 + int2.isDefined mustEqual true + int2.get mustEqual 0 + long1.isDefined mustEqual true + long1.get mustEqual 0 + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (34c)" in { + PacketCoding.DecodePacket(string_34c).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 34 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual true + str.get mustEqual "Badass" + int1.isDefined mustEqual true + int1.get mustEqual 2 + int2.isDefined mustEqual true + int2.get mustEqual 1 + long1.isDefined mustEqual true + long1.get mustEqual 0 + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (34d)" in { + PacketCoding.DecodePacket(string_34d).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 34 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual true + str.get mustEqual "Badass" + int1.isDefined mustEqual true + int1.get mustEqual 2 + int2.isDefined mustEqual true + int2.get mustEqual 2 + long1.isDefined mustEqual true + long1.get mustEqual 536870928L + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (34e)" in { + PacketCoding.DecodePacket(string_34e).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 34 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual true + str.get mustEqual "Badass" + int1.isDefined mustEqual true + int1.get mustEqual 2 + int2.isDefined mustEqual true + int2.get mustEqual 3 + long1.isDefined mustEqual true + long1.get mustEqual 536870928L + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (35)" in { + PacketCoding.DecodePacket(string_35).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 35 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual false + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (40)" in { + PacketCoding.DecodePacket(string_40).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 40 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual true + int1.get mustEqual 1 + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "decode (41)" in { + PacketCoding.DecodePacket(string_41).require match { + case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) => + action mustEqual 41 + unk1 mustEqual 0 + unk2 mustEqual 0 + str.isDefined mustEqual false + int1.isDefined mustEqual false + int2.isDefined mustEqual false + long1.isDefined mustEqual false + long2.isDefined mustEqual false + bool.isDefined mustEqual false + case default => + ko + } + } + + "encode (03)" in { + val msg = SquadDefinitionActionMessage(3, 0, 3, None, None, None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_03 + } + + "encode (08)" in { + val msg = SquadDefinitionActionMessage(8, 0, 0, None, None, None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_08 + } + + "encode (10)" in { + val msg = SquadDefinitionActionMessage(10, 0, 0, None, Some(1), None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_10 + } + + "encode (19)" in { + val msg = SquadDefinitionActionMessage(19, 0, 0, Some("A-Team"), None, None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_19 + } + + "encode (20)" in { + val msg = SquadDefinitionActionMessage(20, 0, 0, None, Some(1), None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_20 + } + + "encode (21)" in { + val msg = SquadDefinitionActionMessage(21, 0, 0, None, Some(2), None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_21 + } + + "encode (22)" in { + val msg = SquadDefinitionActionMessage(22, 0, 0, None, Some(2), None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_22 + } + + "encode (23)" in { + val msg = SquadDefinitionActionMessage(23, 0, 0, Some("BLUFOR"), Some(1), None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_23 + } + + "encode (24)" in { + val msg = SquadDefinitionActionMessage(24, 0, 0, Some("kill bad dudes"), Some(1), None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_24 + } + + "encode (25)" in { + val msg = SquadDefinitionActionMessage(25, 0, 0, None, Some(1), None, Some(536870928L), None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_25 + } + + "encode (26)" in { + val msg = SquadDefinitionActionMessage(26, 0, 0, None, None, None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_26 + } + + "encode (28)" in { + val msg = SquadDefinitionActionMessage(28, 0, 0, None, None, None, None, None, Some(true)) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_28 + } + + "encode (31)" in { + val msg = SquadDefinitionActionMessage(31, 0, 0, None, None, None, None, None, Some(true)) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_31 + } + + "encode (34a)" in { + val msg = SquadDefinitionActionMessage(34, 0, 0, Some("Badass"), Some(1), Some(0), Some(0L), None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_34a + } + + "encode (34b)" in { + val msg = SquadDefinitionActionMessage(34, 0, 0, Some("Badass"), Some(2), Some(0), Some(0L), None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_34b + } + + "encode (34c)" in { + val msg = SquadDefinitionActionMessage(34, 0, 0, Some("Badass"), Some(2), Some(1), Some(0L), None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_34c + } + + "encode (34d)" in { + val msg = SquadDefinitionActionMessage(34, 0, 0, Some("Badass"), Some(2), Some(2), Some(536870928L), None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_34d + } + + "encode (34e)" in { + val msg = SquadDefinitionActionMessage(34, 0, 0, Some("Badass"), Some(2), Some(3), Some(536870928L), None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_34e + } + + "encode (35)" in { + val msg = SquadDefinitionActionMessage(35, 0, 0, None, None, None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_35 + } + + "encode (40)" in { + val msg = SquadDefinitionActionMessage(40, 0, 0, None, Some(1), None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_40 + } + + "encode (41)" in { + val msg = SquadDefinitionActionMessage(41, 0, 0, None, None, None, None, None, None) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_41 + } + } }