diff --git a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala index d0ab02cf..03ed5e25 100644 --- a/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala +++ b/common/src/main/scala/net/psforever/packet/GamePacketOpcode.scala @@ -450,14 +450,14 @@ object GamePacketOpcode extends Enumeration { case 0x6f => game.SquadMembershipResponse.decode // OPCODES 0x70-7f - case 0x70 => noDecoder(SquadMemberEvent) + case 0x70 => game.SquadMemberEvent.decode case 0x71 => noDecoder(PlatoonEvent) case 0x72 => game.FriendsRequest.decode case 0x73 => game.FriendsResponse.decode case 0x74 => game.TriggerEnvironmentalDamageMessage.decode case 0x75 => game.TrainingZoneMessage.decode case 0x76 => game.DeployableObjectsInfoMessage.decode - case 0x77 => noDecoder(SquadState) + case 0x77 => game.SquadState.decode // 0x78 case 0x78 => game.OxygenStateMessage.decode case 0x79 => noDecoder(TradeMessage) diff --git a/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala b/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala index 7709a0d6..43009a3b 100644 --- a/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/SquadDefinitionActionMessage.scala @@ -18,6 +18,8 @@ abstract class SquadAction(val code : Int) object SquadAction{ final case class DisplaySquad() extends SquadAction(0) + final case class AnswerSquadJoinRequest() extends SquadAction(1) + final case class SaveSquadDefinition() extends SquadAction(3) final case class LoadSquadDefinition() extends SquadAction(4) @@ -74,6 +76,13 @@ object SquadAction{ } ) + val answerSquadJoinRequestCodec = everFailCondition.xmap[AnswerSquadJoinRequest] ( + _ => AnswerSquadJoinRequest(), + { + case AnswerSquadJoinRequest() => None + } + ) + val saveSquadDefinitionCodec = everFailCondition.xmap[SaveSquadDefinition] ( _ => SaveSquadDefinition(), { @@ -259,7 +268,7 @@ object SquadAction{ * The following formats are translated; their purposes are listed:
*   `(None)`
*     `0 ` - Display Squad
- *     `1 ` - UNKNOWN
+ *     `1 ` - Answer Squad Join Request
*     `2 ` - UNKNOWN
*     `3 ` - Save Squad Definition
*     `4 ` - Load Squad Definition
@@ -333,6 +342,7 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe import scala.annotation.switch ((code : @switch) match { case 0 => displaySquadCodec + case 1 => answerSquadJoinRequestCodec case 3 => saveSquadDefinitionCodec case 4 => loadSquadDefinitionCodec case 7 => listSquadDefinitionCodec @@ -353,7 +363,7 @@ object SquadDefinitionActionMessage extends Marshallable[SquadDefinitionActionMe case 35 => cancelSquadSearchCodec case 40 => findLfsSoldiersForRoleCodec case 41 => cancelFindCodec - case 1 | 2 | 6 | 9 | 11 | + case 2 | 6 | 9 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 29 | 30 | 32 | 33 | 36 | 37 | 38 | 42 | 43 => unknownCodec(code) diff --git a/common/src/main/scala/net/psforever/packet/game/SquadDetailDefinitionUpdateMessage.scala b/common/src/main/scala/net/psforever/packet/game/SquadDetailDefinitionUpdateMessage.scala index 418fbd2f..76fae022 100644 --- a/common/src/main/scala/net/psforever/packet/game/SquadDetailDefinitionUpdateMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/SquadDetailDefinitionUpdateMessage.scala @@ -62,6 +62,25 @@ object SquadDetailDefinitionUpdateMessage extends Marshallable[SquadDetailDefini CertificationType.AgileExoSuit ) + final val Init = SquadDetailDefinitionUpdateMessage( + PlanetSideGUID(0), + "", + "", + PlanetSideZoneID(0), + List( + SquadPositionDetail(), + SquadPositionDetail(), + SquadPositionDetail(), + SquadPositionDetail(), + SquadPositionDetail(), + SquadPositionDetail(), + SquadPositionDetail(), + SquadPositionDetail(), + SquadPositionDetail(), + SquadPositionDetail() + ) + ) + def apply(guid : PlanetSideGUID, leader_name : String, task : String, zone_id : PlanetSideZoneID, member_info : List[SquadPositionDetail]) : SquadDetailDefinitionUpdateMessage = { import scodec.bits._ SquadDetailDefinitionUpdateMessage(guid, hex"080000000000000000000".toBitVector, leader_name, task, zone_id, member_info) diff --git a/common/src/main/scala/net/psforever/packet/game/SquadMemberEvent.scala b/common/src/main/scala/net/psforever/packet/game/SquadMemberEvent.scala new file mode 100644 index 00000000..df8bd7b0 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/SquadMemberEvent.scala @@ -0,0 +1,61 @@ +// Copyright (c) 2019 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} +import scodec.{Attempt, Codec, Err} +import scodec.codecs._ +import shapeless.{::, HNil} + +final case class SquadMemberEvent(unk1 : Int, + unk2 : Int, + unk3 : Long, + unk4 : Int, + unk5 : Option[String], + unk6 : Option[Int], + unk7 : Option[Long]) + extends PlanetSideGamePacket { + type Packet = SquadMemberEvent + def opcode = GamePacketOpcode.SquadMemberEvent + def encode = SquadMemberEvent.encode(this) +} + +object SquadMemberEvent extends Marshallable[SquadMemberEvent] { + def apply(unk1 : Int, unk2 : Int, unk3 : Long, unk4 : Int) : SquadMemberEvent = + SquadMemberEvent(unk1, unk2, unk3, unk4, None, None, None) + + def apply(unk2 : Int, unk3 : Long, unk4 : Int, unk5 : String, unk6 : Int, unk7 : Long) : SquadMemberEvent = + SquadMemberEvent(0, unk2, unk3, unk4, Some(unk5), Some(unk6), Some(unk7)) + + def apply(unk2 : Int, unk3 : Long, unk4 : Int, unk6 : Int) : SquadMemberEvent = + SquadMemberEvent(3, unk2, unk3, unk4, None, Some(unk6), None) + + def apply(unk2 : Int, unk3 : Long, unk4 : Int, unk7 : Long) : SquadMemberEvent = + SquadMemberEvent(4, unk2, unk3, unk4, None, None, Some(unk7)) + + implicit val codec : Codec[SquadMemberEvent] = ( + ("unk1" | uintL(3)) >>:~ { unk1 => + ("unk2" | uint16L) :: + ("unk3" | uint32L) :: + ("unk4" | uintL(4)) :: + conditional(unk1 == 0, "unk5" | PacketHelpers.encodedWideStringAligned(1)) :: + conditional(unk1 == 0 || unk1 == 3, "unk6" | uint16L) :: + conditional(unk1 == 0 || unk1 == 4, "unk7" | uint32L) + }).exmap[SquadMemberEvent] ( + { + case unk1 :: unk2 :: unk3 :: unk4 :: unk5 :: unk6 :: unk7 :: HNil => + Attempt.Successful(SquadMemberEvent(unk1, unk2, unk3, unk4, unk5, unk6, unk7)) + }, + { + case data @ SquadMemberEvent(0, unk2, unk3, unk4, Some(unk5), Some(unk6), Some(unk7)) => + Attempt.Successful(0 :: unk2 :: unk3 :: unk4 :: Some(unk5) :: Some(unk6) :: Some(unk7) :: HNil) + case data @ SquadMemberEvent(3, unk2, unk3, unk4, None, Some(unk6), None) => + Attempt.Successful(3 :: unk2 :: unk3 :: unk4 :: None :: Some(unk6) :: None :: HNil) + case data @ SquadMemberEvent(4, unk2, unk3, unk4, None, None, Some(unk7)) => + Attempt.Successful(4 :: unk2 :: unk3 :: unk4 :: None :: None :: Some(unk7) :: HNil) + case data @ SquadMemberEvent(unk1, unk2, unk3, unk4, None, None, None) => + Attempt.Successful(unk1 :: unk2 :: unk3 :: unk4 :: None :: None :: None :: HNil) + case data => + Attempt.Failure(Err(s"SquadMemberEvent can not encode with this pattern - $data")) + } + ) +} diff --git a/common/src/main/scala/net/psforever/packet/game/SquadState.scala b/common/src/main/scala/net/psforever/packet/game/SquadState.scala new file mode 100644 index 00000000..ae745a74 --- /dev/null +++ b/common/src/main/scala/net/psforever/packet/game/SquadState.scala @@ -0,0 +1,76 @@ +// Copyright (c) 2019 PSForever +package net.psforever.packet.game + +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} +import net.psforever.types.Vector3 +import scodec.{Attempt, Codec, Err} +import scodec.codecs._ +import shapeless.{::, HNil} + +final case class SquadStateInfo(char_id : Long, + unk2 : Int, + unk3 : Int, + pos : Vector3, + unk4 : Int, + unk5 : Int, + unk6 : Boolean, + unk7 : Int, + unk8 : Option[Int], + unk9 : Option[Boolean]) + +//7704001646c7a02810050a1a2bc97842280000 +// SquadState(PlanetSideGUID(4),List(SquadStateInfo(1684830722,64,64,Vector3(3152.1562,3045.0781,35.515625),2,2,false,0,None,None))) +//770700342a28c028100420d60e9df8c2800000eab58a028100ce514b655ddc341400286d9130000021eb951539f4c4050800 +// SquadState(PlanetSideGUID(7),List(SquadStateInfo(1117948930,64,64,Vector3(2822.125,3919.0234,43.546875),0,0,false,0,None,None), SquadStateInfo(3937765890,64,64,Vector3(2856.3984,3882.3516,53.859375),0,0,false,416,None,None), SquadStateInfo(2262373120,0,0,Vector3(2909.0547,3740.539,67.296875),0,1,false,132,None,None))) +//7704005dd9ccf01810132fdf9f9ef5c4a8000084de7a022c00e5898c8d5e4c429b004ed01d50181016395a4c364e08280001b901a070bd0140805308d59f90641f40000c001db11e280a00088d19e3a190f0ca6c0100 +// SquadState(PlanetSideGUID(4),List(SquadStateInfo(3718041345,64,64,Vector3(3966.5938,6095.8047,75.359375),2,2,false,0,None,None), SquadStateInfo(2229172738,22,0,Vector3(3268.4453,3690.3906,66.296875),2,2,false,728,None,None), SquadStateInfo(3976320257,64,64,Vector3(3530.6875,4635.1484,128.875),2,2,false,0,Some(441),Some(true)), SquadStateInfo(1088518658,64,64,Vector3(3336.3203,4601.3438,60.78125),2,2,false,0,Some(896),Some(true)), SquadStateInfo(1816627714,64,0,Vector3(5027.0625,4931.7734,48.234375),2,2,false,728,None,None))) +final case class SquadState(guid : PlanetSideGUID, + info_list : List[SquadStateInfo]) + extends PlanetSideGamePacket { + type Packet = SquadState + def opcode = GamePacketOpcode.SquadState + def encode = SquadState.encode(this) +} + +object SquadStateInfo { + def apply(unk1 : Long, unk2 : Int, unk3 : Int, pos : Vector3, unk4 : Int, unk5 : Int, unk6 : Boolean, unk7 : Int) : SquadStateInfo = + SquadStateInfo(unk1, unk2, unk3, pos, unk4, unk5, unk6, unk7, None, None) + + def apply(unk1 : Long, unk2 : Int, unk3 : Int, pos : Vector3, unk4 : Int, unk5 : Int, unk6 : Boolean, unk7 : Int, unk8 : Int, unk9 : Boolean) : SquadStateInfo = + SquadStateInfo(unk1, unk2, unk3, pos, unk4, unk5, unk6, unk7, Some(unk8), Some(unk9)) +} + +object SquadState extends Marshallable[SquadState] { + private val info_codec : Codec[SquadStateInfo] = ( + ("char_id" | uint32L) :: + ("unk2" | uint(7)) :: + ("unk3" | uint(7)) :: + ("pos" | Vector3.codec_pos) :: + ("unk4" | uint2) :: + ("unk5" | uint2) :: + ("unk6" | bool) :: + ("unk7" | uint16L) :: + (bool >>:~ { out => + conditional(out, "unk8" | uint16L) :: + conditional(out, "unk9" | bool) + }) + ).exmap[SquadStateInfo] ( + { + case char_id :: u2 :: u3 :: pos :: u4 :: u5 :: u6 :: u7 :: _ :: u8 :: u9 :: HNil => + Attempt.Successful(SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9)) + }, + { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, Some(u8), Some(u9)) => + Attempt.Successful(char_id :: u2 :: u3 :: pos :: u4 :: u5 :: u6 :: u7 :: true :: Some(u8) :: Some(u9) :: HNil) + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, None, None) => + Attempt.Successful(char_id :: u2 :: u3 :: pos :: u4 :: u5 :: u6 :: u7 :: false :: None :: None :: HNil) + case data @ (SquadStateInfo(_, _, _, _, _, _, _, _, Some(_), None) | SquadStateInfo(_, _, _, _, _, _, _, _, None, Some(_))) => + Attempt.Failure(Err(s"SquadStateInfo requires both unk8 and unk9 to be either defined or undefined at the same time - $data")) + } + ) + + implicit val codec : Codec[SquadState] = ( + ("guid" | PlanetSideGUID.codec) :: + ("info_list" | listOfN(uint4, info_codec)) + ).as[SquadState] +} diff --git a/common/src/test/scala/game/SquadMemberEventTest.scala b/common/src/test/scala/game/SquadMemberEventTest.scala new file mode 100644 index 00000000..5ecc1cef --- /dev/null +++ b/common/src/test/scala/game/SquadMemberEventTest.scala @@ -0,0 +1,32 @@ +// Copyright (c) 2019 PSForever +package game + +import net.psforever.packet._ +import net.psforever.packet.game._ +import org.specs2.mutable._ +import scodec.bits._ + +class SquadMemberEventTest extends Specification { + val string = hex"7000e008545180410848006f0066004400070051150800" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case SquadMemberEvent(u1, u2, u3, u4, u5, u6, u7) => + u1 mustEqual 0 + u2 mustEqual 7 + u3 mustEqual 42771010L + u4 mustEqual 0 + u5.contains("HofD") mustEqual true + u6.contains(7) mustEqual true + u7.contains(529745L) mustEqual true + case _ => + ko + } + } + + "encode" in { + val msg = SquadMemberEvent(0, 7, 42771010L, 0, Some("HofD"), Some(7), Some(529745L)) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string + } +} diff --git a/common/src/test/scala/game/SquadStateTest.scala b/common/src/test/scala/game/SquadStateTest.scala new file mode 100644 index 00000000..5cce7ae3 --- /dev/null +++ b/common/src/test/scala/game/SquadStateTest.scala @@ -0,0 +1,244 @@ +// Copyright (c) 2019 PSForever +package game + +import net.psforever.packet._ +import net.psforever.packet.game._ +import net.psforever.types.Vector3 +import org.specs2.mutable._ +import scodec.bits._ + +class SquadStateTest extends Specification { + val string1 = hex"770700186d9130081001b11b27c1c041680000" + val string2 = hex"770700242a28c020003e9237a90e3382695004eab58a0281017eb95613df4c42950040" + val stringx = hex"7704008dd9ccf010042a9837310e1b82a8c006646c7a028103984f34759c904a800014f01c26f3d014081ddd3896931bc25478037680ea80c081d699a147b01e154000031c0bc81407e08c1a3a890de1542c022070bd0140815958bf29efa6214300108023c01000ae491ac68d1a61342c023623c50140011d6ea0878f3026a00009e014" + + "decode (1)" in { + PacketCoding.DecodePacket(string1).require match { + case SquadState(guid, list) => + guid mustEqual PlanetSideGUID(7) + list.size mustEqual 1 + //0 + list.head match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 1300870L + u2 mustEqual 64 + u3 mustEqual 64 + pos mustEqual Vector3(3464.0469f, 4065.5703f, 20.015625f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 0 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + case _ => + ko + } + } + + "decode (2)" in { + PacketCoding.DecodePacket(string2).require match { + case SquadState(guid, list) => + guid mustEqual PlanetSideGUID(7) + list.size mustEqual 2 + //0 + list.head match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 42771010L + u2 mustEqual 0 + u3 mustEqual 0 + pos mustEqual Vector3(6801.953f, 4231.828f, 39.21875f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 680 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + list(1) match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 42644970L + u2 mustEqual 64 + u3 mustEqual 64 + pos mustEqual Vector3(2908.7422f, 3742.6875f, 67.296875f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 680 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + case _ => + ko + } + } + + "decode (8)" in { + PacketCoding.DecodePacket(stringx).require match { + case SquadState(guid, list) => + guid mustEqual PlanetSideGUID(4) + list.size mustEqual 8 + //0 + list.head match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 30383325L + u2 mustEqual 0 + u3 mustEqual 16 + pos mustEqual Vector3(6849.328f, 4231.5938f, 41.71875f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 864 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + list(1) match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 41577572L + u2 mustEqual 64 + u3 mustEqual 64 + pos mustEqual Vector3(6183.797f, 4013.6328f, 72.5625f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 0 + u8.contains(335) mustEqual true + u9.contains(true) mustEqual true + case _ => + ko + } + list(2) match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 41606788L + u2 mustEqual 64 + u3 mustEqual 64 + pos mustEqual Vector3(6611.8594f, 4242.586f, 75.46875f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 888 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + list(3) match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 30736877L + u2 mustEqual 64 + u3 mustEqual 64 + pos mustEqual Vector3(6809.836f, 4218.078f, 40.234375f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 0 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + list(4) match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 41517411L + u2 mustEqual 64 + u3 mustEqual 63 + pos mustEqual Vector3(6848.0312f, 4232.2266f, 41.734375f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 556 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + list(5) match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 41607488L + u2 mustEqual 64 + u3 mustEqual 64 + pos mustEqual Vector3(2905.3438f, 3743.9453f, 67.296875f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 304 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + list(6) match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 41419792L + u2 mustEqual 0 + u3 mustEqual 5 + pos mustEqual Vector3(6800.8906f ,4236.7734f, 39.296875f) + u4 mustEqual 2 + u5 mustEqual 2 + u6 mustEqual false + u7 mustEqual 556 + u8.isEmpty mustEqual true + u9.isEmpty mustEqual true + case _ => + ko + } + list(7) match { + case SquadStateInfo(char_id, u2, u3, pos, u4, u5, u6, u7, u8, u9) => + char_id mustEqual 42616684L + u2 mustEqual 64 + u3 mustEqual 0 + pos mustEqual Vector3(2927.1094f, 3704.0312f, 78.375f) + u4 mustEqual 1 + u5 mustEqual 1 + u6 mustEqual false + u7 mustEqual 0 + u8.contains(572) mustEqual true + u9.contains(true) mustEqual true + case _ => + ko + } + case _ => + ko + } + } + + "encode (1)" in { + val msg = SquadState(PlanetSideGUID(7), List( + SquadStateInfo(1300870L, 64, 64, Vector3(3464.0469f, 4065.5703f, 20.015625f), 2, 2, false, 0) + )) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string1 + } + + "encode (2)" in { + val msg = SquadState(PlanetSideGUID(7), List( + SquadStateInfo(42771010L, 0, 0, Vector3(6801.953f, 4231.828f, 39.21875f), 2, 2, false, 680), + SquadStateInfo(42644970L, 64, 64, Vector3(2908.7422f, 3742.6875f, 67.296875f), 2, 2, false, 680) + )) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual string2 + } + + "encode (8)" in { + val msg = SquadState(PlanetSideGUID(4), List( + SquadStateInfo(30383325L, 0, 16, Vector3(6849.328f, 4231.5938f, 41.71875f), 2, 2, false, 864), + SquadStateInfo(41577572L, 64, 64, Vector3(6183.797f, 4013.6328f, 72.5625f), 2, 2, false, 0, 335, true), + SquadStateInfo(41606788L, 64, 64, Vector3(6611.8594f, 4242.586f, 75.46875f), 2, 2, false, 888), + SquadStateInfo(30736877L, 64, 64, Vector3(6809.836f, 4218.078f, 40.234375f), 2, 2, false, 0), + SquadStateInfo(41517411L, 64, 63, Vector3(6848.0312f, 4232.2266f, 41.734375f), 2, 2, false, 556), + SquadStateInfo(41607488L, 64, 64, Vector3(2905.3438f, 3743.9453f, 67.296875f), 2, 2, false, 304), + SquadStateInfo(41419792L, 0, 5, Vector3(6800.8906f, 4236.7734f, 39.296875f), 2, 2, false, 556), + SquadStateInfo(42616684L, 64, 0, Vector3(2927.1094f, 3704.0312f, 78.375f), 1, 1, false, 0, 572, true) + )) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + pkt mustEqual stringx + } +} \ No newline at end of file diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 8f22f277..b20a2364 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -2853,6 +2853,7 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PlanetsideAttributeMessage(guid, 53, 1)) sendResponse(AvatarSearchCriteriaMessage(guid, List(0, 0, 0, 0, 0, 0))) (1 to 73).foreach(i => { + // not all GUID's are set, and not all of the set ones will always be zero; what does this section do? sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(i), 67, 0)) }) (0 to 30).foreach(i => { @@ -2861,7 +2862,15 @@ class WorldSessionActor extends Actor with MDCContextAware { }) //AvatarAwardMessage //DisplayAwardMessage - //SquadDefinitionActionMessage and SquadDetailDefinitionUpdateMessage; handled elsewhere + sendResponse(PlanetsideStringAttributeMessage(guid, 0, "Outfit Name")) + sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SquadAction.Unknown(6, hex"".toBitVector))) + (0 to 9).foreach(line => { + sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), line, SquadAction.ListSquadDefinition(""))) + }) + sendResponse(SquadDetailDefinitionUpdateMessage.Init) + sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0,SquadAction.Unknown(16, hex"".toBitVector))) + sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0,SquadAction.Unknown(17, hex"".toBitVector))) + sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0,SquadAction.Unknown(18, hex"".toBitVector))) //MapObjectStateBlockMessage and ObjectCreateMessage? //TacticsMessage? //change the owner on our deployables (re-draw the icons for our deployables too) @@ -2896,35 +2905,36 @@ class WorldSessionActor extends Actor with MDCContextAware { interstellarFerryTopLevelGUID = None case _ => ; } -// sendResponse(ReplicationStreamMessage( -// 5, -// Some(6), -// Vector( -// SquadListing(0, SquadInfo(Some("xNick"), Some("FLY,ALL WELCOME!"), Some(PlanetSideZoneID(7)), Some(8), Some(10), Some(PlanetSideGUID(1)))), -// SquadListing(1, SquadInfo(Some("HofD"), Some("=KOK+SPC+FLY= All Welcome"), Some(PlanetSideZoneID(7)), Some(3), Some(10), Some(PlanetSideGUID(3)))) -// ) -// )) -// //sendRawResponse(hex"e803008484000c800259e8809fda020043004a0069006d006d0079006e009b48006f006d006900630069006400690061006c00200053006d007500720066007300200041006e006f006e0079006d006f007500730004000000981401064580540061006e006b002000440072006900760065007200a05200650063006f006d006d0065006e00640065006400200074006f0020006800610076006500200065006e00670069006e0065006500720069006e0067002e0000000000800180000c00020c8c46007200650065006200690065002000730070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0096e27a0290540068006500460069006e0061006c005300740072007500670067006c0065000000000000020c8c46007200650065006200690065002000530070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0000000000800000000000020c8a41004d0053002000440072006900760065007200b34700690076006500200075007300200073007000610077006e00200070006f0069006e00740073002c0020006800610063006b0069006e006700200061006e006400200069006e00660069006c0020006100720065002000750073006500660075006c002e00fb02790287440030004f004d006700750079000100020c00020c8d410076006500720061006700650020004a0069006d006d007900a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b4100760065007200610067006500200042006f006200a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b410076006500720061006700650020004a006f006500a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8753007500700070006f0072007400a2520065007300730075007200650063007400200073006f006c00640069006500720073002c0020006b00650065007000200075007300200061006c006900760065002e0000000000800100000c0c0a0c8845006e00670069006e00650065007200a043006f006d00620061007400200045006e00670069006e0065006500720069006e006700200077006f0075006c00640020006200650020006e0069006300650004b3d101864a0069006d006d0079006e000100000c000a0c854d0065006400690063009a4100640076002e0020004d00650064006900630061006c00200077006f0075006c00640020006200650020006e0069006300650000000000800100000c0400") -// sendResponse( -// SquadDetailDefinitionUpdateMessage( -// PlanetSideGUID(3), -// "HofD", -// "\\#ffdc00***\\#9640ff=KOK+SPC+FLY=\\#ffdc00***\\#FF4040 All Welcome", -// PlanetSideZoneID(7), -// List( -// SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Just a space filler"), -// SquadPositionDetail("\\#ffdc00 C", ""), -// SquadPositionDetail("\\#ffdc00 H", "", "OpoIE"), -// SquadPositionDetail("\\#ffdc00 I", "", "BobaF3tt907"), -// SquadPositionDetail("\\#ffdc00 N", ""), -// SquadPositionDetail("\\#ffdc00 A", ""), -// SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Another space filler"), -// SquadPositionDetail("\\#9640ff K", ""), -// SquadPositionDetail("\\#9640ff O", "", "HofD"), -// SquadPositionDetail("\\#9640ff K", "") -// ) -// ) -// ) + //SQUAD TESTING CODE + sendResponse(ReplicationStreamMessage( + 5, + Some(6), + Vector( + SquadListing(0, SquadInfo(Some("xNick"), Some("FLY,ALL WELCOME!"), Some(PlanetSideZoneID(7)), Some(8), Some(10), Some(PlanetSideGUID(1)))), + SquadListing(1, SquadInfo(Some("HofD"), Some("=KOK+SPC+FLY= All Welcome"), Some(PlanetSideZoneID(7)), Some(3), Some(10), Some(PlanetSideGUID(3)))) + ) + )) + //sendRawResponse(hex"e803008484000c800259e8809fda020043004a0069006d006d0079006e009b48006f006d006900630069006400690061006c00200053006d007500720066007300200041006e006f006e0079006d006f007500730004000000981401064580540061006e006b002000440072006900760065007200a05200650063006f006d006d0065006e00640065006400200074006f0020006800610076006500200065006e00670069006e0065006500720069006e0067002e0000000000800180000c00020c8c46007200650065006200690065002000730070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0096e27a0290540068006500460069006e0061006c005300740072007500670067006c0065000000000000020c8c46007200650065006200690065002000530070006f007400cf44006f002000770068006100740065007600650072002c0020006200750074002000700072006500660065007200610062006c007900200073007400690063006b002000770069007400680020007400680065002000730071007500610064002e00200044006f006e002700740020006e00650065006400200061006e007900200073007000650063006900660069006300200063006500720074002e0000000000800000000000020c8a41004d0053002000440072006900760065007200b34700690076006500200075007300200073007000610077006e00200070006f0069006e00740073002c0020006800610063006b0069006e006700200061006e006400200069006e00660069006c0020006100720065002000750073006500660075006c002e00fb02790287440030004f004d006700750079000100020c00020c8d410076006500720061006700650020004a0069006d006d007900a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b4100760065007200610067006500200042006f006200a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8b410076006500720061006700650020004a006f006500a05200650069006e0066006f0072006300650064002000450078006f007300750069007400200077006f0075006c00640020006200650020006e0069006300650000000000800300000c00020c8753007500700070006f0072007400a2520065007300730075007200650063007400200073006f006c00640069006500720073002c0020006b00650065007000200075007300200061006c006900760065002e0000000000800100000c0c0a0c8845006e00670069006e00650065007200a043006f006d00620061007400200045006e00670069006e0065006500720069006e006700200077006f0075006c00640020006200650020006e0069006300650004b3d101864a0069006d006d0079006e000100000c000a0c854d0065006400690063009a4100640076002e0020004d00650064006900630061006c00200077006f0075006c00640020006200650020006e0069006300650000000000800100000c0400") + sendResponse( + SquadDetailDefinitionUpdateMessage( + PlanetSideGUID(3), + "HofD", + "\\#ffdc00***\\#9640ff=KOK+SPC+FLY=\\#ffdc00***\\#FF4040 All Welcome", + PlanetSideZoneID(7), + List( + SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Just a space filler"), + SquadPositionDetail("\\#ffdc00 C", ""), + SquadPositionDetail(false, "\\#ffdc00 H", "", Set(), 42644970L, "OpoIE"), + SquadPositionDetail(false, "\\#ffdc00 I", "", Set(), 41604210L, "BobaF3tt907"), + SquadPositionDetail("\\#ffdc00 N", ""), + SquadPositionDetail("\\#ffdc00 A", ""), + SquadPositionDetail("\\#ff0000 |||||||||||||||||||||||", "Another space filler"), + SquadPositionDetail("\\#9640ff K", ""), + SquadPositionDetail(false, "\\#9640ff O", "", Set(), 42771010L, "HofD"), + SquadPositionDetail("\\#9640ff K", "") + ) + ) + ) } def handleControlPkt(pkt : PlanetSideControlPacket) = { @@ -3336,11 +3346,19 @@ class WorldSessionActor extends Actor with MDCContextAware { case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) => if(deadState == DeadState.Alive) { -// if(!player.Crouching && is_crouching) { -// sendResponse( -// SquadMembershipRequest(SquadRequestType.Unk01, 1L, Some(1L), "FateJH", Some(None)) -// ) -// } + if(!player.Crouching && is_crouching) { //SQUAD TESTING CODE + sendResponse(SquadMembershipResponse(SquadRequestType.Invite,0,0,42771010,Some(41605313),"HofD",false,None)) + sendResponse(SquadMembershipResponse(SquadRequestType.Accept,0,0,41605313,Some(42771010),"VirusGiver",true,Some(None))) + sendResponse(SquadMemberEvent(0,7,42771010,0,Some("HofD"),Some(7),Some(529745))) + sendResponse(SquadMemberEvent(0,7,42644970,1,Some("OpolE"),Some(7),Some(6418))) + sendResponse(SquadMemberEvent(0,7,41604210,8,Some("BobaF3tt907"),Some(12),Some(8097))) + sendResponse(PlanetsideAttributeMessage(player.GUID, 49, 7)) + sendResponse(PlanetsideAttributeMessage(player.GUID, 50, 2)) + sendResponse(PlanetsideAttributeMessage(player.GUID, 51, 8)) + sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(3), 0, SquadAction.Unknown(18, hex"".toBitVector))) + sendResponse(PlanetsideAttributeMessage(player.GUID, 83, 0)) + sendResponse(SquadState(PlanetSideGUID(7),List(SquadStateInfo(41605313L,64,64,Vector3(3464.0469f,4065.5703f,20.015625f),2,2,false,0,None,None)))) + } player.Position = pos player.Velocity = vel player.Orientation = Vector3(player.Orientation.x, pitch, yaw)