diff --git a/common/src/main/scala/net/psforever/packet/game/ChildObjectStateMessage.scala b/common/src/main/scala/net/psforever/packet/game/ChildObjectStateMessage.scala
index 4b2a3058..fdc03eea 100644
--- a/common/src/main/scala/net/psforever/packet/game/ChildObjectStateMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/ChildObjectStateMessage.scala
@@ -2,6 +2,7 @@
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
+import net.psforever.types.Angular
import scodec.Codec
import scodec.codecs._
@@ -16,18 +17,12 @@ import scodec.codecs._
* The only concern is the direction the object is facing.
* The angles are relative to the object's normal forward-facing and typically begin tracking at 0, 0 (forward-facing).
* @param object_guid the object being manipulated (controlled)
- * @param pitch the angle with respect to the sky and the ground towards which the object is directed;
- * an 8-bit unsigned value;
- * 0 is perfectly level and forward-facing and mapped to 255;
- * positive rotation is downwards from forward-facing
- * @param yaw the angle with respect to the horizon towards which the object is directed;
- * an 8-bit unsigned value;
- * 0 is forward-facing, wrapping around at 127;
- * positive rotation is counter-clockwise of forward-facing
+ * @param pitch the amount of pitch that affects orientation from forward facing (0)
+ * @param yaw the amount of yaw that affects orientation from forward-facing (0)
*/
final case class ChildObjectStateMessage(object_guid : PlanetSideGUID,
- pitch : Int,
- yaw : Int)
+ pitch : Float,
+ yaw : Float)
extends PlanetSideGamePacket {
type Packet = ChildObjectStateMessage
def opcode = GamePacketOpcode.ChildObjectStateMessage
@@ -37,7 +32,7 @@ final case class ChildObjectStateMessage(object_guid : PlanetSideGUID,
object ChildObjectStateMessage extends Marshallable[ChildObjectStateMessage] {
implicit val codec : Codec[ChildObjectStateMessage] = (
("object_guid" | PlanetSideGUID.codec) ::
- ("pitch" | uint8L) ::
- ("yaw" | uint8L)
+ ("pitch" | Angular.codec_pitch) ::
+ ("yaw" | Angular.codec_yaw(0f))
).as[ChildObjectStateMessage]
}
diff --git a/common/src/main/scala/net/psforever/packet/game/ObjectDetachMessage.scala b/common/src/main/scala/net/psforever/packet/game/ObjectDetachMessage.scala
index 8630fc74..4d6abda7 100644
--- a/common/src/main/scala/net/psforever/packet/game/ObjectDetachMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/ObjectDetachMessage.scala
@@ -2,7 +2,7 @@
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
-import net.psforever.types.Vector3
+import net.psforever.types.{Angular, Vector3}
import scodec.Codec
import scodec.codecs._
@@ -23,25 +23,16 @@ import scodec.codecs._
* @param parent_guid the container/connector object
* @param child_guid the contained/connected object
* @param pos where the contained/connected object will be placed after it has detached
- * @param roll the roll of the dropped item;
- * every `0x1` is 2.813 degrees;
- * every `0x10` is 45-degrees;
- * it wraps at `0x0` == `0x80` == top facing up
- * @param pitch the pitch of the dropped item;
- * every `0x1` is 2.813 degrees;
- * every `0x10` is 45-degrees;
- * it wraps at `0x0` == `0x80` == top facing up
- * @param yaw the yaw of the dropped item;
- * every `0x1` is 2.813 degrees counter clockwise from East;
- * every `0x10` is 45-degrees;
- * it wraps at `0x0` == `0x80` == front facing East
+ * @param roll the amount of roll that affects orientation of the dropped item
+ * @param pitch the amount of pitch that affects orientation of the dropped item
+ * @param yaw the amount of yaw that affects orientation of the dropped item
*/
final case class ObjectDetachMessage(parent_guid : PlanetSideGUID,
child_guid : PlanetSideGUID,
pos : Vector3,
- roll : Int,
- pitch : Int,
- yaw : Int)
+ roll : Float,
+ pitch : Float,
+ yaw : Float)
extends PlanetSideGamePacket {
type Packet = ObjectDetachMessage
def opcode = GamePacketOpcode.ObjectDetachMessage
@@ -53,8 +44,8 @@ object ObjectDetachMessage extends Marshallable[ObjectDetachMessage] {
("parent_guid" | PlanetSideGUID.codec) ::
("child_guid" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) ::
- ("roll" | uint8L) ::
- ("pitch" | uint8L) ::
- ("yaw" | uint8L)
+ ("roll" | Angular.codec_roll) ::
+ ("pitch" | Angular.codec_pitch) ::
+ ("yaw" | Angular.codec_yaw())
).as[ObjectDetachMessage]
}
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 1def7ca6..a3758155 100644
--- a/common/src/main/scala/net/psforever/packet/game/PlayerStateMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/PlayerStateMessage.scala
@@ -3,7 +3,7 @@ package net.psforever.packet.game
import net.psforever.newcodecs.newcodecs
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
-import net.psforever.types.Vector3
+import net.psforever.types.{Angular, Vector3}
import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
@@ -20,7 +20,7 @@ import shapeless.{::, HNil}
*
* The avatar model normally moves from where it "currently" is to `pos`.
* When `vel` is defined, `pos` is treated as where the avatar model starts its animation.
- * In that case, it sppears to teleport to `pos` to carry out the interpolated movement according to `vel`.
+ * In that case, it appears to teleport to `pos` to carry out the interpolated movement according to `vel`.
* After the move, it remains at essentially `pos + vel * t`.
* The repositioning always takes the same amount of time.
* The player model is left in a walking/running animation (in place) until directed otherwise.
@@ -29,39 +29,15 @@ import shapeless.{::, HNil}
* A demonstration of this is what happens when one player "runs past"/"into" another player running up stairs.
* The climbing player is frequently reported by the other to appear to bounce over that player's head.
* If the other player is off the ground, passing too near to the observer can cause a rubber band effect on trajectory.
- * This effect is entirely client-side to the observer and affects the moving player in no way.
- *
- * facingYaw:
- * `0x00` -- E
- * `0x10` -- NE
- * `0x20` -- N
- * `0x30` -- NW
- * `0x40` -- W
- * `0x50` -- SW
- * `0x60` -- S
- * `0x70` -- SE
- * `0x80` -- E
- *
- * facingPitch:
- * `0x00`-`0x20` -- downwards-facing angles, with `0x00` as forwards-facing
- * `0x21`-`0x40` -- downwards-facing
- * `0x41`-`0x59` -- upwards-facing
- * `0x60`-`0x80` -- upwards-facing angles, with `0x80` as forwards-facing
- *
- * facingYawUpper:
- * `0x00`-`0x20` -- turning to left, with `0x00` being forward-facing
- * `0x21`-`0x40` -- facing leftwards
- * `0x41`-`0x59` -- facing rightwards
- * `0x60`-`0x80` -- turning to right, with `0x80` being forward-facing
- *
+ * This effect is entirely client-side to the observer and affects the moving player in no way.
* @param guid the avatar's guid
* @param pos the position of the avatar in the world environment (in three coordinates)
* @param vel an optional velocity
- * @param facingYaw the angle with respect to the horizon towards which the avatar is looking;
- * the model's whole body is facing this direction;
- * measurements are counter-clockwise from East
- * @param facingPitch the angle with respect to the sky and the ground towards which the avatar is looking
- * @param facingYawUpper the angle of the avatar's upper body with respect to its forward-facing direction
+ * @param facingYaw a "yaw" angle
+ * @param facingPitch a "pitch" angle
+ * @param facingYawUpper a "yaw" angle that represents the angle of the avatar's upper body with respect to its forward-facing direction;
+ * this number is normally 0 for forward facing;
+ * the range is limited between approximately 61 degrees of center turned to left or right
* @param unk1 na
* @param is_crouching avatar is crouching
* @param is_jumping avatar is jumping;
@@ -72,9 +48,9 @@ import shapeless.{::, HNil}
final case class PlayerStateMessage(guid : PlanetSideGUID,
pos : Vector3,
vel : Option[Vector3],
- facingYaw : Int,
- facingPitch : Int,
- facingYawUpper : Int,
+ facingYaw : Float,
+ facingPitch : Float,
+ facingYawUpper : Float,
unk1 : Int,
is_crouching : Boolean = false,
is_jumping : Boolean = false,
@@ -117,9 +93,9 @@ object PlayerStateMessage extends Marshallable[PlayerStateMessage] {
("guid" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) ::
optional(bool, "vel" | Vector3.codec_vel) ::
- ("facingYaw" | uint8L) ::
- ("facingPitch" | uint8L) ::
- ("facingYawUpper" | uint8L) ::
+ ("facingYaw" | Angular.codec_yaw()) ::
+ ("facingPitch" | Angular.codec_pitch) ::
+ ("facingYawUpper" | Angular.codec_yaw(0f)) ::
("unk1" | uintL(10)) ::
(bool >>:~ { fourBools =>
newcodecs.binary_choice(!fourBools, booleanCodec, defaultCodec)
diff --git a/common/src/main/scala/net/psforever/packet/game/PlayerStateMessageUpstream.scala b/common/src/main/scala/net/psforever/packet/game/PlayerStateMessageUpstream.scala
index 96cd228a..3895dce2 100644
--- a/common/src/main/scala/net/psforever/packet/game/PlayerStateMessageUpstream.scala
+++ b/common/src/main/scala/net/psforever/packet/game/PlayerStateMessageUpstream.scala
@@ -1,8 +1,8 @@
// Copyright (c) 2017 PSForever
package net.psforever.packet.game
-import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
-import net.psforever.types.Vector3
+import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
+import net.psforever.types.{Angular, Vector3}
import scodec.Codec
import scodec.codecs._
@@ -15,11 +15,11 @@ import scodec.codecs._
* @param avatar_guid the player's GUID
* @param pos where the player is in the world
* @param vel how the player is moving
- * @param facingYaw the angle with respect to the horizon towards which the avatar is looking;
- * the model's whole body is facing this direction;
- * measurements are counter-clockwise from East
- * @param facingPitch the angle with respect to the sky and the ground towards which the avatar is looking
- * @param facingYawUpper the angle of the avatar's upper body with respect to its forward-facing direction
+ * @param facingYaw a "yaw" angle
+ * @param facingPitch a "pitch" angle
+ * @param facingYawUpper a "yaw" angle that represents the angle of the avatar's upper body with respect to its forward-facing direction;
+ * this number is normally 0 for forward facing;
+ * the range is limited between approximately 61 degrees of center turned to left or right
* @param seq_time na
* @param unk1 na
* @param is_crouching avatar is crouching
@@ -33,9 +33,9 @@ import scodec.codecs._
final case class PlayerStateMessageUpstream(avatar_guid : PlanetSideGUID,
pos : Vector3,
vel : Option[Vector3],
- facingYaw : Int,
- facingPitch : Int,
- facingYawUpper : Int,
+ facingYaw : Float,
+ facingPitch : Float,
+ facingYawUpper : Float,
seq_time : Int,
unk1 : Int,
is_crouching : Boolean,
@@ -55,9 +55,9 @@ object PlayerStateMessageUpstream extends Marshallable[PlayerStateMessageUpstrea
("avatar_guid" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) ::
("vel" | optional(bool, Vector3.codec_vel)) ::
- ("facingYaw" | uint8L) ::
- ("facingPitch" | uint8L) ::
- ("facingYawUpper" | uint8L) ::
+ ("facingYaw" | Angular.codec_yaw()) ::
+ ("facingPitch" | Angular.codec_pitch) ::
+ ("facingYawUpper" | Angular.codec_yaw(0f)) ::
("seq_time" | uintL(10)) ::
("unk1" | uintL(3)) ::
("is_crouching" | bool) ::
diff --git a/common/src/main/scala/net/psforever/packet/game/PlayerStateShiftMessage.scala b/common/src/main/scala/net/psforever/packet/game/PlayerStateShiftMessage.scala
index df199774..f48c06fc 100644
--- a/common/src/main/scala/net/psforever/packet/game/PlayerStateShiftMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/PlayerStateShiftMessage.scala
@@ -2,8 +2,8 @@
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
-import net.psforever.types.Vector3
-import scodec.{Attempt, Codec, Err}
+import net.psforever.types.{Angular, Vector3}
+import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
@@ -16,23 +16,25 @@ import shapeless.{::, HNil}
* This external force is not accumulative.
* Also, the external force is only applied once the avatar is set to the provided position.
*
- * `viewYawLim` defines a "range of angles" that the avatar may look centered on the supplied angle.
- * The avatar must be facing within 60-degrees of that direction, subjectively his left or his right.
- * The avatar's view is immediately set to the closest 60-degree mark if it is outside of that range.
- * The absolute angular displacement of the avatar is considered before applying this corrective behavior.
- * After rotating any number of times:
- * stopping in a valid part of the range is acceptable;
- * stopping in an invalid part of the range will cause the avatar to align to the __earliest__ still-valid 60-degree mark.
- * For that reason, even if the avatar's final angle is closest to the "left mark," it may re-align to the "right mark."
- * This also resets the avatar's angular displacement.
+ * The angle defines the center of a range of angles that count as "in front of the avatar."
+ * Specifically, this range is the upper body's turn limit.
+ * A stationary player may look left and right, rotating their upper body only, until they hit a certain angle.
+ * Normally, the player's whole body will then turn to accommodate turning further than this angle.
+ * This packet marks that limit as a hard limit for rotation and will reset the player's model and camera if necessary.
+ * While it is in effect, the player will not turn their whole body once they can no longer turn their upper body.
* @param unk na
* @param pos the position to move the character to in the world environment
- * @param viewYawLim an angle with respect to the horizon towards which the avatar is looking (to some respect)
+ * @param viewYawLim the center of the range of upper body angles, the player's actual yaw;
+ * if this value is beyond its angular limit values,
+ * the model will attempt to snap to what it considers the closest upper body turning limit angle;
+ * the actual range is approximately `viewYawLimit +/- 61.8215`;
* @param vel if defined, the velocity to apply to to the character at the given position
+ * @see `PlayerStateMessageUpstream.facingYawUpper`
+ * @see `PlayerStateMessage.facingYawUpper`
*/
final case class ShiftState(unk : Int,
pos : Vector3,
- viewYawLim : Int,
+ viewYawLim : Float,
vel : Option[Vector3])
/**
@@ -55,7 +57,7 @@ final case class PlayerStateShiftMessage(state : Option[ShiftState],
def encode = PlayerStateShiftMessage.encode(this)
}
-object ShiftState extends Marshallable[ShiftState] {
+object ShiftState {
/**
* An abbreviated constructor for creating `ShiftState`, assuming velocity is not applied.
* @param unk na
@@ -64,7 +66,7 @@ object ShiftState extends Marshallable[ShiftState] {
* @param vel the velocity to apply to to the character at the given position
* @return a `ShiftState` object
*/
- def apply(unk : Int, pos : Vector3, viewYawLim : Int, vel : Vector3) : ShiftState =
+ def apply(unk : Int, pos : Vector3, viewYawLim : Float, vel : Vector3) : ShiftState =
ShiftState(unk, pos, viewYawLim, Some(vel))
/**
@@ -74,24 +76,8 @@ object ShiftState extends Marshallable[ShiftState] {
* @param viewYawLim an angle with respect to the horizon towards which the avatar is looking (to some respect)
* @return a `ShiftState` object
*/
- def apply(unk : Int, pos : Vector3, viewYawLim : Int) : ShiftState =
+ def apply(unk : Int, pos : Vector3, viewYawLim : Float) : ShiftState =
ShiftState(unk, pos, viewYawLim, None)
-
- implicit val codec : Codec[ShiftState] = (
- ("unk1" | uintL(3)) ::
- ("pos" | Vector3.codec_pos) ::
- ("viewYawLim" | uint8L) ::
- optional(bool, "pos" | Vector3.codec_vel)
- ).xmap[ShiftState] (
- {
- case a :: b :: c :: d :: HNil =>
- ShiftState(a, b, c, d)
- },
- {
- case ShiftState(a, b, c, d) =>
- a :: b :: c :: d :: HNil
- }
- ).as[ShiftState]
}
object PlayerStateShiftMessage extends Marshallable[PlayerStateShiftMessage] {
@@ -120,8 +106,30 @@ object PlayerStateShiftMessage extends Marshallable[PlayerStateShiftMessage] {
def apply(unk : Int) : PlayerStateShiftMessage =
PlayerStateShiftMessage(None, Some(unk))
+ private val shift_codec : Codec[ShiftState] = (
+ /*
+ IMPORTANT:
+ Packet data indicates that viewYawLimit is an 8u value.
+ When read as an 8u value, the resulting number does not map to directions properly.
+ As a 7u value, the numbers maps better so the first bit will be ignored.
+ */
+ ("unk" | uintL(3)) ::
+ ("pos" | Vector3.codec_pos) ::
+ ("viewYawLim" | Angular.codec_yaw()) ::
+ optional(bool, "pos" | Vector3.codec_vel)
+ ).xmap[ShiftState] (
+ {
+ case a :: b :: c :: d :: HNil =>
+ ShiftState(a, b, c, d)
+ },
+ {
+ case ShiftState(a, b, c, d) =>
+ a :: b :: c :: d :: HNil
+ }
+ ).as[ShiftState]
+
implicit val codec : Codec[PlayerStateShiftMessage] = (
- optional(bool, "state" | ShiftState.codec) ::
+ optional(bool, "state" | shift_codec) ::
optional(bool, "unk" | uintL(3))
).xmap[PlayerStateShiftMessage] (
{
diff --git a/common/src/main/scala/net/psforever/packet/game/VehicleStateMessage.scala b/common/src/main/scala/net/psforever/packet/game/VehicleStateMessage.scala
index 40910c43..4f528584 100644
--- a/common/src/main/scala/net/psforever/packet/game/VehicleStateMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/VehicleStateMessage.scala
@@ -1,12 +1,10 @@
// Copyright (c) 2017 PSForever
package net.psforever.packet.game
-import net.psforever.newcodecs.newcodecs
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
-import net.psforever.types.Vector3
+import net.psforever.types.{Angular, Vector3}
import scodec.Codec
import scodec.codecs._
-import shapeless.{::, HNil}
//TODO write more thorough comments later.
/**
@@ -14,15 +12,7 @@ import shapeless.{::, HNil}
* @param vehicle_guid the vehicle
* @param unk1 na
* @param pos the xyz-coordinate location in the world
- * @param roll the amount of roll that affects orientation;
- * 0.0f is flat to the ground;
- * roll-right rotation increases angle
- * @param pitch the amount of pitch that affects orientation;
- * 0.0f is flat to the ground;
- * front-up rotation increases angle
- * @param yaw the amount of yaw that affects orientation;
- * 0.0f is North (before the correction, 0.0f is East);
- * clockwise rotation increases angle
+ * @param ang the orientation of the vehicle
* @param vel optional movement data
* @param unk2 na
* @param unk3 na
@@ -38,9 +28,7 @@ import shapeless.{::, HNil}
final case class VehicleStateMessage(vehicle_guid : PlanetSideGUID,
unk1 : Int,
pos : Vector3,
- roll : Float,
- pitch : Float,
- yaw : Float,
+ ang : Vector3,
vel : Option[Vector3],
unk2 : Option[Int],
unk3 : Int,
@@ -55,13 +43,23 @@ final case class VehicleStateMessage(vehicle_guid : PlanetSideGUID,
}
object VehicleStateMessage extends Marshallable[VehicleStateMessage] {
+ /**
+ * Calculate common orientation from little-endian bit data.
+ * @see `Angular.codec_roll`
+ * @see `Angular.codec_pitch`
+ * @see `Angular.codec_yaw`
+ */
+ private val codec_orient : Codec[Vector3] = (
+ ("roll" | Angular.codec_roll(10)) ::
+ ("pitch" | Angular.codec_pitch(10)) ::
+ ("yaw" | Angular.codec_yaw(10, 90f))
+ ).as[Vector3]
+
implicit val codec : Codec[VehicleStateMessage] = (
("vehicle_guid" | PlanetSideGUID.codec) ::
("unk1" | uintL(3)) ::
("pos" | Vector3.codec_pos) ::
- ("roll" | newcodecs.q_float(0.0f, 360.0f, 10)) ::
- ("pitch" | newcodecs.q_float(360.0f, 0.0f, 10)) ::
- ("yaw" | newcodecs.q_float(360.0f, 0.0f, 10)) ::
+ ("ang" | codec_orient) ::
optional(bool, "vel" | Vector3.codec_vel) ::
optional(bool, "unk2" | uintL(5)) ::
("unk3" | uintL(7)) ::
@@ -69,27 +67,5 @@ object VehicleStateMessage extends Marshallable[VehicleStateMessage] {
("wheel_direction" | uintL(5)) ::
("int5" | bool) ::
("int6" | bool)
- ).xmap[VehicleStateMessage] (
- {
- case guid :: u1 :: pos :: roll :: pitch :: yaw :: vel :: u2 :: u3 :: u4 :: wheel :: u5 :: u6 :: HNil =>
- var northCorrectedYaw : Float = yaw + 90f
- if(northCorrectedYaw > 360f) {
- northCorrectedYaw = northCorrectedYaw - 360f
- }
- VehicleStateMessage(guid, u1, pos, roll, pitch, northCorrectedYaw, vel, u2, u3, u4, wheel, u5, u6)
- },
-
- {
- case VehicleStateMessage(guid, u1, pos, roll, pitch, yaw, vel, u2, u3, u4, wheel, u5, u6) =>
- var northCorrectedYaw : Float = yaw - 90f
- //TODO this invites imprecision
- while(northCorrectedYaw < 0f) {
- northCorrectedYaw = 360f + northCorrectedYaw
- }
- if(northCorrectedYaw > 360f) {
- northCorrectedYaw = northCorrectedYaw % 360f
- }
- guid :: u1 :: pos :: roll :: pitch :: northCorrectedYaw :: vel :: u2 :: u3 :: u4 :: wheel :: u5 :: u6 :: HNil
- }
- )
+ ).as[VehicleStateMessage]
}
diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala
index 85a01340..66380b62 100644
--- a/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala
+++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala
@@ -2,7 +2,7 @@
package net.psforever.packet.game.objectcreate
import net.psforever.packet.{Marshallable, PacketHelpers}
-import net.psforever.types.{CharacterGender, ExoSuitType, GrenadeState, PlanetSideEmpire}
+import net.psforever.types._
import scodec.{Attempt, Codec, Err}
import scodec.codecs._
import shapeless.{::, HNil}
@@ -74,8 +74,10 @@ final case class BasicCharacterData(name : String,
* if the option is selected, allies with see either "[`outfit_name`]" or "{No Outfit}" under the player's name
* @param outfit_logo the decal seen on the player's exo-suit (and beret and cap) associated with the player's outfit;
* if there is a variable color for that decal, the faction-appropriate one is selected
- * @param facingPitch the angle with respect to the sky and the ground towards which the avatar is looking
- * @param facingYawUpper the angle of the avatar's upper body with respect to its forward-facing direction
+ * @param facingPitch a "pitch" angle
+ * @param facingYawUpper a "yaw" angle that represents the angle of the avatar's upper body with respect to its forward-facing direction;
+ * this number is normally 0 for forward facing;
+ * the range is limited between approximately 61 degrees of center turned to left or right
* @param lfs this player is looking for a squad;
* all allies will see the phrase "[Looking for Squad]" under the player's name
* @param is_cloaking avatar is cloaked by virtue of an Infiltration Suit
@@ -101,8 +103,8 @@ final case class CharacterAppearanceData(pos : PlacementData,
outfit_name : String,
outfit_logo : Int,
backpack : Boolean,
- facingPitch : Int,
- facingYawUpper : Int,
+ facingPitch : Float,
+ facingYawUpper : Float,
lfs : Boolean,
grenade_state : GrenadeState.Value,
is_cloaking : Boolean,
@@ -168,8 +170,8 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
ignore(1) :: //unknown
("backpack" | bool) :: //requires alt_model flag (does NOT require health == 0)
bool :: //stream misalignment when set
- ("facingPitch" | uint8L) ::
- ("facingYawUpper" | uint8L) ::
+ ("facingPitch" | Angular.codec_pitch) ::
+ ("facingYawUpper" | Angular.codec_yaw(0f)) ::
ignore(1) :: //unknown
conditional(alt_model, bool) :: //alt_model flag adds a bit before lfs
ignore(1) :: //an alternate lfs?
diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/PlacementData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/PlacementData.scala
index 51df840a..4865b986 100644
--- a/common/src/main/scala/net/psforever/packet/game/objectcreate/PlacementData.scala
+++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/PlacementData.scala
@@ -2,22 +2,19 @@
package net.psforever.packet.game.objectcreate
import net.psforever.packet.Marshallable
-import net.psforever.types.Vector3
+import net.psforever.types.{Angular, Vector3}
import scodec.codecs._
import scodec.Codec
+import shapeless.{::, HNil}
/**
* A specific location and heading in game world coordinates and game world measurements.
* @param coord the xyz-coordinate location in the world
- * @param roll the amount of roll that affects orientation
- * @param pitch the amount of pitch that affects orientation
- * @param yaw the amount of yaw that affects orientation
+ * @param orient the ijk-orientation around the object's center
* @param vel optional movement data (that occurs upon placement)
*/
final case class PlacementData(coord : Vector3,
- roll : Int,
- pitch : Int,
- yaw : Int,
+ orient : Vector3,
vel : Option[Vector3] = None
) extends StreamBitSize {
override def bitsize : Long = {
@@ -35,7 +32,7 @@ object PlacementData extends Marshallable[PlacementData] {
* @return a `PlacementData` object
*/
def apply(x : Float, y : Float, z : Float) : PlacementData =
- new PlacementData(Vector3(x, y, z), 0, 0, 0)
+ new PlacementData(Vector3(x, y, z), Vector3(0f,0f,0f))
/**
* An abbreviated constructor for creating `PlacementData`, ignoring the `Vector3` for position data, supplying other important fields.
@@ -47,8 +44,8 @@ object PlacementData extends Marshallable[PlacementData] {
* @param yaw the amount of yaw that affects orientation
* @return a `PlacementData` object
*/
- def apply(x : Float, y : Float, z : Float, roll : Int, pitch : Int, yaw : Int) : PlacementData =
- new PlacementData(Vector3(x, y, z), roll, pitch, yaw)
+ def apply(x : Float, y : Float, z : Float, roll : Float, pitch : Float, yaw : Float) : PlacementData =
+ new PlacementData(Vector3(x, y, z), Vector3(roll, pitch, yaw))
/**
* An abbreviated constructor for creating `PlacementData`, ignoring the `Vector3` for position data, supplying all other fields.
@@ -61,14 +58,23 @@ object PlacementData extends Marshallable[PlacementData] {
* @param vel optional movement data that occurs upon placement
* @return a `PlacementData` object
*/
- def apply(x : Float, y : Float, z : Float, roll : Int, pitch : Int, yaw : Int, vel : Vector3) : PlacementData =
- new PlacementData(Vector3(x, y, z), roll, pitch, yaw, Some(vel))
+ def apply(x : Float, y : Float, z : Float, roll : Float, pitch : Float, yaw : Float, vel : Vector3) : PlacementData =
+ new PlacementData(Vector3(x, y, z), Vector3(roll, pitch, yaw), Some(vel))
implicit val codec : Codec[PlacementData] = (
("coord" | Vector3.codec_pos) ::
- ("roll" | uint8L) ::
- ("pitch" | uint8L) ::
- ("yaw" | uint8L) ::
+ ("roll" | Angular.codec_roll) ::
+ ("pitch" | Angular.codec_pitch) ::
+ ("yaw" | Angular.codec_yaw()) ::
optional(bool, "vel" | Vector3.codec_vel)
- ).as[PlacementData]
+ ).xmap[PlacementData] (
+ {
+ case xyz :: i :: j :: k :: vel :: HNil =>
+ PlacementData(xyz, Vector3(i, j, k), vel)
+ },
+ {
+ case PlacementData(xyz, Vector3(i, j, k), vel) =>
+ xyz :: i :: j :: k :: vel :: HNil
+ }
+ )
}
diff --git a/common/src/main/scala/net/psforever/types/Angular.scala b/common/src/main/scala/net/psforever/types/Angular.scala
new file mode 100644
index 00000000..91919eeb
--- /dev/null
+++ b/common/src/main/scala/net/psforever/types/Angular.scala
@@ -0,0 +1,103 @@
+// Copyright (c) 2017 PSForever
+package net.psforever.types
+
+import net.psforever.newcodecs.newcodecs
+import scodec.Codec
+import scodec.codecs.ignore
+import shapeless.{::, HNil}
+
+/**
+ * A series of `Codec`s designed to work with convert between 8-bit angle values in the packets and `Float` numbers.
+ * As far as the data is concerned, the first bit appears to be ignored when it comes to the actual angle measurement.
+ * The latter seven bits map between 0 to 360 perfectly (according to the game).
+ */
+object Angular {
+ //roll
+ val codec_roll : Codec[Float] = (
+ ignore(1) ::
+ codec_roll(7)
+ ).xmap[Float] (
+ {
+ case _ :: roll :: HNil =>
+ roll
+ },
+ {
+ case roll : Float =>
+ () :: roll :: HNil
+ }
+ )
+
+ def codec_roll(bits : Int) : Codec[Float] = newcodecs.q_float(0.0f, 360.0f, bits)
+
+ //pitch
+ val codec_pitch : Codec[Float] = (
+ ignore(1) ::
+ codec_pitch(7)
+ ).xmap[Float] (
+ {
+ case _ :: pitch :: HNil =>
+ pitch
+ },
+ {
+ case pitch : Float =>
+ () :: pitch :: HNil
+ }
+ )
+
+ def codec_pitch(bits : Int) : Codec[Float] = newcodecs.q_float(360.0f, 0.0f, bits).xmap[Float] (
+ {
+ case pitch =>
+ decodeCorrectedAngle(pitch)
+ },
+ {
+ case pitch : Float =>
+ encodeCorrectedAngle(pitch)
+ }
+ )
+
+ //yaw
+ def codec_yaw(North : Float = 90.0f) : Codec[Float] = (
+ ignore(1) ::
+ codec_yaw(7, North)
+ ).xmap[Float] (
+ {
+ case _ :: yaw :: HNil =>
+ yaw
+ },
+ {
+ case yaw : Float =>
+ () :: yaw :: HNil
+ }
+ )
+
+ def codec_yaw(bits : Int, North : Float) : Codec[Float] = newcodecs.q_float(360.0f, 0.0f, bits).xmap[Float] (
+ {
+ case yaw =>
+ decodeCorrectedAngle(yaw, North)
+ },
+ {
+ case yaw : Float =>
+ encodeCorrectedAngle(yaw, North)
+ }
+ )
+
+ //support
+ def decodeCorrectedAngle(angle : Float, correction : Float = 0f) : Float = {
+ var correctedAng : Float = angle + correction
+ if(correctedAng >= 360f) {
+ correctedAng = correctedAng - 360f
+ }
+ correctedAng
+ }
+
+ def encodeCorrectedAngle(angle : Float, correction : Float = 0f) : Float = {
+ var correctedAng : Float = angle - correction
+ if(correctedAng <= 0f) {
+ correctedAng = 360f + correctedAng % 360f
+ }
+ else if(correctedAng > 360f) {
+ correctedAng = correctedAng % 360f
+ }
+ correctedAng
+ }
+}
diff --git a/common/src/main/scala/net/psforever/types/Vector3.scala b/common/src/main/scala/net/psforever/types/Vector3.scala
index 312c9803..ac2b92fe 100644
--- a/common/src/main/scala/net/psforever/types/Vector3.scala
+++ b/common/src/main/scala/net/psforever/types/Vector3.scala
@@ -4,6 +4,7 @@ package net.psforever.types
import net.psforever.newcodecs._
import scodec.Codec
import scodec.codecs._
+import shapeless.{::, HNil}
final case class Vector3(x : Float,
y : Float,
diff --git a/common/src/test/scala/CodecTest.scala b/common/src/test/scala/CodecTest.scala
index 59c0cb3a..f213848a 100644
--- a/common/src/test/scala/CodecTest.scala
+++ b/common/src/test/scala/CodecTest.scala
@@ -34,23 +34,190 @@ class CodecTest extends Specification {
}
"Vector3" should {
- val string_pos = hex"6E2D762222B616"
- val string_vel = hex"857D4E0FFFC0"
+ "position" should {
+ val string_pos = hex"6E2D762222B616"
- "decode position" in {
- Vector3.codec_pos.decode(string_pos.bits).require.value mustEqual Vector3(3674.859375f, 1092.7656f, 90.84375f)
+ "decode" in {
+ Vector3.codec_pos.decode(string_pos.bits).require.value mustEqual Vector3(3674.859375f, 1092.7656f, 90.84375f)
+ }
+
+ "encode" in {
+ Vector3.codec_pos.encode(Vector3(3674.859375f, 1092.7656f, 90.84375f)).require.bytes mustEqual string_pos
+ }
}
- "encode position" in {
- Vector3.codec_pos.encode(Vector3(3674.859375f, 1092.7656f, 90.84375f)).require.bytes mustEqual string_pos
+ "velocity" should {
+ val string_vel = hex"857D4E0FFFC0"
+
+ "decode" in {
+ Vector3.codec_vel.decode(string_vel.bits).require.value mustEqual Vector3(-3.84375f, 2.59375f, 255.96875f)
+ }
+
+ "encode" in {
+ Vector3.codec_vel.encode(Vector3(-3.84375f, 2.59375f, 255.96875f)).require.bytes mustEqual string_vel
+ }
+ }
+ }
+
+ "Angular" should {
+ "roll" should {
+ val string_roll_0 = hex"00"
+ val string_roll_90 = hex"20"
+ val string_roll_180 = hex"40"
+ val string_roll_270 = hex"60"
+
+ "decode (0)" in {
+ Angular.codec_roll.decode(string_roll_0.bits).require.value mustEqual 0f
+ }
+
+ "decode (90)" in {
+ Angular.codec_roll.decode(string_roll_90.bits).require.value mustEqual 90f
+ }
+
+ "decode (180)" in {
+ Angular.codec_roll.decode(string_roll_180.bits).require.value mustEqual 180f
+ }
+
+ "decode (270)" in {
+ Angular.codec_roll.decode(string_roll_270.bits).require.value mustEqual 270f
+ }
+
+ "encode (0)" in {
+ Angular.codec_roll.encode(0f).require.bytes mustEqual string_roll_0
+ }
+
+ "encode (90)" in {
+ Angular.codec_roll.encode(90f).require.bytes mustEqual string_roll_90
+ }
+
+ "encode (180)" in {
+ Angular.codec_roll.encode(180f).require.bytes mustEqual string_roll_180
+ }
+
+ "encode (270)" in {
+ Angular.codec_roll.encode(270f).require.bytes mustEqual string_roll_270
+ }
}
- "decode velocity" in {
- Vector3.codec_vel.decode(string_vel.bits).require.value mustEqual Vector3(-3.84375f, 2.59375f, 255.96875f)
+ "pitch" should {
+ val string_pitch_0 = hex"00"
+ val string_pitch_90 = hex"60"
+ val string_pitch_180 = hex"40"
+ val string_pitch_270 = hex"20"
+
+ "decode (0)" in {
+ Angular.codec_pitch.decode(string_pitch_0.bits).require.value mustEqual 0f
+ }
+
+ "decode (90)" in {
+ Angular.codec_pitch.decode(string_pitch_90.bits).require.value mustEqual 90f
+ }
+
+ "decode (180)" in {
+ Angular.codec_pitch.decode(string_pitch_180.bits).require.value mustEqual 180f
+ }
+
+ "decode (270)" in {
+ Angular.codec_pitch.decode(string_pitch_270.bits).require.value mustEqual 270f
+ }
+
+ "encode (0)" in {
+ Angular.codec_pitch.encode(0f).require.bytes mustEqual string_pitch_0
+ }
+
+ "encode (90)" in {
+ Angular.codec_pitch.encode(90f).require.bytes mustEqual string_pitch_90
+ }
+
+ "encode (180)" in {
+ Angular.codec_pitch.encode(180f).require.bytes mustEqual string_pitch_180
+ }
+
+ "encode (270)" in {
+ Angular.codec_pitch.encode(270f).require.bytes mustEqual string_pitch_270
+ }
}
- "encode velocity" in {
- Vector3.codec_vel.encode(Vector3(-3.84375f, 2.59375f, 255.96875f)).require.bytes mustEqual string_vel
+ "yaw, normal" should {
+ val string_pitch_0 = hex"00"
+ val string_pitch_90 = hex"60"
+ val string_pitch_180 = hex"40"
+ val string_pitch_270 = hex"20"
+ val string_yaw_0 = hex"20"
+ val string_yaw_90 = hex"00"
+ val string_yaw_180 = hex"60"
+ val string_yaw_270 = hex"40"
+
+ "decode (0)" in {
+ Angular.codec_yaw(0f).decode(string_yaw_0.bits).require.value mustEqual 270f
+ }
+
+ "decode (90)" in {
+ Angular.codec_yaw(0f).decode(string_yaw_90.bits).require.value mustEqual 0f
+ }
+
+ "decode (180)" in {
+ Angular.codec_yaw(0f).decode(string_yaw_180.bits).require.value mustEqual 90f
+ }
+
+ "decode (270)" in {
+ Angular.codec_yaw(0f).decode(string_yaw_270.bits).require.value mustEqual 180f
+ }
+
+ "encode (0)" in {
+ Angular.codec_yaw(0f).encode(0f).require.bytes mustEqual string_pitch_0
+ }
+
+ "encode (90)" in {
+ Angular.codec_yaw(0f).encode(90f).require.bytes mustEqual string_pitch_90
+ }
+
+ "encode (180)" in {
+ Angular.codec_yaw(0f).encode(180f).require.bytes mustEqual string_pitch_180
+ }
+
+ "encode (270)" in {
+ Angular.codec_yaw(0f).encode(270f).require.bytes mustEqual string_pitch_270
+ }
+ }
+
+ "yaw, North-corrected" should {
+ val string_yaw_0 = hex"20"
+ val string_yaw_90 = hex"00"
+ val string_yaw_180 = hex"60"
+ val string_yaw_270 = hex"40"
+
+ "decode (0)" in {
+ Angular.codec_yaw().decode(string_yaw_0.bits).require.value mustEqual 0f
+ }
+
+ "decode (90)" in {
+ Angular.codec_yaw().decode(string_yaw_90.bits).require.value mustEqual 90f
+ }
+
+ "decode (180)" in {
+ Angular.codec_yaw().decode(string_yaw_180.bits).require.value mustEqual 180f
+ }
+
+ "decode (270)" in {
+ Angular.codec_yaw().decode(string_yaw_270.bits).require.value mustEqual 270f
+ }
+
+ "encode (0)" in {
+ Angular.codec_yaw().encode(0f).require.bytes mustEqual string_yaw_0
+ }
+
+ "encode (90)" in {
+ Angular.codec_yaw().encode(90f).require.bytes mustEqual string_yaw_90
+ }
+
+ "encode (180)" in {
+ Angular.codec_yaw().encode(180f).require.bytes mustEqual string_yaw_180
+ }
+
+ "encode (270)" in {
+ Angular.codec_yaw().encode(270f).require.bytes mustEqual string_yaw_270
+ }
}
}
}
diff --git a/common/src/test/scala/game/ChildObjectStateMessageTest.scala b/common/src/test/scala/game/ChildObjectStateMessageTest.scala
index 00cba45d..12bb83e8 100644
--- a/common/src/test/scala/game/ChildObjectStateMessageTest.scala
+++ b/common/src/test/scala/game/ChildObjectStateMessageTest.scala
@@ -13,15 +13,15 @@ class ChildObjectStateMessageTest extends Specification {
PacketCoding.DecodePacket(string).require match {
case ChildObjectStateMessage(object_guid, pitch, yaw) =>
object_guid mustEqual PlanetSideGUID(2916)
- pitch mustEqual 6
- yaw mustEqual 71
+ pitch mustEqual 343.125f
+ yaw mustEqual 160.3125f
case _ =>
ko
}
}
"encode" in {
- val msg = ChildObjectStateMessage(PlanetSideGUID(2916), 6, 71)
+ val msg = ChildObjectStateMessage(PlanetSideGUID(2916), 343.125f, 160.3125f)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
diff --git a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala
index 061db99f..f818ac40 100644
--- a/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala
+++ b/common/src/test/scala/game/ObjectCreateDetailedMessageTest.scala
@@ -180,9 +180,9 @@ class ObjectCreateDetailedMessageTest extends Specification {
char.appearance.pos.coord.x mustEqual 3674.8438f
char.appearance.pos.coord.y mustEqual 2726.789f
char.appearance.pos.coord.z mustEqual 91.15625f
- char.appearance.pos.roll mustEqual 0
- char.appearance.pos.pitch mustEqual 0
- char.appearance.pos.yaw mustEqual 19
+ char.appearance.pos.orient.x mustEqual 0
+ char.appearance.pos.orient.y mustEqual 0f
+ char.appearance.pos.orient.z mustEqual 36.5625f
char.appearance.basic_appearance.name mustEqual "IlllIIIlllIlIllIlllIllI"
char.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.VS
char.appearance.basic_appearance.sex mustEqual CharacterGender.Female
@@ -195,8 +195,8 @@ class ObjectCreateDetailedMessageTest extends Specification {
char.appearance.outfit_name mustEqual ""
char.appearance.outfit_logo mustEqual 0
char.appearance.backpack mustEqual false
- char.appearance.facingPitch mustEqual 127
- char.appearance.facingYawUpper mustEqual 181
+ char.appearance.facingPitch mustEqual 2.8125f
+ char.appearance.facingYawUpper mustEqual 210.9375f
char.appearance.lfs mustEqual true
char.appearance.grenade_state mustEqual GrenadeState.None
char.appearance.is_cloaking mustEqual false
@@ -367,8 +367,7 @@ class ObjectCreateDetailedMessageTest extends Specification {
val app = CharacterAppearanceData(
PlacementData(
Vector3(3674.8438f, 2726.789f, 91.15625f),
- 0, 0,
- 19
+ Vector3(0f, 0f, 36.5625f)
),
BasicCharacterData(
"IlllIIIlllIlIllIlllIllI",
@@ -384,7 +383,7 @@ class ObjectCreateDetailedMessageTest extends Specification {
"",
0,
false,
- 127, 181,
+ 2.8125f, 210.9375f,
true,
GrenadeState.None,
false,
@@ -422,7 +421,8 @@ class ObjectCreateDetailedMessageTest extends Specification {
val ori_bitv = string_testchar.toBitVector
pkt_bitv.take(153) mustEqual ori_bitv.take(153) //skip 1
pkt_bitv.drop(154).take(422) mustEqual ori_bitv.drop(154).take(422) //skip 126
- pkt_bitv.drop(702) mustEqual ori_bitv.drop(702)
+ pkt_bitv.drop(702).take(29) mustEqual ori_bitv.drop(702).take(29) //skip 1
+ pkt_bitv.drop(732) mustEqual ori_bitv.drop(732)
//TODO work on DetailedCharacterData to make this pass as a single stream
}
}
diff --git a/common/src/test/scala/game/ObjectCreateMessageTest.scala b/common/src/test/scala/game/ObjectCreateMessageTest.scala
index e3cc4969..7b779f8b 100644
--- a/common/src/test/scala/game/ObjectCreateMessageTest.scala
+++ b/common/src/test/scala/game/ObjectCreateMessageTest.scala
@@ -48,9 +48,9 @@ class ObjectCreateMessageTest extends Specification {
projectile.pos.coord.x mustEqual 4644.5938f
projectile.pos.coord.y mustEqual 5472.0938f
projectile.pos.coord.z mustEqual 82.375f
- projectile.pos.roll mustEqual 0
- projectile.pos.pitch mustEqual 245
- projectile.pos.yaw mustEqual 227
+ projectile.pos.orient.x mustEqual 0f
+ projectile.pos.orient.y mustEqual 30.9375f
+ projectile.pos.orient.z mustEqual 171.5625f
projectile.unk1 mustEqual 0
projectile.unk2 mustEqual TrackedProjectileData.striker_missile_targetting_projectile_data
case _ =>
@@ -88,9 +88,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4579.3438f
drop.pos.coord.y mustEqual 5615.0703f
drop.pos.coord.z mustEqual 72.953125f
- drop.pos.pitch mustEqual 0
- drop.pos.roll mustEqual 0
- drop.pos.yaw mustEqual 125
+ drop.pos.orient.x mustEqual 0f
+ drop.pos.orient.y mustEqual 0f
+ drop.pos.orient.z mustEqual 98.4375f
drop.obj.isInstanceOf[CommonTerminalData] mustEqual true
val term = drop.obj.asInstanceOf[CommonTerminalData]
term.faction mustEqual PlanetSideEmpire.NC
@@ -249,9 +249,9 @@ class ObjectCreateMessageTest extends Specification {
flag.pos.coord.x mustEqual 3912.0312f
flag.pos.coord.y mustEqual 5169.4375f
flag.pos.coord.z mustEqual 59.96875f
- flag.pos.roll mustEqual 0
- flag.pos.pitch mustEqual 0
- flag.pos.yaw mustEqual 15
+ flag.pos.orient.x mustEqual 0f
+ flag.pos.orient.y mustEqual 0f
+ flag.pos.orient.z mustEqual 47.8125f
flag.faction mustEqual PlanetSideEmpire.NC
flag.unk1 mustEqual 21
flag.unk2 mustEqual 4
@@ -274,9 +274,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4708.461f
drop.pos.coord.y mustEqual 5547.539f
drop.pos.coord.z mustEqual 72.703125f
- drop.pos.roll mustEqual 0
- drop.pos.pitch mustEqual 0
- drop.pos.yaw mustEqual 91
+ drop.pos.orient.x mustEqual 0f
+ drop.pos.orient.y mustEqual 0f
+ drop.pos.orient.z mustEqual 194.0625f
drop.obj.isInstanceOf[ACEData] mustEqual true
val ace = drop.obj.asInstanceOf[ACEData]
ace.unk1 mustEqual 8
@@ -299,9 +299,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4777.633f
drop.pos.coord.y mustEqual 5485.4062f
drop.pos.coord.z mustEqual 85.8125f
- drop.pos.roll mustEqual 0
- drop.pos.pitch mustEqual 0
- drop.pos.yaw mustEqual 27
+ drop.pos.orient.x mustEqual 0f
+ drop.pos.orient.y mustEqual 0f
+ drop.pos.orient.z mustEqual 14.0625f
drop.obj.isInstanceOf[CommandDetonaterData] mustEqual true
case _ =>
ko
@@ -321,9 +321,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4684.7344f
drop.pos.coord.y mustEqual 5547.4844f
drop.pos.coord.z mustEqual 83.765625f
- drop.pos.roll mustEqual 0
- drop.pos.pitch mustEqual 0
- drop.pos.yaw mustEqual 89
+ drop.pos.orient.x mustEqual 0f
+ drop.pos.orient.y mustEqual 0f
+ drop.pos.orient.z mustEqual 199.6875f
drop.obj.isInstanceOf[AmmoBoxData] mustEqual true
val box = drop.obj.asInstanceOf[AmmoBoxData]
box.unk mustEqual 0
@@ -345,9 +345,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4691.1953f
drop.pos.coord.y mustEqual 5537.039f
drop.pos.coord.z mustEqual 65.484375f
- drop.pos.roll mustEqual 0
- drop.pos.pitch mustEqual 0
- drop.pos.yaw mustEqual 32
+ drop.pos.orient.x mustEqual 0f
+ drop.pos.orient.y mustEqual 0f
+ drop.pos.orient.z mustEqual 0f
drop.obj.isInstanceOf[WeaponData] mustEqual true
val wep = drop.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 4
@@ -377,9 +377,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4789.133f
drop.pos.coord.y mustEqual 5522.3125f
drop.pos.coord.z mustEqual 72.3125f
- drop.pos.roll mustEqual 0
- drop.pos.pitch mustEqual 0
- drop.pos.yaw mustEqual 51
+ drop.pos.orient.x mustEqual 0f
+ drop.pos.orient.y mustEqual 0f
+ drop.pos.orient.z mustEqual 306.5625f
drop.obj.isInstanceOf[WeaponData] mustEqual true
val wep = drop.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 2
@@ -417,9 +417,9 @@ class ObjectCreateMessageTest extends Specification {
dropped.pos.coord.x mustEqual 4675.039f
dropped.pos.coord.y mustEqual 5506.953f
dropped.pos.coord.z mustEqual 72.703125f
- dropped.pos.roll mustEqual 0
- dropped.pos.pitch mustEqual 0
- dropped.pos.yaw mustEqual 78
+ dropped.pos.orient.x mustEqual 0f
+ dropped.pos.orient.y mustEqual 0f
+ dropped.pos.orient.z mustEqual 230.625f
dropped.obj.isInstanceOf[REKData] mustEqual true
val rek = dropped.obj.asInstanceOf[REKData]
rek.unk1 mustEqual 8
@@ -443,9 +443,9 @@ class ObjectCreateMessageTest extends Specification {
boomer.deploy.pos.coord.x mustEqual 4704.172f
boomer.deploy.pos.coord.y mustEqual 5546.4375f
boomer.deploy.pos.coord.z mustEqual 82.234375f
- boomer.deploy.pos.roll mustEqual 0
- boomer.deploy.pos.pitch mustEqual 0
- boomer.deploy.pos.yaw mustEqual 63
+ boomer.deploy.pos.orient.x mustEqual 0f
+ boomer.deploy.pos.orient.y mustEqual 0f
+ boomer.deploy.pos.orient.z mustEqual 272.8125f
boomer.deploy.unk mustEqual 0
boomer.deploy.player_guid mustEqual PlanetSideGUID(4145)
case _ =>
@@ -466,9 +466,9 @@ class ObjectCreateMessageTest extends Specification {
turret.deploy.pos.coord.x mustEqual 4577.7812f
turret.deploy.pos.coord.y mustEqual 5624.828f
turret.deploy.pos.coord.z mustEqual 72.046875f
- turret.deploy.pos.roll mustEqual 0
- turret.deploy.pos.pitch mustEqual 127
- turret.deploy.pos.yaw mustEqual 66
+ turret.deploy.pos.orient.x mustEqual 0f
+ turret.deploy.pos.orient.y mustEqual 2.8125f
+ turret.deploy.pos.orient.z mustEqual 264.375f
turret.deploy.faction mustEqual PlanetSideEmpire.NC
turret.deploy.unk mustEqual 12
turret.deploy.player_guid mustEqual PlanetSideGUID(3871)
@@ -492,9 +492,9 @@ class ObjectCreateMessageTest extends Specification {
turret.deploy.pos.coord.x mustEqual 4527.633f
turret.deploy.pos.coord.y mustEqual 6271.3594f
turret.deploy.pos.coord.z mustEqual 70.265625f
- turret.deploy.pos.roll mustEqual 0
- turret.deploy.pos.pitch mustEqual 0
- turret.deploy.pos.yaw mustEqual 105
+ turret.deploy.pos.orient.x mustEqual 0f
+ turret.deploy.pos.orient.y mustEqual 0f
+ turret.deploy.pos.orient.z mustEqual 154.6875f
turret.deploy.faction mustEqual PlanetSideEmpire.VS
turret.deploy.unk mustEqual 4
turret.deploy.player_guid mustEqual PlanetSideGUID(4232)
@@ -533,9 +533,9 @@ class ObjectCreateMessageTest extends Specification {
trap.deploy.pos.coord.x mustEqual 3572.4453f
trap.deploy.pos.coord.y mustEqual 3277.9766f
trap.deploy.pos.coord.z mustEqual 114.0f
- trap.deploy.pos.roll mustEqual 0
- trap.deploy.pos.pitch mustEqual 0
- trap.deploy.pos.yaw mustEqual 0
+ trap.deploy.pos.orient.x mustEqual 0f
+ trap.deploy.pos.orient.y mustEqual 0f
+ trap.deploy.pos.orient.z mustEqual 90.0f
trap.deploy.faction mustEqual PlanetSideEmpire.VS
trap.deploy.unk mustEqual 4
trap.health mustEqual 255
@@ -558,9 +558,9 @@ class ObjectCreateMessageTest extends Specification {
aegis.deploy.pos.coord.x mustEqual 3571.2266f
aegis.deploy.pos.coord.y mustEqual 3278.0938f
aegis.deploy.pos.coord.z mustEqual 114.0f
- aegis.deploy.pos.roll mustEqual 0
- aegis.deploy.pos.pitch mustEqual 0
- aegis.deploy.pos.yaw mustEqual 0
+ aegis.deploy.pos.orient.x mustEqual 0f
+ aegis.deploy.pos.orient.y mustEqual 0f
+ aegis.deploy.pos.orient.z mustEqual 90.0f
aegis.deploy.faction mustEqual PlanetSideEmpire.VS
aegis.deploy.unk mustEqual 4
aegis.health mustEqual 255
@@ -583,9 +583,9 @@ class ObjectCreateMessageTest extends Specification {
omft.deploy.pos.coord.x mustEqual 3567.1406f
omft.deploy.pos.coord.y mustEqual 2988.0078f
omft.deploy.pos.coord.z mustEqual 71.84375f
- omft.deploy.pos.roll mustEqual 0
- omft.deploy.pos.pitch mustEqual 0
- omft.deploy.pos.yaw mustEqual 94
+ omft.deploy.pos.orient.x mustEqual 0f
+ omft.deploy.pos.orient.y mustEqual 0f
+ omft.deploy.pos.orient.z mustEqual 185.625f
omft.deploy.faction mustEqual PlanetSideEmpire.VS
omft.deploy.unk mustEqual 4
omft.deploy.player_guid mustEqual PlanetSideGUID(2502)
@@ -666,9 +666,9 @@ class ObjectCreateMessageTest extends Specification {
pc.appearance.pos.coord.x mustEqual 3674.8438f
pc.appearance.pos.coord.y mustEqual 2726.789f
pc.appearance.pos.coord.z mustEqual 91.15625f
- pc.appearance.pos.roll mustEqual 0
- pc.appearance.pos.pitch mustEqual 0
- pc.appearance.pos.yaw mustEqual 9
+ pc.appearance.pos.orient.x mustEqual 0f
+ pc.appearance.pos.orient.y mustEqual 0f
+ pc.appearance.pos.orient.z mustEqual 64.6875f
pc.appearance.pos.vel.isDefined mustEqual true
pc.appearance.pos.vel.get.x mustEqual 1.4375f
pc.appearance.pos.vel.get.y mustEqual -0.4375f
@@ -684,7 +684,7 @@ class ObjectCreateMessageTest extends Specification {
pc.appearance.exosuit mustEqual ExoSuitType.Reinforced
pc.appearance.outfit_name mustEqual "Black Beret Armoured Corps"
pc.appearance.outfit_logo mustEqual 23
- pc.appearance.facingPitch mustEqual 7
+ pc.appearance.facingPitch mustEqual 340.3125f
pc.appearance.facingYawUpper mustEqual 0
pc.appearance.lfs mustEqual false
pc.appearance.grenade_state mustEqual GrenadeState.None
@@ -765,9 +765,9 @@ class ObjectCreateMessageTest extends Specification {
pc.appearance.pos.coord.x mustEqual 4629.8906f
pc.appearance.pos.coord.y mustEqual 6316.4453f
pc.appearance.pos.coord.z mustEqual 54.734375f
- pc.appearance.pos.roll mustEqual 0
- pc.appearance.pos.pitch mustEqual 0
- pc.appearance.pos.yaw mustEqual 115
+ pc.appearance.pos.orient.x mustEqual 0f
+ pc.appearance.pos.orient.y mustEqual 0f
+ pc.appearance.pos.orient.z mustEqual 126.5625f
pc.appearance.pos.vel.isDefined mustEqual false
pc.appearance.basic_appearance.name mustEqual "Angello"
pc.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.VS
@@ -781,7 +781,7 @@ class ObjectCreateMessageTest extends Specification {
pc.appearance.outfit_name mustEqual "Original District"
pc.appearance.outfit_logo mustEqual 23
pc.appearance.facingPitch mustEqual 0
- pc.appearance.facingYawUpper mustEqual 192
+ pc.appearance.facingYawUpper mustEqual 180.0f
pc.appearance.lfs mustEqual false
pc.appearance.grenade_state mustEqual GrenadeState.None
pc.appearance.is_cloaking mustEqual false
@@ -811,13 +811,15 @@ class ObjectCreateMessageTest extends Specification {
"encode (striker projectile)" in {
val obj = TrackedProjectileData.striker(
- PlacementData(4644.5938f, 5472.0938f, 82.375f, 0, 245, 227),
+ PlacementData(4644.5938f, 5472.0938f, 82.375f, 0f, 30.9375f, 171.5625f),
0
)
val msg = ObjectCreateMessage(ObjectClass.striker_missile_targeting_projectile, PlanetSideGUID(40192), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
- pkt mustEqual string_striker_projectile
+ pkt.toBitVector.take(132) mustEqual string_striker_projectile.toBitVector.take(132)
+ pkt.toBitVector.drop(133).take(7) mustEqual string_striker_projectile.toBitVector.drop(133).take(7)
+ pkt.toBitVector.drop(141) mustEqual string_striker_projectile.toBitVector.drop(141)
}
"encode (implant interface)" in {
@@ -830,7 +832,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (order terminal a)" in {
val obj = DroppedItemData(
- PlacementData(4579.3438f, 5615.0703f, 72.953125f, 0, 0, 125),
+ PlacementData(4579.3438f, 5615.0703f, 72.953125f, 0f, 0f, 98.4375f),
CommonTerminalData(PlanetSideEmpire.NC)
)
val msg = ObjectCreateMessage(ObjectClass.order_terminala, PlanetSideGUID(3827), obj)
@@ -893,7 +895,7 @@ class ObjectCreateMessageTest extends Specification {
}
"encode (capture flag)" in {
- val obj = CaptureFlagData(PlacementData(3912.0312f, 5169.4375f, 59.96875f, 0, 0, 15), PlanetSideEmpire.NC, 21, 4, 2838, 9)
+ val obj = CaptureFlagData(PlacementData(3912.0312f, 5169.4375f, 59.96875f, 0f, 0f, 47.8125f), PlanetSideEmpire.NC, 21, 4, 2838, 9)
val msg = ObjectCreateMessage(ObjectClass.capture_flag, PlanetSideGUID(4330), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
@@ -902,7 +904,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (ace, dropped)" in {
val obj = DroppedItemData(
- PlacementData(Vector3(4708.461f, 5547.539f, 72.703125f), 0, 0, 91),
+ PlacementData(4708.461f, 5547.539f, 72.703125f, 0f, 0f, 194.0625f),
ACEData(8, 8)
)
val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(4388), obj)
@@ -913,7 +915,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (detonator, dropped)" in {
val obj = DroppedItemData(
- PlacementData(Vector3(4777.633f, 5485.4062f, 85.8125f), 0, 0, 27),
+ PlacementData(4777.633f, 5485.4062f, 85.8125f, 0f, 0f, 14.0625f),
CommandDetonaterData()
)
val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(3682), obj)
@@ -924,7 +926,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (shotgun shells, dropped)" in {
val obj = DroppedItemData(
- PlacementData(Vector3(4684.7344f, 5547.4844f, 83.765625f), 0, 0, 89),
+ PlacementData(4684.7344f, 5547.4844f, 83.765625f, 0f, 0f, 199.6875f),
AmmoBoxData()
)
val msg = ObjectCreateMessage(ObjectClass.shotgun_shell, PlanetSideGUID(3453), obj)
@@ -935,7 +937,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (lasher, dropped)" in {
val obj = DroppedItemData(
- PlacementData(Vector3(4691.1953f, 5537.039f, 65.484375f), 0, 0, 32),
+ PlacementData(4691.1953f, 5537.039f, 65.484375f, 0.0f, 0.0f, 0.0f),
WeaponData(4, 0, ObjectClass.energy_cell, PlanetSideGUID(3268), 0, AmmoBoxData())
)
val msg = ObjectCreateMessage(ObjectClass.lasher, PlanetSideGUID(3074), obj)
@@ -946,7 +948,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (punisher, dropped)" in {
val obj = DroppedItemData(
- PlacementData(Vector3(4789.133f, 5522.3125f, 72.3125f), 0, 0, 51),
+ PlacementData(4789.133f, 5522.3125f, 72.3125f, 0f, 0f, 306.5625f),
WeaponData(2, 0, 0,
AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3528), 0, AmmoBoxData()) ::
AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3031), 1, AmmoBoxData()) ::
@@ -961,7 +963,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (REK, dropped)" in {
val obj = DroppedItemData(
- PlacementData(Vector3(4675.039f, 5506.953f, 72.703125f), 0, 0, 78),
+ PlacementData(4675.039f, 5506.953f, 72.703125f, 0f, 0f, 230.625f),
REKData(8, 0, 3)
)
val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(4355), obj)
@@ -973,7 +975,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (boomer)" in {
val obj = SmallDeployableData(
CommonFieldData(
- PlacementData(Vector3(4704.172f, 5546.4375f, 82.234375f), 0, 0, 63),
+ PlacementData(4704.172f, 5546.4375f, 82.234375f, 0f, 0f, 272.8125f),
PlanetSideEmpire.TR, 0, PlanetSideGUID(4145)
)
)
@@ -986,7 +988,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (spitfire, short)" in {
val obj = SmallTurretData(
CommonFieldData(
- PlacementData(Vector3(4577.7812f, 5624.828f, 72.046875f), 0, 127, 66),
+ PlacementData(4577.7812f, 5624.828f, 72.046875f, 0f, 2.8125f, 264.375f),
PlanetSideEmpire.NC, 12, PlanetSideGUID(3871)
),
255 //sets to 0
@@ -1004,7 +1006,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (spitfire)" in {
val obj = SmallTurretData(
CommonFieldData(
- PlacementData(Vector3(4527.633f, 6271.3594f, 70.265625f), 0, 0, 105),
+ PlacementData(4527.633f, 6271.3594f, 70.265625f, 0f, 0f, 154.6875f),
PlanetSideEmpire.VS, 4, PlanetSideGUID(4232)
),
255,
@@ -1023,7 +1025,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (trap)" in {
val obj = TRAPData(
CommonFieldData(
- PlacementData(Vector3(3572.4453f, 3277.9766f, 114.0f), 0, 0, 0),
+ PlacementData(3572.4453f, 3277.9766f, 114.0f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 4, PlanetSideGUID(2502)
),
255
@@ -1041,7 +1043,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (aegis)" in {
val obj = AegisShieldGeneratorData(
CommonFieldData(
- PlacementData(Vector3(3571.2266f, 3278.0938f, 114.0f), 0, 0, 0),
+ PlacementData(3571.2266f, 3278.0938f, 114.0f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 4, PlanetSideGUID(2366)
),
255
@@ -1055,7 +1057,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (orion)" in {
val obj = OneMannedFieldTurretData(
CommonFieldData(
- PlacementData(Vector3(3567.1406f, 2988.0078f, 71.84375f), 0, 0, 94),
+ PlacementData(3567.1406f, 2988.0078f, 71.84375f, 0f, 0f, 185.625f),
PlanetSideEmpire.VS, 4, PlanetSideGUID(2502)
),
255,
@@ -1091,7 +1093,7 @@ class ObjectCreateMessageTest extends Specification {
CharacterAppearanceData(
PlacementData(
Vector3(3674.8438f, 2726.789f, 91.15625f),
- 0, 0, 9,
+ Vector3(0f, 0f, 64.6875f),
Some(Vector3(1.4375f, -0.4375f, 0f))
),
BasicCharacterData(
@@ -1108,7 +1110,7 @@ class ObjectCreateMessageTest extends Specification {
"Black Beret Armoured Corps",
23,
false,
- 7, 0,
+ 340.3125f, 0f,
false,
GrenadeState.None,
false, false, false,
@@ -1150,7 +1152,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (character, backpack)" in {
val obj = CharacterData(
CharacterAppearanceData(
- PlacementData(4629.8906f, 6316.4453f, 54.734375f, 0, 0, 115),
+ PlacementData(4629.8906f, 6316.4453f, 54.734375f, 0f, 0f, 126.5625f),
BasicCharacterData(
"Angello",
PlanetSideEmpire.VS,
@@ -1165,7 +1167,7 @@ class ObjectCreateMessageTest extends Specification {
"Original District",
23,
true, //backpack
- 0, 192,
+ 0f, 180.0f,
false,
GrenadeState.None,
false, false, false,
@@ -1191,8 +1193,9 @@ class ObjectCreateMessageTest extends Specification {
val ori_bitv = string_character_backpack.toBitVector
pkt_bitv.take(300) mustEqual ori_bitv.take(300) //skip 2
pkt_bitv.drop(302).take(14) mustEqual ori_bitv.drop(302).take(14) //skip 126
- pkt_bitv.drop(442).take(317) mustEqual ori_bitv.drop(442).take(317) //skip 2
- pkt_bitv.drop(761).take(155) mustEqual ori_bitv.drop(761).take(155) //skip 1
+ pkt_bitv.drop(442).take(305) mustEqual ori_bitv.drop(442).take(305) //skip 1
+ pkt_bitv.drop(748).take(9) mustEqual ori_bitv.drop(748).take(9) // skip 2
+ pkt_bitv.drop(759).take(157) mustEqual ori_bitv.drop(759).take(157) //skip 1
pkt_bitv.drop(917) mustEqual ori_bitv.drop(917)
//TODO work on CharacterData to make this pass as a single stream
}
diff --git a/common/src/test/scala/game/ObjectCreateMessageVehiclesTest.scala b/common/src/test/scala/game/ObjectCreateMessageVehiclesTest.scala
index f51aa2d4..cd66e598 100644
--- a/common/src/test/scala/game/ObjectCreateMessageVehiclesTest.scala
+++ b/common/src/test/scala/game/ObjectCreateMessageVehiclesTest.scala
@@ -33,9 +33,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
fury.basic.pos.coord.x mustEqual 6531.961f
fury.basic.pos.coord.y mustEqual 1872.1406f
fury.basic.pos.coord.z mustEqual 24.734375f
- fury.basic.pos.roll mustEqual 0
- fury.basic.pos.pitch mustEqual 0
- fury.basic.pos.yaw mustEqual 33
+ fury.basic.pos.orient.x mustEqual 0f
+ fury.basic.pos.orient.y mustEqual 0f
+ fury.basic.pos.orient.z mustEqual 357.1875f
fury.basic.pos.vel.isDefined mustEqual false
fury.basic.faction mustEqual PlanetSideEmpire.VS
fury.basic.unk mustEqual 4
@@ -78,9 +78,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
ant.basic.pos.coord.x mustEqual 3674.8438f
ant.basic.pos.coord.y mustEqual 2726.789f
ant.basic.pos.coord.z mustEqual 91.15625f
- ant.basic.pos.roll mustEqual 0
- ant.basic.pos.pitch mustEqual 0
- ant.basic.pos.yaw mustEqual 0
+ ant.basic.pos.orient.x mustEqual 0f
+ ant.basic.pos.orient.y mustEqual 0f
+ ant.basic.pos.orient.z mustEqual 90.0f
ant.basic.faction mustEqual PlanetSideEmpire.VS
ant.basic.unk mustEqual 4
ant.basic.player_guid mustEqual PlanetSideGUID(0)
@@ -104,9 +104,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
lightning.basic.pos.coord.x mustEqual 3674.8438f
lightning.basic.pos.coord.y mustEqual 2726.789f
lightning.basic.pos.coord.z mustEqual 91.15625f
- lightning.basic.pos.roll mustEqual 0
- lightning.basic.pos.pitch mustEqual 0
- lightning.basic.pos.yaw mustEqual 0
+ lightning.basic.pos.orient.x mustEqual 0f
+ lightning.basic.pos.orient.y mustEqual 0f
+ lightning.basic.pos.orient.z mustEqual 90.0f
lightning.basic.faction mustEqual PlanetSideEmpire.VS
lightning.basic.unk mustEqual 4
lightning.basic.player_guid mustEqual PlanetSideGUID(0)
@@ -155,9 +155,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
deliverer.basic.pos.coord.x mustEqual 6531.961f
deliverer.basic.pos.coord.y mustEqual 1872.1406f
deliverer.basic.pos.coord.z mustEqual 24.734375f
- deliverer.basic.pos.roll mustEqual 0
- deliverer.basic.pos.pitch mustEqual 0
- deliverer.basic.pos.yaw mustEqual 33
+ deliverer.basic.pos.orient.x mustEqual 0f
+ deliverer.basic.pos.orient.y mustEqual 0f
+ deliverer.basic.pos.orient.z mustEqual 357.1875f
deliverer.basic.faction mustEqual PlanetSideEmpire.NC
deliverer.basic.unk mustEqual 4
deliverer.basic.player_guid mustEqual PlanetSideGUID(0)
@@ -221,9 +221,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
ams.basic.pos.coord.x mustEqual 3674.0f
ams.basic.pos.coord.y mustEqual 2726.789f
ams.basic.pos.coord.z mustEqual 91.15625f
- ams.basic.pos.roll mustEqual 0
- ams.basic.pos.pitch mustEqual 0
- ams.basic.pos.yaw mustEqual 0
+ ams.basic.pos.orient.x mustEqual 0f
+ ams.basic.pos.orient.y mustEqual 0f
+ ams.basic.pos.orient.z mustEqual 90.0f
ams.basic.faction mustEqual PlanetSideEmpire.VS
ams.basic.unk mustEqual 0
ams.basic.player_guid mustEqual PlanetSideGUID(34082)
@@ -253,9 +253,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
dams.pos.coord.x mustEqual 3674.0f
dams.pos.coord.y mustEqual 2726.789f
dams.pos.coord.z mustEqual 91.15625f
- dams.pos.roll mustEqual 0
- dams.pos.pitch mustEqual 0
- dams.pos.yaw mustEqual 0
+ dams.pos.orient.x mustEqual 0f
+ dams.pos.orient.y mustEqual 0f
+ dams.pos.orient.z mustEqual 90.0f
case _ =>
ko
}
@@ -274,9 +274,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
switchblade.basic.pos.coord.x mustEqual 6531.961f
switchblade.basic.pos.coord.y mustEqual 1872.1406f
switchblade.basic.pos.coord.z mustEqual 24.734375f
- switchblade.basic.pos.roll mustEqual 0
- switchblade.basic.pos.pitch mustEqual 0
- switchblade.basic.pos.yaw mustEqual 33
+ switchblade.basic.pos.orient.x mustEqual 0f
+ switchblade.basic.pos.orient.y mustEqual 0f
+ switchblade.basic.pos.orient.z mustEqual 357.1875f
switchblade.basic.faction mustEqual PlanetSideEmpire.VS
switchblade.basic.unk mustEqual 4
switchblade.health mustEqual 255
@@ -321,9 +321,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
droppod.basic.pos.coord.x mustEqual 5108.0f
droppod.basic.pos.coord.y mustEqual 6164.0f
droppod.basic.pos.coord.z mustEqual 1023.9844f
- droppod.basic.pos.roll mustEqual 0
- droppod.basic.pos.pitch mustEqual 0
- droppod.basic.pos.yaw mustEqual 0
+ droppod.basic.pos.orient.x mustEqual 0f
+ droppod.basic.pos.orient.y mustEqual 0f
+ droppod.basic.pos.orient.z mustEqual 90.0f
droppod.basic.unk mustEqual 4
droppod.basic.player_guid mustEqual PlanetSideGUID(0)
droppod.burn mustEqual false
@@ -366,9 +366,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
shuttle.pos.get.coord.x mustEqual 5610.0156f
shuttle.pos.get.coord.y mustEqual 4255.258f
shuttle.pos.get.coord.z mustEqual 134.1875f
- shuttle.pos.get.roll mustEqual 0
- shuttle.pos.get.pitch mustEqual 0
- shuttle.pos.get.yaw mustEqual 96
+ shuttle.pos.get.orient.x mustEqual 0f
+ shuttle.pos.get.orient.y mustEqual 0f
+ shuttle.pos.get.orient.z mustEqual 180.0f
case _ =>
ko
}
@@ -377,7 +377,7 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (fury)" in {
val obj = VehicleData(
CommonFieldData(
- PlacementData(6531.961f, 1872.1406f, 24.734375f, 0, 0, 33),
+ PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.VS, 4
),
255,
@@ -394,7 +394,7 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (ant)" in {
val obj = ANTData(
CommonFieldData(
- PlacementData(3674.8438f, 2726.789f, 91.15625f),
+ PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 4
),
255,
@@ -409,7 +409,7 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (lightning)" in {
val obj = VehicleData(
CommonFieldData(
- PlacementData(3674.8438f, 2726.789f, 91.15625f),
+ PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 4
),
255,
@@ -423,10 +423,10 @@ class ObjectCreateMessageVehiclesTest extends Specification {
pkt mustEqual string_lightning
}
- "encode (deliverer)" in {
+ "encode (medium transport)" in {
val obj = VehicleData(
CommonFieldData(
- PlacementData(6531.961f, 1872.1406f, 24.734375f, 0, 0, 33),
+ PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.NC, 4
),
0,
@@ -455,7 +455,8 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (ams)" in {
val obj = AMSData(
- CommonFieldData(PlacementData(3674.0f, 2726.789f, 91.15625f, 0, 0, 0),
+ CommonFieldData(
+ PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 0,
PlanetSideGUID(34082)
),
@@ -476,17 +477,19 @@ class ObjectCreateMessageVehiclesTest extends Specification {
}
"encode (ams, destroyed)" in {
- val obj = DestroyedVehicleData(PlacementData(3674.0f, 2726.789f, 91.15625f))
+ val obj = DestroyedVehicleData(PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f))
val msg = ObjectCreateMessage(ObjectClass.ams_destroyed, PlanetSideGUID(4157), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ams_destroyed
}
- "encode (switchblade(" in {
+ "encode (switchblade)" in {
val obj = Vehicle2Data(
- CommonFieldData(PlacementData(6531.961f, 1872.1406f, 24.734375f ,0 ,0 ,33),
- PlanetSideEmpire.VS, 4
+ CommonFieldData(
+ PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
+ PlanetSideEmpire.VS,
+ 4
),
255,
DriveState.Mobile,
@@ -503,8 +506,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (droppod)" in {
val obj = DroppodData(
CommonFieldData(
- PlacementData(5108.0f, 6164.0f, 1023.9844f),
- PlanetSideEmpire.VS, 4
+ PlacementData(5108.0f, 6164.0f, 1023.9844f, 0f, 0f, 90.0f),
+ PlanetSideEmpire.VS,
+ 4
)
)
val msg = ObjectCreateMessage(ObjectClass.droppod, PlanetSideGUID(3595), obj)
@@ -522,7 +526,7 @@ class ObjectCreateMessageVehiclesTest extends Specification {
}
"encode (shuttle 2)" in {
- val obj = OrbitalShuttleData(PlacementData(5610.0156f, 4255.258f, 134.1875f, 0, 0, 96), PlanetSideEmpire.VS)
+ val obj = OrbitalShuttleData(PlacementData(5610.0156f, 4255.258f, 134.1875f, 0f, 0f, 180.0f), PlanetSideEmpire.VS)
val msg = ObjectCreateMessage(ObjectClass.orbital_shuttle, PlanetSideGUID(1127), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
diff --git a/common/src/test/scala/game/ObjectDetachMessageTest.scala b/common/src/test/scala/game/ObjectDetachMessageTest.scala
index 0b2b8605..f7ee8b52 100644
--- a/common/src/test/scala/game/ObjectDetachMessageTest.scala
+++ b/common/src/test/scala/game/ObjectDetachMessageTest.scala
@@ -18,16 +18,16 @@ class ObjectDetachMessageTest extends Specification {
pos.x mustEqual 3567.1406f
pos.y mustEqual 2988.0078f
pos.z mustEqual 71.84375f
- roll mustEqual 0
- pitch mustEqual 0
- yaw mustEqual 64
+ roll mustEqual 0f
+ pitch mustEqual 0f
+ yaw mustEqual 270f
case _ =>
ko
}
}
"encode" in {
- val msg = ObjectDetachMessage(PlanetSideGUID(2916), PlanetSideGUID(2502), Vector3(3567.1406f, 2988.0078f, 71.84375f), 0, 0, 64)
+ val msg = ObjectDetachMessage(PlanetSideGUID(2916), PlanetSideGUID(2502), Vector3(3567.1406f, 2988.0078f, 71.84375f), 0f, 0f, 270f)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
diff --git a/common/src/test/scala/game/PlayerStateMessageTest.scala b/common/src/test/scala/game/PlayerStateMessageTest.scala
index e8ab270d..ab5441c7 100644
--- a/common/src/test/scala/game/PlayerStateMessageTest.scala
+++ b/common/src/test/scala/game/PlayerStateMessageTest.scala
@@ -20,9 +20,9 @@ class PlayerStateMessageTest extends Specification {
pos.y mustEqual 5981.414f
pos.z mustEqual 44.875f
vel.isDefined mustEqual false
- facingYaw mustEqual 31
- facingPitch mustEqual 0
- facingUpper mustEqual 0
+ facingYaw mustEqual 2.8125f
+ facingPitch mustEqual 0f
+ facingUpper mustEqual 0f
unk1 mustEqual 83
crouching mustEqual false
jumping mustEqual false
@@ -41,9 +41,9 @@ class PlayerStateMessageTest extends Specification {
pos.y mustEqual 5981.414f
pos.z mustEqual 44.875f
vel.isDefined mustEqual false
- facingYaw mustEqual 31
- facingPitch mustEqual 0
- facingUpper mustEqual 0
+ facingYaw mustEqual 2.8125f
+ facingPitch mustEqual 0f
+ facingUpper mustEqual 0f
unk1 mustEqual 83
crouching mustEqual false
jumping mustEqual true
@@ -65,9 +65,9 @@ class PlayerStateMessageTest extends Specification {
vel.get.x mustEqual 2.53125f
vel.get.y mustEqual 6.5625f
vel.get.z mustEqual 0.0f
- facingYaw mustEqual 24
- facingPitch mustEqual 4
- facingUpper mustEqual 0
+ facingYaw mustEqual 22.5f
+ facingPitch mustEqual 348.75f
+ facingUpper mustEqual 0f
unk1 mustEqual 165
crouching mustEqual false
jumping mustEqual false
@@ -83,7 +83,7 @@ class PlayerStateMessageTest extends Specification {
PlanetSideGUID(1696),
Vector3(4003.7422f, 5981.414f, 44.875f),
None,
- 31, 0, 0, 83,
+ 2.8125f, 0f, 0f, 83,
false, false, false, false)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_short
@@ -94,7 +94,7 @@ class PlayerStateMessageTest extends Specification {
PlanetSideGUID(1696),
Vector3(4003.7422f, 5981.414f, 44.875f),
None,
- 31, 0, 0, 83,
+ 2.8125f, 0f, 0f, 83,
false, true, false, true)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_mod
@@ -105,7 +105,7 @@ class PlayerStateMessageTest extends Specification {
PlanetSideGUID(1696),
Vector3(4008.6016f, 5987.6016f, 44.1875f),
Some(Vector3(2.53125f, 6.5625f, 0f)),
- 24, 4, 0, 165,
+ 22.5f, 348.75f, 0f, 165,
false, false, false, false)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_vel
diff --git a/common/src/test/scala/game/PlayerStateMessageUpstreamTest.scala b/common/src/test/scala/game/PlayerStateMessageUpstreamTest.scala
index a95286da..d3402697 100644
--- a/common/src/test/scala/game/PlayerStateMessageUpstreamTest.scala
+++ b/common/src/test/scala/game/PlayerStateMessageUpstreamTest.scala
@@ -16,9 +16,9 @@ class PlayerStateMessageUpstreamTest extends Specification {
avatar_guid mustEqual PlanetSideGUID(75)
pos mustEqual Vector3(3694.1094f, 2735.4531f, 90.84375f)
vel mustEqual Some(Vector3(4.375f, 2.59375f, 0.0f))
- facingYaw mustEqual 10
- facingPitch mustEqual 3
- facingYawUpper mustEqual 0
+ facingYaw mustEqual 61.875f
+ facingPitch mustEqual 351.5625f
+ facingYawUpper mustEqual 0.0f
seq_time mustEqual 136
unk1 mustEqual 0
is_crouching mustEqual false
@@ -33,7 +33,7 @@ class PlayerStateMessageUpstreamTest extends Specification {
}
"encode" in {
- val msg = PlayerStateMessageUpstream(PlanetSideGUID(75), Vector3(3694.1094f, 2735.4531f, 90.84375f), Some(Vector3(4.375f, 2.59375f, 0.0f)), 10, 3, 0, 136, 0, false, false, false, false, 112, 0)
+ val msg = PlayerStateMessageUpstream(PlanetSideGUID(75), Vector3(3694.1094f, 2735.4531f, 90.84375f), Some(Vector3(4.375f, 2.59375f, 0.0f)), 61.875f, 351.5625f, 0.0f, 136, 0, false, false, false, false, 112, 0)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
diff --git a/common/src/test/scala/game/PlayerStateShiftMessageTest.scala b/common/src/test/scala/game/PlayerStateShiftMessageTest.scala
index c7a3fd28..db411a31 100644
--- a/common/src/test/scala/game/PlayerStateShiftMessageTest.scala
+++ b/common/src/test/scala/game/PlayerStateShiftMessageTest.scala
@@ -9,7 +9,7 @@ import scodec.bits._
class PlayerStateShiftMessageTest extends Specification {
val string_short = hex"BE 68"
- val string_pos = hex"BE 95 A0 89 13 91 B8 B0 BF F0"
+ val string_pos = hex"BE 95 A0 89 13 91 B8 B0 B7 F0" //orig: ... B0 BF F0
val string_posAndVel = hex"BE AE 01 29 CD 59 B9 40 C0 EA D4 00 0F 86 40"
"decode (short)" in {
@@ -31,7 +31,7 @@ class PlayerStateShiftMessageTest extends Specification {
state.get.pos.x mustEqual 4624.703f
state.get.pos.y mustEqual 5922.1484f
state.get.pos.z mustEqual 46.171875f
- state.get.viewYawLim mustEqual 255
+ state.get.viewYawLim mustEqual 92.8125f
state.get.vel.isDefined mustEqual false
unk.isDefined mustEqual false
case _ =>
@@ -47,7 +47,7 @@ class PlayerStateShiftMessageTest extends Specification {
state.get.pos.x mustEqual 4645.75f
state.get.pos.y mustEqual 5811.6016f
state.get.pos.z mustEqual 50.3125f
- state.get.viewYawLim mustEqual 14
+ state.get.viewYawLim mustEqual 50.625f
state.get.vel.isDefined mustEqual true
state.get.vel.get.x mustEqual 2.8125f
state.get.vel.get.y mustEqual -8.0f
@@ -66,14 +66,14 @@ class PlayerStateShiftMessageTest extends Specification {
}
"encode (pos)" in {
- val msg = PlayerStateShiftMessage(ShiftState(1, Vector3(4624.703f, 5922.1484f, 46.171875f), 255))
+ val msg = PlayerStateShiftMessage(ShiftState(1, Vector3(4624.703f, 5922.1484f, 46.171875f), 92.8125f))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_pos
}
"encode (pos and vel)" in {
- val msg = PlayerStateShiftMessage(ShiftState(2, Vector3(4645.75f, 5811.6016f, 50.3125f), 14, Vector3(2.8125f, -8.0f, 0.375f)))
+ val msg = PlayerStateShiftMessage(ShiftState(2, Vector3(4645.75f, 5811.6016f, 50.3125f), 50.625f, Vector3(2.8125f, -8.0f, 0.375f)))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_posAndVel
diff --git a/common/src/test/scala/game/VehicleStateMessageTest.scala b/common/src/test/scala/game/VehicleStateMessageTest.scala
index d9290863..1903fee9 100644
--- a/common/src/test/scala/game/VehicleStateMessageTest.scala
+++ b/common/src/test/scala/game/VehicleStateMessageTest.scala
@@ -12,15 +12,15 @@ class VehicleStateMessageTest extends Specification {
"decode" in {
PacketCoding.DecodePacket(string).require match {
- case VehicleStateMessage(guid, unk1, pos, roll, pitch, yaw, vel, unk2, unk3, unk4, wheel, unk5, unk6) =>
+ case VehicleStateMessage(guid, unk1, pos, ang, vel, unk2, unk3, unk4, wheel, unk5, unk6) =>
guid mustEqual PlanetSideGUID(413)
unk1 mustEqual 0
pos.x mustEqual 3674.8438f
pos.y mustEqual 2726.789f
pos.z mustEqual 91.09375f
- roll mustEqual 359.29688f
- pitch mustEqual 1.0546875f
- yaw mustEqual 90.35156f
+ ang.x mustEqual 359.29688f
+ ang.y mustEqual 1.0546875f
+ ang.z mustEqual 90.35156f
vel.isDefined mustEqual true
vel.get.x mustEqual 0.0f
vel.get.y mustEqual 0.0f
@@ -41,7 +41,7 @@ class VehicleStateMessageTest extends Specification {
PlanetSideGUID(413),
0,
Vector3(3674.8438f, 2726.789f, 91.09375f),
- 359.29688f, 1.0546875f, 90.35156f,
+ Vector3(359.29688f, 1.0546875f, 90.35156f),
Some(Vector3(0.0f, 0.0f, 0.03125f)),
None,
0, 0, 15,
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index d44ce0f3..f3940e9f 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -1,6 +1,4 @@
// Copyright (c) 2017 PSForever
-import java.net.{InetAddress, InetSocketAddress}
-
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
import net.psforever.packet.{PlanetSideGamePacket, _}
import net.psforever.packet.control._
@@ -31,8 +29,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
def receive = Initializing
def Initializing : Receive = {
- case HelloFriend(sessionId, right) =>
- this.sessionId = sessionId
+ case HelloFriend(inSessionId, right) =>
+ this.sessionId = inSessionId
leftRef = sender()
rightRef = right.asInstanceOf[ActorRef]
@@ -81,7 +79,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
handlePkt(v)
}
case sync @ ControlSync(diff, unk, f1, f2, f3, f4, fa, fb) =>
- log.debug(s"SYNC: ${sync}")
+ log.debug(s"SYNC: $sync")
val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error
sendResponse(PacketCoding.CreateControlPacket(ControlSyncResp(diff, serverTick,
fa, fb, fb, fa)))
@@ -113,8 +111,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
val app = CharacterAppearanceData(
PlacementData(
Vector3(3674.8438f, 2726.789f, 91.15625f),
- 0, 0,
- 19
+ Vector3(0f, 0f, 90f)
),
BasicCharacterData(
"IlllIIIlllIlIllIlllIllI",
@@ -166,9 +163,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match {
case ConnectToWorldRequestMessage(server, token, majorVersion, minorVersion, revision, buildDate, unk) =>
- val clientVersion = s"Client Version: ${majorVersion}.${minorVersion}.${revision}, ${buildDate}"
+ val clientVersion = s"Client Version: $majorVersion.$minorVersion.$revision, $buildDate"
- log.info(s"New world login to ${server} with Token:${token}. ${clientVersion}")
+ log.info(s"New world login to $server with Token:$token. $clientVersion")
// ObjectCreateMessage
sendResponse(PacketCoding.CreateGamePacket(0, objectHex))
@@ -229,6 +226,18 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(PacketCoding.CreateGamePacket(0, CreateShortcutMessage(guid, 1, 0, true, Shortcut.MEDKIT)))
sendResponse(PacketCoding.CreateGamePacket(0, ReplicationStreamMessage(5, Some(6), Vector(SquadListing())))) //clear squad list
+ val fury = VehicleData(
+ CommonFieldData(
+ PlacementData(3674.8438f, 2732f, 91.15625f, 0.0f, 0.0f, 90.0f),
+ PlanetSideEmpire.VS, 4
+ ),
+ 255,
+ MountItem(ObjectClass.fury_weapon_systema, PlanetSideGUID(400), 1,
+ WeaponData(0x6, 0x8, 0, ObjectClass.hellfire_ammo, PlanetSideGUID(432), 0, AmmoBoxData(0x8))
+ )
+ )
+ sendResponse(PacketCoding.CreateGamePacket(0, ObjectCreateMessage(ObjectClass.fury, PlanetSideGUID(413), fury)))
+
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
clientKeepAlive = context.system.scheduler.schedule(0 seconds, 500 milliseconds, self, PokeClient())
@@ -249,13 +258,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ BeginZoningMessage() =>
log.info("Reticulating splines ...")
- case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, unk1, aim_pitch, unk2, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
+ case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yawUpper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
//log.info("PlayerState: " + msg)
- case msg @ ChildObjectStateMessage(object_guid : PlanetSideGUID, pitch : Int, yaw : Int) =>
+ case msg @ ChildObjectStateMessage(object_guid, pitch, yaw) =>
//log.info("ChildObjectState: " + msg)
- case msg @ VehicleStateMessage(vehicle_guid, unk1, pos, roll, pitch, yaw, vel, unk5, unk6, unk7, wheels, unk9, unkA) =>
+ case msg @ VehicleStateMessage(vehicle_guid, unk1, pos, ang, vel, unk5, unk6, unk7, wheels, unk9, unkA) =>
//log.info("VehicleState: " + msg)
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vector, unk1, unk2, unk3, unk4, time_alive) =>
@@ -456,7 +465,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ TargetingImplantRequest(list) =>
log.info("TargetingImplantRequest: "+msg)
- case default => log.error(s"Unhandled GamePacket ${pkt}")
+ case default => log.error(s"Unhandled GamePacket $pkt")
}
def failWithError(error : String) = {