fixed encodings on DetailedCharacterData, DetailedConstructionToolData, DroppodData, HandheldData, OMFTData, and REKData patterns; added a deprecated pattern for weapon data that permits no ammunition fields; adjusted relevant tests (#263)

This commit is contained in:
Fate-JH 2019-08-21 10:36:56 -04:00 committed by GitHub
parent ad60b443e1
commit ef65c91740
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 621 additions and 158 deletions

View file

@ -21,7 +21,8 @@ class ACEConverter extends ObjectCreateConverter[ConstructionItem]() {
None, None,
None, None,
PlanetSideGUID(0) PlanetSideGUID(0)
) ),
obj.FireModeIndex
) )
) )
} }
@ -39,7 +40,8 @@ class ACEConverter extends ObjectCreateConverter[ConstructionItem]() {
None, None,
None, None,
PlanetSideGUID(0) PlanetSideGUID(0)
) ),
obj.FireModeIndex
) )
) )
} }

View file

@ -30,7 +30,7 @@ final case class ImplantEntry(implant : ImplantType.Value,
object ImplantEntry { object ImplantEntry {
def apply(implant : ImplantType.Value, initialization : Option[Int]) : ImplantEntry = { def apply(implant : ImplantType.Value, initialization : Option[Int]) : ImplantEntry = {
ImplantEntry(implant, initialization, false) ImplantEntry(implant, initialization, active = false)
} }
} }
@ -155,11 +155,10 @@ final case class DetailedCharacterB(unk1 : Option[Long],
0L 0L
} }
//character is at least BR24 //character is at least BR24
val br24 = DetailedCharacterData.isBR24(bep) val unk9Size : Long = if(unk9.isEmpty) { 0L } else { 13L }
val unk9Size : Long = if(br24) { 0L } else { 13L }
val unkASize : Long = unkA.length * 32L val unkASize : Long = unkA.length * 32L
val unkBSize : Long = unkB.foldLeft(0L)(_ + StreamBitSize.stringBitSize(_)) val unkBSize : Long = unkB.foldLeft(0L)(_ + StreamBitSize.stringBitSize(_))
val cosmeticsSize : Long = if(br24) { cosmetics.get.bitsize } else { 0L } val cosmeticsSize : Long = if(DetailedCharacterData.isBR24(bep)) { cosmetics.get.bitsize } else { 0L }
val paddingSize : Int = val paddingSize : Int =
DetailedCharacterData.paddingCalculations(pad_length, implants, Nil)(unk2Len) + /* unk2 */ DetailedCharacterData.paddingCalculations(pad_length, implants, Nil)(unk2Len) + /* unk2 */
@ -214,7 +213,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
0L, 0L,
0L, 0L,
healthMax, health, healthMax, health,
false, unk4 = false,
armor, armor,
0L, 0L,
staminaMax, stamina, staminaMax, stamina,
@ -240,10 +239,10 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
None, None,
Nil, Nil,
Nil, Nil,
false, unkC = false,
cosmetics cosmetics
) )
(pad_length : Option[Int]) => DetailedCharacterData(a, b(a.bep, pad_length))(pad_length) pad_length : Option[Int] => DetailedCharacterData(a, b(a.bep, pad_length))(pad_length)
} }
/** /**
@ -261,7 +260,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
ImplantEntry(ImplantType(implant), None, activeBool) //TODO catch potential NoSuchElementException? ImplantEntry(ImplantType(implant), None, activeBool) //TODO catch potential NoSuchElementException?
case implant :: false :: extra :: HNil => //uninitialized (timer), inactive case implant :: false :: extra :: HNil => //uninitialized (timer), inactive
ImplantEntry(ImplantType(implant), Some(extra), false) //TODO catch potential NoSuchElementException? ImplantEntry(ImplantType(implant), Some(extra), active = false) //TODO catch potential NoSuchElementException?
}, },
{ {
case ImplantEntry(implant, None, n) => //initialized (no timer), active/inactive? case ImplantEntry(implant, None, n) => //initialized (no timer), active/inactive?
@ -298,7 +297,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
* `Codec` for a `List` of `DCDExtra1` objects. * `Codec` for a `List` of `DCDExtra1` objects.
* The first entry contains a padded `String` so it must be processed different from the remainder. * The first entry contains a padded `String` so it must be processed different from the remainder.
*/ */
private def dcd_list_codec(padFunc : (Long)=>Int) : Codec[List[DCDExtra1]] = ( private def dcd_list_codec(padFunc : Long=>Int) : Codec[List[DCDExtra1]] = (
uint8 >>:~ { size => uint8 >>:~ { size =>
conditional(size > 0, dcd_extra1_codec(padFunc(size))) :: conditional(size > 0, dcd_extra1_codec(padFunc(size))) ::
PacketHelpers.listOfNSized(size - 1, dcd_extra1_codec(0)) PacketHelpers.listOfNSized(size - 1, dcd_extra1_codec(0))
@ -344,7 +343,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
* The first entry contains a padded `String` so it must be processed different from the remainder. * The first entry contains a padded `String` so it must be processed different from the remainder.
* @param padFunc a curried function awaiting the extracted length of the current `List` * @param padFunc a curried function awaiting the extracted length of the current `List`
*/ */
private def eventsListCodec(padFunc : (Long)=>Int) : Codec[List[String]] = ( private def eventsListCodec(padFunc : Long=>Int) : Codec[List[String]] = (
uint32L >>:~ { size => uint32L >>:~ { size =>
conditional(size > 0, PacketHelpers.encodedStringAligned(padFunc(size))) :: conditional(size > 0, PacketHelpers.encodedStringAligned(padFunc(size))) ::
PacketHelpers.listOfNSized(size - 1, PacketHelpers.encodedString) PacketHelpers.listOfNSized(size - 1, PacketHelpers.encodedString)
@ -382,7 +381,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
* @see `paddingCalculations` * @see `paddingCalculations`
* @param padFunc a curried function awaiting the extracted length of the current `List` and will count the padding bits * @param padFunc a curried function awaiting the extracted length of the current `List` and will count the padding bits
*/ */
private def unkBCodec(padFunc : (Long)=>Int) : Codec[List[String]] = ( private def unkBCodec(padFunc : Long=>Int) : Codec[List[String]] = (
uint16L >>:~ { size => uint16L >>:~ { size =>
conditional(size > 0, PacketHelpers.encodedStringAligned(padFunc(size))) :: conditional(size > 0, PacketHelpers.encodedStringAligned(padFunc(size))) ::
PacketHelpers.listOfNSized(size - 1, PacketHelpers.encodedString) PacketHelpers.listOfNSized(size - 1, PacketHelpers.encodedString)
@ -405,7 +404,16 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
) )
/** /**
* Suport function that obtains the "absolute list value" of an `Option` object. * A `Codec[Boolean]` that parses a `1u` value according to a NOT truth table.
* `0` is `true` and `1` is `false`.
*/
private val isFalse : Codec[Boolean] = bool.xmap[Boolean] (
value => !value,
value => !value
)
/**
* Support function that obtains the "absolute list value" of an `Option` object.
* @param opt the `Option` object * @param opt the `Option` object
* @return if defined, returns a `List` of the `Option` object's contents; * @return if defined, returns a `List` of the `Option` object's contents;
* if undefined (`None`), returns an empty list * if undefined (`None`), returns an empty list
@ -577,19 +585,17 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
("unk6" | uint32L) :: ("unk6" | uint32L) ::
("unk7" | uint32L) :: ("unk7" | uint32L) ::
("unk8" | uint32L) :: ("unk8" | uint32L) ::
(bool >>:~ { br24 => //BR24+ (optional(isFalse, "unk9" | dcd_extra2_codec) >>:~ { unk9 =>
conditional(!br24, "unk9" | dcd_extra2_codec) >>:~ { unk9 => ("unkA" | listOfN(uint16L, uint32L)) ::
("unkA" | listOfN(uint16L, uint32L)) :: ("unkB" | unkBCodec(
("unkB" | unkBCodec( paddingCalculations(
paddingCalculations( displaceByUnk9(pad_length, unk9, 5),
displaceByUnk9(pad_length, unk9, 5), implants,
implants, List(optToList(unk9), tut, fte, unk3, unk2)
List(optToList(unk9), tut, fte, unk3, unk2) )
) )) ::
)) :: ("unkC" | bool) ::
("unkC" | bool) :: conditional(isBR24(bep), "cosmetics" | Cosmetics.codec)
conditional(br24, "cosmetics" | Cosmetics.codec)
}
}) })
} }
} }
@ -598,7 +604,7 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
}) })
).exmap[DetailedCharacterB] ( ).exmap[DetailedCharacterB] (
{ {
case u1 :: implants :: u2 :: u3 :: fte :: tut :: u4 :: u5 :: u6 :: u7 :: u8 :: _ :: u9 :: uA :: uB :: uC :: cosmetics :: HNil => case u1 :: implants :: u2 :: u3 :: fte :: tut :: u4 :: u5 :: u6 :: u7 :: u8 :: u9 :: uA :: uB :: uC :: cosmetics :: HNil =>
Attempt.successful( Attempt.successful(
DetailedCharacterB(u1, implants, u2, u3, fte, tut, u4, u5, u6, u7, u8, u9, uA, uB, uC, cosmetics)(bep, pad_length) DetailedCharacterB(u1, implants, u2, u3, fte, tut, u4, u5, u6, u7, u8, u9, uA, uB, uC, cosmetics)(bep, pad_length)
) )
@ -612,10 +618,9 @@ object DetailedCharacterData extends Marshallable[DetailedCharacterData] {
else { else {
recursiveEnsureImplantSlots(implantCapacity, implants) recursiveEnsureImplantSlots(implantCapacity, implants)
} }
val br24 : Boolean = isBR24(bep) val cos : Option[Cosmetics] = if(isBR24(bep)) { cosmetics } else { None }
val cos : Option[Cosmetics] = if(br24) { cosmetics } else { None }
Attempt.successful( Attempt.successful(
u1 :: implantList :: u2 :: u3 :: fte :: tut :: u4 :: u5 :: u6 :: u7 :: u8 :: br24 :: u9 :: uA :: uB :: uC :: cos :: HNil u1 :: implantList :: u2 :: u3 :: fte :: tut :: u4 :: u5 :: u6 :: u7 :: u8 :: u9 :: uA :: uB :: uC :: cos :: HNil
) )
} }
) )

View file

@ -11,26 +11,29 @@ import shapeless.{::, HNil}
* `DetailedBoomerTriggerData` - `data.faction` can be `NEUTRAL`, `data.unk1` is `true` * `DetailedBoomerTriggerData` - `data.faction` can be `NEUTRAL`, `data.unk1` is `true`
* `DetailedTelepadData` - `data.faction` can be `NEUTRAL`, `data.jammered` is the router's GUID * `DetailedTelepadData` - `data.faction` can be `NEUTRAL`, `data.jammered` is the router's GUID
*/ */
final case class DetailedConstructionToolData(data : CommonFieldData) extends ConstructorData { final case class DetailedConstructionToolData(data : CommonFieldData, mode : Int) extends ConstructorData {
override def bitsize : Long = 28L + data.bitsize override def bitsize : Long = 28L + data.bitsize
} }
object DetailedConstructionToolData extends Marshallable[DetailedConstructionToolData] { object DetailedConstructionToolData extends Marshallable[DetailedConstructionToolData] {
def apply(data : CommonFieldData) : DetailedConstructionToolData = DetailedConstructionToolData(data, 0)
implicit val codec : Codec[DetailedConstructionToolData] = ( implicit val codec : Codec[DetailedConstructionToolData] = (
("data" | CommonFieldData.codec(false)) :: ("data" | CommonFieldData.codec(false)) ::
uint8 :: uint8 ::
uint(18) :: ("mode" | uint16) ::
uint2 ::
uint2 uint2
).exmap[DetailedConstructionToolData] ( ).exmap[DetailedConstructionToolData] (
{ {
case data :: 1 :: 1 :: _ :: HNil => case data :: 1 :: mode :: 1 :: _ :: HNil =>
Attempt.successful(DetailedConstructionToolData(data)) Attempt.successful(DetailedConstructionToolData(data, mode))
case data => case data =>
Attempt.failure(Err(s"invalid detailed construction tool data format - $data")) Attempt.failure(Err(s"invalid detailed construction tool data format - $data"))
}, },
{ {
case DetailedConstructionToolData(data) => case DetailedConstructionToolData(data, mode) =>
Attempt.successful(data :: 1 :: 1 :: 0 :: HNil) Attempt.successful(data :: 1 :: mode :: 1 :: 0 :: HNil)
} }
) )
} }

View file

@ -26,14 +26,15 @@ import shapeless.{::, HNil}
* When `basic.player_guid` is defined, the droppod will not be at the world ceiling anymore and its boosters will be activate. * When `basic.player_guid` is defined, the droppod will not be at the world ceiling anymore and its boosters will be activate.
* Does this `basic.player_guid` actually represent the player who is in the pod? * Does this `basic.player_guid` actually represent the player who is in the pod?
* @param basic data common to objects * @param basic data common to objects
* @param burn whether the boosters are ignited
* @param health the amount of health the object has, as a percentage of a filled bar * @param health the amount of health the object has, as a percentage of a filled bar
* @param burn whether the boosters are ignited
* @see `DroppodLaunchRequestMessage` * @see `DroppodLaunchRequestMessage`
* @see `DroppodLaunchResponseMessage` * @see `DroppodLaunchResponseMessage`
*/ */
final case class DroppodData(basic : CommonFieldDataWithPlacement, final case class DroppodData(basic : CommonFieldDataWithPlacement,
burn : Boolean = false, health : Int,
health : Int = 255 burn : Boolean,
unk : Boolean
) extends ConstructorData { ) extends ConstructorData {
override def bitsize : Long = { override def bitsize : Long = {
val basicSize = basic.bitsize val basicSize = basic.bitsize
@ -42,6 +43,8 @@ final case class DroppodData(basic : CommonFieldDataWithPlacement,
} }
object DroppodData extends Marshallable[DroppodData] { object DroppodData extends Marshallable[DroppodData] {
def apply(basic : CommonFieldDataWithPlacement) : DroppodData = DroppodData(basic, 255, burn = false, unk = false)
implicit val codec : Codec[DroppodData] = ( implicit val codec : Codec[DroppodData] = (
("basic" | CommonFieldDataWithPlacement.codec) :: ("basic" | CommonFieldDataWithPlacement.codec) ::
bool :: bool ::
@ -50,20 +53,20 @@ object DroppodData extends Marshallable[DroppodData] {
uint4L :: //0xF uint4L :: //0xF
uintL(6) :: //0x0 uintL(6) :: //0x0
("boosters" | uint4L) :: //0x9 on standby, 0x0 when burning and occupied (basic.player_guid?) ("boosters" | uint4L) :: //0x9 on standby, 0x0 when burning and occupied (basic.player_guid?)
bool ("unk" | bool)
).exmap[DroppodData] ( ).exmap[DroppodData] (
{ {
case basic :: false :: health :: 0 :: 0xF :: 0 :: boosters :: false :: HNil => case basic :: false :: health :: 0 :: 0xF :: 0 :: boosters :: unk :: HNil =>
val burn : Boolean = boosters == 0 val burn : Boolean = boosters == 0
Attempt.successful(DroppodData(basic, burn, health)) Attempt.successful(DroppodData(basic, health, burn, unk))
case data => case data =>
Attempt.failure(Err(s"invalid droppod data format - $data")) Attempt.failure(Err(s"invalid droppod data format - $data"))
}, },
{ {
case DroppodData(basic, burn, health) => case DroppodData(basic, health, burn, unk) =>
val boosters : Int = if(burn) { 0 } else { 9 } val boosters : Int = if(burn) { 0 } else { 9 }
Attempt.successful(basic :: false :: health :: 0 :: 0xF :: 0 :: boosters :: false :: HNil) Attempt.successful(basic :: false :: health :: 0 :: 0xF :: 0 :: boosters :: unk :: HNil)
} }
) )
} }

View file

@ -18,29 +18,34 @@ import shapeless.{::, HNil}
* - v4 - not used, i.e., the simple format `CommonFieldData` object is employed * - v4 - not used, i.e., the simple format `CommonFieldData` object is employed
* - v5 - for the telepad, this field is expected to be the GUID of the associated Router * - v5 - for the telepad, this field is expected to be the GUID of the associated Router
*/ */
final case class HandheldData(data : CommonFieldData) extends ConstructorData { final case class HandheldData(data : CommonFieldData,
mode : Int,
unk : Int) extends ConstructorData {
override def bitsize : Long = { override def bitsize : Long = {
11L + data.bitsize 11L + data.bitsize
} }
} }
object HandheldData extends Marshallable[HandheldData] { object HandheldData extends Marshallable[HandheldData] {
def apply(data : CommonFieldData) : HandheldData = HandheldData(data, 0, 0)
def apply(data : CommonFieldData, mode : Int) : HandheldData = HandheldData(data, mode, 0)
implicit val codec : Codec[HandheldData] = ( implicit val codec : Codec[HandheldData] = (
("data" | CommonFieldData.codec) :: ("data" | CommonFieldData.codec) ::
uint4 :: ("mode" | uint8) ::
uint4 :: ("unk" | uint(3))
uint(3)
).exmap[HandheldData] ( ).exmap[HandheldData] (
{ {
case data :: 0 :: 0 :: 0 :: HNil => case data :: mode :: unk :: HNil =>
Attempt.successful(HandheldData(data)) Attempt.successful(HandheldData(data, mode, unk))
case data => case data =>
Attempt.failure(Err(s"invalid handheld tool data format - $data")) Attempt.failure(Err(s"invalid handheld tool data format - $data"))
}, },
{ {
case HandheldData(data) => case HandheldData(data, mode, unk) =>
Attempt.successful(data :: 0 :: 0 :: 0 :: HNil) Attempt.successful(data :: mode :: unk :: HNil)
} }
) )
} }

View file

@ -48,84 +48,6 @@ object OneMannedFieldTurretData extends Marshallable[OneMannedFieldTurretData] {
def apply(deploy : CommonFieldDataWithPlacement, health : Int, internals : InventoryData) : OneMannedFieldTurretData = def apply(deploy : CommonFieldDataWithPlacement, health : Int, internals : InventoryData) : OneMannedFieldTurretData =
new OneMannedFieldTurretData(deploy, health, Some(internals)) new OneMannedFieldTurretData(deploy, health, Some(internals))
// /**
// * Prefabricated weapon data for a weaponless field turret mount (`portable_manned_turret`).
// * @param wep_guid the uid to assign to the weapon
// * @param wep_unk1 na;
// * used by `WeaponData`
// *
// * @param wep_unk2 na;
// * used by `WeaponData`
// * @param ammo_guid the uid to assign to the ammo
// * @param ammo_unk na;
// * used by `AmmoBoxData`
// * @return an `InternalSlot` object
// */
// def generic(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot =
// InternalSlot(ObjectClass.energy_gun, wep_guid, 1,
// WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0,
// CommonFieldData(PlanetSideEmpire.NEUTRAL, ammo_unk(false)
// )
// )
//
// /**
// * Prefabricated weapon data for the Terran Republic field turret, the Avenger (`portable_manned_turret_tr`).
// * @param wep_guid the uid to assign to the weapon
// * @param wep_unk1 na;
// * used by `WeaponData`
// *
// * @param wep_unk2 na;
// * used by `WeaponData`
// * @param ammo_guid the uid to assign to the ammo
// * @param ammo_unk na;
// * used by `AmmoBoxData`
// * @return an `InternalSlot` object
// */
// def avenger(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot =
// InternalSlot(ObjectClass.energy_gun_tr, wep_guid, 1,
// WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0,
// CommonFieldData(PlanetSideEmpire.NEUTRAL, ammo_unk(false)
// )
// )
//
// /**
// * Prefabricated weapon data for the New Conglomerate field turret, the Osprey (`portable_manned_turret_vnc`).
// * @param wep_guid the uid to assign to the weapon
// * @param wep_unk1 na;
// * used by `WeaponData`
// * @param wep_unk2 na;
// * used by `WeaponData`
// * @param ammo_guid the uid to assign to the ammo
// * @param ammo_unk na;
// * used by `AmmoBoxData`
// * @return an `InternalSlot` object
// */
// def osprey(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot =
// InternalSlot(ObjectClass.energy_gun_nc, wep_guid, 1,
// WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0,
// CommonFieldData(PlanetSideEmpire.NEUTRAL, ammo_unk(false)
// )
// )
//
// /**
// * Prefabricated weapon data for the Vanu Soveriegnty field turret, the Orion (`portable_manned_turret_vs`).
// * @param wep_guid the uid to assign to the weapon
// * @param wep_unk1 na;
// * used by `WeaponData`
// * @param wep_unk2 na;
// * used by `WeaponData`
// * @param ammo_guid the uid to assign to the ammo
// * @param ammo_unk na;
// * used by `AmmoBoxData`
// * @return an `InternalSlot` object
// */
// def orion(wep_guid : PlanetSideGUID, wep_unk1 : Int, wep_unk2 : Int, ammo_guid : PlanetSideGUID, ammo_unk : Int) : InternalSlot =
// InternalSlot(ObjectClass.energy_gun_vs, wep_guid, 1,
// WeaponData(wep_unk1, wep_unk2, ObjectClass.energy_gun_ammo, ammo_guid, 0,
// CommonFieldData(PlanetSideEmpire.NEUTRAL, ammo_unk(false)
// )
// )
implicit val codec : Codec[OneMannedFieldTurretData] = ( implicit val codec : Codec[OneMannedFieldTurretData] = (
("deploy" | CommonFieldDataWithPlacement.codec2) :: ("deploy" | CommonFieldDataWithPlacement.codec2) ::
PlanetSideGUID.codec :: //hoist/extract with the deploy.owner_guid in field above PlanetSideGUID.codec :: //hoist/extract with the deploy.owner_guid in field above

View file

@ -9,32 +9,34 @@ import shapeless.{::, HNil}
/** /**
* na * na
* @param data na * @param data na
* @param unk na; * @param unk1 na;
* defaults to 0 * defaults to 0
* @see `DetailedREKData` * @see `DetailedREKData`
*/ */
final case class REKData(data : CommonFieldData, final case class REKData(data : CommonFieldData,
unk : Int = 0 unk1 : Int,
unk2 : Int
) extends ConstructorData { ) extends ConstructorData {
override def bitsize : Long = 50L override def bitsize : Long = 50L
} }
object REKData extends Marshallable[REKData] { object REKData extends Marshallable[REKData] {
def apply(data : CommonFieldData) : REKData = REKData(data, 0, 0)
implicit val codec : Codec[REKData] = ( implicit val codec : Codec[REKData] = (
("data" | CommonFieldData.codec2) :: ("data" | CommonFieldData.codec2) ::
uint8 :: ("unk1" | uint16) ::
("unk" | uint8) :: ("unk2" | uint(10))
uint(10)
).exmap[REKData] ( ).exmap[REKData] (
{ {
case data :: 0 :: unk :: 0 :: HNil => case data :: u1 :: u2 :: HNil =>
Attempt.successful(REKData(data, unk)) Attempt.successful(REKData(data, u1, u2))
case data => case data =>
Attempt.failure(Err(s"invalid rek data format - $data")) Attempt.failure(Err(s"invalid rek data format - $data"))
}, },
{ {
case REKData(data, unk) => case REKData(data, u1, u2) =>
Attempt.successful(data :: 0 :: unk :: 0 :: HNil) Attempt.successful(data :: u1 :: u2 :: HNil)
} }
) )
} }

View file

@ -143,7 +143,9 @@ object WeaponData extends Marshallable[WeaponData] {
else { else {
Attempt.successful(WeaponData(data, fmode, ammo, unk)) Attempt.successful(WeaponData(data, fmode, ammo, unk))
} }
case data :: fmode :: false :: None :: unk :: HNil =>
//rare pass condition, usually found in LockerContainer objects or temporarily existing as a dropped item
Attempt.successful(WeaponData(data, fmode, Nil, unk))
case data => case data =>
Attempt.failure(Err(s"invalid weapon data format - $data")) Attempt.failure(Err(s"invalid weapon data format - $data"))
}, },
@ -159,7 +161,6 @@ object WeaponData extends Marshallable[WeaponData] {
else { else {
Attempt.successful(data :: fmode :: false :: Some(InventoryData(ammo)) :: unk :: HNil) Attempt.successful(data :: fmode :: false :: Some(InventoryData(ammo)) :: unk :: HNil)
} }
case _ => case _ =>
Attempt.failure(Err("invalid weapon data format")) Attempt.failure(Err("invalid weapon data format"))
} }

View file

@ -23,7 +23,7 @@ class HandheldDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(3336) parent.get.guid mustEqual PlanetSideGUID(3336)
parent.get.slot mustEqual 0 parent.get.slot mustEqual 0
data match { data match {
case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), mode, unk) =>
faction mustEqual PlanetSideEmpire.NC faction mustEqual PlanetSideEmpire.NC
bops mustEqual false bops mustEqual false
alternate mustEqual false alternate mustEqual false
@ -50,7 +50,7 @@ class HandheldDataTest extends Specification {
parent.isDefined mustEqual false parent.isDefined mustEqual false
data.isInstanceOf[DroppedItemData[_]] mustEqual true data.isInstanceOf[DroppedItemData[_]] mustEqual true
data match { data match {
case DroppedItemData(pos, HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid))) => case DroppedItemData(pos, HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), mode, unk)) =>
pos.coord mustEqual Vector3(4708.461f, 5547.539f, 72.703125f) pos.coord mustEqual Vector3(4708.461f, 5547.539f, 72.703125f)
pos.orient mustEqual Vector3.z(194.0625f) pos.orient mustEqual Vector3.z(194.0625f)
@ -102,7 +102,7 @@ class HandheldDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(430) parent.get.guid mustEqual PlanetSideGUID(430)
parent.get.slot mustEqual 0 parent.get.slot mustEqual 0
data match { data match {
case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), mode, unk) =>
faction mustEqual PlanetSideEmpire.TR faction mustEqual PlanetSideEmpire.TR
bops mustEqual false bops mustEqual false
alternate mustEqual false alternate mustEqual false
@ -142,7 +142,7 @@ class HandheldDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(4272) parent.get.guid mustEqual PlanetSideGUID(4272)
parent.get.slot mustEqual 0 parent.get.slot mustEqual 0
data match { data match {
case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), mode, unk) =>
faction mustEqual PlanetSideEmpire.NEUTRAL faction mustEqual PlanetSideEmpire.NEUTRAL
bops mustEqual false bops mustEqual false
alternate mustEqual false alternate mustEqual false
@ -182,7 +182,7 @@ class HandheldDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(4149) parent.get.guid mustEqual PlanetSideGUID(4149)
parent.get.slot mustEqual 0 parent.get.slot mustEqual 0
data match { data match {
case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid)) => case HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), mode, unk) =>
faction mustEqual PlanetSideEmpire.NC faction mustEqual PlanetSideEmpire.NC
bops mustEqual false bops mustEqual false
alternate mustEqual false alternate mustEqual false
@ -208,7 +208,7 @@ class HandheldDataTest extends Specification {
guid mustEqual PlanetSideGUID(3682) guid mustEqual PlanetSideGUID(3682)
parent.isDefined mustEqual false parent.isDefined mustEqual false
data match { data match {
case DroppedItemData(pos, HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid))) => case DroppedItemData(pos, HandheldData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), mode, unk)) =>
pos.coord mustEqual Vector3(4777.633f, 5485.4062f, 85.8125f) pos.coord mustEqual Vector3(4777.633f, 5485.4062f, 85.8125f)
pos.orient mustEqual Vector3.z(14.0625f) pos.orient mustEqual Vector3.z(14.0625f)

View file

@ -23,7 +23,7 @@ class REKDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(4174) parent.get.guid mustEqual PlanetSideGUID(4174)
parent.get.slot mustEqual 0 parent.get.slot mustEqual 0
data match { data match {
case REKData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), unk) => case REKData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), unk1, unk2) =>
faction mustEqual PlanetSideEmpire.TR faction mustEqual PlanetSideEmpire.TR
bops mustEqual false bops mustEqual false
alternate mustEqual false alternate mustEqual false
@ -33,7 +33,8 @@ class REKDataTest extends Specification {
v4.contains(false) mustEqual true v4.contains(false) mustEqual true
v5.isEmpty mustEqual true v5.isEmpty mustEqual true
fguid mustEqual PlanetSideGUID(0) fguid mustEqual PlanetSideGUID(0)
unk mustEqual 0 unk1 mustEqual 0
unk2 mustEqual 0
case _ => case _ =>
ko ko
} }
@ -50,7 +51,7 @@ class REKDataTest extends Specification {
guid mustEqual PlanetSideGUID(4355) guid mustEqual PlanetSideGUID(4355)
parent.isDefined mustEqual false parent.isDefined mustEqual false
data match { data match {
case DroppedItemData(pos, REKData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), unk)) => case DroppedItemData(pos, REKData(CommonFieldData(faction, bops, alternate, v1, v2, v3, v4, v5, fguid), unk1, unk2)) =>
pos.coord mustEqual Vector3(4675.039f, 5506.953f, 72.703125f) pos.coord mustEqual Vector3(4675.039f, 5506.953f, 72.703125f)
pos.orient mustEqual Vector3.z(230.625f) pos.orient mustEqual Vector3.z(230.625f)
@ -64,7 +65,8 @@ class REKDataTest extends Specification {
v5.isEmpty mustEqual true v5.isEmpty mustEqual true
fguid mustEqual PlanetSideGUID(0) fguid mustEqual PlanetSideGUID(0)
unk mustEqual 3 unk1 mustEqual 3
unk2 mustEqual 0
case _ => case _ =>
ko ko
} }
@ -83,7 +85,7 @@ class REKDataTest extends Specification {
"encode (dropped)" in { "encode (dropped)" in {
val obj = DroppedItemData( val obj = DroppedItemData(
PlacementData(4675.039f, 5506.953f, 72.703125f, 0f, 0f, 230.625f), PlacementData(4675.039f, 5506.953f, 72.703125f, 0f, 0f, 230.625f),
REKData(CommonFieldData(PlanetSideEmpire.VS, false, false, false, None, false, Some(false), None, PlanetSideGUID(0)), 3) REKData(CommonFieldData(PlanetSideEmpire.VS, false, false, false, None, false, Some(false), None, PlanetSideGUID(0)), 3, 0)
) )
val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(4355), obj) val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(4355), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector

File diff suppressed because one or more lines are too long

View file

@ -25,7 +25,7 @@ class DetailedConstructionToolDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(3104) parent.get.guid mustEqual PlanetSideGUID(3104)
parent.get.slot mustEqual 0 parent.get.slot mustEqual 0
data match { data match {
case DetailedConstructionToolData(cdata) => case DetailedConstructionToolData(cdata, mode) =>
cdata.faction mustEqual PlanetSideEmpire.VS cdata.faction mustEqual PlanetSideEmpire.VS
cdata.bops mustEqual false cdata.bops mustEqual false
cdata.alternate mustEqual false cdata.alternate mustEqual false
@ -65,7 +65,7 @@ class DetailedConstructionToolDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(2502) parent.get.guid mustEqual PlanetSideGUID(2502)
parent.get.slot mustEqual 0 parent.get.slot mustEqual 0
data match { data match {
case DetailedConstructionToolData(cdata) => case DetailedConstructionToolData(cdata, mode) =>
cdata.faction mustEqual PlanetSideEmpire.NEUTRAL cdata.faction mustEqual PlanetSideEmpire.NEUTRAL
cdata.bops mustEqual false cdata.bops mustEqual false
cdata.alternate mustEqual false cdata.alternate mustEqual false
@ -105,7 +105,7 @@ class DetailedConstructionToolDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(414) parent.get.guid mustEqual PlanetSideGUID(414)
parent.get.slot mustEqual 0 parent.get.slot mustEqual 0
data match { data match {
case DetailedConstructionToolData(cdata) => case DetailedConstructionToolData(cdata, mode) =>
cdata.faction mustEqual PlanetSideEmpire.NC cdata.faction mustEqual PlanetSideEmpire.NC
cdata.bops mustEqual false cdata.bops mustEqual false
cdata.alternate mustEqual false cdata.alternate mustEqual false
@ -133,7 +133,7 @@ class DetailedConstructionToolDataTest extends Specification {
parent.get.guid mustEqual PlanetSideGUID(340) parent.get.guid mustEqual PlanetSideGUID(340)
parent.get.slot mustEqual 9 parent.get.slot mustEqual 9
data match { data match {
case DetailedConstructionToolData(cdata) => case DetailedConstructionToolData(cdata, mode) =>
cdata.faction mustEqual PlanetSideEmpire.VS cdata.faction mustEqual PlanetSideEmpire.VS
cdata.bops mustEqual false cdata.bops mustEqual false
cdata.alternate mustEqual false cdata.alternate mustEqual false

View file

@ -22,7 +22,7 @@ class NonstandardVehiclesTest extends Specification {
guid mustEqual PlanetSideGUID(3595) guid mustEqual PlanetSideGUID(3595)
parent.isDefined mustEqual false parent.isDefined mustEqual false
data match { data match {
case DroppodData(basic, burn, health) => case DroppodData(basic, health, burn, unk) =>
basic.pos.coord mustEqual Vector3(5108.0f, 6164.0f, 1023.9844f) basic.pos.coord mustEqual Vector3(5108.0f, 6164.0f, 1023.9844f)
basic.pos.orient mustEqual Vector3.z(90.0f) basic.pos.orient mustEqual Vector3.z(90.0f)