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
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Angular
import scodec.Codec
import scodec.codecs._
@ -16,18 +17,12 @@ import scodec.codecs._
* The only concern is the direction the object is facing.
* The angles are relative to the object's normal forward-facing and typically begin tracking at 0, 0 (forward-facing).
* @param object_guid the object being manipulated (controlled)
* @param pitch the angle with respect to the sky and the ground towards which the object is directed;
* an 8-bit unsigned value;
* 0 is perfectly level and forward-facing and mapped to 255;
* positive rotation is downwards from forward-facing
* @param yaw the angle with respect to the horizon towards which the object is directed;
* an 8-bit unsigned value;
* 0 is forward-facing, wrapping around at 127;
* positive rotation is counter-clockwise of forward-facing
* @param pitch the amount of pitch that affects orientation from forward facing (0)
* @param yaw the amount of yaw that affects orientation from forward-facing (0)
*/
final case class ChildObjectStateMessage(object_guid : PlanetSideGUID,
pitch : Int,
yaw : Int)
pitch : Float,
yaw : Float)
extends PlanetSideGamePacket {
type Packet = ChildObjectStateMessage
def opcode = GamePacketOpcode.ChildObjectStateMessage
@ -37,7 +32,7 @@ final case class ChildObjectStateMessage(object_guid : PlanetSideGUID,
object ChildObjectStateMessage extends Marshallable[ChildObjectStateMessage] {
implicit val codec : Codec[ChildObjectStateMessage] = (
("object_guid" | PlanetSideGUID.codec) ::
("pitch" | uint8L) ::
("yaw" | uint8L)
("pitch" | Angular.codec_pitch) ::
("yaw" | Angular.codec_yaw(0f))
).as[ChildObjectStateMessage]
}

View file

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

View file

@ -3,7 +3,7 @@ package net.psforever.packet.game
import net.psforever.newcodecs.newcodecs
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3
import net.psforever.types.{Angular, Vector3}
import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
@ -20,7 +20,7 @@ import shapeless.{::, HNil}
* <br>
* The avatar model normally moves from where it "currently" is to `pos`.
* When `vel` is defined, `pos` is treated as where the avatar model starts its animation.
* In that case, it sppears to teleport to `pos` to carry out the interpolated movement according to `vel`.
* In that case, it appears to teleport to `pos` to carry out the interpolated movement according to `vel`.
* After the move, it remains at essentially `pos + vel * t`.
* The repositioning always takes the same amount of time.
* The player model is left in a walking/running animation (in place) until directed otherwise.<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.
* The climbing player is frequently reported by the other to appear to bounce over that player's head.
* If the other player is off the ground, passing too near to the observer can cause a rubber band effect on trajectory.
* This effect is entirely client-side to the observer and affects the moving player in no way.<br>
* <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
*
* This effect is entirely client-side to the observer and affects the moving player in no way.
* @param guid the avatar's guid
* @param pos the position of the avatar in the world environment (in three coordinates)
* @param vel an optional velocity
* @param facingYaw the angle with respect to the horizon towards which the avatar is looking;
* the model's whole body is facing this direction;
* measurements are counter-clockwise from East
* @param facingPitch the angle with respect to the sky and the ground towards which the avatar is looking
* @param facingYawUpper the angle of the avatar's upper body with respect to its forward-facing direction
* @param facingYaw a "yaw" angle
* @param facingPitch a "pitch" angle
* @param facingYawUpper a "yaw" angle that represents the angle of the avatar's upper body with respect to its forward-facing direction;
* this number is normally 0 for forward facing;
* the range is limited between approximately 61 degrees of center turned to left or right
* @param unk1 na
* @param is_crouching avatar is crouching
* @param is_jumping avatar is jumping;
@ -72,9 +48,9 @@ import shapeless.{::, HNil}
final case class PlayerStateMessage(guid : PlanetSideGUID,
pos : Vector3,
vel : Option[Vector3],
facingYaw : Int,
facingPitch : Int,
facingYawUpper : Int,
facingYaw : Float,
facingPitch : Float,
facingYawUpper : Float,
unk1 : Int,
is_crouching : Boolean = false,
is_jumping : Boolean = false,
@ -117,9 +93,9 @@ object PlayerStateMessage extends Marshallable[PlayerStateMessage] {
("guid" | PlanetSideGUID.codec) ::
("pos" | Vector3.codec_pos) ::
optional(bool, "vel" | Vector3.codec_vel) ::
("facingYaw" | uint8L) ::
("facingPitch" | uint8L) ::
("facingYawUpper" | uint8L) ::
("facingYaw" | Angular.codec_yaw()) ::
("facingPitch" | Angular.codec_pitch) ::
("facingYawUpper" | Angular.codec_yaw(0f)) ::
("unk1" | uintL(10)) ::
(bool >>:~ { fourBools =>
newcodecs.binary_choice(!fourBools, booleanCodec, defaultCodec)

View file

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

View file

@ -2,8 +2,8 @@
package net.psforever.packet.game
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3
import scodec.{Attempt, Codec, Err}
import net.psforever.types.{Angular, Vector3}
import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
@ -16,23 +16,25 @@ import shapeless.{::, HNil}
* This external force is not accumulative.
* Also, the external force is only applied once the avatar is set to the provided position.<br>
* <br>
* `viewYawLim` defines a "range of angles" that the avatar may look centered on the supplied angle.
* The avatar must be facing within 60-degrees of that direction, subjectively his left or his right.
* The avatar's view is immediately set to the closest 60-degree mark if it is outside of that range.
* The absolute angular displacement of the avatar is considered before applying this corrective behavior.
* After rotating any number of times:
* stopping in a valid part of the range is acceptable;
* stopping in an invalid part of the range will cause the avatar to align to the __earliest__ still-valid 60-degree mark.
* For that reason, even if the avatar's final angle is closest to the "left mark," it may re-align to the "right mark."
* This also resets the avatar's angular displacement.
* The angle defines the center of a range of angles that count as "in front of the avatar."
* Specifically, this range is the upper body's turn limit.
* A stationary player may look left and right, rotating their upper body only, until they hit a certain angle.
* Normally, the player's whole body will then turn to accommodate turning further than this angle.
* This packet marks that limit as a hard limit for rotation and will reset the player's model and camera if necessary.
* While it is in effect, the player will not turn their whole body once they can no longer turn their upper body.
* @param unk na
* @param pos the position to move the character to in the world environment
* @param viewYawLim an angle with respect to the horizon towards which the avatar is looking (to some respect)
* @param viewYawLim the center of the range of upper body angles, the player's actual yaw;
* if this value is beyond its angular limit values,
* the model will attempt to snap to what it considers the closest upper body turning limit angle;
* the actual range is approximately `viewYawLimit +/- 61.8215`;
* @param vel if defined, the velocity to apply to to the character at the given position
* @see `PlayerStateMessageUpstream.facingYawUpper`
* @see `PlayerStateMessage.facingYawUpper`
*/
final case class ShiftState(unk : Int,
pos : Vector3,
viewYawLim : Int,
viewYawLim : Float,
vel : Option[Vector3])
/**
@ -55,7 +57,7 @@ final case class PlayerStateShiftMessage(state : Option[ShiftState],
def encode = PlayerStateShiftMessage.encode(this)
}
object ShiftState extends Marshallable[ShiftState] {
object ShiftState {
/**
* An abbreviated constructor for creating `ShiftState`, assuming velocity is not applied.
* @param unk na
@ -64,7 +66,7 @@ object ShiftState extends Marshallable[ShiftState] {
* @param vel the velocity to apply to to the character at the given position
* @return a `ShiftState` object
*/
def apply(unk : Int, pos : Vector3, viewYawLim : Int, vel : Vector3) : ShiftState =
def apply(unk : Int, pos : Vector3, viewYawLim : Float, vel : Vector3) : ShiftState =
ShiftState(unk, pos, viewYawLim, Some(vel))
/**
@ -74,24 +76,8 @@ object ShiftState extends Marshallable[ShiftState] {
* @param viewYawLim an angle with respect to the horizon towards which the avatar is looking (to some respect)
* @return a `ShiftState` object
*/
def apply(unk : Int, pos : Vector3, viewYawLim : Int) : ShiftState =
def apply(unk : Int, pos : Vector3, viewYawLim : Float) : ShiftState =
ShiftState(unk, pos, viewYawLim, None)
implicit val codec : Codec[ShiftState] = (
("unk1" | uintL(3)) ::
("pos" | Vector3.codec_pos) ::
("viewYawLim" | uint8L) ::
optional(bool, "pos" | Vector3.codec_vel)
).xmap[ShiftState] (
{
case a :: b :: c :: d :: HNil =>
ShiftState(a, b, c, d)
},
{
case ShiftState(a, b, c, d) =>
a :: b :: c :: d :: HNil
}
).as[ShiftState]
}
object PlayerStateShiftMessage extends Marshallable[PlayerStateShiftMessage] {
@ -120,8 +106,30 @@ object PlayerStateShiftMessage extends Marshallable[PlayerStateShiftMessage] {
def apply(unk : Int) : PlayerStateShiftMessage =
PlayerStateShiftMessage(None, Some(unk))
private val shift_codec : Codec[ShiftState] = (
/*
IMPORTANT:
Packet data indicates that viewYawLimit is an 8u value.
When read as an 8u value, the resulting number does not map to directions properly.
As a 7u value, the numbers maps better so the first bit will be ignored.
*/
("unk" | uintL(3)) ::
("pos" | Vector3.codec_pos) ::
("viewYawLim" | Angular.codec_yaw()) ::
optional(bool, "pos" | Vector3.codec_vel)
).xmap[ShiftState] (
{
case a :: b :: c :: d :: HNil =>
ShiftState(a, b, c, d)
},
{
case ShiftState(a, b, c, d) =>
a :: b :: c :: d :: HNil
}
).as[ShiftState]
implicit val codec : Codec[PlayerStateShiftMessage] = (
optional(bool, "state" | ShiftState.codec) ::
optional(bool, "state" | shift_codec) ::
optional(bool, "unk" | uintL(3))
).xmap[PlayerStateShiftMessage] (
{

View file

@ -1,12 +1,10 @@
// Copyright (c) 2017 PSForever
package net.psforever.packet.game
import net.psforever.newcodecs.newcodecs
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.Vector3
import net.psforever.types.{Angular, Vector3}
import scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
//TODO write more thorough comments later.
/**
@ -14,15 +12,7 @@ import shapeless.{::, HNil}
* @param vehicle_guid the vehicle
* @param unk1 na
* @param pos the xyz-coordinate location in the world
* @param roll the amount of roll that affects orientation;
* 0.0f is flat to the ground;
* roll-right rotation increases angle
* @param pitch the amount of pitch that affects orientation;
* 0.0f is flat to the ground;
* front-up rotation increases angle
* @param yaw the amount of yaw that affects orientation;
* 0.0f is North (before the correction, 0.0f is East);
* clockwise rotation increases angle
* @param ang the orientation of the vehicle
* @param vel optional movement data
* @param unk2 na
* @param unk3 na
@ -38,9 +28,7 @@ import shapeless.{::, HNil}
final case class VehicleStateMessage(vehicle_guid : PlanetSideGUID,
unk1 : Int,
pos : Vector3,
roll : Float,
pitch : Float,
yaw : Float,
ang : Vector3,
vel : Option[Vector3],
unk2 : Option[Int],
unk3 : Int,
@ -55,13 +43,23 @@ final case class VehicleStateMessage(vehicle_guid : PlanetSideGUID,
}
object VehicleStateMessage extends Marshallable[VehicleStateMessage] {
/**
* Calculate common orientation from little-endian bit data.
* @see `Angular.codec_roll`
* @see `Angular.codec_pitch`
* @see `Angular.codec_yaw`
*/
private val codec_orient : Codec[Vector3] = (
("roll" | Angular.codec_roll(10)) ::
("pitch" | Angular.codec_pitch(10)) ::
("yaw" | Angular.codec_yaw(10, 90f))
).as[Vector3]
implicit val codec : Codec[VehicleStateMessage] = (
("vehicle_guid" | PlanetSideGUID.codec) ::
("unk1" | uintL(3)) ::
("pos" | Vector3.codec_pos) ::
("roll" | newcodecs.q_float(0.0f, 360.0f, 10)) ::
("pitch" | newcodecs.q_float(360.0f, 0.0f, 10)) ::
("yaw" | newcodecs.q_float(360.0f, 0.0f, 10)) ::
("ang" | codec_orient) ::
optional(bool, "vel" | Vector3.codec_vel) ::
optional(bool, "unk2" | uintL(5)) ::
("unk3" | uintL(7)) ::
@ -69,27 +67,5 @@ object VehicleStateMessage extends Marshallable[VehicleStateMessage] {
("wheel_direction" | uintL(5)) ::
("int5" | bool) ::
("int6" | bool)
).xmap[VehicleStateMessage] (
{
case guid :: u1 :: pos :: roll :: pitch :: yaw :: vel :: u2 :: u3 :: u4 :: wheel :: u5 :: u6 :: HNil =>
var northCorrectedYaw : Float = yaw + 90f
if(northCorrectedYaw > 360f) {
northCorrectedYaw = northCorrectedYaw - 360f
}
VehicleStateMessage(guid, u1, pos, roll, pitch, northCorrectedYaw, vel, u2, u3, u4, wheel, u5, u6)
},
{
case VehicleStateMessage(guid, u1, pos, roll, pitch, yaw, vel, u2, u3, u4, wheel, u5, u6) =>
var northCorrectedYaw : Float = yaw - 90f
//TODO this invites imprecision
while(northCorrectedYaw < 0f) {
northCorrectedYaw = 360f + northCorrectedYaw
}
if(northCorrectedYaw > 360f) {
northCorrectedYaw = northCorrectedYaw % 360f
}
guid :: u1 :: pos :: roll :: pitch :: northCorrectedYaw :: vel :: u2 :: u3 :: u4 :: wheel :: u5 :: u6 :: HNil
}
)
).as[VehicleStateMessage]
}

View file

@ -2,7 +2,7 @@
package net.psforever.packet.game.objectcreate
import net.psforever.packet.{Marshallable, PacketHelpers}
import net.psforever.types.{CharacterGender, ExoSuitType, GrenadeState, PlanetSideEmpire}
import net.psforever.types._
import scodec.{Attempt, Codec, Err}
import scodec.codecs._
import shapeless.{::, HNil}
@ -74,8 +74,10 @@ final case class BasicCharacterData(name : String,
* if the option is selected, allies with see either "[`outfit_name`]" or "{No Outfit}" under the player's name
* @param outfit_logo the decal seen on the player's exo-suit (and beret and cap) associated with the player's outfit;
* if there is a variable color for that decal, the faction-appropriate one is selected
* @param facingPitch the angle with respect to the sky and the ground towards which the avatar is looking
* @param facingYawUpper the angle of the avatar's upper body with respect to its forward-facing direction
* @param facingPitch a "pitch" angle
* @param facingYawUpper a "yaw" angle that represents the angle of the avatar's upper body with respect to its forward-facing direction;
* this number is normally 0 for forward facing;
* the range is limited between approximately 61 degrees of center turned to left or right
* @param lfs this player is looking for a squad;
* all allies will see the phrase "[Looking for Squad]" under the player's name
* @param is_cloaking avatar is cloaked by virtue of an Infiltration Suit
@ -101,8 +103,8 @@ final case class CharacterAppearanceData(pos : PlacementData,
outfit_name : String,
outfit_logo : Int,
backpack : Boolean,
facingPitch : Int,
facingYawUpper : Int,
facingPitch : Float,
facingYawUpper : Float,
lfs : Boolean,
grenade_state : GrenadeState.Value,
is_cloaking : Boolean,
@ -168,8 +170,8 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] {
ignore(1) :: //unknown
("backpack" | bool) :: //requires alt_model flag (does NOT require health == 0)
bool :: //stream misalignment when set
("facingPitch" | uint8L) ::
("facingYawUpper" | uint8L) ::
("facingPitch" | Angular.codec_pitch) ::
("facingYawUpper" | Angular.codec_yaw(0f)) ::
ignore(1) :: //unknown
conditional(alt_model, bool) :: //alt_model flag adds a bit before lfs
ignore(1) :: //an alternate lfs?

View file

@ -2,22 +2,19 @@
package net.psforever.packet.game.objectcreate
import net.psforever.packet.Marshallable
import net.psforever.types.Vector3
import net.psforever.types.{Angular, Vector3}
import scodec.codecs._
import scodec.Codec
import shapeless.{::, HNil}
/**
* A specific location and heading in game world coordinates and game world measurements.
* @param coord the xyz-coordinate location in the world
* @param roll the amount of roll that affects orientation
* @param pitch the amount of pitch that affects orientation
* @param yaw the amount of yaw that affects orientation
* @param orient the ijk-orientation around the object's center
* @param vel optional movement data (that occurs upon placement)
*/
final case class PlacementData(coord : Vector3,
roll : Int,
pitch : Int,
yaw : Int,
orient : Vector3,
vel : Option[Vector3] = None
) extends StreamBitSize {
override def bitsize : Long = {
@ -35,7 +32,7 @@ object PlacementData extends Marshallable[PlacementData] {
* @return a `PlacementData` object
*/
def apply(x : Float, y : Float, z : Float) : PlacementData =
new PlacementData(Vector3(x, y, z), 0, 0, 0)
new PlacementData(Vector3(x, y, z), Vector3(0f,0f,0f))
/**
* An abbreviated constructor for creating `PlacementData`, ignoring the `Vector3` for position data, supplying other important fields.
@ -47,8 +44,8 @@ object PlacementData extends Marshallable[PlacementData] {
* @param yaw the amount of yaw that affects orientation
* @return a `PlacementData` object
*/
def apply(x : Float, y : Float, z : Float, roll : Int, pitch : Int, yaw : Int) : PlacementData =
new PlacementData(Vector3(x, y, z), roll, pitch, yaw)
def apply(x : Float, y : Float, z : Float, roll : Float, pitch : Float, yaw : Float) : PlacementData =
new PlacementData(Vector3(x, y, z), Vector3(roll, pitch, yaw))
/**
* An abbreviated constructor for creating `PlacementData`, ignoring the `Vector3` for position data, supplying all other fields.
@ -61,14 +58,23 @@ object PlacementData extends Marshallable[PlacementData] {
* @param vel optional movement data that occurs upon placement
* @return a `PlacementData` object
*/
def apply(x : Float, y : Float, z : Float, roll : Int, pitch : Int, yaw : Int, vel : Vector3) : PlacementData =
new PlacementData(Vector3(x, y, z), roll, pitch, yaw, Some(vel))
def apply(x : Float, y : Float, z : Float, roll : Float, pitch : Float, yaw : Float, vel : Vector3) : PlacementData =
new PlacementData(Vector3(x, y, z), Vector3(roll, pitch, yaw), Some(vel))
implicit val codec : Codec[PlacementData] = (
("coord" | Vector3.codec_pos) ::
("roll" | uint8L) ::
("pitch" | uint8L) ::
("yaw" | uint8L) ::
("roll" | Angular.codec_roll) ::
("pitch" | Angular.codec_pitch) ::
("yaw" | Angular.codec_yaw()) ::
optional(bool, "vel" | Vector3.codec_vel)
).as[PlacementData]
).xmap[PlacementData] (
{
case xyz :: i :: j :: k :: vel :: HNil =>
PlacementData(xyz, Vector3(i, j, k), vel)
},
{
case PlacementData(xyz, Vector3(i, j, k), vel) =>
xyz :: i :: j :: k :: vel :: HNil
}
)
}

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 scodec.Codec
import scodec.codecs._
import shapeless.{::, HNil}
final case class Vector3(x : Float,
y : Float,

View file

@ -34,23 +34,190 @@ class CodecTest extends Specification {
}
"Vector3" should {
val string_pos = hex"6E2D762222B616"
val string_vel = hex"857D4E0FFFC0"
"position" should {
val string_pos = hex"6E2D762222B616"
"decode position" in {
Vector3.codec_pos.decode(string_pos.bits).require.value mustEqual Vector3(3674.859375f, 1092.7656f, 90.84375f)
"decode" in {
Vector3.codec_pos.decode(string_pos.bits).require.value mustEqual Vector3(3674.859375f, 1092.7656f, 90.84375f)
}
"encode" in {
Vector3.codec_pos.encode(Vector3(3674.859375f, 1092.7656f, 90.84375f)).require.bytes mustEqual string_pos
}
}
"encode position" in {
Vector3.codec_pos.encode(Vector3(3674.859375f, 1092.7656f, 90.84375f)).require.bytes mustEqual string_pos
"velocity" should {
val string_vel = hex"857D4E0FFFC0"
"decode" in {
Vector3.codec_vel.decode(string_vel.bits).require.value mustEqual Vector3(-3.84375f, 2.59375f, 255.96875f)
}
"encode" in {
Vector3.codec_vel.encode(Vector3(-3.84375f, 2.59375f, 255.96875f)).require.bytes mustEqual string_vel
}
}
}
"Angular" should {
"roll" should {
val string_roll_0 = hex"00"
val string_roll_90 = hex"20"
val string_roll_180 = hex"40"
val string_roll_270 = hex"60"
"decode (0)" in {
Angular.codec_roll.decode(string_roll_0.bits).require.value mustEqual 0f
}
"decode (90)" in {
Angular.codec_roll.decode(string_roll_90.bits).require.value mustEqual 90f
}
"decode (180)" in {
Angular.codec_roll.decode(string_roll_180.bits).require.value mustEqual 180f
}
"decode (270)" in {
Angular.codec_roll.decode(string_roll_270.bits).require.value mustEqual 270f
}
"encode (0)" in {
Angular.codec_roll.encode(0f).require.bytes mustEqual string_roll_0
}
"encode (90)" in {
Angular.codec_roll.encode(90f).require.bytes mustEqual string_roll_90
}
"encode (180)" in {
Angular.codec_roll.encode(180f).require.bytes mustEqual string_roll_180
}
"encode (270)" in {
Angular.codec_roll.encode(270f).require.bytes mustEqual string_roll_270
}
}
"decode velocity" in {
Vector3.codec_vel.decode(string_vel.bits).require.value mustEqual Vector3(-3.84375f, 2.59375f, 255.96875f)
"pitch" should {
val string_pitch_0 = hex"00"
val string_pitch_90 = hex"60"
val string_pitch_180 = hex"40"
val string_pitch_270 = hex"20"
"decode (0)" in {
Angular.codec_pitch.decode(string_pitch_0.bits).require.value mustEqual 0f
}
"decode (90)" in {
Angular.codec_pitch.decode(string_pitch_90.bits).require.value mustEqual 90f
}
"decode (180)" in {
Angular.codec_pitch.decode(string_pitch_180.bits).require.value mustEqual 180f
}
"decode (270)" in {
Angular.codec_pitch.decode(string_pitch_270.bits).require.value mustEqual 270f
}
"encode (0)" in {
Angular.codec_pitch.encode(0f).require.bytes mustEqual string_pitch_0
}
"encode (90)" in {
Angular.codec_pitch.encode(90f).require.bytes mustEqual string_pitch_90
}
"encode (180)" in {
Angular.codec_pitch.encode(180f).require.bytes mustEqual string_pitch_180
}
"encode (270)" in {
Angular.codec_pitch.encode(270f).require.bytes mustEqual string_pitch_270
}
}
"encode velocity" in {
Vector3.codec_vel.encode(Vector3(-3.84375f, 2.59375f, 255.96875f)).require.bytes mustEqual string_vel
"yaw, normal" should {
val string_pitch_0 = hex"00"
val string_pitch_90 = hex"60"
val string_pitch_180 = hex"40"
val string_pitch_270 = hex"20"
val string_yaw_0 = hex"20"
val string_yaw_90 = hex"00"
val string_yaw_180 = hex"60"
val string_yaw_270 = hex"40"
"decode (0)" in {
Angular.codec_yaw(0f).decode(string_yaw_0.bits).require.value mustEqual 270f
}
"decode (90)" in {
Angular.codec_yaw(0f).decode(string_yaw_90.bits).require.value mustEqual 0f
}
"decode (180)" in {
Angular.codec_yaw(0f).decode(string_yaw_180.bits).require.value mustEqual 90f
}
"decode (270)" in {
Angular.codec_yaw(0f).decode(string_yaw_270.bits).require.value mustEqual 180f
}
"encode (0)" in {
Angular.codec_yaw(0f).encode(0f).require.bytes mustEqual string_pitch_0
}
"encode (90)" in {
Angular.codec_yaw(0f).encode(90f).require.bytes mustEqual string_pitch_90
}
"encode (180)" in {
Angular.codec_yaw(0f).encode(180f).require.bytes mustEqual string_pitch_180
}
"encode (270)" in {
Angular.codec_yaw(0f).encode(270f).require.bytes mustEqual string_pitch_270
}
}
"yaw, North-corrected" should {
val string_yaw_0 = hex"20"
val string_yaw_90 = hex"00"
val string_yaw_180 = hex"60"
val string_yaw_270 = hex"40"
"decode (0)" in {
Angular.codec_yaw().decode(string_yaw_0.bits).require.value mustEqual 0f
}
"decode (90)" in {
Angular.codec_yaw().decode(string_yaw_90.bits).require.value mustEqual 90f
}
"decode (180)" in {
Angular.codec_yaw().decode(string_yaw_180.bits).require.value mustEqual 180f
}
"decode (270)" in {
Angular.codec_yaw().decode(string_yaw_270.bits).require.value mustEqual 270f
}
"encode (0)" in {
Angular.codec_yaw().encode(0f).require.bytes mustEqual string_yaw_0
}
"encode (90)" in {
Angular.codec_yaw().encode(90f).require.bytes mustEqual string_yaw_90
}
"encode (180)" in {
Angular.codec_yaw().encode(180f).require.bytes mustEqual string_yaw_180
}
"encode (270)" in {
Angular.codec_yaw().encode(270f).require.bytes mustEqual string_yaw_270
}
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,7 @@ import scodec.bits._
class PlayerStateShiftMessageTest extends Specification {
val string_short = hex"BE 68"
val string_pos = hex"BE 95 A0 89 13 91 B8 B0 BF F0"
val string_pos = hex"BE 95 A0 89 13 91 B8 B0 B7 F0" //orig: ... B0 BF F0
val string_posAndVel = hex"BE AE 01 29 CD 59 B9 40 C0 EA D4 00 0F 86 40"
"decode (short)" in {
@ -31,7 +31,7 @@ class PlayerStateShiftMessageTest extends Specification {
state.get.pos.x mustEqual 4624.703f
state.get.pos.y mustEqual 5922.1484f
state.get.pos.z mustEqual 46.171875f
state.get.viewYawLim mustEqual 255
state.get.viewYawLim mustEqual 92.8125f
state.get.vel.isDefined mustEqual false
unk.isDefined mustEqual false
case _ =>
@ -47,7 +47,7 @@ class PlayerStateShiftMessageTest extends Specification {
state.get.pos.x mustEqual 4645.75f
state.get.pos.y mustEqual 5811.6016f
state.get.pos.z mustEqual 50.3125f
state.get.viewYawLim mustEqual 14
state.get.viewYawLim mustEqual 50.625f
state.get.vel.isDefined mustEqual true
state.get.vel.get.x mustEqual 2.8125f
state.get.vel.get.y mustEqual -8.0f
@ -66,14 +66,14 @@ class PlayerStateShiftMessageTest extends Specification {
}
"encode (pos)" in {
val msg = PlayerStateShiftMessage(ShiftState(1, Vector3(4624.703f, 5922.1484f, 46.171875f), 255))
val msg = PlayerStateShiftMessage(ShiftState(1, Vector3(4624.703f, 5922.1484f, 46.171875f), 92.8125f))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_pos
}
"encode (pos and vel)" in {
val msg = PlayerStateShiftMessage(ShiftState(2, Vector3(4645.75f, 5811.6016f, 50.3125f), 14, Vector3(2.8125f, -8.0f, 0.375f)))
val msg = PlayerStateShiftMessage(ShiftState(2, Vector3(4645.75f, 5811.6016f, 50.3125f), 50.625f, Vector3(2.8125f, -8.0f, 0.375f)))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_posAndVel

View file

@ -12,15 +12,15 @@ class VehicleStateMessageTest extends Specification {
"decode" in {
PacketCoding.DecodePacket(string).require match {
case VehicleStateMessage(guid, unk1, pos, roll, pitch, yaw, vel, unk2, unk3, unk4, wheel, unk5, unk6) =>
case VehicleStateMessage(guid, unk1, pos, ang, vel, unk2, unk3, unk4, wheel, unk5, unk6) =>
guid mustEqual PlanetSideGUID(413)
unk1 mustEqual 0
pos.x mustEqual 3674.8438f
pos.y mustEqual 2726.789f
pos.z mustEqual 91.09375f
roll mustEqual 359.29688f
pitch mustEqual 1.0546875f
yaw mustEqual 90.35156f
ang.x mustEqual 359.29688f
ang.y mustEqual 1.0546875f
ang.z mustEqual 90.35156f
vel.isDefined mustEqual true
vel.get.x mustEqual 0.0f
vel.get.y mustEqual 0.0f
@ -41,7 +41,7 @@ class VehicleStateMessageTest extends Specification {
PlanetSideGUID(413),
0,
Vector3(3674.8438f, 2726.789f, 91.09375f),
359.29688f, 1.0546875f, 90.35156f,
Vector3(359.29688f, 1.0546875f, 90.35156f),
Some(Vector3(0.0f, 0.0f, 0.03125f)),
None,
0, 0, 15,

View file

@ -1,6 +1,4 @@
// Copyright (c) 2017 PSForever
import java.net.{InetAddress, InetSocketAddress}
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
import net.psforever.packet.{PlanetSideGamePacket, _}
import net.psforever.packet.control._
@ -31,8 +29,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
def receive = Initializing
def Initializing : Receive = {
case HelloFriend(sessionId, right) =>
this.sessionId = sessionId
case HelloFriend(inSessionId, right) =>
this.sessionId = inSessionId
leftRef = sender()
rightRef = right.asInstanceOf[ActorRef]
@ -81,7 +79,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
handlePkt(v)
}
case sync @ ControlSync(diff, unk, f1, f2, f3, f4, fa, fb) =>
log.debug(s"SYNC: ${sync}")
log.debug(s"SYNC: $sync")
val serverTick = Math.abs(System.nanoTime().toInt) // limit the size to prevent encoding error
sendResponse(PacketCoding.CreateControlPacket(ControlSyncResp(diff, serverTick,
fa, fb, fb, fa)))
@ -113,8 +111,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
val app = CharacterAppearanceData(
PlacementData(
Vector3(3674.8438f, 2726.789f, 91.15625f),
0, 0,
19
Vector3(0f, 0f, 90f)
),
BasicCharacterData(
"IlllIIIlllIlIllIlllIllI",
@ -166,9 +163,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match {
case ConnectToWorldRequestMessage(server, token, majorVersion, minorVersion, revision, buildDate, unk) =>
val clientVersion = s"Client Version: ${majorVersion}.${minorVersion}.${revision}, ${buildDate}"
val clientVersion = s"Client Version: $majorVersion.$minorVersion.$revision, $buildDate"
log.info(s"New world login to ${server} with Token:${token}. ${clientVersion}")
log.info(s"New world login to $server with Token:$token. $clientVersion")
// ObjectCreateMessage
sendResponse(PacketCoding.CreateGamePacket(0, objectHex))
@ -229,6 +226,18 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(PacketCoding.CreateGamePacket(0, CreateShortcutMessage(guid, 1, 0, true, Shortcut.MEDKIT)))
sendResponse(PacketCoding.CreateGamePacket(0, ReplicationStreamMessage(5, Some(6), Vector(SquadListing())))) //clear squad list
val fury = VehicleData(
CommonFieldData(
PlacementData(3674.8438f, 2732f, 91.15625f, 0.0f, 0.0f, 90.0f),
PlanetSideEmpire.VS, 4
),
255,
MountItem(ObjectClass.fury_weapon_systema, PlanetSideGUID(400), 1,
WeaponData(0x6, 0x8, 0, ObjectClass.hellfire_ammo, PlanetSideGUID(432), 0, AmmoBoxData(0x8))
)
)
sendResponse(PacketCoding.CreateGamePacket(0, ObjectCreateMessage(ObjectClass.fury, PlanetSideGUID(413), fury)))
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
clientKeepAlive = context.system.scheduler.schedule(0 seconds, 500 milliseconds, self, PokeClient())
@ -249,13 +258,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ BeginZoningMessage() =>
log.info("Reticulating splines ...")
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, unk1, aim_pitch, unk2, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yawUpper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) =>
//log.info("PlayerState: " + msg)
case msg @ ChildObjectStateMessage(object_guid : PlanetSideGUID, pitch : Int, yaw : Int) =>
case msg @ ChildObjectStateMessage(object_guid, pitch, yaw) =>
//log.info("ChildObjectState: " + msg)
case msg @ VehicleStateMessage(vehicle_guid, unk1, pos, roll, pitch, yaw, vel, unk5, unk6, unk7, wheels, unk9, unkA) =>
case msg @ VehicleStateMessage(vehicle_guid, unk1, pos, ang, vel, unk5, unk6, unk7, wheels, unk9, unkA) =>
//log.info("VehicleState: " + msg)
case msg @ ProjectileStateMessage(projectile_guid, shot_pos, shot_vector, unk1, unk2, unk3, unk4, time_alive) =>
@ -456,7 +465,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ TargetingImplantRequest(list) =>
log.info("TargetingImplantRequest: "+msg)
case default => log.error(s"Unhandled GamePacket ${pkt}")
case default => log.error(s"Unhandled GamePacket $pkt")
}
def failWithError(error : String) = {