diff --git a/common/src/main/scala/net/psforever/packet/game/CharacterInfoMessage.scala b/common/src/main/scala/net/psforever/packet/game/CharacterInfoMessage.scala index 3369310be..c75fface7 100644 --- a/common/src/main/scala/net/psforever/packet/game/CharacterInfoMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/CharacterInfoMessage.scala @@ -26,7 +26,8 @@ object PlanetSideGUID { * * @param finished True when there are no more characters to give info on */ -final case class CharacterInfoMessage(zoneId : PlanetSideZoneID, +final case class CharacterInfoMessage(unk : Long, + zoneId : PlanetSideZoneID, charId : Long, guid : PlanetSideGUID, finished : Boolean, @@ -39,8 +40,8 @@ final case class CharacterInfoMessage(zoneId : PlanetSideZoneID, object CharacterInfoMessage extends Marshallable[CharacterInfoMessage] { implicit val codec : Codec[CharacterInfoMessage] = ( - ("unknown" | uint32L).unit(0) :: // this type is set to unit as we dont know what it is yet - ("zoneId" | PlanetSideZoneID.codec) :: + ("unk" | uint32L) :: + ("zoneId" | PlanetSideZoneID.codec) :: ("charId" | uint32L) :: ("charGUID" | PlanetSideGUID.codec) :: ("finished" | bool) :: diff --git a/common/src/main/scala/net/psforever/packet/game/KeepAliveMessage.scala b/common/src/main/scala/net/psforever/packet/game/KeepAliveMessage.scala index c26efbebd..c0547750d 100644 --- a/common/src/main/scala/net/psforever/packet/game/KeepAliveMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/KeepAliveMessage.scala @@ -1,11 +1,11 @@ // Copyright (c) 2017 PSForever package net.psforever.packet.game -import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} +import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} import scodec.Codec import scodec.codecs._ -final case class KeepAliveMessage(code : Int) extends PlanetSideGamePacket { +final case class KeepAliveMessage(code : Int = 0) extends PlanetSideGamePacket { type Packet = KeepAliveMessage def opcode = GamePacketOpcode.KeepAliveMessage def encode = KeepAliveMessage.encode(this) diff --git a/common/src/main/scala/net/psforever/packet/game/ObjectDetectedMessage.scala b/common/src/main/scala/net/psforever/packet/game/ObjectDetectedMessage.scala index e7f0600dd..16851e9bf 100644 --- a/common/src/main/scala/net/psforever/packet/game/ObjectDetectedMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/ObjectDetectedMessage.scala @@ -7,18 +7,18 @@ import scodec.{Attempt, Codec, Err} import shapeless.{::, HNil} /** - * na - * @param guid1 na - * @param guid2 na; - * often matches with `guid1` - * @param unk1 na - * @param unk2 na; + * Update a list of (new) objects that have been detected by this client in one way or another. + * @param player_guid1 the player + * @param player_guid2 the player(?); + * often matches with `player_guid1` + * @param unk na + * @param list list of detected objects; * normally contains at least one element */ -final case class ObjectDetectedMessage(guid1 : PlanetSideGUID, - guid2 : PlanetSideGUID, - unk1 : Int, - unk2 : List[Int]) +final case class ObjectDetectedMessage(player_guid1 : PlanetSideGUID, + player_guid2 : PlanetSideGUID, + unk : Int, + list : List[PlanetSideGUID]) extends PlanetSideGamePacket { type Packet = ObjectDetectedMessage def opcode = GamePacketOpcode.ObjectDetectedMessage @@ -27,22 +27,22 @@ final case class ObjectDetectedMessage(guid1 : PlanetSideGUID, object ObjectDetectedMessage extends Marshallable[ObjectDetectedMessage] { implicit val codec : Codec[ObjectDetectedMessage] = ( - ("guid1" | PlanetSideGUID.codec) :: - ("guid2" | PlanetSideGUID.codec) :: - ("unk1" | uint8L) :: - ("unk2" | listOfN(uintL(6), uint16L)) //TODO are these uids? + ("player_guid1" | PlanetSideGUID.codec) :: + ("player_guid2" | PlanetSideGUID.codec) :: + ("unk" | uint8L) :: + ("list" | listOfN(uintL(6), PlanetSideGUID.codec)) ).exmap[ObjectDetectedMessage] ( { - case g1 :: g2 :: u1 :: u2 :: HNil => - Attempt.successful(ObjectDetectedMessage(g1, g2, u1, u2)) + case g1 :: g2 :: u :: lst :: HNil => + Attempt.successful(ObjectDetectedMessage(g1, g2, u, lst)) }, { - case ObjectDetectedMessage(g1, g2, u1, u2) => - if(u2.size > 63) { - Attempt.failure(Err(s"too many list elements (max: 63, actual: ${u2.size})")) + case ObjectDetectedMessage(g1, g2, u, lst) => + if(lst.size > 63) { + Attempt.failure(Err(s"too many list elements (max: 63, actual: ${lst.size})")) } else { - Attempt.successful(g1 :: g2 :: u1 :: u2 :: HNil) + Attempt.successful(g1 :: g2 :: u :: lst :: HNil) } } ) diff --git a/common/src/test/scala/game/CharacterCreateRequestMessageTest.scala b/common/src/test/scala/game/CharacterCreateRequestMessageTest.scala new file mode 100644 index 000000000..416ac237f --- /dev/null +++ b/common/src/test/scala/game/CharacterCreateRequestMessageTest.scala @@ -0,0 +1,33 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import net.psforever.types.{CharacterGender, PlanetSideEmpire} +import scodec.bits._ + +class CharacterCreateRequestMessageTest extends Specification { + val string = hex"2f 88 54006500730074004300680061007200 320590" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case CharacterCreateRequestMessage(name, head, voice, gender, faction) => + name mustEqual "TestChar" + head mustEqual 50 + voice mustEqual 5 + gender mustEqual CharacterGender.Female + faction mustEqual PlanetSideEmpire.NC + case _ => + ko + } + } + + "encode" in { + val msg = CharacterCreateRequestMessage("TestChar", 50, 5, CharacterGender.Female, PlanetSideEmpire.NC) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} + diff --git a/common/src/test/scala/game/CharacterInfoMessageTest.scala b/common/src/test/scala/game/CharacterInfoMessageTest.scala new file mode 100644 index 000000000..0d03c6871 --- /dev/null +++ b/common/src/test/scala/game/CharacterInfoMessageTest.scala @@ -0,0 +1,32 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class CharacterInfoMessageTest extends Specification { + val string = hex"14 0F000000 10270000C1D87A024B00265CB08000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case CharacterInfoMessage(unk, zone, charId, guid, finished, last) => + unk mustEqual 15L + zone mustEqual PlanetSideZoneID(10000) + charId mustEqual 41605313L + guid mustEqual PlanetSideGUID(75) + finished mustEqual false + last mustEqual 6404428L + case _ => + ko + } + } + + "encode" in { + val msg = CharacterInfoMessage(15L, PlanetSideZoneID(10000), 41605313L, PlanetSideGUID(75), false, 6404428L) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} diff --git a/common/src/test/scala/game/CharacterRequestMessageTest.scala b/common/src/test/scala/game/CharacterRequestMessageTest.scala new file mode 100644 index 000000000..8c7152447 --- /dev/null +++ b/common/src/test/scala/game/CharacterRequestMessageTest.scala @@ -0,0 +1,30 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import net.psforever.types.{CharacterGender, PlanetSideEmpire} +import scodec.bits._ + +class CharacterRequestMessageTest extends Specification { + val string = hex"30 c1d87a02 00000000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case CharacterRequestMessage(charId, action) => + charId mustEqual 41605313L + action mustEqual CharacterRequestAction.Select + case _ => + ko + } + } + + "encode" in { + val msg = CharacterRequestMessage(41605313L, CharacterRequestAction.Select) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} + diff --git a/common/src/test/scala/game/KeepAliveMessageTest.scala b/common/src/test/scala/game/KeepAliveMessageTest.scala new file mode 100644 index 000000000..4f7a4d2d5 --- /dev/null +++ b/common/src/test/scala/game/KeepAliveMessageTest.scala @@ -0,0 +1,28 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class KeepAliveMessageTest extends Specification { + val string = hex"BA 0000" + + "decode" in { + PacketCoding.DecodePacket(string).require match { + case KeepAliveMessage(code) => + code mustEqual 0 + case _ => + ko + } + } + + "encode" in { + val msg = KeepAliveMessage() + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string + } +} + diff --git a/common/src/test/scala/game/ObjectDetectedMessageTest.scala b/common/src/test/scala/game/ObjectDetectedMessageTest.scala index 674f1ba44..159e86a6f 100644 --- a/common/src/test/scala/game/ObjectDetectedMessageTest.scala +++ b/common/src/test/scala/game/ObjectDetectedMessageTest.scala @@ -11,25 +11,37 @@ class ObjectDetectedMessageTest extends Specification { "decode" in { PacketCoding.DecodePacket(string).require match { - case ObjectDetectedMessage(guid1, guid2, unk1, unk2) => + case ObjectDetectedMessage(guid1, guid2, unk1, list) => guid1 mustEqual PlanetSideGUID(4070) guid2 mustEqual PlanetSideGUID(4070) unk1 mustEqual 0 - unk2.size mustEqual 7 - unk2.head mustEqual 3623 - unk2(1) mustEqual 3198 - unk2(2) mustEqual 3088 - unk2(3) mustEqual 1579 - unk2(4) mustEqual 1578 - unk2(5) mustEqual 3341 - unk2(6) mustEqual 2997 + list.size mustEqual 7 + list.head mustEqual PlanetSideGUID(3623) + list(1) mustEqual PlanetSideGUID(3198) + list(2) mustEqual PlanetSideGUID(3088) + list(3) mustEqual PlanetSideGUID(1579) + list(4) mustEqual PlanetSideGUID(1578) + list(5) mustEqual PlanetSideGUID(3341) + list(6) mustEqual PlanetSideGUID(2997) case _ => ko } } "encode" in { - val msg = ObjectDetectedMessage(PlanetSideGUID(4070), PlanetSideGUID(4070), 0, 3623 :: 3198 :: 3088 :: 1579 :: 1578 :: 3341 :: 2997 :: Nil) + val msg = ObjectDetectedMessage( + PlanetSideGUID(4070), + PlanetSideGUID(4070), + 0, + PlanetSideGUID(3623) :: + PlanetSideGUID(3198) :: + PlanetSideGUID(3088) :: + PlanetSideGUID(1579) :: + PlanetSideGUID(1578) :: + PlanetSideGUID(3341) :: + PlanetSideGUID(2997) :: + Nil + ) val pkt = PacketCoding.EncodePacket(msg).require.toByteVector pkt mustEqual string diff --git a/common/src/test/scala/game/VoiceHostInfoTest.scala b/common/src/test/scala/game/VoiceHostInfoTest.scala new file mode 100644 index 000000000..7272815d7 --- /dev/null +++ b/common/src/test/scala/game/VoiceHostInfoTest.scala @@ -0,0 +1,27 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class VoiceHostInfoTest extends Specification { + val string_info = hex"b2 4b00" + + "decode" in { + PacketCoding.DecodePacket(string_info).require match { + case VoiceHostInfo(player, _) => + player mustEqual PlanetSideGUID(75) + case _ => + ko + } + } + + "encode" in { + val msg = VoiceHostInfo(PlanetSideGUID(75), ByteVector.empty) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_info + } +} diff --git a/common/src/test/scala/game/VoiceHostKillTest.scala b/common/src/test/scala/game/VoiceHostKillTest.scala new file mode 100644 index 000000000..fa85c2e9d --- /dev/null +++ b/common/src/test/scala/game/VoiceHostKillTest.scala @@ -0,0 +1,27 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class VoiceHostKillTest extends Specification { + val string_kill = hex"b1" + + "decode" in { + PacketCoding.DecodePacket(string_kill).require match { + case VoiceHostKill() => + ok + case _ => + ko + } + } + + "encode" in { + val msg = VoiceHostKill() + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_kill + } +} diff --git a/common/src/test/scala/game/VoiceHostRequestTest.scala b/common/src/test/scala/game/VoiceHostRequestTest.scala new file mode 100644 index 000000000..2e5b5690e --- /dev/null +++ b/common/src/test/scala/game/VoiceHostRequestTest.scala @@ -0,0 +1,28 @@ +// Copyright (c) 2017 PSForever +package game + +import org.specs2.mutable._ +import net.psforever.packet._ +import net.psforever.packet.game._ +import scodec.bits._ + +class VoiceHostRequestTest extends Specification { + val string_request = hex"b0 2580 00" + + "decode" in { + PacketCoding.DecodePacket(string_request).require match { + case VoiceHostRequest(unk, player, _) => + unk mustEqual false + player mustEqual PlanetSideGUID(75) + case _ => + ko + } + } + + "encode" in { + val msg = VoiceHostRequest(false, PlanetSideGUID(75), ByteVector.empty) + val pkt = PacketCoding.EncodePacket(msg).require.toByteVector + + pkt mustEqual string_request + } +} diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 8c778c332..160d78020 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -177,7 +177,7 @@ class WorldSessionActor extends Actor with MDCContextAware { // NOTE: PlanetSideZoneID just chooses the background sendResponse(PacketCoding.CreateGamePacket(0, - CharacterInfoMessage(PlanetSideZoneID(1), 0, PlanetSideGUID(0), true, 0))) + CharacterInfoMessage(0, PlanetSideZoneID(1), 0, PlanetSideGUID(0), true, 0))) case msg @ CharacterRequestMessage(charId, action) => log.info("Handling " + msg) @@ -190,7 +190,7 @@ class WorldSessionActor extends Actor with MDCContextAware { log.debug("Object: " + obj) // LoadMapMessage 13714 in mossy .gcap // XXX: hardcoded shit - sendResponse(PacketCoding.CreateGamePacket(0, LoadMapMessage("map10","z10",40100,25,true,3770441820L))) //VS Sanctuary + sendResponse(PacketCoding.CreateGamePacket(0, LoadMapMessage("map13","home3",40100,25,true,3770441820L))) //VS Sanctuary sendResponse(PacketCoding.CreateGamePacket(0, ZonePopulationUpdateMessage(PlanetSideGUID(13), 414, 138, 0, 138, 0, 138, 0, 138, 0))) sendResponse(PacketCoding.CreateGamePacket(0, objectHex)) @@ -241,10 +241,10 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PacketCoding.CreateGamePacket(0, ActionResultMessage(true, None))) sendResponse(PacketCoding.CreateGamePacket(0, - CharacterInfoMessage(PlanetSideZoneID(0), 0, PlanetSideGUID(0), true, 0))) + CharacterInfoMessage(0, PlanetSideZoneID(0), 0, PlanetSideGUID(0), true, 0))) case KeepAliveMessage(code) => - sendResponse(PacketCoding.CreateGamePacket(0, KeepAliveMessage(0))) + sendResponse(PacketCoding.CreateGamePacket(0, KeepAliveMessage())) case msg @ BeginZoningMessage() => log.info("Reticulating splines ...")