Merge pull request #154 from Fate-JH/angles

Float Angles
This commit is contained in:
Fate-JH 2017-07-10 19:26:55 -04:00 committed by GitHub
commit 9a8e1e8f95
21 changed files with 600 additions and 359 deletions

View file

@ -2,6 +2,7 @@
package net.psforever.packet.game package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Angular
import scodec.Codec import scodec.Codec
import scodec.codecs._ import scodec.codecs._
@ -16,18 +17,12 @@ import scodec.codecs._
* The only concern is the direction the object is facing. * 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). * 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 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; * @param pitch the amount of pitch that affects orientation from forward facing (0)
* an 8-bit unsigned value; * @param yaw the amount of yaw that affects orientation from forward-facing (0)
* 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
*/ */
final case class ChildObjectStateMessage(object_guid : PlanetSideGUID, final case class ChildObjectStateMessage(object_guid : PlanetSideGUID,
pitch : Int, pitch : Float,
yaw : Int) yaw : Float)
extends PlanetSideGamePacket { extends PlanetSideGamePacket {
type Packet = ChildObjectStateMessage type Packet = ChildObjectStateMessage
def opcode = GamePacketOpcode.ChildObjectStateMessage def opcode = GamePacketOpcode.ChildObjectStateMessage
@ -37,7 +32,7 @@ final case class ChildObjectStateMessage(object_guid : PlanetSideGUID,
object ChildObjectStateMessage extends Marshallable[ChildObjectStateMessage] { object ChildObjectStateMessage extends Marshallable[ChildObjectStateMessage] {
implicit val codec : Codec[ChildObjectStateMessage] = ( implicit val codec : Codec[ChildObjectStateMessage] = (
("object_guid" | PlanetSideGUID.codec) :: ("object_guid" | PlanetSideGUID.codec) ::
("pitch" | uint8L) :: ("pitch" | Angular.codec_pitch) ::
("yaw" | uint8L) ("yaw" | Angular.codec_yaw(0f))
).as[ChildObjectStateMessage] ).as[ChildObjectStateMessage]
} }

View file

@ -2,7 +2,7 @@
package net.psforever.packet.game package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3 import net.psforever.types.{Angular, Vector3}
import scodec.Codec import scodec.Codec
import scodec.codecs._ import scodec.codecs._
@ -23,25 +23,16 @@ import scodec.codecs._
* @param parent_guid the container/connector object * @param parent_guid the container/connector object
* @param child_guid the contained/connected object * @param child_guid the contained/connected object
* @param pos where the contained/connected object will be placed after it has detached * @param pos where the contained/connected object will be placed after it has detached
* @param roll the roll of the dropped item; * @param roll the amount of roll that affects orientation of the dropped item
* every `0x1` is 2.813 degrees; * @param pitch the amount of pitch that affects orientation of the dropped item
* every `0x10` is 45-degrees; * @param yaw the amount of yaw that affects orientation of the dropped item
* 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
*/ */
final case class ObjectDetachMessage(parent_guid : PlanetSideGUID, final case class ObjectDetachMessage(parent_guid : PlanetSideGUID,
child_guid : PlanetSideGUID, child_guid : PlanetSideGUID,
pos : Vector3, pos : Vector3,
roll : Int, roll : Float,
pitch : Int, pitch : Float,
yaw : Int) yaw : Float)
extends PlanetSideGamePacket { extends PlanetSideGamePacket {
type Packet = ObjectDetachMessage type Packet = ObjectDetachMessage
def opcode = GamePacketOpcode.ObjectDetachMessage def opcode = GamePacketOpcode.ObjectDetachMessage
@ -53,8 +44,8 @@ object ObjectDetachMessage extends Marshallable[ObjectDetachMessage] {
("parent_guid" | PlanetSideGUID.codec) :: ("parent_guid" | PlanetSideGUID.codec) ::
("child_guid" | PlanetSideGUID.codec) :: ("child_guid" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) :: ("pos" | Vector3.codec_pos) ::
("roll" | uint8L) :: ("roll" | Angular.codec_roll) ::
("pitch" | uint8L) :: ("pitch" | Angular.codec_pitch) ::
("yaw" | uint8L) ("yaw" | Angular.codec_yaw())
).as[ObjectDetachMessage] ).as[ObjectDetachMessage]
} }

View file

@ -3,7 +3,7 @@ package net.psforever.packet.game
import net.psforever.newcodecs.newcodecs import net.psforever.newcodecs.newcodecs
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3 import net.psforever.types.{Angular, Vector3}
import scodec.Codec import scodec.Codec
import scodec.codecs._ import scodec.codecs._
import shapeless.{::, HNil} import shapeless.{::, HNil}
@ -20,7 +20,7 @@ import shapeless.{::, HNil}
* <br> * <br>
* The avatar model normally moves from where it "currently" is to `pos`. * 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. * 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`. * After the move, it remains at essentially `pos + vel * t`.
* The repositioning always takes the same amount of time. * The repositioning always takes the same amount of time.
* The player model is left in a walking/running animation (in place) until directed otherwise.<br> * The player model is left in a walking/running animation (in place) until directed otherwise.<br>
@ -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. * 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. * 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. * 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.<br> * This effect is entirely client-side to the observer and affects the moving player in no way.
* <br>
* facingYaw:<br>
* `0x00` -- E<br>
* `0x10` -- NE<br>
* `0x20` -- N<br>
* `0x30` -- NW<br>
* `0x40` -- W<br>
* `0x50` -- SW<br>
* `0x60` -- S<br>
* `0x70` -- SE<br>
* `0x80` -- E<br>
* <br>
* facingPitch:<br>
* `0x00`-`0x20` -- downwards-facing angles, with `0x00` as forwards-facing<br>
* `0x21`-`0x40` -- downwards-facing<br>
* `0x41`-`0x59` -- upwards-facing<br>
* `0x60`-`0x80` -- upwards-facing angles, with `0x80` as forwards-facing<br>
* <br>
* facingYawUpper:<br>
* `0x00`-`0x20` -- turning to left, with `0x00` being forward-facing<br>
* `0x21`-`0x40` -- facing leftwards<br>
* `0x41`-`0x59` -- facing rightwards<br>
* `0x60`-`0x80` -- turning to right, with `0x80` being forward-facing
*
* @param guid the avatar's guid * @param guid the avatar's guid
* @param pos the position of the avatar in the world environment (in three coordinates) * @param pos the position of the avatar in the world environment (in three coordinates)
* @param vel an optional velocity * @param vel an optional velocity
* @param facingYaw the angle with respect to the horizon towards which the avatar is looking; * @param facingYaw a "yaw" angle
* the model's whole body is facing this direction; * @param facingPitch a "pitch" angle
* measurements are counter-clockwise from East * @param facingYawUpper a "yaw" angle that represents the angle of the avatar's upper body with respect to its forward-facing direction;
* @param facingPitch the angle with respect to the sky and the ground towards which the avatar is looking * this number is normally 0 for forward facing;
* @param facingYawUpper the angle of the avatar's upper body with respect to its forward-facing direction * the range is limited between approximately 61 degrees of center turned to left or right
* @param unk1 na * @param unk1 na
* @param is_crouching avatar is crouching * @param is_crouching avatar is crouching
* @param is_jumping avatar is jumping; * @param is_jumping avatar is jumping;
@ -72,9 +48,9 @@ import shapeless.{::, HNil}
final case class PlayerStateMessage(guid : PlanetSideGUID, final case class PlayerStateMessage(guid : PlanetSideGUID,
pos : Vector3, pos : Vector3,
vel : Option[Vector3], vel : Option[Vector3],
facingYaw : Int, facingYaw : Float,
facingPitch : Int, facingPitch : Float,
facingYawUpper : Int, facingYawUpper : Float,
unk1 : Int, unk1 : Int,
is_crouching : Boolean = false, is_crouching : Boolean = false,
is_jumping : Boolean = false, is_jumping : Boolean = false,
@ -117,9 +93,9 @@ object PlayerStateMessage extends Marshallable[PlayerStateMessage] {
("guid" | PlanetSideGUID.codec) :: ("guid" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) :: ("pos" | Vector3.codec_pos) ::
optional(bool, "vel" | Vector3.codec_vel) :: optional(bool, "vel" | Vector3.codec_vel) ::
("facingYaw" | uint8L) :: ("facingYaw" | Angular.codec_yaw()) ::
("facingPitch" | uint8L) :: ("facingPitch" | Angular.codec_pitch) ::
("facingYawUpper" | uint8L) :: ("facingYawUpper" | Angular.codec_yaw(0f)) ::
("unk1" | uintL(10)) :: ("unk1" | uintL(10)) ::
(bool >>:~ { fourBools => (bool >>:~ { fourBools =>
newcodecs.binary_choice(!fourBools, booleanCodec, defaultCodec) newcodecs.binary_choice(!fourBools, booleanCodec, defaultCodec)

View file

@ -1,8 +1,8 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.packet.game package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3 import net.psforever.types.{Angular, Vector3}
import scodec.Codec import scodec.Codec
import scodec.codecs._ import scodec.codecs._
@ -15,11 +15,11 @@ import scodec.codecs._
* @param avatar_guid the player's GUID * @param avatar_guid the player's GUID
* @param pos where the player is in the world * @param pos where the player is in the world
* @param vel how the player is moving * @param vel how the player is moving
* @param facingYaw the angle with respect to the horizon towards which the avatar is looking; * @param facingYaw a "yaw" angle
* the model's whole body is facing this direction; * @param facingPitch a "pitch" angle
* measurements are counter-clockwise from East * @param facingYawUpper a "yaw" angle that represents the angle of the avatar's upper body with respect to its forward-facing direction;
* @param facingPitch the angle with respect to the sky and the ground towards which the avatar is looking * this number is normally 0 for forward facing;
* @param facingYawUpper the angle of the avatar's upper body with respect to its forward-facing direction * the range is limited between approximately 61 degrees of center turned to left or right
* @param seq_time na * @param seq_time na
* @param unk1 na * @param unk1 na
* @param is_crouching avatar is crouching * @param is_crouching avatar is crouching
@ -33,9 +33,9 @@ import scodec.codecs._
final case class PlayerStateMessageUpstream(avatar_guid : PlanetSideGUID, final case class PlayerStateMessageUpstream(avatar_guid : PlanetSideGUID,
pos : Vector3, pos : Vector3,
vel : Option[Vector3], vel : Option[Vector3],
facingYaw : Int, facingYaw : Float,
facingPitch : Int, facingPitch : Float,
facingYawUpper : Int, facingYawUpper : Float,
seq_time : Int, seq_time : Int,
unk1 : Int, unk1 : Int,
is_crouching : Boolean, is_crouching : Boolean,
@ -55,9 +55,9 @@ object PlayerStateMessageUpstream extends Marshallable[PlayerStateMessageUpstrea
("avatar_guid" | PlanetSideGUID.codec) :: ("avatar_guid" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) :: ("pos" | Vector3.codec_pos) ::
("vel" | optional(bool, Vector3.codec_vel)) :: ("vel" | optional(bool, Vector3.codec_vel)) ::
("facingYaw" | uint8L) :: ("facingYaw" | Angular.codec_yaw()) ::
("facingPitch" | uint8L) :: ("facingPitch" | Angular.codec_pitch) ::
("facingYawUpper" | uint8L) :: ("facingYawUpper" | Angular.codec_yaw(0f)) ::
("seq_time" | uintL(10)) :: ("seq_time" | uintL(10)) ::
("unk1" | uintL(3)) :: ("unk1" | uintL(3)) ::
("is_crouching" | bool) :: ("is_crouching" | bool) ::

View file

@ -2,8 +2,8 @@
package net.psforever.packet.game package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3 import net.psforever.types.{Angular, Vector3}
import scodec.{Attempt, Codec, Err} import scodec.Codec
import scodec.codecs._ import scodec.codecs._
import shapeless.{::, HNil} import shapeless.{::, HNil}
@ -16,23 +16,25 @@ import shapeless.{::, HNil}
* This external force is not accumulative. * This external force is not accumulative.
* Also, the external force is only applied once the avatar is set to the provided position.<br> * Also, the external force is only applied once the avatar is set to the provided position.<br>
* <br> * <br>
* `viewYawLim` defines a "range of angles" that the avatar may look centered on the supplied angle. * The angle defines the center of a range of angles that count as "in front of the avatar."
* The avatar must be facing within 60-degrees of that direction, subjectively his left or his right. * Specifically, this range is the upper body's turn limit.
* The avatar's view is immediately set to the closest 60-degree mark if it is outside of that range. * A stationary player may look left and right, rotating their upper body only, until they hit a certain angle.
* The absolute angular displacement of the avatar is considered before applying this corrective behavior. * Normally, the player's whole body will then turn to accommodate turning further than this angle.
* After rotating any number of times: * This packet marks that limit as a hard limit for rotation and will reset the player's model and camera if necessary.
* stopping in a valid part of the range is acceptable; * While it is in effect, the player will not turn their whole body once they can no longer turn their upper body.
* 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.
* @param unk na * @param unk na
* @param pos the position to move the character to in the world environment * @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 * @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, final case class ShiftState(unk : Int,
pos : Vector3, pos : Vector3,
viewYawLim : Int, viewYawLim : Float,
vel : Option[Vector3]) vel : Option[Vector3])
/** /**
@ -55,7 +57,7 @@ final case class PlayerStateShiftMessage(state : Option[ShiftState],
def encode = PlayerStateShiftMessage.encode(this) def encode = PlayerStateShiftMessage.encode(this)
} }
object ShiftState extends Marshallable[ShiftState] { object ShiftState {
/** /**
* An abbreviated constructor for creating `ShiftState`, assuming velocity is not applied. * An abbreviated constructor for creating `ShiftState`, assuming velocity is not applied.
* @param unk na * @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 * @param vel the velocity to apply to to the character at the given position
* @return a `ShiftState` object * @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)) 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) * @param viewYawLim an angle with respect to the horizon towards which the avatar is looking (to some respect)
* @return a `ShiftState` object * @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) 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] { object PlayerStateShiftMessage extends Marshallable[PlayerStateShiftMessage] {
@ -120,8 +106,30 @@ object PlayerStateShiftMessage extends Marshallable[PlayerStateShiftMessage] {
def apply(unk : Int) : PlayerStateShiftMessage = def apply(unk : Int) : PlayerStateShiftMessage =
PlayerStateShiftMessage(None, Some(unk)) 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] = ( implicit val codec : Codec[PlayerStateShiftMessage] = (
optional(bool, "state" | ShiftState.codec) :: optional(bool, "state" | shift_codec) ::
optional(bool, "unk" | uintL(3)) optional(bool, "unk" | uintL(3))
).xmap[PlayerStateShiftMessage] ( ).xmap[PlayerStateShiftMessage] (
{ {

View file

@ -1,12 +1,10 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.packet.game package net.psforever.packet.game
import net.psforever.newcodecs.newcodecs
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3 import net.psforever.types.{Angular, Vector3}
import scodec.Codec import scodec.Codec
import scodec.codecs._ import scodec.codecs._
import shapeless.{::, HNil}
//TODO write more thorough comments later. //TODO write more thorough comments later.
/** /**
@ -14,15 +12,7 @@ import shapeless.{::, HNil}
* @param vehicle_guid the vehicle * @param vehicle_guid the vehicle
* @param unk1 na * @param unk1 na
* @param pos the xyz-coordinate location in the world * @param pos the xyz-coordinate location in the world
* @param roll the amount of roll that affects orientation; * @param ang the orientation of the vehicle
* 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 vel optional movement data * @param vel optional movement data
* @param unk2 na * @param unk2 na
* @param unk3 na * @param unk3 na
@ -38,9 +28,7 @@ import shapeless.{::, HNil}
final case class VehicleStateMessage(vehicle_guid : PlanetSideGUID, final case class VehicleStateMessage(vehicle_guid : PlanetSideGUID,
unk1 : Int, unk1 : Int,
pos : Vector3, pos : Vector3,
roll : Float, ang : Vector3,
pitch : Float,
yaw : Float,
vel : Option[Vector3], vel : Option[Vector3],
unk2 : Option[Int], unk2 : Option[Int],
unk3 : Int, unk3 : Int,
@ -55,13 +43,23 @@ final case class VehicleStateMessage(vehicle_guid : PlanetSideGUID,
} }
object VehicleStateMessage extends Marshallable[VehicleStateMessage] { 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] = ( implicit val codec : Codec[VehicleStateMessage] = (
("vehicle_guid" | PlanetSideGUID.codec) :: ("vehicle_guid" | PlanetSideGUID.codec) ::
("unk1" | uintL(3)) :: ("unk1" | uintL(3)) ::
("pos" | Vector3.codec_pos) :: ("pos" | Vector3.codec_pos) ::
("roll" | newcodecs.q_float(0.0f, 360.0f, 10)) :: ("ang" | codec_orient) ::
("pitch" | newcodecs.q_float(360.0f, 0.0f, 10)) ::
("yaw" | newcodecs.q_float(360.0f, 0.0f, 10)) ::
optional(bool, "vel" | Vector3.codec_vel) :: optional(bool, "vel" | Vector3.codec_vel) ::
optional(bool, "unk2" | uintL(5)) :: optional(bool, "unk2" | uintL(5)) ::
("unk3" | uintL(7)) :: ("unk3" | uintL(7)) ::
@ -69,27 +67,5 @@ object VehicleStateMessage extends Marshallable[VehicleStateMessage] {
("wheel_direction" | uintL(5)) :: ("wheel_direction" | uintL(5)) ::
("int5" | bool) :: ("int5" | bool) ::
("int6" | bool) ("int6" | bool)
).xmap[VehicleStateMessage] ( ).as[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
}
)
} }

View file

@ -2,7 +2,7 @@
package net.psforever.packet.game.objectcreate package net.psforever.packet.game.objectcreate
import net.psforever.packet.{Marshallable, PacketHelpers} 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.{Attempt, Codec, Err}
import scodec.codecs._ import scodec.codecs._
import shapeless.{::, HNil} 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 * 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; * @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 * 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 facingPitch a "pitch" angle
* @param facingYawUpper the angle of the avatar's upper body with respect to its forward-facing direction * @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; * @param lfs this player is looking for a squad;
* all allies will see the phrase "[Looking for Squad]" under the player's name * 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 * @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_name : String,
outfit_logo : Int, outfit_logo : Int,
backpack : Boolean, backpack : Boolean,
facingPitch : Int, facingPitch : Float,
facingYawUpper : Int, facingYawUpper : Float,
lfs : Boolean, lfs : Boolean,
grenade_state : GrenadeState.Value, grenade_state : GrenadeState.Value,
is_cloaking : Boolean, is_cloaking : Boolean,
@ -168,8 +170,8 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
ignore(1) :: //unknown ignore(1) :: //unknown
("backpack" | bool) :: //requires alt_model flag (does NOT require health == 0) ("backpack" | bool) :: //requires alt_model flag (does NOT require health == 0)
bool :: //stream misalignment when set bool :: //stream misalignment when set
("facingPitch" | uint8L) :: ("facingPitch" | Angular.codec_pitch) ::
("facingYawUpper" | uint8L) :: ("facingYawUpper" | Angular.codec_yaw(0f)) ::
ignore(1) :: //unknown ignore(1) :: //unknown
conditional(alt_model, bool) :: //alt_model flag adds a bit before lfs conditional(alt_model, bool) :: //alt_model flag adds a bit before lfs
ignore(1) :: //an alternate lfs? ignore(1) :: //an alternate lfs?

View file

@ -2,22 +2,19 @@
package net.psforever.packet.game.objectcreate package net.psforever.packet.game.objectcreate
import net.psforever.packet.Marshallable import net.psforever.packet.Marshallable
import net.psforever.types.Vector3 import net.psforever.types.{Angular, Vector3}
import scodec.codecs._ import scodec.codecs._
import scodec.Codec import scodec.Codec
import shapeless.{::, HNil}
/** /**
* A specific location and heading in game world coordinates and game world measurements. * A specific location and heading in game world coordinates and game world measurements.
* @param coord the xyz-coordinate location in the world * @param coord the xyz-coordinate location in the world
* @param roll the amount of roll that affects orientation * @param orient the ijk-orientation around the object's center
* @param pitch the amount of pitch that affects orientation
* @param yaw the amount of yaw that affects orientation
* @param vel optional movement data (that occurs upon placement) * @param vel optional movement data (that occurs upon placement)
*/ */
final case class PlacementData(coord : Vector3, final case class PlacementData(coord : Vector3,
roll : Int, orient : Vector3,
pitch : Int,
yaw : Int,
vel : Option[Vector3] = None vel : Option[Vector3] = None
) extends StreamBitSize { ) extends StreamBitSize {
override def bitsize : Long = { override def bitsize : Long = {
@ -35,7 +32,7 @@ object PlacementData extends Marshallable[PlacementData] {
* @return a `PlacementData` object * @return a `PlacementData` object
*/ */
def apply(x : Float, y : Float, z : Float) : PlacementData = 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. * 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 * @param yaw the amount of yaw that affects orientation
* @return a `PlacementData` object * @return a `PlacementData` object
*/ */
def apply(x : Float, y : Float, z : Float, roll : Int, pitch : Int, yaw : Int) : PlacementData = def apply(x : Float, y : Float, z : Float, roll : Float, pitch : Float, yaw : Float) : PlacementData =
new PlacementData(Vector3(x, y, z), roll, pitch, yaw) 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. * 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 * @param vel optional movement data that occurs upon placement
* @return a `PlacementData` object * @return a `PlacementData` object
*/ */
def apply(x : Float, y : Float, z : Float, roll : Int, pitch : Int, yaw : Int, vel : Vector3) : PlacementData = def apply(x : Float, y : Float, z : Float, roll : Float, pitch : Float, yaw : Float, vel : Vector3) : PlacementData =
new PlacementData(Vector3(x, y, z), roll, pitch, yaw, Some(vel)) new PlacementData(Vector3(x, y, z), Vector3(roll, pitch, yaw), Some(vel))
implicit val codec : Codec[PlacementData] = ( implicit val codec : Codec[PlacementData] = (
("coord" | Vector3.codec_pos) :: ("coord" | Vector3.codec_pos) ::
("roll" | uint8L) :: ("roll" | Angular.codec_roll) ::
("pitch" | uint8L) :: ("pitch" | Angular.codec_pitch) ::
("yaw" | uint8L) :: ("yaw" | Angular.codec_yaw()) ::
optional(bool, "vel" | Vector3.codec_vel) 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
}
)
} }

View file

@ -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
}
}

View file

@ -4,6 +4,7 @@ package net.psforever.types
import net.psforever.newcodecs._ import net.psforever.newcodecs._
import scodec.Codec import scodec.Codec
import scodec.codecs._ import scodec.codecs._
import shapeless.{::, HNil}
final case class Vector3(x : Float, final case class Vector3(x : Float,
y : Float, y : Float,

View file

@ -34,23 +34,190 @@ class CodecTest extends Specification {
} }
"Vector3" should { "Vector3" should {
val string_pos = hex"6E2D762222B616" "position" should {
val string_vel = hex"857D4E0FFFC0" val string_pos = hex"6E2D762222B616"
"decode position" in { "decode" in {
Vector3.codec_pos.decode(string_pos.bits).require.value mustEqual Vector3(3674.859375f, 1092.7656f, 90.84375f) 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 { "velocity" should {
Vector3.codec_pos.encode(Vector3(3674.859375f, 1092.7656f, 90.84375f)).require.bytes mustEqual string_pos 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 { "pitch" should {
Vector3.codec_vel.decode(string_vel.bits).require.value mustEqual Vector3(-3.84375f, 2.59375f, 255.96875f) 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 { "yaw, normal" should {
Vector3.codec_vel.encode(Vector3(-3.84375f, 2.59375f, 255.96875f)).require.bytes mustEqual string_vel 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
}
} }
} }
} }

View file

@ -13,15 +13,15 @@ class ChildObjectStateMessageTest extends Specification {
PacketCoding.DecodePacket(string).require match { PacketCoding.DecodePacket(string).require match {
case ChildObjectStateMessage(object_guid, pitch, yaw) => case ChildObjectStateMessage(object_guid, pitch, yaw) =>
object_guid mustEqual PlanetSideGUID(2916) object_guid mustEqual PlanetSideGUID(2916)
pitch mustEqual 6 pitch mustEqual 343.125f
yaw mustEqual 71 yaw mustEqual 160.3125f
case _ => case _ =>
ko ko
} }
} }
"encode" in { "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 val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string pkt mustEqual string

View file

@ -180,9 +180,9 @@ class ObjectCreateDetailedMessageTest extends Specification {
char.appearance.pos.coord.x mustEqual 3674.8438f char.appearance.pos.coord.x mustEqual 3674.8438f
char.appearance.pos.coord.y mustEqual 2726.789f char.appearance.pos.coord.y mustEqual 2726.789f
char.appearance.pos.coord.z mustEqual 91.15625f char.appearance.pos.coord.z mustEqual 91.15625f
char.appearance.pos.roll mustEqual 0 char.appearance.pos.orient.x mustEqual 0
char.appearance.pos.pitch mustEqual 0 char.appearance.pos.orient.y mustEqual 0f
char.appearance.pos.yaw mustEqual 19 char.appearance.pos.orient.z mustEqual 36.5625f
char.appearance.basic_appearance.name mustEqual "IlllIIIlllIlIllIlllIllI" char.appearance.basic_appearance.name mustEqual "IlllIIIlllIlIllIlllIllI"
char.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.VS char.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.VS
char.appearance.basic_appearance.sex mustEqual CharacterGender.Female char.appearance.basic_appearance.sex mustEqual CharacterGender.Female
@ -195,8 +195,8 @@ class ObjectCreateDetailedMessageTest extends Specification {
char.appearance.outfit_name mustEqual "" char.appearance.outfit_name mustEqual ""
char.appearance.outfit_logo mustEqual 0 char.appearance.outfit_logo mustEqual 0
char.appearance.backpack mustEqual false char.appearance.backpack mustEqual false
char.appearance.facingPitch mustEqual 127 char.appearance.facingPitch mustEqual 2.8125f
char.appearance.facingYawUpper mustEqual 181 char.appearance.facingYawUpper mustEqual 210.9375f
char.appearance.lfs mustEqual true char.appearance.lfs mustEqual true
char.appearance.grenade_state mustEqual GrenadeState.None char.appearance.grenade_state mustEqual GrenadeState.None
char.appearance.is_cloaking mustEqual false char.appearance.is_cloaking mustEqual false
@ -367,8 +367,7 @@ class ObjectCreateDetailedMessageTest extends Specification {
val app = CharacterAppearanceData( val app = CharacterAppearanceData(
PlacementData( PlacementData(
Vector3(3674.8438f, 2726.789f, 91.15625f), Vector3(3674.8438f, 2726.789f, 91.15625f),
0, 0, Vector3(0f, 0f, 36.5625f)
19
), ),
BasicCharacterData( BasicCharacterData(
"IlllIIIlllIlIllIlllIllI", "IlllIIIlllIlIllIlllIllI",
@ -384,7 +383,7 @@ class ObjectCreateDetailedMessageTest extends Specification {
"", "",
0, 0,
false, false,
127, 181, 2.8125f, 210.9375f,
true, true,
GrenadeState.None, GrenadeState.None,
false, false,
@ -422,7 +421,8 @@ class ObjectCreateDetailedMessageTest extends Specification {
val ori_bitv = string_testchar.toBitVector val ori_bitv = string_testchar.toBitVector
pkt_bitv.take(153) mustEqual ori_bitv.take(153) //skip 1 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(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 //TODO work on DetailedCharacterData to make this pass as a single stream
} }
} }

View file

@ -48,9 +48,9 @@ class ObjectCreateMessageTest extends Specification {
projectile.pos.coord.x mustEqual 4644.5938f projectile.pos.coord.x mustEqual 4644.5938f
projectile.pos.coord.y mustEqual 5472.0938f projectile.pos.coord.y mustEqual 5472.0938f
projectile.pos.coord.z mustEqual 82.375f projectile.pos.coord.z mustEqual 82.375f
projectile.pos.roll mustEqual 0 projectile.pos.orient.x mustEqual 0f
projectile.pos.pitch mustEqual 245 projectile.pos.orient.y mustEqual 30.9375f
projectile.pos.yaw mustEqual 227 projectile.pos.orient.z mustEqual 171.5625f
projectile.unk1 mustEqual 0 projectile.unk1 mustEqual 0
projectile.unk2 mustEqual TrackedProjectileData.striker_missile_targetting_projectile_data projectile.unk2 mustEqual TrackedProjectileData.striker_missile_targetting_projectile_data
case _ => case _ =>
@ -88,9 +88,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4579.3438f drop.pos.coord.x mustEqual 4579.3438f
drop.pos.coord.y mustEqual 5615.0703f drop.pos.coord.y mustEqual 5615.0703f
drop.pos.coord.z mustEqual 72.953125f drop.pos.coord.z mustEqual 72.953125f
drop.pos.pitch mustEqual 0 drop.pos.orient.x mustEqual 0f
drop.pos.roll mustEqual 0 drop.pos.orient.y mustEqual 0f
drop.pos.yaw mustEqual 125 drop.pos.orient.z mustEqual 98.4375f
drop.obj.isInstanceOf[CommonTerminalData] mustEqual true drop.obj.isInstanceOf[CommonTerminalData] mustEqual true
val term = drop.obj.asInstanceOf[CommonTerminalData] val term = drop.obj.asInstanceOf[CommonTerminalData]
term.faction mustEqual PlanetSideEmpire.NC term.faction mustEqual PlanetSideEmpire.NC
@ -249,9 +249,9 @@ class ObjectCreateMessageTest extends Specification {
flag.pos.coord.x mustEqual 3912.0312f flag.pos.coord.x mustEqual 3912.0312f
flag.pos.coord.y mustEqual 5169.4375f flag.pos.coord.y mustEqual 5169.4375f
flag.pos.coord.z mustEqual 59.96875f flag.pos.coord.z mustEqual 59.96875f
flag.pos.roll mustEqual 0 flag.pos.orient.x mustEqual 0f
flag.pos.pitch mustEqual 0 flag.pos.orient.y mustEqual 0f
flag.pos.yaw mustEqual 15 flag.pos.orient.z mustEqual 47.8125f
flag.faction mustEqual PlanetSideEmpire.NC flag.faction mustEqual PlanetSideEmpire.NC
flag.unk1 mustEqual 21 flag.unk1 mustEqual 21
flag.unk2 mustEqual 4 flag.unk2 mustEqual 4
@ -274,9 +274,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4708.461f drop.pos.coord.x mustEqual 4708.461f
drop.pos.coord.y mustEqual 5547.539f drop.pos.coord.y mustEqual 5547.539f
drop.pos.coord.z mustEqual 72.703125f drop.pos.coord.z mustEqual 72.703125f
drop.pos.roll mustEqual 0 drop.pos.orient.x mustEqual 0f
drop.pos.pitch mustEqual 0 drop.pos.orient.y mustEqual 0f
drop.pos.yaw mustEqual 91 drop.pos.orient.z mustEqual 194.0625f
drop.obj.isInstanceOf[ACEData] mustEqual true drop.obj.isInstanceOf[ACEData] mustEqual true
val ace = drop.obj.asInstanceOf[ACEData] val ace = drop.obj.asInstanceOf[ACEData]
ace.unk1 mustEqual 8 ace.unk1 mustEqual 8
@ -299,9 +299,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4777.633f drop.pos.coord.x mustEqual 4777.633f
drop.pos.coord.y mustEqual 5485.4062f drop.pos.coord.y mustEqual 5485.4062f
drop.pos.coord.z mustEqual 85.8125f drop.pos.coord.z mustEqual 85.8125f
drop.pos.roll mustEqual 0 drop.pos.orient.x mustEqual 0f
drop.pos.pitch mustEqual 0 drop.pos.orient.y mustEqual 0f
drop.pos.yaw mustEqual 27 drop.pos.orient.z mustEqual 14.0625f
drop.obj.isInstanceOf[CommandDetonaterData] mustEqual true drop.obj.isInstanceOf[CommandDetonaterData] mustEqual true
case _ => case _ =>
ko ko
@ -321,9 +321,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4684.7344f drop.pos.coord.x mustEqual 4684.7344f
drop.pos.coord.y mustEqual 5547.4844f drop.pos.coord.y mustEqual 5547.4844f
drop.pos.coord.z mustEqual 83.765625f drop.pos.coord.z mustEqual 83.765625f
drop.pos.roll mustEqual 0 drop.pos.orient.x mustEqual 0f
drop.pos.pitch mustEqual 0 drop.pos.orient.y mustEqual 0f
drop.pos.yaw mustEqual 89 drop.pos.orient.z mustEqual 199.6875f
drop.obj.isInstanceOf[AmmoBoxData] mustEqual true drop.obj.isInstanceOf[AmmoBoxData] mustEqual true
val box = drop.obj.asInstanceOf[AmmoBoxData] val box = drop.obj.asInstanceOf[AmmoBoxData]
box.unk mustEqual 0 box.unk mustEqual 0
@ -345,9 +345,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4691.1953f drop.pos.coord.x mustEqual 4691.1953f
drop.pos.coord.y mustEqual 5537.039f drop.pos.coord.y mustEqual 5537.039f
drop.pos.coord.z mustEqual 65.484375f drop.pos.coord.z mustEqual 65.484375f
drop.pos.roll mustEqual 0 drop.pos.orient.x mustEqual 0f
drop.pos.pitch mustEqual 0 drop.pos.orient.y mustEqual 0f
drop.pos.yaw mustEqual 32 drop.pos.orient.z mustEqual 0f
drop.obj.isInstanceOf[WeaponData] mustEqual true drop.obj.isInstanceOf[WeaponData] mustEqual true
val wep = drop.obj.asInstanceOf[WeaponData] val wep = drop.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 4 wep.unk1 mustEqual 4
@ -377,9 +377,9 @@ class ObjectCreateMessageTest extends Specification {
drop.pos.coord.x mustEqual 4789.133f drop.pos.coord.x mustEqual 4789.133f
drop.pos.coord.y mustEqual 5522.3125f drop.pos.coord.y mustEqual 5522.3125f
drop.pos.coord.z mustEqual 72.3125f drop.pos.coord.z mustEqual 72.3125f
drop.pos.roll mustEqual 0 drop.pos.orient.x mustEqual 0f
drop.pos.pitch mustEqual 0 drop.pos.orient.y mustEqual 0f
drop.pos.yaw mustEqual 51 drop.pos.orient.z mustEqual 306.5625f
drop.obj.isInstanceOf[WeaponData] mustEqual true drop.obj.isInstanceOf[WeaponData] mustEqual true
val wep = drop.obj.asInstanceOf[WeaponData] val wep = drop.obj.asInstanceOf[WeaponData]
wep.unk1 mustEqual 2 wep.unk1 mustEqual 2
@ -417,9 +417,9 @@ class ObjectCreateMessageTest extends Specification {
dropped.pos.coord.x mustEqual 4675.039f dropped.pos.coord.x mustEqual 4675.039f
dropped.pos.coord.y mustEqual 5506.953f dropped.pos.coord.y mustEqual 5506.953f
dropped.pos.coord.z mustEqual 72.703125f dropped.pos.coord.z mustEqual 72.703125f
dropped.pos.roll mustEqual 0 dropped.pos.orient.x mustEqual 0f
dropped.pos.pitch mustEqual 0 dropped.pos.orient.y mustEqual 0f
dropped.pos.yaw mustEqual 78 dropped.pos.orient.z mustEqual 230.625f
dropped.obj.isInstanceOf[REKData] mustEqual true dropped.obj.isInstanceOf[REKData] mustEqual true
val rek = dropped.obj.asInstanceOf[REKData] val rek = dropped.obj.asInstanceOf[REKData]
rek.unk1 mustEqual 8 rek.unk1 mustEqual 8
@ -443,9 +443,9 @@ class ObjectCreateMessageTest extends Specification {
boomer.deploy.pos.coord.x mustEqual 4704.172f boomer.deploy.pos.coord.x mustEqual 4704.172f
boomer.deploy.pos.coord.y mustEqual 5546.4375f boomer.deploy.pos.coord.y mustEqual 5546.4375f
boomer.deploy.pos.coord.z mustEqual 82.234375f boomer.deploy.pos.coord.z mustEqual 82.234375f
boomer.deploy.pos.roll mustEqual 0 boomer.deploy.pos.orient.x mustEqual 0f
boomer.deploy.pos.pitch mustEqual 0 boomer.deploy.pos.orient.y mustEqual 0f
boomer.deploy.pos.yaw mustEqual 63 boomer.deploy.pos.orient.z mustEqual 272.8125f
boomer.deploy.unk mustEqual 0 boomer.deploy.unk mustEqual 0
boomer.deploy.player_guid mustEqual PlanetSideGUID(4145) boomer.deploy.player_guid mustEqual PlanetSideGUID(4145)
case _ => case _ =>
@ -466,9 +466,9 @@ class ObjectCreateMessageTest extends Specification {
turret.deploy.pos.coord.x mustEqual 4577.7812f turret.deploy.pos.coord.x mustEqual 4577.7812f
turret.deploy.pos.coord.y mustEqual 5624.828f turret.deploy.pos.coord.y mustEqual 5624.828f
turret.deploy.pos.coord.z mustEqual 72.046875f turret.deploy.pos.coord.z mustEqual 72.046875f
turret.deploy.pos.roll mustEqual 0 turret.deploy.pos.orient.x mustEqual 0f
turret.deploy.pos.pitch mustEqual 127 turret.deploy.pos.orient.y mustEqual 2.8125f
turret.deploy.pos.yaw mustEqual 66 turret.deploy.pos.orient.z mustEqual 264.375f
turret.deploy.faction mustEqual PlanetSideEmpire.NC turret.deploy.faction mustEqual PlanetSideEmpire.NC
turret.deploy.unk mustEqual 12 turret.deploy.unk mustEqual 12
turret.deploy.player_guid mustEqual PlanetSideGUID(3871) 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.x mustEqual 4527.633f
turret.deploy.pos.coord.y mustEqual 6271.3594f turret.deploy.pos.coord.y mustEqual 6271.3594f
turret.deploy.pos.coord.z mustEqual 70.265625f turret.deploy.pos.coord.z mustEqual 70.265625f
turret.deploy.pos.roll mustEqual 0 turret.deploy.pos.orient.x mustEqual 0f
turret.deploy.pos.pitch mustEqual 0 turret.deploy.pos.orient.y mustEqual 0f
turret.deploy.pos.yaw mustEqual 105 turret.deploy.pos.orient.z mustEqual 154.6875f
turret.deploy.faction mustEqual PlanetSideEmpire.VS turret.deploy.faction mustEqual PlanetSideEmpire.VS
turret.deploy.unk mustEqual 4 turret.deploy.unk mustEqual 4
turret.deploy.player_guid mustEqual PlanetSideGUID(4232) 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.x mustEqual 3572.4453f
trap.deploy.pos.coord.y mustEqual 3277.9766f trap.deploy.pos.coord.y mustEqual 3277.9766f
trap.deploy.pos.coord.z mustEqual 114.0f trap.deploy.pos.coord.z mustEqual 114.0f
trap.deploy.pos.roll mustEqual 0 trap.deploy.pos.orient.x mustEqual 0f
trap.deploy.pos.pitch mustEqual 0 trap.deploy.pos.orient.y mustEqual 0f
trap.deploy.pos.yaw mustEqual 0 trap.deploy.pos.orient.z mustEqual 90.0f
trap.deploy.faction mustEqual PlanetSideEmpire.VS trap.deploy.faction mustEqual PlanetSideEmpire.VS
trap.deploy.unk mustEqual 4 trap.deploy.unk mustEqual 4
trap.health mustEqual 255 trap.health mustEqual 255
@ -558,9 +558,9 @@ class ObjectCreateMessageTest extends Specification {
aegis.deploy.pos.coord.x mustEqual 3571.2266f aegis.deploy.pos.coord.x mustEqual 3571.2266f
aegis.deploy.pos.coord.y mustEqual 3278.0938f aegis.deploy.pos.coord.y mustEqual 3278.0938f
aegis.deploy.pos.coord.z mustEqual 114.0f aegis.deploy.pos.coord.z mustEqual 114.0f
aegis.deploy.pos.roll mustEqual 0 aegis.deploy.pos.orient.x mustEqual 0f
aegis.deploy.pos.pitch mustEqual 0 aegis.deploy.pos.orient.y mustEqual 0f
aegis.deploy.pos.yaw mustEqual 0 aegis.deploy.pos.orient.z mustEqual 90.0f
aegis.deploy.faction mustEqual PlanetSideEmpire.VS aegis.deploy.faction mustEqual PlanetSideEmpire.VS
aegis.deploy.unk mustEqual 4 aegis.deploy.unk mustEqual 4
aegis.health mustEqual 255 aegis.health mustEqual 255
@ -583,9 +583,9 @@ class ObjectCreateMessageTest extends Specification {
omft.deploy.pos.coord.x mustEqual 3567.1406f omft.deploy.pos.coord.x mustEqual 3567.1406f
omft.deploy.pos.coord.y mustEqual 2988.0078f omft.deploy.pos.coord.y mustEqual 2988.0078f
omft.deploy.pos.coord.z mustEqual 71.84375f omft.deploy.pos.coord.z mustEqual 71.84375f
omft.deploy.pos.roll mustEqual 0 omft.deploy.pos.orient.x mustEqual 0f
omft.deploy.pos.pitch mustEqual 0 omft.deploy.pos.orient.y mustEqual 0f
omft.deploy.pos.yaw mustEqual 94 omft.deploy.pos.orient.z mustEqual 185.625f
omft.deploy.faction mustEqual PlanetSideEmpire.VS omft.deploy.faction mustEqual PlanetSideEmpire.VS
omft.deploy.unk mustEqual 4 omft.deploy.unk mustEqual 4
omft.deploy.player_guid mustEqual PlanetSideGUID(2502) 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.x mustEqual 3674.8438f
pc.appearance.pos.coord.y mustEqual 2726.789f pc.appearance.pos.coord.y mustEqual 2726.789f
pc.appearance.pos.coord.z mustEqual 91.15625f pc.appearance.pos.coord.z mustEqual 91.15625f
pc.appearance.pos.roll mustEqual 0 pc.appearance.pos.orient.x mustEqual 0f
pc.appearance.pos.pitch mustEqual 0 pc.appearance.pos.orient.y mustEqual 0f
pc.appearance.pos.yaw mustEqual 9 pc.appearance.pos.orient.z mustEqual 64.6875f
pc.appearance.pos.vel.isDefined mustEqual true pc.appearance.pos.vel.isDefined mustEqual true
pc.appearance.pos.vel.get.x mustEqual 1.4375f pc.appearance.pos.vel.get.x mustEqual 1.4375f
pc.appearance.pos.vel.get.y mustEqual -0.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.exosuit mustEqual ExoSuitType.Reinforced
pc.appearance.outfit_name mustEqual "Black Beret Armoured Corps" pc.appearance.outfit_name mustEqual "Black Beret Armoured Corps"
pc.appearance.outfit_logo mustEqual 23 pc.appearance.outfit_logo mustEqual 23
pc.appearance.facingPitch mustEqual 7 pc.appearance.facingPitch mustEqual 340.3125f
pc.appearance.facingYawUpper mustEqual 0 pc.appearance.facingYawUpper mustEqual 0
pc.appearance.lfs mustEqual false pc.appearance.lfs mustEqual false
pc.appearance.grenade_state mustEqual GrenadeState.None 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.x mustEqual 4629.8906f
pc.appearance.pos.coord.y mustEqual 6316.4453f pc.appearance.pos.coord.y mustEqual 6316.4453f
pc.appearance.pos.coord.z mustEqual 54.734375f pc.appearance.pos.coord.z mustEqual 54.734375f
pc.appearance.pos.roll mustEqual 0 pc.appearance.pos.orient.x mustEqual 0f
pc.appearance.pos.pitch mustEqual 0 pc.appearance.pos.orient.y mustEqual 0f
pc.appearance.pos.yaw mustEqual 115 pc.appearance.pos.orient.z mustEqual 126.5625f
pc.appearance.pos.vel.isDefined mustEqual false pc.appearance.pos.vel.isDefined mustEqual false
pc.appearance.basic_appearance.name mustEqual "Angello" pc.appearance.basic_appearance.name mustEqual "Angello"
pc.appearance.basic_appearance.faction mustEqual PlanetSideEmpire.VS 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_name mustEqual "Original District"
pc.appearance.outfit_logo mustEqual 23 pc.appearance.outfit_logo mustEqual 23
pc.appearance.facingPitch mustEqual 0 pc.appearance.facingPitch mustEqual 0
pc.appearance.facingYawUpper mustEqual 192 pc.appearance.facingYawUpper mustEqual 180.0f
pc.appearance.lfs mustEqual false pc.appearance.lfs mustEqual false
pc.appearance.grenade_state mustEqual GrenadeState.None pc.appearance.grenade_state mustEqual GrenadeState.None
pc.appearance.is_cloaking mustEqual false pc.appearance.is_cloaking mustEqual false
@ -811,13 +811,15 @@ class ObjectCreateMessageTest extends Specification {
"encode (striker projectile)" in { "encode (striker projectile)" in {
val obj = TrackedProjectileData.striker( 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 0
) )
val msg = ObjectCreateMessage(ObjectClass.striker_missile_targeting_projectile, PlanetSideGUID(40192), obj) val msg = ObjectCreateMessage(ObjectClass.striker_missile_targeting_projectile, PlanetSideGUID(40192), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector 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 { "encode (implant interface)" in {
@ -830,7 +832,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (order terminal a)" in { "encode (order terminal a)" in {
val obj = DroppedItemData( 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) CommonTerminalData(PlanetSideEmpire.NC)
) )
val msg = ObjectCreateMessage(ObjectClass.order_terminala, PlanetSideGUID(3827), obj) val msg = ObjectCreateMessage(ObjectClass.order_terminala, PlanetSideGUID(3827), obj)
@ -893,7 +895,7 @@ class ObjectCreateMessageTest extends Specification {
} }
"encode (capture flag)" in { "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 msg = ObjectCreateMessage(ObjectClass.capture_flag, PlanetSideGUID(4330), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
@ -902,7 +904,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (ace, dropped)" in { "encode (ace, dropped)" in {
val obj = DroppedItemData( 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) ACEData(8, 8)
) )
val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(4388), obj) val msg = ObjectCreateMessage(ObjectClass.ace, PlanetSideGUID(4388), obj)
@ -913,7 +915,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (detonator, dropped)" in { "encode (detonator, dropped)" in {
val obj = DroppedItemData( 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() CommandDetonaterData()
) )
val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(3682), obj) val msg = ObjectCreateMessage(ObjectClass.command_detonater, PlanetSideGUID(3682), obj)
@ -924,7 +926,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (shotgun shells, dropped)" in { "encode (shotgun shells, dropped)" in {
val obj = DroppedItemData( 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() AmmoBoxData()
) )
val msg = ObjectCreateMessage(ObjectClass.shotgun_shell, PlanetSideGUID(3453), obj) val msg = ObjectCreateMessage(ObjectClass.shotgun_shell, PlanetSideGUID(3453), obj)
@ -935,7 +937,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (lasher, dropped)" in { "encode (lasher, dropped)" in {
val obj = DroppedItemData( 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()) WeaponData(4, 0, ObjectClass.energy_cell, PlanetSideGUID(3268), 0, AmmoBoxData())
) )
val msg = ObjectCreateMessage(ObjectClass.lasher, PlanetSideGUID(3074), obj) val msg = ObjectCreateMessage(ObjectClass.lasher, PlanetSideGUID(3074), obj)
@ -946,7 +948,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (punisher, dropped)" in { "encode (punisher, dropped)" in {
val obj = DroppedItemData( 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, WeaponData(2, 0, 0,
AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3528), 0, AmmoBoxData()) :: AmmoBoxData(ObjectClass.bullet_9mm, PlanetSideGUID(3528), 0, AmmoBoxData()) ::
AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3031), 1, AmmoBoxData()) :: AmmoBoxData(ObjectClass.rocket, PlanetSideGUID(3031), 1, AmmoBoxData()) ::
@ -961,7 +963,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (REK, dropped)" in { "encode (REK, dropped)" in {
val obj = DroppedItemData( 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) REKData(8, 0, 3)
) )
val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(4355), obj) val msg = ObjectCreateMessage(ObjectClass.remote_electronics_kit, PlanetSideGUID(4355), obj)
@ -973,7 +975,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (boomer)" in { "encode (boomer)" in {
val obj = SmallDeployableData( val obj = SmallDeployableData(
CommonFieldData( 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) PlanetSideEmpire.TR, 0, PlanetSideGUID(4145)
) )
) )
@ -986,7 +988,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (spitfire, short)" in { "encode (spitfire, short)" in {
val obj = SmallTurretData( val obj = SmallTurretData(
CommonFieldData( 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) PlanetSideEmpire.NC, 12, PlanetSideGUID(3871)
), ),
255 //sets to 0 255 //sets to 0
@ -1004,7 +1006,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (spitfire)" in { "encode (spitfire)" in {
val obj = SmallTurretData( val obj = SmallTurretData(
CommonFieldData( 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) PlanetSideEmpire.VS, 4, PlanetSideGUID(4232)
), ),
255, 255,
@ -1023,7 +1025,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (trap)" in { "encode (trap)" in {
val obj = TRAPData( val obj = TRAPData(
CommonFieldData( 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) PlanetSideEmpire.VS, 4, PlanetSideGUID(2502)
), ),
255 255
@ -1041,7 +1043,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (aegis)" in { "encode (aegis)" in {
val obj = AegisShieldGeneratorData( val obj = AegisShieldGeneratorData(
CommonFieldData( 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) PlanetSideEmpire.VS, 4, PlanetSideGUID(2366)
), ),
255 255
@ -1055,7 +1057,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (orion)" in { "encode (orion)" in {
val obj = OneMannedFieldTurretData( val obj = OneMannedFieldTurretData(
CommonFieldData( 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) PlanetSideEmpire.VS, 4, PlanetSideGUID(2502)
), ),
255, 255,
@ -1091,7 +1093,7 @@ class ObjectCreateMessageTest extends Specification {
CharacterAppearanceData( CharacterAppearanceData(
PlacementData( PlacementData(
Vector3(3674.8438f, 2726.789f, 91.15625f), Vector3(3674.8438f, 2726.789f, 91.15625f),
0, 0, 9, Vector3(0f, 0f, 64.6875f),
Some(Vector3(1.4375f, -0.4375f, 0f)) Some(Vector3(1.4375f, -0.4375f, 0f))
), ),
BasicCharacterData( BasicCharacterData(
@ -1108,7 +1110,7 @@ class ObjectCreateMessageTest extends Specification {
"Black Beret Armoured Corps", "Black Beret Armoured Corps",
23, 23,
false, false,
7, 0, 340.3125f, 0f,
false, false,
GrenadeState.None, GrenadeState.None,
false, false, false, false, false, false,
@ -1150,7 +1152,7 @@ class ObjectCreateMessageTest extends Specification {
"encode (character, backpack)" in { "encode (character, backpack)" in {
val obj = CharacterData( val obj = CharacterData(
CharacterAppearanceData( CharacterAppearanceData(
PlacementData(4629.8906f, 6316.4453f, 54.734375f, 0, 0, 115), PlacementData(4629.8906f, 6316.4453f, 54.734375f, 0f, 0f, 126.5625f),
BasicCharacterData( BasicCharacterData(
"Angello", "Angello",
PlanetSideEmpire.VS, PlanetSideEmpire.VS,
@ -1165,7 +1167,7 @@ class ObjectCreateMessageTest extends Specification {
"Original District", "Original District",
23, 23,
true, //backpack true, //backpack
0, 192, 0f, 180.0f,
false, false,
GrenadeState.None, GrenadeState.None,
false, false, false, false, false, false,
@ -1191,8 +1193,9 @@ class ObjectCreateMessageTest extends Specification {
val ori_bitv = string_character_backpack.toBitVector val ori_bitv = string_character_backpack.toBitVector
pkt_bitv.take(300) mustEqual ori_bitv.take(300) //skip 2 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(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(442).take(305) mustEqual ori_bitv.drop(442).take(305) //skip 1
pkt_bitv.drop(761).take(155) mustEqual ori_bitv.drop(761).take(155) //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) pkt_bitv.drop(917) mustEqual ori_bitv.drop(917)
//TODO work on CharacterData to make this pass as a single stream //TODO work on CharacterData to make this pass as a single stream
} }

View file

@ -33,9 +33,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
fury.basic.pos.coord.x mustEqual 6531.961f fury.basic.pos.coord.x mustEqual 6531.961f
fury.basic.pos.coord.y mustEqual 1872.1406f fury.basic.pos.coord.y mustEqual 1872.1406f
fury.basic.pos.coord.z mustEqual 24.734375f fury.basic.pos.coord.z mustEqual 24.734375f
fury.basic.pos.roll mustEqual 0 fury.basic.pos.orient.x mustEqual 0f
fury.basic.pos.pitch mustEqual 0 fury.basic.pos.orient.y mustEqual 0f
fury.basic.pos.yaw mustEqual 33 fury.basic.pos.orient.z mustEqual 357.1875f
fury.basic.pos.vel.isDefined mustEqual false fury.basic.pos.vel.isDefined mustEqual false
fury.basic.faction mustEqual PlanetSideEmpire.VS fury.basic.faction mustEqual PlanetSideEmpire.VS
fury.basic.unk mustEqual 4 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.x mustEqual 3674.8438f
ant.basic.pos.coord.y mustEqual 2726.789f ant.basic.pos.coord.y mustEqual 2726.789f
ant.basic.pos.coord.z mustEqual 91.15625f ant.basic.pos.coord.z mustEqual 91.15625f
ant.basic.pos.roll mustEqual 0 ant.basic.pos.orient.x mustEqual 0f
ant.basic.pos.pitch mustEqual 0 ant.basic.pos.orient.y mustEqual 0f
ant.basic.pos.yaw mustEqual 0 ant.basic.pos.orient.z mustEqual 90.0f
ant.basic.faction mustEqual PlanetSideEmpire.VS ant.basic.faction mustEqual PlanetSideEmpire.VS
ant.basic.unk mustEqual 4 ant.basic.unk mustEqual 4
ant.basic.player_guid mustEqual PlanetSideGUID(0) 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.x mustEqual 3674.8438f
lightning.basic.pos.coord.y mustEqual 2726.789f lightning.basic.pos.coord.y mustEqual 2726.789f
lightning.basic.pos.coord.z mustEqual 91.15625f lightning.basic.pos.coord.z mustEqual 91.15625f
lightning.basic.pos.roll mustEqual 0 lightning.basic.pos.orient.x mustEqual 0f
lightning.basic.pos.pitch mustEqual 0 lightning.basic.pos.orient.y mustEqual 0f
lightning.basic.pos.yaw mustEqual 0 lightning.basic.pos.orient.z mustEqual 90.0f
lightning.basic.faction mustEqual PlanetSideEmpire.VS lightning.basic.faction mustEqual PlanetSideEmpire.VS
lightning.basic.unk mustEqual 4 lightning.basic.unk mustEqual 4
lightning.basic.player_guid mustEqual PlanetSideGUID(0) 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.x mustEqual 6531.961f
deliverer.basic.pos.coord.y mustEqual 1872.1406f deliverer.basic.pos.coord.y mustEqual 1872.1406f
deliverer.basic.pos.coord.z mustEqual 24.734375f deliverer.basic.pos.coord.z mustEqual 24.734375f
deliverer.basic.pos.roll mustEqual 0 deliverer.basic.pos.orient.x mustEqual 0f
deliverer.basic.pos.pitch mustEqual 0 deliverer.basic.pos.orient.y mustEqual 0f
deliverer.basic.pos.yaw mustEqual 33 deliverer.basic.pos.orient.z mustEqual 357.1875f
deliverer.basic.faction mustEqual PlanetSideEmpire.NC deliverer.basic.faction mustEqual PlanetSideEmpire.NC
deliverer.basic.unk mustEqual 4 deliverer.basic.unk mustEqual 4
deliverer.basic.player_guid mustEqual PlanetSideGUID(0) 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.x mustEqual 3674.0f
ams.basic.pos.coord.y mustEqual 2726.789f ams.basic.pos.coord.y mustEqual 2726.789f
ams.basic.pos.coord.z mustEqual 91.15625f ams.basic.pos.coord.z mustEqual 91.15625f
ams.basic.pos.roll mustEqual 0 ams.basic.pos.orient.x mustEqual 0f
ams.basic.pos.pitch mustEqual 0 ams.basic.pos.orient.y mustEqual 0f
ams.basic.pos.yaw mustEqual 0 ams.basic.pos.orient.z mustEqual 90.0f
ams.basic.faction mustEqual PlanetSideEmpire.VS ams.basic.faction mustEqual PlanetSideEmpire.VS
ams.basic.unk mustEqual 0 ams.basic.unk mustEqual 0
ams.basic.player_guid mustEqual PlanetSideGUID(34082) 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.x mustEqual 3674.0f
dams.pos.coord.y mustEqual 2726.789f dams.pos.coord.y mustEqual 2726.789f
dams.pos.coord.z mustEqual 91.15625f dams.pos.coord.z mustEqual 91.15625f
dams.pos.roll mustEqual 0 dams.pos.orient.x mustEqual 0f
dams.pos.pitch mustEqual 0 dams.pos.orient.y mustEqual 0f
dams.pos.yaw mustEqual 0 dams.pos.orient.z mustEqual 90.0f
case _ => case _ =>
ko ko
} }
@ -274,9 +274,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
switchblade.basic.pos.coord.x mustEqual 6531.961f switchblade.basic.pos.coord.x mustEqual 6531.961f
switchblade.basic.pos.coord.y mustEqual 1872.1406f switchblade.basic.pos.coord.y mustEqual 1872.1406f
switchblade.basic.pos.coord.z mustEqual 24.734375f switchblade.basic.pos.coord.z mustEqual 24.734375f
switchblade.basic.pos.roll mustEqual 0 switchblade.basic.pos.orient.x mustEqual 0f
switchblade.basic.pos.pitch mustEqual 0 switchblade.basic.pos.orient.y mustEqual 0f
switchblade.basic.pos.yaw mustEqual 33 switchblade.basic.pos.orient.z mustEqual 357.1875f
switchblade.basic.faction mustEqual PlanetSideEmpire.VS switchblade.basic.faction mustEqual PlanetSideEmpire.VS
switchblade.basic.unk mustEqual 4 switchblade.basic.unk mustEqual 4
switchblade.health mustEqual 255 switchblade.health mustEqual 255
@ -321,9 +321,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
droppod.basic.pos.coord.x mustEqual 5108.0f droppod.basic.pos.coord.x mustEqual 5108.0f
droppod.basic.pos.coord.y mustEqual 6164.0f droppod.basic.pos.coord.y mustEqual 6164.0f
droppod.basic.pos.coord.z mustEqual 1023.9844f droppod.basic.pos.coord.z mustEqual 1023.9844f
droppod.basic.pos.roll mustEqual 0 droppod.basic.pos.orient.x mustEqual 0f
droppod.basic.pos.pitch mustEqual 0 droppod.basic.pos.orient.y mustEqual 0f
droppod.basic.pos.yaw mustEqual 0 droppod.basic.pos.orient.z mustEqual 90.0f
droppod.basic.unk mustEqual 4 droppod.basic.unk mustEqual 4
droppod.basic.player_guid mustEqual PlanetSideGUID(0) droppod.basic.player_guid mustEqual PlanetSideGUID(0)
droppod.burn mustEqual false droppod.burn mustEqual false
@ -366,9 +366,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
shuttle.pos.get.coord.x mustEqual 5610.0156f shuttle.pos.get.coord.x mustEqual 5610.0156f
shuttle.pos.get.coord.y mustEqual 4255.258f shuttle.pos.get.coord.y mustEqual 4255.258f
shuttle.pos.get.coord.z mustEqual 134.1875f shuttle.pos.get.coord.z mustEqual 134.1875f
shuttle.pos.get.roll mustEqual 0 shuttle.pos.get.orient.x mustEqual 0f
shuttle.pos.get.pitch mustEqual 0 shuttle.pos.get.orient.y mustEqual 0f
shuttle.pos.get.yaw mustEqual 96 shuttle.pos.get.orient.z mustEqual 180.0f
case _ => case _ =>
ko ko
} }
@ -377,7 +377,7 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (fury)" in { "encode (fury)" in {
val obj = VehicleData( val obj = VehicleData(
CommonFieldData( 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 PlanetSideEmpire.VS, 4
), ),
255, 255,
@ -394,7 +394,7 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (ant)" in { "encode (ant)" in {
val obj = ANTData( val obj = ANTData(
CommonFieldData( CommonFieldData(
PlacementData(3674.8438f, 2726.789f, 91.15625f), PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 4 PlanetSideEmpire.VS, 4
), ),
255, 255,
@ -409,7 +409,7 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (lightning)" in { "encode (lightning)" in {
val obj = VehicleData( val obj = VehicleData(
CommonFieldData( CommonFieldData(
PlacementData(3674.8438f, 2726.789f, 91.15625f), PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 4 PlanetSideEmpire.VS, 4
), ),
255, 255,
@ -423,10 +423,10 @@ class ObjectCreateMessageVehiclesTest extends Specification {
pkt mustEqual string_lightning pkt mustEqual string_lightning
} }
"encode (deliverer)" in { "encode (medium transport)" in {
val obj = VehicleData( val obj = VehicleData(
CommonFieldData( 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 PlanetSideEmpire.NC, 4
), ),
0, 0,
@ -455,7 +455,8 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (ams)" in { "encode (ams)" in {
val obj = AMSData( 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, PlanetSideEmpire.VS, 0,
PlanetSideGUID(34082) PlanetSideGUID(34082)
), ),
@ -476,17 +477,19 @@ class ObjectCreateMessageVehiclesTest extends Specification {
} }
"encode (ams, destroyed)" in { "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 msg = ObjectCreateMessage(ObjectClass.ams_destroyed, PlanetSideGUID(4157), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ams_destroyed pkt mustEqual string_ams_destroyed
} }
"encode (switchblade(" in { "encode (switchblade)" in {
val obj = Vehicle2Data( val obj = Vehicle2Data(
CommonFieldData(PlacementData(6531.961f, 1872.1406f, 24.734375f ,0 ,0 ,33), CommonFieldData(
PlanetSideEmpire.VS, 4 PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
PlanetSideEmpire.VS,
4
), ),
255, 255,
DriveState.Mobile, DriveState.Mobile,
@ -503,8 +506,9 @@ class ObjectCreateMessageVehiclesTest extends Specification {
"encode (droppod)" in { "encode (droppod)" in {
val obj = DroppodData( val obj = DroppodData(
CommonFieldData( CommonFieldData(
PlacementData(5108.0f, 6164.0f, 1023.9844f), PlacementData(5108.0f, 6164.0f, 1023.9844f, 0f, 0f, 90.0f),
PlanetSideEmpire.VS, 4 PlanetSideEmpire.VS,
4
) )
) )
val msg = ObjectCreateMessage(ObjectClass.droppod, PlanetSideGUID(3595), obj) val msg = ObjectCreateMessage(ObjectClass.droppod, PlanetSideGUID(3595), obj)
@ -522,7 +526,7 @@ class ObjectCreateMessageVehiclesTest extends Specification {
} }
"encode (shuttle 2)" in { "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 msg = ObjectCreateMessage(ObjectClass.orbital_shuttle, PlanetSideGUID(1127), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector

View file

@ -18,16 +18,16 @@ class ObjectDetachMessageTest extends Specification {
pos.x mustEqual 3567.1406f pos.x mustEqual 3567.1406f
pos.y mustEqual 2988.0078f pos.y mustEqual 2988.0078f
pos.z mustEqual 71.84375f pos.z mustEqual 71.84375f
roll mustEqual 0 roll mustEqual 0f
pitch mustEqual 0 pitch mustEqual 0f
yaw mustEqual 64 yaw mustEqual 270f
case _ => case _ =>
ko ko
} }
} }
"encode" in { "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 val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string pkt mustEqual string

View file

@ -20,9 +20,9 @@ class PlayerStateMessageTest extends Specification {
pos.y mustEqual 5981.414f pos.y mustEqual 5981.414f
pos.z mustEqual 44.875f pos.z mustEqual 44.875f
vel.isDefined mustEqual false vel.isDefined mustEqual false
facingYaw mustEqual 31 facingYaw mustEqual 2.8125f
facingPitch mustEqual 0 facingPitch mustEqual 0f
facingUpper mustEqual 0 facingUpper mustEqual 0f
unk1 mustEqual 83 unk1 mustEqual 83
crouching mustEqual false crouching mustEqual false
jumping mustEqual false jumping mustEqual false
@ -41,9 +41,9 @@ class PlayerStateMessageTest extends Specification {
pos.y mustEqual 5981.414f pos.y mustEqual 5981.414f
pos.z mustEqual 44.875f pos.z mustEqual 44.875f
vel.isDefined mustEqual false vel.isDefined mustEqual false
facingYaw mustEqual 31 facingYaw mustEqual 2.8125f
facingPitch mustEqual 0 facingPitch mustEqual 0f
facingUpper mustEqual 0 facingUpper mustEqual 0f
unk1 mustEqual 83 unk1 mustEqual 83
crouching mustEqual false crouching mustEqual false
jumping mustEqual true jumping mustEqual true
@ -65,9 +65,9 @@ class PlayerStateMessageTest extends Specification {
vel.get.x mustEqual 2.53125f vel.get.x mustEqual 2.53125f
vel.get.y mustEqual 6.5625f vel.get.y mustEqual 6.5625f
vel.get.z mustEqual 0.0f vel.get.z mustEqual 0.0f
facingYaw mustEqual 24 facingYaw mustEqual 22.5f
facingPitch mustEqual 4 facingPitch mustEqual 348.75f
facingUpper mustEqual 0 facingUpper mustEqual 0f
unk1 mustEqual 165 unk1 mustEqual 165
crouching mustEqual false crouching mustEqual false
jumping mustEqual false jumping mustEqual false
@ -83,7 +83,7 @@ class PlayerStateMessageTest extends Specification {
PlanetSideGUID(1696), PlanetSideGUID(1696),
Vector3(4003.7422f, 5981.414f, 44.875f), Vector3(4003.7422f, 5981.414f, 44.875f),
None, None,
31, 0, 0, 83, 2.8125f, 0f, 0f, 83,
false, false, false, false) false, false, false, false)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_short pkt mustEqual string_short
@ -94,7 +94,7 @@ class PlayerStateMessageTest extends Specification {
PlanetSideGUID(1696), PlanetSideGUID(1696),
Vector3(4003.7422f, 5981.414f, 44.875f), Vector3(4003.7422f, 5981.414f, 44.875f),
None, None,
31, 0, 0, 83, 2.8125f, 0f, 0f, 83,
false, true, false, true) false, true, false, true)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_mod pkt mustEqual string_mod
@ -105,7 +105,7 @@ class PlayerStateMessageTest extends Specification {
PlanetSideGUID(1696), PlanetSideGUID(1696),
Vector3(4008.6016f, 5987.6016f, 44.1875f), Vector3(4008.6016f, 5987.6016f, 44.1875f),
Some(Vector3(2.53125f, 6.5625f, 0f)), Some(Vector3(2.53125f, 6.5625f, 0f)),
24, 4, 0, 165, 22.5f, 348.75f, 0f, 165,
false, false, false, false) false, false, false, false)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_vel pkt mustEqual string_vel

View file

@ -16,9 +16,9 @@ class PlayerStateMessageUpstreamTest extends Specification {
avatar_guid mustEqual PlanetSideGUID(75) avatar_guid mustEqual PlanetSideGUID(75)
pos mustEqual Vector3(3694.1094f, 2735.4531f, 90.84375f) pos mustEqual Vector3(3694.1094f, 2735.4531f, 90.84375f)
vel mustEqual Some(Vector3(4.375f, 2.59375f, 0.0f)) vel mustEqual Some(Vector3(4.375f, 2.59375f, 0.0f))
facingYaw mustEqual 10 facingYaw mustEqual 61.875f
facingPitch mustEqual 3 facingPitch mustEqual 351.5625f
facingYawUpper mustEqual 0 facingYawUpper mustEqual 0.0f
seq_time mustEqual 136 seq_time mustEqual 136
unk1 mustEqual 0 unk1 mustEqual 0
is_crouching mustEqual false is_crouching mustEqual false
@ -33,7 +33,7 @@ class PlayerStateMessageUpstreamTest extends Specification {
} }
"encode" in { "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 val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string pkt mustEqual string

View file

@ -9,7 +9,7 @@ import scodec.bits._
class PlayerStateShiftMessageTest extends Specification { class PlayerStateShiftMessageTest extends Specification {
val string_short = hex"BE 68" 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" val string_posAndVel = hex"BE AE 01 29 CD 59 B9 40 C0 EA D4 00 0F 86 40"
"decode (short)" in { "decode (short)" in {
@ -31,7 +31,7 @@ class PlayerStateShiftMessageTest extends Specification {
state.get.pos.x mustEqual 4624.703f state.get.pos.x mustEqual 4624.703f
state.get.pos.y mustEqual 5922.1484f state.get.pos.y mustEqual 5922.1484f
state.get.pos.z mustEqual 46.171875f state.get.pos.z mustEqual 46.171875f
state.get.viewYawLim mustEqual 255 state.get.viewYawLim mustEqual 92.8125f
state.get.vel.isDefined mustEqual false state.get.vel.isDefined mustEqual false
unk.isDefined mustEqual false unk.isDefined mustEqual false
case _ => case _ =>
@ -47,7 +47,7 @@ class PlayerStateShiftMessageTest extends Specification {
state.get.pos.x mustEqual 4645.75f state.get.pos.x mustEqual 4645.75f
state.get.pos.y mustEqual 5811.6016f state.get.pos.y mustEqual 5811.6016f
state.get.pos.z mustEqual 50.3125f 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.isDefined mustEqual true
state.get.vel.get.x mustEqual 2.8125f state.get.vel.get.x mustEqual 2.8125f
state.get.vel.get.y mustEqual -8.0f state.get.vel.get.y mustEqual -8.0f
@ -66,14 +66,14 @@ class PlayerStateShiftMessageTest extends Specification {
} }
"encode (pos)" in { "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 val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_pos pkt mustEqual string_pos
} }
"encode (pos and vel)" in { "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 val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_posAndVel pkt mustEqual string_posAndVel

View file

@ -12,15 +12,15 @@ class VehicleStateMessageTest extends Specification {
"decode" in { "decode" in {
PacketCoding.DecodePacket(string).require match { 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) guid mustEqual PlanetSideGUID(413)
unk1 mustEqual 0 unk1 mustEqual 0
pos.x mustEqual 3674.8438f pos.x mustEqual 3674.8438f
pos.y mustEqual 2726.789f pos.y mustEqual 2726.789f
pos.z mustEqual 91.09375f pos.z mustEqual 91.09375f
roll mustEqual 359.29688f ang.x mustEqual 359.29688f
pitch mustEqual 1.0546875f ang.y mustEqual 1.0546875f
yaw mustEqual 90.35156f ang.z mustEqual 90.35156f
vel.isDefined mustEqual true vel.isDefined mustEqual true
vel.get.x mustEqual 0.0f vel.get.x mustEqual 0.0f
vel.get.y mustEqual 0.0f vel.get.y mustEqual 0.0f
@ -41,7 +41,7 @@ class VehicleStateMessageTest extends Specification {
PlanetSideGUID(413), PlanetSideGUID(413),
0, 0,
Vector3(3674.8438f, 2726.789f, 91.09375f), 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)), Some(Vector3(0.0f, 0.0f, 0.03125f)),
None, None,
0, 0, 15, 0, 0, 15,

View file

@ -1,6 +1,4 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
import java.net.{InetAddress, InetSocketAddress}
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware} import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
import net.psforever.packet.{PlanetSideGamePacket, _} import net.psforever.packet.{PlanetSideGamePacket, _}
import net.psforever.packet.control._ import net.psforever.packet.control._
@ -31,8 +29,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
def receive = Initializing def receive = Initializing
def Initializing : Receive = { def Initializing : Receive = {
case HelloFriend(sessionId, right) => case HelloFriend(inSessionId, right) =>
this.sessionId = sessionId this.sessionId = inSessionId
leftRef = sender() leftRef = sender()
rightRef = right.asInstanceOf[ActorRef] rightRef = right.asInstanceOf[ActorRef]
@ -81,7 +79,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
handlePkt(v) handlePkt(v)
} }
case sync @ ControlSync(diff, unk, f1, f2, f3, f4, fa, fb) => 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 val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error
sendResponse(PacketCoding.CreateControlPacket(ControlSyncResp(diff, serverTick, sendResponse(PacketCoding.CreateControlPacket(ControlSyncResp(diff, serverTick,
fa, fb, fb, fa))) fa, fb, fb, fa)))
@ -113,8 +111,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
val app = CharacterAppearanceData( val app = CharacterAppearanceData(
PlacementData( PlacementData(
Vector3(3674.8438f, 2726.789f, 91.15625f), Vector3(3674.8438f, 2726.789f, 91.15625f),
0, 0, Vector3(0f, 0f, 90f)
19
), ),
BasicCharacterData( BasicCharacterData(
"IlllIIIlllIlIllIlllIllI", "IlllIIIlllIlIllIlllIllI",
@ -166,9 +163,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match { def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match {
case ConnectToWorldRequestMessage(server, token, majorVersion, minorVersion, revision, buildDate, unk) => 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 // ObjectCreateMessage
sendResponse(PacketCoding.CreateGamePacket(0, objectHex)) 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, CreateShortcutMessage(guid, 1, 0, true, Shortcut.MEDKIT)))
sendResponse(PacketCoding.CreateGamePacket(0, ReplicationStreamMessage(5, Some(6), Vector(SquadListing())))) //clear squad list 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.duration._
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
clientKeepAlive = context.system.scheduler.schedule(0 seconds, 500 milliseconds, self, PokeClient()) clientKeepAlive = context.system.scheduler.schedule(0 seconds, 500 milliseconds, self, PokeClient())
@ -249,13 +258,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ BeginZoningMessage() => case msg @ BeginZoningMessage() =>
log.info("Reticulating splines ...") 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) //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) //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) //log.info("VehicleState: " + msg)
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vector, unk1, unk2, unk3, unk4, time_alive) => 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) => case msg @ TargetingImplantRequest(list) =>
log.info("TargetingImplantRequest: "+msg) log.info("TargetingImplantRequest: "+msg)
case default => log.error(s"Unhandled GamePacket ${pkt}") case default => log.error(s"Unhandled GamePacket $pkt")
} }
def failWithError(error : String) = { def failWithError(error : String) = {