mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-07-14 16:04:41 +00:00
initial work on PlayerStateShiftMessage packet and working tests
This commit is contained in:
parent
daa22c572e
commit
bf05592c91
3 changed files with 197 additions and 1 deletions
|
|
@ -543,7 +543,7 @@ object GamePacketOpcode extends Enumeration {
|
||||||
case 0xbb => noDecoder(MapObjectStateBlockMessage)
|
case 0xbb => noDecoder(MapObjectStateBlockMessage)
|
||||||
case 0xbc => noDecoder(SnoopMsg)
|
case 0xbc => noDecoder(SnoopMsg)
|
||||||
case 0xbd => game.PlayerStateMessageUpstream.decode
|
case 0xbd => game.PlayerStateMessageUpstream.decode
|
||||||
case 0xbe => noDecoder(PlayerStateShiftMessage)
|
case 0xbe => game.PlayerStateShiftMessage.decode
|
||||||
case 0xbf => noDecoder(ZipLineMessage)
|
case 0xbf => noDecoder(ZipLineMessage)
|
||||||
|
|
||||||
// OPCODES 0xc0-cf
|
// OPCODES 0xc0-cf
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright (c) 2016 PSForever.net to present
|
||||||
|
package net.psforever.packet.game
|
||||||
|
|
||||||
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
|
||||||
|
import net.psforever.types.Vector3
|
||||||
|
import scodec.Codec
|
||||||
|
import scodec.codecs._
|
||||||
|
import shapeless.{::, HNil}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param pos the position to move the character to in the world environment (in three coordinates)
|
||||||
|
* @param viewYawLim an angle with respect to the horizon towards which the avatar is looking (to some respect)
|
||||||
|
* @param vel the velocity to apply to to the character at the given position (in three coordinates)
|
||||||
|
*/
|
||||||
|
final case class PlayerState(pos : Vector3,
|
||||||
|
viewYawLim : Int,
|
||||||
|
vel : Option[Vector3])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force the client's character to adhere to the influence of specific external stimulus.
|
||||||
|
* @param unk1 na
|
||||||
|
* @param state the state to influence the character with respect to his environment in the current zone
|
||||||
|
|
||||||
|
*/
|
||||||
|
final case class PlayerStateShiftMessage(unk1 : Int,
|
||||||
|
state : Option[PlayerState],
|
||||||
|
unk2 : Boolean)
|
||||||
|
extends PlanetSideGamePacket {
|
||||||
|
type Packet = TimeOfDayMessage
|
||||||
|
def opcode = GamePacketOpcode.PlayerStateShiftMessage
|
||||||
|
def encode = PlayerStateShiftMessage.encode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object PlayerState extends Marshallable[PlayerState] {
|
||||||
|
/**
|
||||||
|
* An abbreviated constructor for creating `PlayerState`, assuming velocity is not applied.
|
||||||
|
* @param pos the position of the character in the world environment (in three coordinates)
|
||||||
|
* @param viewYawLim an angle with respect to the horizon towards which the avatar is looking (to some respect)
|
||||||
|
* @param vel the velocity to apply to to the character at the given position (in three coordinates)
|
||||||
|
* @return a `PlayerState` object
|
||||||
|
*/
|
||||||
|
def apply(pos : Vector3, viewYawLim : Int, vel : Vector3) : PlayerState =
|
||||||
|
PlayerState(pos, viewYawLim, Some(vel))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abbreviated constructor for creating `PlayerState`, removing the optional condition of all parameters.
|
||||||
|
* @param pos the position of the character in the world environment (in three coordinates)
|
||||||
|
* @param viewYawLim an angle with respect to the horizon towards which the avatar is looking (to some respect)
|
||||||
|
* @return a `PlayerState` object
|
||||||
|
*/
|
||||||
|
def apply(pos : Vector3, viewYawLim : Int) : PlayerState =
|
||||||
|
PlayerState(pos, viewYawLim, None)
|
||||||
|
|
||||||
|
implicit val codec : Codec[PlayerState] = (
|
||||||
|
("pos" | Vector3.codec_pos) ::
|
||||||
|
("unk2" | uint8L) ::
|
||||||
|
(bool >>:~ { test =>
|
||||||
|
ignore(0) ::
|
||||||
|
conditional(test, "pos" | Vector3.codec_vel)
|
||||||
|
})
|
||||||
|
).xmap[PlayerState] (
|
||||||
|
{
|
||||||
|
case a :: b :: false :: _ :: None :: HNil =>
|
||||||
|
PlayerState(a, b, None)
|
||||||
|
case a :: b :: true :: _ :: Some(vel) :: HNil =>
|
||||||
|
PlayerState(a, b, Some(vel))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case PlayerState(a, b, None) =>
|
||||||
|
a :: b :: false :: () :: None :: HNil
|
||||||
|
case PlayerState(a, b, Some(vel)) =>
|
||||||
|
a :: b :: true :: () :: Some(vel) :: HNil
|
||||||
|
}
|
||||||
|
).as[PlayerState]
|
||||||
|
}
|
||||||
|
|
||||||
|
object PlayerStateShiftMessage extends Marshallable[PlayerStateShiftMessage] {
|
||||||
|
private type pattern = Int :: Option[PlayerState] :: Boolean :: HNil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abbreviated constructor for creating `PlayerStateShiftMessage`, removing the optional condition of `state`.
|
||||||
|
* @param unk1 na
|
||||||
|
* @param state the state to which to influence the character with respect to his environment in the current zone
|
||||||
|
* @param unk2 na
|
||||||
|
* @return a `PlayerStateShiftMessage` packet
|
||||||
|
*/
|
||||||
|
def apply(unk1 : Int, state : PlayerState, unk2 : Boolean) : PlayerStateShiftMessage =
|
||||||
|
PlayerStateShiftMessage(unk1, Some(state), unk2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abbreviated constructor for creating `PlayerStateShiftMessage`, assuming the parameter `state` is not defined.
|
||||||
|
* @param unk1 na
|
||||||
|
* @param unk2 na
|
||||||
|
* @return a `PlayerStateShiftMessage` packet
|
||||||
|
*/
|
||||||
|
def apply(unk1 : Int, unk2 : Boolean) : PlayerStateShiftMessage =
|
||||||
|
PlayerStateShiftMessage(unk1, None, unk2)
|
||||||
|
|
||||||
|
implicit val codec : Codec[PlayerStateShiftMessage] = (
|
||||||
|
bool >>:~ { test1 =>
|
||||||
|
("unk1" | uintL(3)) ::
|
||||||
|
conditional(test1, "pos" | PlayerState.codec) ::
|
||||||
|
("unk2" | bool)
|
||||||
|
}).xmap[PlayerStateShiftMessage] (
|
||||||
|
{
|
||||||
|
case false :: a :: None :: b :: HNil =>
|
||||||
|
PlayerStateShiftMessage(a, None, b)
|
||||||
|
case true :: a :: Some(pos) :: b :: HNil =>
|
||||||
|
PlayerStateShiftMessage(a, Some(pos), b)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
case PlayerStateShiftMessage(a, None, b) =>
|
||||||
|
false :: a :: None :: b :: HNil
|
||||||
|
case PlayerStateShiftMessage(a, Some(pos), b) =>
|
||||||
|
true :: a :: Some(pos) :: b :: HNil
|
||||||
|
}
|
||||||
|
).as[PlayerStateShiftMessage]
|
||||||
|
}
|
||||||
|
|
@ -527,6 +527,83 @@ class GamePacketTest extends Specification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"PlayerStateShiftMessage" should {
|
||||||
|
val string_short = hex"BE 68"
|
||||||
|
val string_pos = hex"BE 95 A0 89 13 91 B8 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 {
|
||||||
|
PacketCoding.DecodePacket(string_short).require match {
|
||||||
|
case PlayerStateShiftMessage(unk1, state, unk2) =>
|
||||||
|
unk1 mustEqual 6
|
||||||
|
state.isDefined mustEqual false
|
||||||
|
unk2 mustEqual true
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"decode (pos)" in {
|
||||||
|
PacketCoding.DecodePacket(string_pos).require match {
|
||||||
|
case PlayerStateShiftMessage(unk1, state, unk2) =>
|
||||||
|
unk1 mustEqual 1
|
||||||
|
state.isDefined mustEqual true
|
||||||
|
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.vel.isDefined mustEqual false
|
||||||
|
unk2 mustEqual false
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"decode (pos and vel)" in {
|
||||||
|
PacketCoding.DecodePacket(string_posAndVel).require match {
|
||||||
|
case PlayerStateShiftMessage(unk1, state, unk2) =>
|
||||||
|
unk1 mustEqual 2
|
||||||
|
state.isDefined mustEqual true
|
||||||
|
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.vel.isDefined mustEqual true
|
||||||
|
state.get.vel.get.x mustEqual 2.8125f
|
||||||
|
state.get.vel.get.y mustEqual -8.0f
|
||||||
|
state.get.vel.get.z mustEqual 0.375f
|
||||||
|
unk2 mustEqual false
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode (short)" in {
|
||||||
|
val msg = PlayerStateShiftMessage(6, true)
|
||||||
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual string_short
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode (pos)" in {
|
||||||
|
val msg = PlayerStateShiftMessage(1,
|
||||||
|
PlayerState(Vector3(4624.703f, 5922.1484f, 46.171875f), 255),
|
||||||
|
false)
|
||||||
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual string_pos
|
||||||
|
}
|
||||||
|
|
||||||
|
"encode (pos and vel)" in {
|
||||||
|
val msg = PlayerStateShiftMessage(2,
|
||||||
|
PlayerState(Vector3(4645.75f, 5811.6016f, 50.3125f), 14, Vector3(2.8125f, -8.0f, 0.375f)),
|
||||||
|
false)
|
||||||
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
|
pkt mustEqual string_posAndVel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
"UseItemMessage" should {
|
"UseItemMessage" should {
|
||||||
val string = hex"10 4B00 0000 7401 FFFFFFFF 4001000000000000000000000000058C803600800000"
|
val string = hex"10 4B00 0000 7401 FFFFFFFF 4001000000000000000000000000058C803600800000"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue