restored SquadDefinitionActionMessage to the past upgrade form that was lost; preliminary objects for squad infromation and squad member position information

This commit is contained in:
FateJH 2019-05-25 15:49:51 -04:00
parent 6fdc617a87
commit afb10f57c3
4 changed files with 477 additions and 505 deletions

View file

@ -0,0 +1,65 @@
// Copyright (c) 2019 PSForever
package net.psforever.objects.teamwork
import net.psforever.types.{CertificationType, Vector3}
class Member {
//about the position to be filled
private var role : String = ""
private var restrictions : Set[CertificationType.Value] = Set()
//about the individual filling the position
private var name : String = ""
private var health : Int = 0
private var armor : Int = 0
private var zoneId : String = "Nowhere"
private var position : Vector3 = Vector3.Zero
def Role : String = role
def Role_=(title : String) : String = {
role = title
Role
}
def Restrictions : Set[CertificationType.Value] = restrictions
def Restrictions_=(requirements : Set[CertificationType.Value]) = {
restrictions = requirements
Restrictions
}
def Name : String = name
def Name_=(moniker : String) : String = {
name = moniker
Name
}
def Health : Int = health
def Health_=(red : Int) : Int = {
health = red
Health
}
def Armor : Int = armor
def Armor_=(blue : Int) : Int = {
armor = blue
Armor
}
def ZoneId : String = zoneId
def ZoneId_=(id : String) : String = {
zoneId = id
ZoneId
}
def Position : Vector3 = position
def Position_=(pos : Vector3) : Vector3 = {
position = pos
Position
}
}

View file

@ -0,0 +1,51 @@
// Copyright (c) 2019 PSForever
package net.psforever.objects.teamwork
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.types.PlanetSideEmpire
class Squad(squadId : PlanetSideGUID, alignment : PlanetSideEmpire.Value) extends IdentifiableEntity {
super.GUID_=(squadId)
private val faction : PlanetSideEmpire.Value = alignment //does not change
private val zoneId : Option[String] = None
private var task : String = ""
private var description : String = ""
private val membership : Array[Member] = Array.fill[Member](10)(new Member)
private val availability : Array[Boolean] = Array.fill[Boolean](10)(true)
override def GUID_=(d : PlanetSideGUID) : PlanetSideGUID = GUID
def Faction : PlanetSideEmpire.Value = faction
def ZoneId : String = zoneId.getOrElse({
membership.headOption match {
case Some(leader) =>
leader.ZoneId
case _ =>
"Nowhere"
}
})
def Task : String = task
def Task_=(assignment : String) : String = {
task = assignment
Task
}
def Description : String = description
def Description_=(desc : String) : String = {
description = desc
Description
}
def Membership : Array[Member] = membership
def Availability : Array[Boolean] = availability
def Size : Int = membership.count(member => !member.Name.equals(""))
def Capacity : Int = availability.count(open => open)
}

View file

