diff --git a/common/src/main/scala/net/psforever/packet/game/PlayerStateMessage.scala b/common/src/main/scala/net/psforever/packet/game/PlayerStateMessage.scala
index 5b4443c1..1def7ca6 100644
--- a/common/src/main/scala/net/psforever/packet/game/PlayerStateMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/PlayerStateMessage.scala
@@ -8,8 +8,6 @@ import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
-import scala.collection.mutable
-
/**
* The server instructs some clients to render a player (usually not that client's avatar) to move in a certain way.
*
@@ -68,7 +66,7 @@ import scala.collection.mutable
* @param is_crouching avatar is crouching
* @param is_jumping avatar is jumping;
* must remain flagged for jump to maintain animation
- * @param unk2 na
+ * @param jump_thrust provide a measure of vertical stability when really close to the avatar character
* @param is_cloaked avatar is cloaked by virtue of an Infiltration Suit
*/
final case class PlayerStateMessage(guid : PlanetSideGUID,
@@ -80,7 +78,7 @@ final case class PlayerStateMessage(guid : PlanetSideGUID,
unk1 : Int,
is_crouching : Boolean = false,
is_jumping : Boolean = false,
- unk2 : Boolean = false,
+ jump_thrust : Boolean = false,
is_cloaked : Boolean = false)
extends PlanetSideGamePacket {
type Packet = PlayerStateMessage
@@ -97,7 +95,7 @@ object PlayerStateMessage extends Marshallable[PlayerStateMessage] {
val booleanCodec : Codec[fourBoolPattern] = (
("is_crouching" | bool) ::
("is_jumping" | bool) ::
- ("unk2" | bool) ::
+ ("jump_thrust" | bool) ::
("is_cloaked" | bool)
).as[fourBoolPattern]
@@ -118,7 +116,7 @@ object PlayerStateMessage extends Marshallable[PlayerStateMessage] {
implicit val codec : Codec[PlayerStateMessage] = (
("guid" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) ::
- optional(bool, "unk1" | Vector3.codec_vel) ::
+ optional(bool, "vel" | Vector3.codec_vel) ::
("facingYaw" | uint8L) ::
("facingPitch" | uint8L) ::
("facingYawUpper" | uint8L) ::
@@ -138,192 +136,3 @@ object PlayerStateMessage extends Marshallable[PlayerStateMessage] {
}
)
}
-
-//TODO the following logic is unimplemented
-/*
-There is a boolean that is currently unhandled(?) that determines if the packet is aware that this code would run.
-If it passes, the first 8-bit value is the number of times the data will be iterated over.
-On each pass, a 4-bit value is extracted from the packet and compared against 15.
-When 15 is read, an 8-bit value is read on that same turn.
-On each subsequent turn, 8-bit values will be read until the number of iterations or until there is an exception.
-Until I find a packet that responds somehow, I have no clue what any of this is supposed to do.
- */
-/**
- * na
- * @param size a length to be applied to the next list, but not necessarily the length of that list
- * (if I could prove that size == list.size always then I could eliminate superfluous logic from `Extra1`)
- * @param data a list of data that comes as either an 8-bit value, or as a 4-bit value and, maybe, an 8-bit value
- */
-final case class Extra1(size : Int,
- data : List[Extra2])
-
-/**
- * na
- * @param unk1 na;
- * the first 8-bit value in one-value form or the first 4-bit value in two-value form;
- * in two-value form, when equal to 15, the second value is read
- * @param unk2 na;
- * the potential second 8-bit value in two-value form
- * @param more the next data in the sequence
- */
-final case class Extra2(unk1 : Int,
- unk2 : Option[Int],
- more : Option[Extra2] = None)
-
-object Extra1 {
- /**
- * Take a chain of `Extra2` objects produced from decoding and compress it into a `List`.
- * @param lst the list in which the `Extra2` data will be stored
- * @param nesting the current link in the chain of `Extra2` objects
- */
- private def packExtraList(lst : mutable.ListBuffer[Extra2], nesting : Option[Extra2]) : Unit = {
- if(nesting.isEmpty) { //escape case
- return
- }
- val elem : Extra2 = nesting.get
- lst += Extra2(elem.unk1, elem.unk2)
- packExtraList(lst, elem.more) //tail recursion
- }
-
- /**
- * Take a `List` of `Extra2` objects for encoding and expand it into a chain.
- * @param iter the iterator for a `List` of `Extra2` data
- * @return the head of a chain of `Extra2` objects
- */
- private def unpackExtraList(iter : Iterator[Extra2]) : Option[Extra2] = {
- //TODO as I don't think I can use tail recursion, how do I do this iteratively?
- if(!iter.hasNext)
- return None
- val elem : Extra2 = iter.next
- Some(Extra2(elem.unk1, elem.unk2, unpackExtraList(iter)))
- }
-
- implicit val codec : Codec[Extra1] = (
- ("size" | uint8L) >>:~ { sz =>
- //external logic: the client checks sz < dword_D33D38 before decoding beyond this point
- conditional(sz != 0, "data" | Extra2.processData(sz)).hlist
- }
- ).xmap[Extra1] (
- {
- case a :: None :: HNil =>
- Extra1(a, List.empty) //it's okay if a != 0
- case a :: b :: HNil =>
- val list = mutable.ListBuffer[Extra2]()
- packExtraList(list, b)
- Extra1(a, list.toList)
- },
- {
- case Extra1(a, Nil) =>
- a :: None :: HNil
- case Extra1(a, b) =>
- a :: unpackExtraList(b.iterator) :: HNil
- }
- )
-}
-
-object Extra2 {
- /**
- * An abbreviated constructor for the one-value form.
- * @param a na
- * @return an `Extra2` object
- */
- def apply(a : Int) : Extra2 = {
- Extra2(a, None)
- }
-
- /**
- * An abbreviated constructor for the two-value form.
- * @param a na
- * @param b na
- * @return an `Extra2` object
- */
- def apply(a : Int, b : Int) : Extra2 = {
- Extra2(a, Some(b))
- }
-
- /**
- * A `Codec` for reading a single value.
- */
- private val oneValueCodec : Codec[Extra2] = ("unk2" | uint8L).hlist.xmap[Extra2] (
- {
- case a :: HNil =>
- Extra2(a, None, None)
- },
- {
- case Extra2(a, None, _) =>
- a :: HNil
- }
- )
-
- /**
- * A `Codec` for reading potentially two values.
- */
- private val twoValueCodec : Codec[Extra2] = (
- ("unk1" | uint4L) >>:~ { unk =>
- conditional(unk == 15, "unk2" | uint8L).hlist
- }
- ).xmap[Extra2] (
- {
- case a :: b :: HNil =>
- Extra2(a, b, None)
- },
- {
- case Extra2(a, b, _) =>
- a :: b :: HNil
- }
- )
-
- /**
- * Half of a recursive `Codec` that allows for swapping between different `Codec`s in between `List` elements.
- *
- * The function calls itself to process each element in the sequence of data in the same manner until complete.
- * The `Extra2` object that is recovered from the first choice of `Codec`s is merely an intermediary object.
- * Due to immutability, the initial object is repackaged to append the chain of `Extra2` in an `Extra2` object.
- * Eventually, `processData` will parse a 4-bit value of 15 and will pass control over to `processDataSingle`.
- * @param size the number of iterations of the looping process left to perform, including this one
- * @return a `Codec` translating a chain of `Extra2` data
- * @see Extra2.processDataSingle
- */
- def processData(size : Int) : Codec[Extra2] = (
- //TODO: without tail recursion, this might cause a stack overflow
- twoValueCodec >>:~ { elem =>
- conditional(size > 0, newcodecs.binary_choice(elem.unk2.isDefined,
- processDataSingle(size - 1),
- processData(size - 1))
- ).hlist
- }
- ).xmap[Extra2] (
- {
- case a :: b :: HNil =>
- Extra2(a.unk1, a.unk2, b)
- },
- {
- case Extra2(a, b, c) =>
- Extra2(a, b) :: c :: HNil
- }
- )
-
- /**
- * Latter half of a recursive `Codec` that allows for swapping between different `Codec`s in between `List` elements.
- * This `Codec` no longer performs swapping and merely runs out the data.
- *
- * @param size the number of iterations of the looping process left to perform, including this one
- * @return a `Codec` translating a chain of `Extra2` data
- * @see Extra2.processData
- */
- private def processDataSingle(size : Int) : Codec[Extra2] = (
- //TODO: without tail recursion, this might cause a stack overflow
- oneValueCodec >>:~ { elem =>
- conditional(size > 0, processDataSingle(size - 1)).hlist
- }
- ).xmap[Extra2] (
- {
- case a :: b :: HNil =>
- Extra2(a.unk1, a.unk2, b)
- },
- {
- case Extra2(a, b, c) =>
- Extra2(a, b) :: c :: HNil
- }
- )
-}
diff --git a/common/src/test/scala/game/PlayerStateMessageTest.scala b/common/src/test/scala/game/PlayerStateMessageTest.scala
index 1ac78289..e8ab270d 100644
--- a/common/src/test/scala/game/PlayerStateMessageTest.scala
+++ b/common/src/test/scala/game/PlayerStateMessageTest.scala
@@ -14,7 +14,7 @@ class PlayerStateMessageTest extends Specification {
"decode (short)" in {
PacketCoding.DecodePacket(string_short).require match {
- case PlayerStateMessage(guid, pos, vel, facingYaw, facingPitch, facingUpper, unk1, crouching, jumping, unk2, unk3) =>
+ case PlayerStateMessage(guid, pos, vel, facingYaw, facingPitch, facingUpper, unk1, crouching, jumping, jthrust, cloaked) =>
guid mustEqual PlanetSideGUID(1696)
pos.x mustEqual 4003.7422f
pos.y mustEqual 5981.414f
@@ -26,8 +26,8 @@ class PlayerStateMessageTest extends Specification {
unk1 mustEqual 83
crouching mustEqual false
jumping mustEqual false
- unk2 mustEqual false
- unk3 mustEqual false
+ jthrust mustEqual false
+ cloaked mustEqual false
case _ =>
ko
}
@@ -35,7 +35,7 @@ class PlayerStateMessageTest extends Specification {
"decode (mod)" in {
PacketCoding.DecodePacket(string_mod).require match {
- case PlayerStateMessage(guid, pos, vel, facingYaw, facingPitch, facingUpper, unk1, crouching, jumping, unk2, unk3) =>
+ case PlayerStateMessage(guid, pos, vel, facingYaw, facingPitch, facingUpper, unk1, crouching, jumping, jthrust, cloaked) =>
guid mustEqual PlanetSideGUID(1696)
pos.x mustEqual 4003.7422f
pos.y mustEqual 5981.414f
@@ -47,8 +47,8 @@ class PlayerStateMessageTest extends Specification {
unk1 mustEqual 83
crouching mustEqual false
jumping mustEqual true
- unk2 mustEqual false
- unk3 mustEqual true
+ jthrust mustEqual false
+ cloaked mustEqual true
case _ =>
ko
}
@@ -56,7 +56,7 @@ class PlayerStateMessageTest extends Specification {
"decode (vel)" in {
PacketCoding.DecodePacket(string_vel).require match {
- case PlayerStateMessage(guid, pos, vel, facingYaw, facingPitch, facingUpper, unk1, crouching, jumping, unk2, unk3) =>
+ case PlayerStateMessage(guid, pos, vel, facingYaw, facingPitch, facingUpper, unk1, crouching, jumping, jthrust, cloaked) =>
guid mustEqual PlanetSideGUID(1696)
pos.x mustEqual 4008.6016f
pos.y mustEqual 5987.6016f
@@ -71,8 +71,8 @@ class PlayerStateMessageTest extends Specification {
unk1 mustEqual 165
crouching mustEqual false
jumping mustEqual false
- unk2 mustEqual false
- unk3 mustEqual false
+ jthrust mustEqual false
+ cloaked mustEqual false
case _ =>
ko
}