2016-03-04 18:00:03 +00:00
|
|
|
// Copyright (c) 2016 PSForever.net to present
|
2016-03-04 19:47:38 +00:00
|
|
|
import java.net.{InetAddress, InetSocketAddress}
|
|
|
|
|
|
2016-03-04 18:00:03 +00:00
|
|
|
import org.specs2.mutable._
|
2016-05-03 07:58:58 +00:00
|
|
|
import net.psforever.packet._
|
2016-05-04 00:11:45 +00:00
|
|
|
import net.psforever.packet.game._
|
2016-06-04 17:22:25 +00:00
|
|
|
import scodec.Attempt.Successful
|
2016-03-04 18:00:03 +00:00
|
|
|
import scodec.bits._
|
|
|
|
|
|
|
|
|
|
class GamePacketTest extends Specification {
|
|
|
|
|
|
|
|
|
|
"PlanetSide game packet" in {
|
2016-05-14 18:50:33 +00:00
|
|
|
|
2016-05-14 19:38:34 +00:00
|
|
|
"ConnectToWorldRequestMessage" should {
|
|
|
|
|
val string = hex"03 8667656D696E69 0000000000000000 00000000 00000000 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 "
|
|
|
|
|
|
|
|
|
|
"decode" in {
|
|
|
|
|
PacketCoding.DecodePacket(string).require match {
|
2016-05-19 07:11:15 +00:00
|
|
|
case ConnectToWorldRequestMessage(serverName, token, majorVersion, minorVersion, revision, buildDate, unk) =>
|
2016-05-14 19:38:34 +00:00
|
|
|
serverName mustEqual "gemini"
|
2016-05-19 07:11:15 +00:00
|
|
|
token mustEqual ""
|
2016-05-14 19:38:34 +00:00
|
|
|
majorVersion mustEqual 0
|
|
|
|
|
minorVersion mustEqual 0
|
|
|
|
|
revision mustEqual 0
|
|
|
|
|
buildDate mustEqual ""
|
|
|
|
|
unk mustEqual 0
|
|
|
|
|
case default =>
|
2016-06-04 01:47:45 +00:00
|
|
|
ko
|
2016-05-14 19:38:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"encode" in {
|
2016-05-19 07:11:15 +00:00
|
|
|
val msg = ConnectToWorldRequestMessage("gemini", "", 0, 0, 0, "", 0)
|
2016-05-14 19:38:34 +00:00
|
|
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
|
|
|
|
|
|
|
|
|
pkt mustEqual string
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-14 18:50:33 +00:00
|
|
|
"ConnectToWorldMessage" should {
|
|
|
|
|
val string = hex"04 8667656D696E69 8C36342E33372E3135382E36393C75"
|
|
|
|
|
|
|
|
|
|
"decode" in {
|
|
|
|
|
PacketCoding.DecodePacket(string).require match {
|
|
|
|
|
case ConnectToWorldMessage(serverName, serverIp, serverPort) =>
|
|
|
|
|
serverName mustEqual "gemini"
|
|
|
|
|
serverIp mustEqual "64.37.158.69"
|
|
|
|
|
serverPort mustEqual 30012
|
|
|
|
|
case default =>
|
2016-06-04 01:47:45 +00:00
|
|
|
ko
|
2016-05-14 18:50:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"encode" in {
|
|
|
|
|
val msg = ConnectToWorldMessage("gemini", "64.37.158.69", 30012)
|
|
|
|
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
|
|
|
|
|
|
|
|
|
pkt mustEqual string
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-04 18:00:03 +00:00
|
|
|
|
|
|
|
|
"VNLWorldStatusMessage" should {
|
2016-05-14 18:50:33 +00:00
|
|
|
// NOTE: the ServerType is encoded as 0x03 here, but the real planetside server will encode it as 0x04
|
2016-03-04 18:00:03 +00:00
|
|
|
val string = hex"0597570065006c0063006f006d006500200074006f00200050006c0061006e00650074005300690064006500210020000186" ++
|
2016-05-14 18:50:33 +00:00
|
|
|
hex"67656d696e69" ++ hex"0100 03 00 01459e2540 3775" ++ bin"01".toByteVector
|
2016-03-04 18:00:03 +00:00
|
|
|
|
|
|
|
|
"decode" in {
|
|
|
|
|
PacketCoding.DecodePacket(string).require match {
|
|
|
|
|
case VNLWorldStatusMessage(message, worlds) =>
|
|
|
|
|
worlds.length mustEqual 1
|
|
|
|
|
message mustEqual "Welcome to PlanetSide! "
|
2016-03-04 19:47:38 +00:00
|
|
|
val world = worlds{0}
|
|
|
|
|
|
|
|
|
|
world.name mustEqual "gemini"
|
2016-06-04 07:33:11 +00:00
|
|
|
world.empireNeed mustEqual PlanetSideEmpire.NC
|
2016-03-04 19:47:38 +00:00
|
|
|
world.status mustEqual WorldStatus.Up
|
2016-05-14 18:50:33 +00:00
|
|
|
world.serverType mustEqual ServerType.Released
|
2016-03-04 19:47:38 +00:00
|
|
|
|
|
|
|
|
world.connections.length mustEqual 1
|
|
|
|
|
world.connections{0}.address.getPort mustEqual 30007
|
|
|
|
|
world.connections{0}.address.getAddress.toString mustEqual "/64.37.158.69"
|
2016-03-04 18:00:03 +00:00
|
|
|
case default =>
|
2016-06-04 01:47:45 +00:00
|
|
|
ko
|
2016-03-04 18:00:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"encode" in {
|
|
|
|
|
val msg = VNLWorldStatusMessage("Welcome to PlanetSide! ",
|
2016-03-04 19:47:38 +00:00
|
|
|
Vector(
|
2016-05-14 18:50:33 +00:00
|
|
|
WorldInformation("gemini", WorldStatus.Up, ServerType.Released,
|
2016-03-04 19:47:38 +00:00
|
|
|
Vector(
|
|
|
|
|
WorldConnectionInfo(new InetSocketAddress(InetAddress.getByName("64.37.158.69"), 30007))
|
2016-06-04 07:33:11 +00:00
|
|
|
), PlanetSideEmpire.NC
|
2016-03-04 19:47:38 +00:00
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
2016-03-04 18:00:03 +00:00
|
|
|
//0100 04 00 01459e2540377540
|
|
|
|
|
|
|
|
|
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
|
|
|
|
|
|
|
|
|
pkt mustEqual string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"encode and decode multiple worlds" in {
|
|
|
|
|
val msg = VNLWorldStatusMessage("Welcome to PlanetSide! ",
|
|
|
|
|
Vector(
|
2016-06-04 07:33:11 +00:00
|
|
|
WorldInformation("PSForever1", WorldStatus.Up, ServerType.Released, Vector(), PlanetSideEmpire.NC),
|
|
|
|
|
WorldInformation("PSForever2", WorldStatus.Down, ServerType.Beta, Vector(), PlanetSideEmpire.TR)
|
2016-03-04 18:00:03 +00:00
|
|
|
))
|
|
|
|
|
|
|
|
|
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
|
|
|
|
|
2016-05-01 08:37:36 +00:00
|
|
|
//println(pkt)
|
2016-03-04 18:00:03 +00:00
|
|
|
|
2016-06-04 01:47:45 +00:00
|
|
|
// TODO: actually test something
|
|
|
|
|
ok
|
2016-03-04 18:00:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-04 17:22:25 +00:00
|
|
|
"ActionResultMessage" should {
|
|
|
|
|
"decode" in {
|
|
|
|
|
PacketCoding.DecodePacket(hex"1f 80").require match {
|
|
|
|
|
case ActionResultMessage(okay, code) =>
|
|
|
|
|
okay === true
|
|
|
|
|
code === None
|
|
|
|
|
case default =>
|
|
|
|
|
ko
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PacketCoding.DecodePacket((hex"1f".bits ++ bin"0" ++ hex"01000000".bits).toByteVector).require match {
|
|
|
|
|
case ActionResultMessage(okay, code) =>
|
|
|
|
|
okay === false
|
|
|
|
|
code === Some(1)
|
|
|
|
|
case default =>
|
|
|
|
|
ko
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"encode" in {
|
|
|
|
|
PacketCoding.EncodePacket(ActionResultMessage(true, None)).require.toByteVector === hex"1f 80"
|
|
|
|
|
PacketCoding.EncodePacket(ActionResultMessage(false, Some(1))).require.toByteVector ===
|
|
|
|
|
(hex"1f".bits ++ bin"0" ++ hex"01000000".bits).toByteVector
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-07-15 05:45:10 +00:00
|
|
|
|
|
|
|
|
"ObjectCreateMessage" should {
|
|
|
|
|
val packet = hex"18 CF 13 00 00 BC 87 00 0A F0 16 C3 43 A1 30 90 00 02 C0 40 00 08 70 43 00 68 00 6F 00 72 00 64 00 54 00 52 00 82 65 1F F5 9E 80 80 00 00 00 00 00 3F FF C0 00 00 00 20 00 00 00 20 27 03 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FC CC 10 00 03 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 90 01 90 00 00 00 00 01 00 7E C8 00 C8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 C0 00 42 C5 46 86 C7 00 00 02 A0 00 00 12 60 78 70 65 5F 77 61 72 70 5F 67 61 74 65 5F 75 73 61 67 65 92 78 70 65 5F 69 6E 73 74 61 6E 74 5F 61 63 74 69 6F 6E 92 78 70 65 5F 73 61 6E 63 74 75 61 72 79 5F 68 65 6C 70 91 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 32 8E 78 70 65 5F 66 6F 72 6D 5F 73 71 75 61 64 8E 78 70 65 5F 74 68 5F 6E 6F 6E 73 61 6E 63 8B 78 70 65 5F 74 68 5F 61 6D 6D 6F 90 78 70 65 5F 74 68 5F 66 69 72 65 6D 6F 64 65 73 8F 75 73 65 64 5F 63 68 61 69 6E 62 6C 61 64 65 9A 76 69 73 69 74 65 64 5F 62 72 6F 61 64 63 61 73 74 5F 77 61 72 70 67 61 74 65 8E 76 69 73 69 74 65 64 5F 6C 6F 63 6B 65 72 8D 75 73 65 64 5F 70 75 6E 69 73 68 65 72 88 75 73 65 64 5F 72 65 6B 8D 75 73 65 64 5F 72 65 70 65 61 74 65 72 9F 76 69 73 69 74 65 64 5F 64 65 63 6F 6E 73 74 72 75 63 74 69 6F 6E 5F 74 65 72 6D 69 6E 61 6C 8F 75 73 65 64 5F 73 75 70 70 72 65 73 73 6F 72 96 76 69 73 69 74 65 64 5F 6F 72 64 65 72 5F 74 65 72 6D 69 6E 61 6C 85 6D 61 70 31 35 85 6D 61 70 31 34 85 6D 61 70 31 32 85 6D 61 70 30 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 0A 36 13 88 04 00 40 00 00 10 00 04 00 00 4D 6E 40 10 41 00 00 00 40 00 18 08 38 1C C0 20 32 00 00 07 80 15 E1 D0 02 10 20 00 00 08 00 03 01 07 13 A8 04 06 40 00 00 10 03 20 BB 00 42 E4 00 00 01 00 0E 07 70 08 6C 80 00 06 40 01 C0 F0 01 13 90 00 00 C8 00 38 1E 40 23 32 00 00 19 00 07 03 D0 05 0E 40 00 03 20 00 E8 7B 00 A4 C8 00 00 64 00 DA 4F 80 14 E1 00 00 00 40 00 18 08 38 1F 40 20 32 00 00 0A 00 08 "
|
|
|
|
|
val packet2 = hex"18 17 74 00 00 BC 8C 10 90 3B 45 C6 FA 94 00 9F F0 00 00 40 00 08 C0 44 00 69 00 66 00 66 00 45"
|
|
|
|
|
|
|
|
|
|
"decode" in {
|
|
|
|
|
PacketCoding.DecodePacket(packet2).require match {
|
|
|
|
|
case obj @ ObjectCreateMessage(len, cls, guid, parent) =>
|
|
|
|
|
len === 29719
|
|
|
|
|
cls === 121
|
|
|
|
|
guid === 2497
|
|
|
|
|
parent === None
|
|
|
|
|
case default =>
|
|
|
|
|
ko
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"encode" in {
|
|
|
|
|
ok
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-04 18:00:03 +00:00
|
|
|
}
|
|
|
|
|
}
|