@ -2,21 +2,239 @@
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
import scodec.bits.BitVector
import scodec.{Attempt, Codec, Err}
import scodec.codecs._
import shapeless.{::, HNil}
/**
* The generic superclass of a specific behavior for this type of squad definition action.
* All behaviors have a "code" that indicates how the rest of the data is parsed.
* @param code the action behavior code
*/
protected abstract class SquadAction(val code : Int)
object SquadAction{
final case class SaveSquadDefinition() extends SquadAction(3)
final case class ListSquad() extends SquadAction(8)
final case class SelectRoleForYourself(state : Int) extends SquadAction(10)
final case class ChangeSquadPurpose(purpose : String) extends SquadAction(19)
final case class ChangeSquadZone(zone : PlanetSideZoneID) extends SquadAction(20)
final case class CloseSquadMemberPosition(position : Int) extends SquadAction(21)
final case class AddSquadMemberPosition(position : Int) extends SquadAction(22)
final case class ChangeSquadMemberRequirementsRole(u1 : Int, role : String) extends SquadAction(23)
final case class ChangeSquadMemberRequirementsDetailedOrders(u1 : Int, orders : String) extends SquadAction(24)
final case class ChangeSquadMemberRequirementsWeapons(u1 : Int, u2 : Long) extends SquadAction(25)
final case class ResetAll() extends SquadAction(26)
final case class AutoApproveInvitationRequests(state : Boolean) extends SquadAction(28)
final case class LocationFollowsSquadLead(state : Boolean) extends SquadAction(31)
final case class SearchForSquadsWithParticularRole(u1: String, u2 : Long, u3: Int, u4 : Int) extends SquadAction(34)
final case class CancelSquadSearch() extends SquadAction(35)
final case class FindLfsSoldiersForRole(state : Int) extends SquadAction(40)
final case class CancelFind() extends SquadAction(41)
final case class Unknown(badCode : Int, data : BitVector) extends SquadAction(badCode)
/**
* The `Codec`s used to transform the input stream into the context of a specific action
* and extract the field data from that stream.
*/
object Codecs {
private val everFailCondition = conditional(included = false, bool)
val saveSquadDefinitionCodec = everFailCondition.xmap[SaveSquadDefinition] (
_ => SaveSquadDefinition(),
{
case SaveSquadDefinition() => None
}
)
val listSquadCodec = everFailCondition.xmap[ListSquad] (
_ => ListSquad(),
{
case ListSquad() => None
}
)
val selectRoleForYourselfCodec = uint4.xmap[SelectRoleForYourself] (
value => SelectRoleForYourself(value),
{
case SelectRoleForYourself(value) => value
}
)
val changeSquadPurposeCodec = PacketHelpers.encodedWideStringAligned(6).xmap[ChangeSquadPurpose] (
purpose => ChangeSquadPurpose(purpose),
{
case ChangeSquadPurpose(purpose) => purpose
}
)
val changeSquadZoneCodec = uint16L.xmap[ChangeSquadZone] (
value => ChangeSquadZone(PlanetSideZoneID(value)),
{
case ChangeSquadZone(value) => value.zoneId.toInt
}
)
val closeSquadMemberPositionCodec = uint4.xmap[CloseSquadMemberPosition] (
position => CloseSquadMemberPosition(position),
{
case CloseSquadMemberPosition(position) => position
}
)
val addSquadMemberPositionCodec = uint4.xmap[AddSquadMemberPosition] (
position => AddSquadMemberPosition(position),
{
case AddSquadMemberPosition(position) => position
}
)
val changeSquadMemberRequirementsRoleCodec = (uint4L :: PacketHelpers.encodedWideStringAligned(2)).xmap[ChangeSquadMemberRequirementsRole] (
{
case u1 :: role :: HNil => ChangeSquadMemberRequirementsRole(u1, role)
},
{
case ChangeSquadMemberRequirementsRole(u1, role) => u1 :: role :: HNil
}
)
val changeSquadMemberRequirementsDetailedOrdersCodec = (uint4L :: PacketHelpers.encodedWideStringAligned(2)).xmap[ChangeSquadMemberRequirementsDetailedOrders] (
{
case u1 :: role :: HNil => ChangeSquadMemberRequirementsDetailedOrders(u1, role)
},
{
case ChangeSquadMemberRequirementsDetailedOrders(u1, role) => u1 :: role :: HNil
}
)
val changeSquadMemberRequirementsWeaponsCodec = (uint4 :: ulongL(46)).xmap[ChangeSquadMemberRequirementsWeapons] (
{
case u1 :: u2 :: HNil => ChangeSquadMemberRequirementsWeapons(u1, u2)
},
{
case ChangeSquadMemberRequirementsWeapons(u1, u2) => u1 :: u2 :: HNil
}
)
val resetAllCodec = everFailCondition.xmap[ResetAll] (
_ => ResetAll(),
{
case ResetAll() => None
}
)
val autoApproveInvitationRequestsCodec = bool.xmap[AutoApproveInvitationRequests] (
state => AutoApproveInvitationRequests(state),
{
case AutoApproveInvitationRequests(state) => state
}
)
val locationFollowsSquadLeadCodec = bool.xmap[LocationFollowsSquadLead] (
state => LocationFollowsSquadLead(state),
{
case LocationFollowsSquadLead(state) => state
}
)
val searchForSquadsWithParticularRoleCodec = (
PacketHelpers.encodedWideStringAligned(6) ::
ulongL(46) ::
uint16L ::
uintL(3)).xmap[SearchForSquadsWithParticularRole] (
{
case u1 :: u2 :: u3 :: u4 :: HNil => SearchForSquadsWithParticularRole(u1, u2, u3, u4)
},
{
case SearchForSquadsWithParticularRole(u1, u2, u3, u4) => u1 :: u2 :: u3 :: u4 :: HNil
}
)
val cancelSquadSearchCodec = everFailCondition.xmap[CancelSquadSearch] (
_ => CancelSquadSearch(),
{
case CancelSquadSearch() => None
}
)
val findLfsSoldiersForRoleCodec = uint4.xmap[FindLfsSoldiersForRole] (
state => FindLfsSoldiersForRole(state),
{
case FindLfsSoldiersForRole(state) => state
}
)
val cancelFindCodec = everFailCondition.xmap[CancelFind] (
_ => CancelFind(),
{
case CancelFind() => None
}
)
/**
* A common form for known action code indexes with an unknown purpose and transformation is an "Unknown" object.
* @param action the action behavior code
* @return a transformation between the action code and the unknown bit data
*/
def unknownCodec(action : Int) = bits.xmap[Unknown] (
data => Unknown(action, data),
{
case Unknown(_, data) => data
}
)
/**
* The action code was completely unanticipated!
* @param action the action behavior code
* @return nothing; always fail
*/
def failureCodec(action : Int)= everFailCondition.exmap[SquadAction] (
_ => Attempt.failure(Err(s"can not match a codec pattern for decoding $action")),
_ => Attempt.failure(Err(s"can not match a codec pattern for encoding $action"))
)
}
}
/**
* Manage composition and details of a player's current squad, or the currently-viewed squad.<br>
* <br>
* The `action` code indicates the format of the remainder data in the packet.
* The following formats are translated; their purposes are listed:<br>
* &nbsp;&nbsp;`(None)`<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`3 ` - Save Squad Definition
* &nbsp;&nbsp;&nbsp;&nbsp;`8 ` - List Squad
* &nbsp;&nbsp;&nbsp;&nbsp;`26` - Reset All
* &nbsp;&nbsp;&nbsp;&nbsp;`35` - Cancel Squad Search
* &nbsp;&nbsp;&nbsp;&nbsp;`41` - Cancel Find
* &nbsp;&nbsp;&nbsp;&nbsp;`0 ` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`1 ` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`2 ` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`3 ` - Save Squad Definition<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`4 ` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`6 ` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`8 ` - List Squad<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`9 ` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`16` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`17` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`18` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`26` - Reset All<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`35` - Cancel Squad Search<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`41` - Cancel Find<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`42` - UNKNOWN<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`43` - UNKNOWN<br>
* &nbsp;&nbsp;`Boolean`<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`28` - Auto-approve Requests for Invitation<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`29` - UNKNOWN<br>
@ -48,34 +266,15 @@ import shapeless.{::, HNil}
* &nbsp;&nbsp;`Long :: Long`<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`36` - UNKNOWN<br>
* &nbsp;&nbsp;`String :: Long :: Int :: Int`<br>
* &nbsp;&nbsp;&nbsp;&nbsp;`34` - Search for Squads with a Particular Role<br>
* <br>
* Exploration:<br>
* 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
* &nbsp;&nbsp;&nbsp;&nbsp;`34` - Search for Squads with a Particular Role
* @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
* @param action the purpose of this packet;
* also decides the content of the parameter fields
*/
final case class SquadDefinitionActionMessage(action : Int,
unk1 : Int,
final case class SquadDefinitionActionMessage(unk1 : Int,
unk2 : Int,
string_opt : Option[String],
int1_opt : Option[Int],
int2_opt : Option[Int],
long1_opt : Option[Long],
long2_opt : Option[Long],
bool_opt : Option[Boolean])
action : SquadAction)
extends PlanetSideGamePacket {
type Packet = SquadDefinitionActionMessage
def opcode = GamePacketOpcode.SquadDefinitionActionMessage
@ -84,266 +283,57 @@ 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.
* Use the action code to transform between
* the specific action object and its field data
* and the stream of bits of the original packet.
* @param code the action behavior code
* @return the `SquadAction` `Codec` to use for the given `code`
*/
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 =>
Attempt.successful(None :: None :: None :: None :: None :: Some(n) :: HNil)
},
{
case _ :: _ :: _ :: _ :: _ :: None :: HNil =>
Attempt.failure(Err("expected a boolean value but found nothing"))
case _ :: _ :: _ :: _ :: _ :: Some(n) :: HNil =>
Attempt.successful(n :: HNil)
}
)
/**
* `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 =>
Attempt.successful(None :: Some(n) :: None :: None :: None :: None :: HNil)
},
{
case _ :: None :: _ :: _ :: _ :: _ :: HNil =>
Attempt.failure(Err("expected an integer value but found nothing"))
case _ :: Some(n) :: _ :: _ :: _ :: _ :: HNil =>
Attempt.successful(n :: HNil)
}
)
/**
* `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 =>
Attempt.successful(None :: None :: None :: Some(n) :: None :: None :: HNil)
},
{
case _ :: _ :: _ :: None :: _ :: _ :: HNil =>
Attempt.failure(Err("expected a long value but found nothing"))
case _ :: _ :: _ :: Some(n) :: _ :: _ :: HNil =>
Attempt.successful(n :: HNil)
}
)
/**
* `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 =>
Attempt.successful(Some(a) :: None :: None :: None :: None :: None :: HNil)
},
{
case None:: _ :: _ :: _ :: _ :: _ :: HNil =>
Attempt.failure(Err("expected a string value but found nothing"))
case Some(a) :: _ :: _ :: _ :: _ :: _ :: HNil =>
Attempt.successful(a :: HNil)
}
)
/**
* `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
).exmap[allPattern] (
{
case a :: b :: HNil =>
Attempt.successful(None :: Some(a) :: None :: Some(b) :: None :: None :: HNil)
},
{
case _ :: None :: _ :: _ :: _ :: _ :: HNil =>
Attempt.failure(Err("expected a integer value but found nothing"))
case _ :: _ :: _ :: None :: _ :: _ :: HNil =>
Attempt.failure(Err("expected a long value but found nothing"))
case _ :: Some(a) :: _ :: Some(b) :: _ :: _ :: HNil =>
Attempt.successful(a :: b :: HNil)
}
)
/**
* `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)
).exmap[allPattern] (
{
case a :: b :: HNil =>
Attempt.successful(Some(b) :: Some(a) :: None :: None :: None :: None :: HNil)
},
{
case None:: _ :: _ :: _ :: _ :: _ :: HNil =>
Attempt.failure(Err("expected a string value but found nothing"))
case _ :: None :: _ :: _ :: _ :: _ :: HNil =>
Attempt.failure(Err("expected an integer value but found nothing"))
case Some(b) :: Some(a) :: _ :: _ :: _ :: _ :: HNil =>
Attempt.successful(a :: b :: HNil)
}
)
/**
* `Codec` for reading two `Long`s from remaining stream data.
* @return a filled-out `allPattern` if successful
*/
def longLongCodec : Codec[allPattern] = (
ulongL(46) ::
uint32L
).exmap[allPattern] (
{
case a :: b :: HNil =>
Attempt.successful(None :: None :: None :: Some(a) :: Some(b) :: None :: HNil)
},
{
case (_ :: _ :: _ :: None :: _ :: _ :: HNil) | (_ :: _ :: _ :: _ :: None :: _ :: HNil) =>
Attempt.failure(Err("expected two long values but found one"))
case _ :: _ :: _ :: Some(a) :: Some(b) :: _ :: HNil =>
Attempt.successful(a :: b :: HNil)
}
)
/**
* `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) ::
uint16L ::
uintL(3)
).exmap[allPattern] (
{
case a :: b :: c :: d :: HNil =>
Attempt.successful(Some(a) :: Some(c) :: Some(d) :: Some(b) :: None :: None :: HNil)
},
{
case None:: _ :: _ :: _ :: _ :: _ :: HNil =>
Attempt.failure(Err("expected a string value but found nothing"))
case _ :: _ :: _ :: None :: _ :: _ :: HNil =>
Attempt.failure(Err("expected a long value but found nothing"))
case (_ :: None :: _ :: _ :: _ :: _ :: HNil) | (_ :: _ :: None :: _ :: _ :: _ :: HNil) =>
Attempt.failure(Err("expected two integer values but found one"))
case Some(a) :: Some(c) :: Some(d) :: Some(b) :: _ :: _ :: HNil =>
Attempt.successful(a :: b :: c :: d :: HNil)
}
)
import scala.annotation.switch
/**
* 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
case 33 =>
intCodec(uintL(3))
case 10 | 11 | 21 | 22 | 40 =>
intCodec(uint4L)
case 20 =>
intCodec(uint16L)
case 13 | 14 | 15 | 37 =>
longCodec
case 7 | 19 =>
stringCodec
case 12 | 38 =>
intLongCodec(uint32L)
case 25 =>
intLongCodec(ulongL(46))
case 23 | 24 =>
intStringCodec
case 36 =>
longLongCodec
case 34 =>
complexCodec
case _ =>
//TODO for debugging purposes only; normal failure condition below
bits.hlist.exmap[allPattern] (
{
case x :: HNil =>
org.log4s.getLogger.warn(s"can not match a codec pattern for decoding $action")
Attempt.successful(Some(x.toString) :: None :: None :: None :: None :: None :: HNil)
},
{
case Some(x) :: None :: None :: None :: None :: None :: HNil =>
org.log4s.getLogger.warn(s"can not match a codec pattern for encoding $action")
Attempt.successful(scodec.bits.BitVector.fromValidBin(x) :: HNil)
}
)
// ignore(0).exmap[allPattern] (
// {
// case () =>
// Attempt.failure(Err(s"can not match a codec pattern for decoding $action"))
// },
// {
// case _ :: _ :: _ :: _ :: _ :: _ :: HNil =>
// Attempt.failure(Err(s"can not match a codec pattern for encoding $action"))
// }
// )
def selectFromActionCode(code : Int) : Codec[SquadAction] = {
import SquadAction.Codecs._
import scala.annotation.switch
((code : @switch) match {
case 3 => saveSquadDefinitionCodec
case 8 => listSquadCodec
case 10 => selectRoleForYourselfCodec
case 19 => changeSquadPurposeCodec
case 20 => changeSquadZoneCodec
case 21 => closeSquadMemberPositionCodec
case 22 => addSquadMemberPositionCodec
case 23 => changeSquadMemberRequirementsRoleCodec
case 24 => changeSquadMemberRequirementsDetailedOrdersCodec
case 25 => changeSquadMemberRequirementsWeaponsCodec
case 26 => resetAllCodec
case 28 => autoApproveInvitationRequestsCodec
case 31 => locationFollowsSquadLeadCodec
case 34 => searchForSquadsWithParticularRoleCodec
case 35 => cancelSquadSearchCodec
case 40 => findLfsSoldiersForRoleCodec
case 41 => cancelFindCodec
case 0 | 1 | 2 | 4 | 6 | 7 | 9 |
11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 29 | 30 | 33 | 36 |
37 | 38 | 42 | 43 => unknownCodec(code)
case _ => failureCodec(code)
}).asInstanceOf[Codec[SquadAction]]
}
implicit val codec : Codec[SquadDefinitionActionMessage] = (
("action" | uintL(6)) >>:~ { action =>
uintL(6) >>:~ { code =>
("unk1" | uint16L) ::
("unk2" | uint4L) ::
selectCodec(action)
("action" | selectFromActionCode(code))
}
).as[SquadDefinitionActionMessage]
).xmap[SquadDefinitionActionMessage] (
{
case _ :: u1 :: u2 :: action :: HNil =>
SquadDefinitionActionMessage(u1, u2, action)
},
{
case SquadDefinitionActionMessage(u1, u2, action) =>
action.code :: u1 :: u2 :: action :: HNil
}
)
}
/*

View file

@ -3,6 +3,7 @@ package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.SquadAction._
import net.psforever.packet.game._
import scodec.bits._
@ -30,18 +31,15 @@ class SquadDefinitionActionMessageTest extends Specification {
val string_40 = hex"E7 a0 000004" //index: 1
val string_41 = hex"E7 a4 000000"
val string_43 = hex"e7 ac 000000"
val string_failure = hex"E7 ff"
"decode (03)" in {
PacketCoding.DecodePacket(string_03).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 3
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual SaveSquadDefinition()
case _ =>
ko
}
@ -49,16 +47,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (08)" in {
PacketCoding.DecodePacket(string_08).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 8
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual ListSquad()
case _ =>
ko
}
@ -66,17 +58,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (10)" in {
PacketCoding.DecodePacket(string_10).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 10
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual SelectRoleForYourself(1)
case _ =>
ko
}
@ -84,17 +69,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (19)" in {
PacketCoding.DecodePacket(string_19).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 19
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual ChangeSquadPurpose("A-Team")
case _ =>
ko
}
@ -102,17 +80,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (20)" in {
PacketCoding.DecodePacket(string_20).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 20
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual ChangeSquadZone(PlanetSideZoneID(1))
case _ =>
ko
}
@ -120,17 +91,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (21)" in {
PacketCoding.DecodePacket(string_21).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 21
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual CloseSquadMemberPosition(2)
case _ =>
ko
}
@ -138,17 +102,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (22)" in {
PacketCoding.DecodePacket(string_22).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 22
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual AddSquadMemberPosition(2)
case _ =>
ko
}
@ -156,18 +113,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (23)" in {
PacketCoding.DecodePacket(string_23).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 23
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual ChangeSquadMemberRequirementsRole(1, "BLUFOR")
case _ =>
ko
}
@ -175,18 +124,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (24)" in {
PacketCoding.DecodePacket(string_24).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 24
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual ChangeSquadMemberRequirementsDetailedOrders(1, "kill bad dudes")
case _ =>
ko
}
@ -194,18 +135,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (25)" in {
PacketCoding.DecodePacket(string_25).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 25
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual ChangeSquadMemberRequirementsWeapons(1, 536870928L)
case _ =>
ko
}
@ -213,16 +146,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (26)" in {
PacketCoding.DecodePacket(string_26).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 26
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual ResetAll()
case _ =>
ko
}
@ -230,17 +157,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (28)" in {
PacketCoding.DecodePacket(string_28).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 28
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual AutoApproveInvitationRequests(true)
case _ =>
ko
}
@ -248,17 +168,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (31)" in {
PacketCoding.DecodePacket(string_31).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 31
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual LocationFollowsSquadLead(true)
case _ =>
ko
}
@ -266,20 +179,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34a)" in {
PacketCoding.DecodePacket(string_34a).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 34
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 1, 0)
case _ =>
ko
}
@ -287,20 +190,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34b)" in {
PacketCoding.DecodePacket(string_34b).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 34
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 0)
case _ =>
ko
}
@ -308,20 +201,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34c)" in {
PacketCoding.DecodePacket(string_34c).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 34
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual SearchForSquadsWithParticularRole("Badass", 0L, 2, 1)
case _ =>
ko
}
@ -329,20 +212,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34d)" in {
PacketCoding.DecodePacket(string_34d).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 34
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2)
case _ =>
ko
}
@ -350,20 +223,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (34e)" in {
PacketCoding.DecodePacket(string_34e).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 34
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3)
case _ =>
ko
}
@ -371,16 +234,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (35)" in {
PacketCoding.DecodePacket(string_35).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 35
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual CancelSquadSearch()
case _ =>
ko
}
@ -388,17 +245,10 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (40)" in {
PacketCoding.DecodePacket(string_40).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 40
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual FindLfsSoldiersForRole(1)
case _ =>
ko
}
@ -406,165 +256,181 @@ class SquadDefinitionActionMessageTest extends Specification {
"decode (41)" in {
PacketCoding.DecodePacket(string_41).require match {
case SquadDefinitionActionMessage(action, unk1, unk2, str, int1, int2, long1, long2, bool) =>
action mustEqual 41
case SquadDefinitionActionMessage(unk1, unk2, action) =>
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
action mustEqual CancelFind()
case _ =>
ko
}
}
"decode (43, unknown)" in {
PacketCoding.DecodePacket(string_43).require match {
case SquadDefinitionActionMessage(unk1, unk2, action) =>
unk1 mustEqual 0
unk2 mustEqual 0
action mustEqual Unknown(43, hex"00".toBitVector.take(6))
case _ =>
ko
}
}
"decode (failure)" in {
PacketCoding.DecodePacket(string_failure).isFailure mustEqual true
}
"encode (03)" in {
val msg = SquadDefinitionActionMessage(3, 0, 3, None, None, None, None, None, None)
val msg = SquadDefinitionActionMessage(0, 3, SaveSquadDefinition())
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 msg = SquadDefinitionActionMessage(0, 0, ListSquad())
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 msg = SquadDefinitionActionMessage(0, 0, SelectRoleForYourself(1))
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 msg = SquadDefinitionActionMessage(0, 0, ChangeSquadPurpose("A-Team"))
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 msg = SquadDefinitionActionMessage(0, 0, ChangeSquadZone(PlanetSideZoneID(1)))
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 msg = SquadDefinitionActionMessage(0, 0, CloseSquadMemberPosition(2))
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 msg = SquadDefinitionActionMessage(0, 0, AddSquadMemberPosition(2))
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 msg = SquadDefinitionActionMessage(0, 0, ChangeSquadMemberRequirementsRole(1, "BLUFOR"))
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 msg = SquadDefinitionActionMessage(0, 0, ChangeSquadMemberRequirementsDetailedOrders(1, "kill bad dudes"))
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 msg = SquadDefinitionActionMessage(0, 0, ChangeSquadMemberRequirementsWeapons(1, 536870928L))
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 msg = SquadDefinitionActionMessage(0, 0, ResetAll())
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 msg = SquadDefinitionActionMessage(0, 0, AutoApproveInvitationRequests(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 msg = SquadDefinitionActionMessage(0, 0, LocationFollowsSquadLead(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 msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 0L, 1, 0))
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 msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 0L, 2, 0))
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 msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 0L, 2, 1))
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 msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 2))
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 msg = SquadDefinitionActionMessage(0, 0, SearchForSquadsWithParticularRole("Badass", 536870928L, 2, 3))
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 msg = SquadDefinitionActionMessage(0, 0, CancelSquadSearch())
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 msg = SquadDefinitionActionMessage(0, 0, FindLfsSoldiersForRole(1))
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 msg = SquadDefinitionActionMessage(0, 0, CancelFind())
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_41
}
"encode (43, unknown)" in {
val msg = SquadDefinitionActionMessage(0, 0, Unknown(43, BitVector.empty))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_43
}
}