mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-04-28 15:25:22 +00:00
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:
parent
ad60b443e1
commit
ef65c91740
13 changed files with 621 additions and 158 deletions
|
|
@ -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
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue