Restructure repository

* Move /common/src to /src
* Move services to net.psforever package
* Move /pslogin to /server
This commit is contained in:
Jakob Gillich 2020-08-23 03:26:06 +02:00
parent 89a30ae6f6
commit f4fd78fc5d
958 changed files with 527 additions and 725 deletions

View file

@ -0,0 +1,11 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="ERROR">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View file

@ -0,0 +1,223 @@
// Copyright (c) 2017 PSForever
import org.specs2.mutable._
import net.psforever.newcodecs._
import net.psforever.types._
import scodec.bits._
class CodecTest extends Specification {
"QuantizedDoubleCodec" should {
val string_1 = hex"6E2D70"
val string_2 = hex"000000"
val string_3 = hex"B616"
val string_4 = hex"857C"
val string_5 = hex"5380"
val string_6 = hex"FFFC"
"decode" in {
newcodecs.q_double(0.0, 8192.0, 20).decode(string_1.bits).require.value mustEqual 3674.859375
newcodecs.q_double(0.0, 8192.0, 20).decode(string_2.bits).require.value mustEqual 0.0
newcodecs.q_double(0.0, 1024.0, 16).decode(string_3.bits).require.value mustEqual 90.84375
newcodecs.q_double(-256.0, 256.0, 14).decode(string_4.bits).require.value mustEqual -3.84375
newcodecs.q_double(-256.0, 256.0, 14).decode(string_5.bits).require.value mustEqual 2.59375
newcodecs.q_double(-256.0, 256.0, 14).decode(string_6.bits).require.value mustEqual 255.96875
}
"encode" in {
newcodecs.q_double(0.0, 8192.0, 20).encode(3674.859375).require.bytes mustEqual string_1
newcodecs.q_double(0.0, 8192.0, 20).encode(-1.23).require.bytes mustEqual string_2
newcodecs.q_double(0.0, 1024.0, 16).encode(90.84375).require.bytes mustEqual string_3
newcodecs.q_double(-256.0, 256.0, 14).encode(-3.84375).require.bytes mustEqual string_4
newcodecs.q_double(-256.0, 256.0, 14).encode(2.59375).require.bytes mustEqual string_5
newcodecs.q_double(-256.0, 256.0, 14).encode(257.0).require.bytes mustEqual string_6
}
}
"Vector3" should {
"position" should {
val string_pos = hex"6E2D762222B616"
"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
}
}
"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
}
}
"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
}
}
"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

@ -0,0 +1,136 @@
// Copyright (c) 2017 PSForever
import org.specs2.mutable._
import net.psforever.crypto.CryptoInterface
import net.psforever.crypto.CryptoInterface.CryptoDHState
import scodec.bits._
class CryptoInterfaceTest extends Specification {
args(stopOnFail = true)
"Crypto interface" should {
"correctly initialize" in {
CryptoInterface.initialize()
ok
}
"encrypt and decrypt" in {
val key = hex"41414141"
val plaintext = ByteVector.fill(16)(0x42)
val crypto = new CryptoInterface.CryptoState(key, key)
val ciphertext = crypto.encrypt(plaintext)
val decrypted = crypto.decrypt(ciphertext)
crypto.close
decrypted mustEqual plaintext
ciphertext mustNotEqual plaintext
}
"encrypt and decrypt must handle no bytes" in {
val key = hex"41414141"
val empty = ByteVector.empty
val crypto = new CryptoInterface.CryptoState(key, key)
val ciphertext = crypto.encrypt(empty)
val decrypted = crypto.decrypt(ciphertext)
crypto.close
ciphertext mustEqual empty
decrypted mustEqual empty
}
"encrypt and decrypt must only accept block aligned inputs" in {
val key = hex"41414141"
val badPad = ByteVector.fill(CryptoInterface.RC5_BLOCK_SIZE - 1)('a')
val crypto = new CryptoInterface.CryptoState(key, key)
crypto.encrypt(badPad) must throwA[IllegalArgumentException]
crypto.decrypt(badPad) must throwA[IllegalArgumentException]
crypto.close
ok
}
"arrive at a shared secret" in {
val server = new CryptoInterface.CryptoDHState()
val client = new CryptoInterface.CryptoDHState()
// 1. Client generates p, g, and its key pair
client.start()
// 2. Client sends p and g to server who then generates a key pair as well
server.start(client.getModulus, client.getGenerator)
// 3. Both parties come to a shared secret
val clientAgreed = client.agree(server.getPublicKey)
val serverAgreed = server.agree(client.getPublicKey)
// Free resources
server.close
client.close
clientAgreed mustEqual serverAgreed
}
"must fail to agree on a secret with a bad public key" in {
val server = new CryptoInterface.CryptoDHState()
val client = new CryptoInterface.CryptoDHState()
// 1. Client generates p, g, and its key pair
client.start()
// 2. Client sends p and g to server who then generates a key pair as well
server.start(client.getModulus, client.getGenerator)
// 3. Client agrees with a bad public key, so it must fail
val clientAgreed = client.agree(client.getPublicKey)
val serverAgreed = server.agree(client.getPublicKey)
// Free resources
server.close
client.close
clientAgreed mustNotEqual serverAgreed
}
"MD5MAC correctly" in {
val key = hex"377b60f8790f91b35a9da82945743da9"
val message = ByteVector(Array[Byte]('m', 'a', 's', 't', 'e', 'r', ' ', 's', 'e', 'c', 'r', 'e', 't')) ++
hex"b4aea1559444a20b6112a2892de40eac00000000c8aea155b53d187076b79abab59001b600000000"
val expected = hex"5aa15de41f5220cf5cca489155e1438c5aa15de4"
val output = CryptoInterface.MD5MAC(key, message, expected.length.toInt)
output mustEqual expected
}
"safely handle multiple starts" in {
val dontCare = ByteVector.fill(16)(0x42)
val dh = new CryptoDHState()
dh.start()
dh.start() must throwA[IllegalStateException]
dh.close
ok
}
"prevent function calls before initialization" in {
val dontCare = ByteVector.fill(16)(0x42)
val dh = new CryptoDHState()
dh.getGenerator must throwA[IllegalStateException]
dh.getModulus must throwA[IllegalStateException]
dh.getPrivateKey must throwA[IllegalStateException]
dh.getPublicKey must throwA[IllegalStateException]
dh.agree(dontCare) must throwA[IllegalStateException]
dh.close
ok
}
}
}

View file

@ -0,0 +1,135 @@
// Copyright (c) 2017 PSForever
import org.specs2.mutable._
import net.psforever.packet.control.{ClientStart, ServerStart}
import net.psforever.packet.crypto.{ClientChallengeXchg, ClientFinished, ServerChallengeXchg, ServerFinished}
import scodec.Codec
import scodec.bits._
class CryptoPacketTest extends Specification {
"PlanetSide crypto packet" in {
val cNonce = 656287232
"ClientStart" should {
val string = hex"0000000200261e27000001f0".bits
"decode" in {
val res = Codec.decode[ClientStart](string)
res.isSuccessful mustEqual true
res.require.value.clientNonce mustEqual cNonce
}
"encode" in {
val res = Codec.encode(ClientStart(cNonce))
res.require mustEqual string
}
}
"ServerStart" should {
val sNonce = 3468803409L
val string = hex"00261e2751bdc1ce000000000001d300000002".bits
"decode" in {
val res = Codec.decode[ServerStart](string)
val value = res.require.value
value.clientNonce mustEqual cNonce
value.serverNonce mustEqual sNonce
}
"encode" in {
val res = Codec.encode(ServerStart(cNonce, sNonce))
res.require mustEqual string
}
}
"ClientChallengeXchg" should {
val time = hex"962d8453"
val timeDecoded = scodec.codecs.uint32L.decode(time.bits).require.value
val challenge = hex"24f5997c c7d16031 d1f567e9"
val p = hex"f57511eb 8e5d1efb 8b7f3287 d5a18b17"
val g = hex"00000000 00000000 00000000 00000002"
val string = (hex"0101" ++ time ++ challenge ++ hex"00 01 0002 ff 2400 00 1000" ++
p ++ hex"1000" ++ g ++ hex"0000010307000000").bits
"decode" in {
val res = Codec.decode[ClientChallengeXchg](string)
val value = res.require.value
value.time mustEqual timeDecoded
value.challenge mustEqual challenge
value.p mustEqual p
value.g mustEqual g
}
"encode" in {
val res = Codec.encode(ClientChallengeXchg(timeDecoded, challenge, p, g))
res.require mustEqual string
}
}
"ServerChallengeXchg" should {
val time = hex"962d8453"
val timeDecoded = scodec.codecs.uint32L.decode(time.bits).require.value
val challenge = hex"1b0e6408 cd935ec2 429aeb58"
val pubKey = hex"51f83ce6 45e86c3e 79c8fc70 f6ddf14b"
val string = (hex"0201" ++ time ++ challenge ++ hex"00 01 03070000000c00 1000 " ++ pubKey ++ hex"0e").bits
"decode" in {
val res = Codec.decode[ServerChallengeXchg](string)
val value = res.require.value
value.time mustEqual timeDecoded
value.challenge mustEqual challenge
value.pubKey mustEqual pubKey
}
"encode" in {
val res = Codec.encode(ServerChallengeXchg(timeDecoded, challenge, pubKey))
res.require mustEqual string
}
}
"ClientFinished" should {
val challengeResult = hex"ea3cf05d a5cb4256 8bb91aa7"
val pubKey = hex"eddc35f2 52b02d0e 496ba273 54578e73"
val string = (hex"10 1000" ++ pubKey ++ hex"0114 " ++ challengeResult).bits
"decode" in {
val res = Codec.decode[ClientFinished](string)
val value = res.require.value
value.challengeResult mustEqual challengeResult
value.pubKey mustEqual pubKey
}
"encode" in {
val res = Codec.encode(ClientFinished(pubKey, challengeResult))
res.require mustEqual string
}
}
"ServerFinished" should {
val challengeResult = hex"d64ffb8e 526311b4 af46bece"
val string = (hex"0114" ++ challengeResult).bits
"decode" in {
val res = Codec.decode[ServerFinished](string)
val value = res.require.value
value.challengeResult mustEqual challengeResult
}
"encode" in {
val res = Codec.encode(ServerFinished(challengeResult))
res.require mustEqual string
}
}
}
}

View file

@ -0,0 +1,69 @@
// Copyright (c) 2017 PSForever
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control.{ClientStart, ServerStart}
import scodec.bits._
class PacketCodingTest extends Specification {
/*def roundTrip[Container <: PlanetSidePacketContainer, Packet <: PlanetSidePacket](cont : Container, pkt : Packet) = {
val filledContainer = cont match {
case x : ControlPacket => x.copy(packet = pkt.asInstanceOf[PlanetSideControlPacket])
}
val pktEncoded = PacketCoding.MarshalPacket(ControlPacket(packetUnderTest.opcode, packetUnderTest)).require
val pktDecoded = PacketCoding.UnMarshalPacket(pkt.toByteVector).require.asInstanceOf[ControlPacket]
val recvPkt = decoded.packet.asInstanceOf[ServerStart]
}*/
"Packet coding" should {
"correctly decode control packets" in {
val packet = PacketCoding.UnmarshalPacket(hex"0001 00000002 00261e27 000001f0").require
packet.isInstanceOf[ControlPacket] mustEqual true
val controlPacket = packet.asInstanceOf[ControlPacket]
controlPacket.opcode mustEqual ControlPacketOpcode.ClientStart
controlPacket.packet mustEqual ClientStart(656287232)
}
"encode and decode to identical packets" in {
val clientNonce = 213129
val serverNonce = 848483
val packetUnderTest = ServerStart(clientNonce, serverNonce)
val pkt = PacketCoding.MarshalPacket(ControlPacket(packetUnderTest.opcode, packetUnderTest)).require
val decoded = PacketCoding.UnmarshalPacket(pkt.toByteVector).require.asInstanceOf[ControlPacket]
val recvPkt = decoded.packet.asInstanceOf[ServerStart]
packetUnderTest mustEqual recvPkt
}
"reject corrupted control packets" in {
val packet = PacketCoding.UnmarshalPacket(hex"0001 00001002 00261e27 004101f0")
packet.isSuccessful mustEqual false
}
"correctly decode crypto packets" in {
val packet = PacketCoding.UnmarshalPacket(hex"0001 00000002 00261e27 000001f0").require
packet.isInstanceOf[ControlPacket] mustEqual true
val controlPacket = packet.asInstanceOf[ControlPacket]
controlPacket.opcode mustEqual ControlPacketOpcode.ClientStart
controlPacket.packet mustEqual ClientStart(656287232)
}
"reject bad packet types" in {
PacketCoding.UnmarshalPacket(hex"ff414141").isFailure mustEqual true
}
"reject small packets" in {
PacketCoding.UnmarshalPacket(hex"00").isFailure mustEqual true
PacketCoding.UnmarshalPacket(hex"").isFailure mustEqual true
}
}
}

View file

@ -0,0 +1,244 @@
// Copyright (c) 2017 PSForever
import org.specs2.mutable._
import net.psforever.types.Vector3
class Vector3Test extends Specification {
val vec = Vector3(1.3f, -2.6f, 3.9f)
"Vector3" should {
"construct" in {
vec.x mustEqual 1.3f
vec.y mustEqual -2.6f
vec.z mustEqual 3.9f
}
"isolate x,y components" in {
vec.xy mustEqual Vector3(1.3f, -2.6f, 0)
}
"promote float values into a specific z-format" in {
Vector3.z(3.9f) mustEqual Vector3(0, 0, 3.9f)
}
"calculate magnitude (like a vector) 1" in {
val obj = Vector3(2.0f, 0.0f, 0.0f)
Vector3.Magnitude(obj) mustEqual 2.0f
}
"calculate magnitude (like a vector) 2" in {
val obj = Vector3(3.0f, 4.0f, 0.0f)
Vector3.Magnitude(obj) mustEqual 5.0f
}
"calculate magnitude (like a vector) 3" in {
Vector3.Magnitude(vec) mustEqual 4.864155f
}
"calculate square magnitude (like a vector)" in {
Vector3.MagnitudeSquared(vec) mustEqual 23.66f
}
"calculate distance 1" in {
val obj1 = Vector3(0.0f, 0.0f, 0.0f)
val obj2 = Vector3(2.0f, 0.0f, 0.0f)
Vector3.Distance(obj1, obj2) mustEqual 2.0f
}
"calculate distance 2" in {
val obj1 = Vector3(0.0f, 0.0f, 0.0f)
val obj2 = Vector3(2.0f, 0.0f, 0.0f)
Vector3.Distance(obj1, obj2) mustEqual Vector3.Magnitude(obj2)
}
"calculate distance 3" in {
val obj1 = Vector3(3.0f, 4.0f, 5.0f)
val obj2 = Vector3(3.0f, 4.0f, 5.0f)
Vector3.Distance(obj1, obj2) mustEqual 0f
}
"perform addition" in {
val obj1 = Vector3(3.0f, 4.0f, 5.0f)
val obj2 = Vector3(3.0f, 4.0f, 5.0f)
obj1 + obj2 mustEqual Vector3(6f, 8f, 10f)
}
"perform subtraction" in {
val obj1 = Vector3(3.0f, 4.0f, 5.0f)
val obj2 = Vector3(3.0f, 4.0f, 5.0f)
obj1 - obj2 mustEqual Vector3(0f, 0f, 0f)
}
"multiply by a scalar" in {
vec * 3f mustEqual Vector3(3.8999999f, -7.7999997f, 11.700001f)
}
"separate into x-component and y-component only" in {
val obj = Vector3(1.1f, 2.2f, 3.3f)
obj.xy mustEqual Vector3(1.1f, 2.2f, 0f)
}
"calculate the unit vector (zero)" in {
Vector3.Unit(Vector3.Zero) mustEqual Vector3(0, 0, 0)
}
"calculate the unit vector (normal)" in {
import Vector3._
val one_root_two: Float = (1 / math.sqrt(2)).toFloat
val one_root_three: Float = (1 / math.sqrt(3)).toFloat
val ulp: Float = math.ulp(1) //measure of insignificance
Unit(Vector3(1, 0, 0)) mustEqual Vector3(1, 0, 0)
1 - Magnitude(Vector3(1, 0, 0)) < ulp mustEqual true
Unit(Vector3(1, 1, 0)) mustEqual Vector3(one_root_two, one_root_two, 0)
1 - Magnitude(Vector3(one_root_two, one_root_two, 0)) < ulp mustEqual true
Unit(Vector3(1, 1, 1)) mustEqual Vector3(one_root_three, one_root_three, one_root_three)
1 - Magnitude(Vector3(one_root_three, one_root_three, one_root_three)) < ulp mustEqual true
}
"calculate the dot product (magnitude-squared)" in {
Vector3.DotProduct(vec, vec) mustEqual Vector3.MagnitudeSquared(vec)
}
"calculate the dot product (two vectors)" in {
Vector3.DotProduct(vec, Vector3(3.4f, -5.6f, 7.8f)) mustEqual 49.4f
}
"calculate the dot product (zero vector)" in {
Vector3.DotProduct(vec, Vector3.Zero) mustEqual 0f
}
"calculate the cross product (identity)" in {
val Vx: Vector3 = Vector3(1, 0, 0)
val Vy: Vector3 = Vector3(0, 1, 0)
val Vz: Vector3 = Vector3(0, 0, 1)
Vector3.CrossProduct(Vx, Vy) mustEqual Vz
Vector3.CrossProduct(Vy, Vz) mustEqual Vx
Vector3.CrossProduct(Vz, Vx) mustEqual Vy
Vector3.CrossProduct(Vy, Vx) mustEqual Vector3(0, 0, -1)
Vector3.CrossProduct(Vz, Vy) mustEqual Vector3(-1, 0, 0)
Vector3.CrossProduct(Vx, Vz) mustEqual Vector3(0, -1, 0)
}
"calculate the cross product (full)" in {
val A: Vector3 = Vector3(2, 1, -1)
val B: Vector3 = Vector3(-3, 4, 1)
Vector3.CrossProduct(A, B) mustEqual Vector3(5, 1, 11)
Vector3.CrossProduct(B, A) mustEqual Vector3(-5, -1, -11)
}
"find a perpendicular vector with cross product" in {
val A: Vector3 = Vector3(2, 1, -1)
val B: Vector3 = Vector3(-3, 4, 1)
val C: Vector3 = Vector3.CrossProduct(A, B)
Vector3.DotProduct(A, C) mustEqual 0
Vector3.DotProduct(B, C) mustEqual 0
}
"calculate the scalar projection (perpendicular vectors)" in {
val Vx: Vector3 = Vector3(1, 0, 0)
val Vy: Vector3 = Vector3(0, 1, 0)
Vector3.ScalarProjection(Vx, Vy) mustEqual 0
}
"calculate the scalar projection (parallel vectors)" in {
val A: Vector3 = Vector3(2, 0, 0)
val B: Vector3 = Vector3(10, 0, 0)
Vector3.ScalarProjection(A, B) mustEqual 2
Vector3.ScalarProjection(B, A) mustEqual 10
}
"calculate the scalar projection (antiparallel vectors)" in {
val A: Vector3 = Vector3(2, 0, 0)
val B: Vector3 = Vector3(-10, 0, 0)
Vector3.ScalarProjection(A, B) mustEqual -2
Vector3.ScalarProjection(B, A) mustEqual -10
}
"calculate the scalar projection (normal)" in {
val A: Vector3 = Vector3(2, 1, -1)
val B: Vector3 = Vector3(3, 4, 1)
Vector3.ScalarProjection(A, B) mustEqual 1.7650452f
Vector3.ScalarProjection(B, A) mustEqual 3.6742344f
}
"calculate the vector projection (perpendicular vectors)" in {
val Vx: Vector3 = Vector3(1, 0, 0)
val Vy: Vector3 = Vector3(0, 1, 0)
Vector3.VectorProjection(Vx, Vy) mustEqual Vector3.Zero
}
"calculate the vector projection (parallel vectors)" in {
val A: Vector3 = Vector3(2, 0, 0)
val B: Vector3 = Vector3(10, 0, 0)
Vector3.VectorProjection(A, B) mustEqual A
Vector3.VectorProjection(B, A) mustEqual B
}
"calculate the vector projection (antiparallel vectors)" in {
val A: Vector3 = Vector3(2, 0, 0)
val B: Vector3 = Vector3(-10, 0, 0)
Vector3.VectorProjection(A, B) mustEqual A
Vector3.VectorProjection(B, A) mustEqual B
}
"calculate the vector projection (normal)" in {
val A: Vector3 = Vector3(2, 1, -1)
val B: Vector3 = Vector3(3, 4, 1)
Vector3.VectorProjection(A, B) mustEqual Vector3(1.0384614f, 1.3846153f, 0.34615383f)
Vector3.VectorProjection(B, A) mustEqual Vector3(2.9999998f, 1.4999999f, -1.4999999f)
}
"rotate positive x-axis-vector 90-degrees around the z-axis" in {
val A: Vector3 = Vector3(1, 0, 0)
A.Rz(0) mustEqual A
A.Rz(90) mustEqual Vector3(0, 1, 0)
A.Rz(180) mustEqual Vector3(-1, 0, 0)
A.Rz(270) mustEqual Vector3(0, -1, 0)
A.Rz(360) mustEqual A
}
"rotate positive y-axis-vector 90-degrees around the x-axis" in {
val A: Vector3 = Vector3(0, 1, 0)
A.Rx(0) mustEqual A
A.Rx(90) mustEqual Vector3(0, 0, 1)
A.Rx(180) mustEqual Vector3(0, -1, 0)
A.Rx(270) mustEqual Vector3(0, 0, -1)
A.Rx(360) mustEqual A
}
"rotate positive x-axis-vector 90-degrees around the y-axis" in {
val A: Vector3 = Vector3(1, 0, 0)
A.Ry(0) mustEqual A
A.Ry(90) mustEqual Vector3(0, 0, -1)
A.Ry(180) mustEqual Vector3(-1, 0, 0)
A.Ry(270) mustEqual Vector3(0, 0, 1)
A.Ry(360) mustEqual A
}
"compound rotation" in {
val A: Vector3 = Vector3(1, 0, 0)
A.Rz(90)
.Rx(90)
.Ry(90) mustEqual A
}
"45-degree rotation" in {
val A: Vector3 = Vector3(1, 0, 0)
A.Rz(45) mustEqual Vector3(0.70710677f, 0.70710677f, 0)
}
}
}

View file

@ -0,0 +1,81 @@
// Copyright (c) 2017 PSForever
package base
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import akka.testkit.{ImplicitSender, TestKit}
import com.typesafe.config.ConfigFactory
import org.scalatest.BeforeAndAfterAll
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike
import org.specs2.specification.Scope
import scala.collection.mutable
import scala.concurrent.duration.FiniteDuration
abstract class ActorTest(sys: ActorSystem = ActorSystem("system", ConfigFactory.parseMap(ActorTest.LoggingConfig)))
extends TestKit(sys)
with Scope
with ImplicitSender
with AnyWordSpecLike
with Matchers
with BeforeAndAfterAll {
override def afterAll(): Unit = {
TestKit.shutdownActorSystem(system)
}
}
object ActorTest {
import scala.jdk.CollectionConverters._
private val LoggingConfig = Map(
"akka.loggers" -> List("akka.testkit.TestEventListener").asJava,
"akka.loglevel" -> "OFF",
"akka.stdout-loglevel" -> "OFF",
"akka.log-dead-letters" -> "OFF"
).asJava
/**
* A (potential) workaround to a Travis CI issue involving polling a series of messages over a period of time.
* Running the test in isolation works every time.
* Running the test as part of a series produces mixed results.
* Travis CI fails the test every time by not getting any messages.
* @see TestKit.receiveN
* @param n the number of messages to poll
* @param timeout how long to wait for each message
* @param sys what to poll
* @return a list of messages
*/
def receiveMultiple(n: Int, timeout: FiniteDuration, sys: TestKit): List[Any] = {
assert(0 < n, s"number of expected messages must be positive non-zero integer - $n")
val out = {
val msgs = mutable.ListBuffer[Any]()
(0 until n).foreach(_ => {
msgs += sys.receiveOne(timeout)
})
msgs.toList
}
out
}
/**
* A middleman Actor that accepts a `Props` object to instantiate and accepts messages back from it.
* The purpose is to bypass a message receive issue with the `ActorTest` / `TestKit` class
* that does not properly queue messages dispatched to it
* when messages may be sent to it via a `context.parent` call.
* Please do not wrap and parameterize Props objects like this during normal Ops.
* @param actorProps the uninitialized `Actor` that uses `context.parent` to direct communication
* @param sendTo where to send mesages that have originated from an `actorProps` object;
* typically should point back to the test environment constructed by `TestKit`
*/
class SupportActorInterface(actorProps: Props, sendTo: ActorRef) extends Actor {
val test = context.actorOf(actorProps, "support-actor")
def receive: Receive = {
case msg =>
(if (sender() == test) {
sendTo
} else {
test
}) ! msg
}
}
}

View file

@ -0,0 +1,54 @@
// Copyright (c) 2020 PSForever
package base
import akka.actor.{Actor, ActorContext, ActorRef, Props}
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.Await
/**
* Create an `ActorTest` environment that has an `ActorContext` object.
*/
abstract class FreedContextActorTest extends ActorTest {
/*
Never do this in actual production code!
ActorSystem and ActorContext offer similar mechanisms for instantiating actors.
This is a consequence of their shared inheritance of the ActorRefFactory trait.
They are not equivalent enough to be able to pass one as the other as a parameter.
Because the ActorSystem has no context of its own,
various bizarre mechanisms have to be developed to use any methods that would pass in a context object.
We create a middleman Actor whose main purpose is to surrender its context object to the test environment directly
and then direct all messages sent to that object to the test environment.
*/
private val _testContextHandler = system.actorOf(Props(classOf[ContextSensitive]), "actor-test-cs")
private implicit val timeout = Timeout(5 seconds)
private val _testContextHandlerResult = ask(_testContextHandler, message = "", self)
implicit val context = Await.result(_testContextHandlerResult, timeout.duration).asInstanceOf[ActorContext]
}
/**
* Surrender your `context` object for a greater good!
*/
private class ContextSensitive extends Actor {
var output: ActorRef = ActorRef.noSender
def receive: Receive = {
case _ =>
context.become(PassThroughBehavior)
output = sender()
sender() ! context
}
/**
* Once the `context` object has been leased,
* this `Actor` becomes transparent.
* Calling `context.parent` from whatever `Actor` was spurned by the previously provided `context`,
* will now refer to whatever was the contact to gain access to it - the test environment.
* @return something to `become`
*/
def PassThroughBehavior: Receive = {
case msg => output forward msg
}
}

View file

@ -0,0 +1,27 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class ClientStartTest extends Specification {
val string = hex"0001 00000002 00261e27 000001f0"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ClientStart(nonce) =>
nonce mustEqual 656287232
case _ =>
ko
}
}
"encode" in {
val msg = ClientStart(656287232)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,26 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class ConnectionCloseTest extends Specification {
val string = hex"001D"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ConnectionClose() =>
ok
case _ =>
ko
}
}
"encode" in {
val msg = ConnectionClose()
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,32 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class ControlSyncRespTest extends Specification {
val string = hex"0008 5268 21392D92 0000000000000276 0000000000000275 0000000000000275 0000000000000276"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ControlSyncResp(a, b, c, d, e, f) =>
a mustEqual 21096
b mustEqual 0x21392d92
c mustEqual 0x276
d mustEqual 0x275
e mustEqual 0x275
f mustEqual 0x276
case _ =>
ko
}
}
"encode" in {
val encoded = PacketCoding.EncodePacket(ControlSyncResp(21096, 0x21392d92, 0x276, 0x275, 0x275, 0x276)).require
encoded.toByteVector mustEqual string
}
}

View file

@ -0,0 +1,32 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class ControlSyncTest extends Specification {
val string = hex"0007 5268 0000004D 00000052 0000004D 0000007C 0000004D 0000000000000276 0000000000000275"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ControlSync(a, b, c, d, e, f, g, h) =>
a mustEqual 21096
b mustEqual 0x4d
c mustEqual 0x52
d mustEqual 0x4d
e mustEqual 0x7c
f mustEqual 0x4d
g mustEqual 0x276
h mustEqual 0x275
case _ =>
ko
}
}
"encode" in {
val encoded = PacketCoding.EncodePacket(ControlSync(21096, 0x4d, 0x52, 0x4d, 0x7c, 0x4d, 0x276, 0x275)).require
encoded.toByteVector mustEqual string
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class HandleGamePacketTest extends Specification {
//this is the first from a series of SlottedMetaPacket4s; the length field was modified from 12 DC to pass the test
val base =
hex"18 D5 96 00 00 BC 8E 00 03 A2 16 5D A4 5F B0 80 00 04 30 40 00 08 30 46 00 4A 00 48 00 02 02 F0 62 1E 80 80 00 00 00 00 00 3F FF CC 0D 40 00 20 00 03 00 27 C3 01 C8 00 00 03 08 00 00 03 FF FF FF FC A4 04 00 00 62 00 18 02 00 50 00 00 00 00 00 00 00 00 00 00 00 00 00 01 90 01 90 00 C8 00 00 01 00 7E C8 00 C8 00 00 00 5D B0 81 40 00 00 00 00 00 00 00 00 00 00 00 00 02 C0 00 40 83 85 46 86 C7 07 8A 4A 80 70 0C 00 01 98 00 00 01 24 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 31 30 90 78 70 65 5F 6A 6F 69 6E 5F 70 6C 61 74 6F 6F 6E 92 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 31 34 8F 78 70 65 5F 6A 6F 69 6E 5F 6F 75 74 66 69 74 92 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 31 31 91 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 39 91 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 38 92 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 31 33 93 78 70 65 5F 77 61 72 70 5F 67 61 74 65 5F 75 73 61 67 65 91 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 32 92 78 70 65 5F 69 6E 73 74 61 6E 74 5F 61 63 74 69 6F 6E 8E 78 70 65 5F 66 6F 72 6D 5F 73 71 75 61 64 91 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 36 91 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 37 8E 78 70 65 5F 6A 6F 69 6E 5F 73 71 75 61 64 8C 78 70 65 5F 62 69 6E 64 5F 61 6D 73 91 78 70 65 5F 62 61 74 74 6C 65 5F 72 61 6E 6B 5F 35 91 78 70 65 5F 62 69 6E 64 5F 66 61 63 69 6C 69 74"
val string = hex"00 00 01 CB" ++ base
"decode" in {
PacketCoding.DecodePacket(string).require match {
case HandleGamePacket(len, data, extra) =>
len mustEqual 459
data mustEqual base
extra mustEqual BitVector.empty
case _ =>
ko
}
}
"encode" in {
val pkt = HandleGamePacket(base)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string
}
}

View file

@ -0,0 +1,199 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet.control.{ControlSync, MultiPacketBundle, MultiPacketCollector}
import net.psforever.packet.crypto.{ClientFinished, ServerFinished}
import net.psforever.packet.game.ObjectDeleteMessage
import net.psforever.types.PlanetSideGUID
class MultiPacketCollectorTest extends Specification {
val packet1 = ObjectDeleteMessage(PlanetSideGUID(1103), 2)
"MultiPacketBundle" should {
import scodec.bits._
val packet2 = ControlSync(21096, 0x4d, 0x52, 0x4d, 0x7c, 0x4d, 0x276, 0x275)
"construct" in {
MultiPacketBundle(List(packet1))
ok
}
"fail to construct if not initialized with PlanetSidePackets" in {
MultiPacketBundle(Nil) must throwA[IllegalArgumentException]
}
"concatenate bundles into a new bundle" in {
val obj1 = MultiPacketBundle(List(packet1))
val obj2 = MultiPacketBundle(List(packet2))
val obj3 = obj1 + obj2
obj3 match {
case MultiPacketBundle(list) =>
list.size mustEqual 2
list.head mustEqual packet1
list(1) mustEqual packet2
case _ =>
ko
}
}
"accept PlanetSideGamePackets and PlanetSideControlPackets" in {
MultiPacketBundle(List(packet2, packet1)) match {
case MultiPacketBundle(list) =>
list.size mustEqual 2
list.head mustEqual packet2
list(1) mustEqual packet1
case _ =>
ko
}
}
"ignore other types of PlanetSideContainerPackets" in {
val param = List(packet2, ClientFinished(hex"", hex""), packet1, ServerFinished(hex""))
MultiPacketBundle(param) match { //warning message will display in log
case MultiPacketBundle(list) =>
list.size mustEqual 2
list.head mustEqual param.head
list(1) mustEqual param(2)
case _ =>
ko
}
}
}
"MultiPacketCollector" should {
val packet2 = ObjectDeleteMessage(PlanetSideGUID(1105), 2)
val packet3 = ObjectDeleteMessage(PlanetSideGUID(1107), 2)
"construct" in {
new MultiPacketCollector()
ok
}
"construct with initial packets" in {
MultiPacketCollector(List(packet1, packet2))
ok
}
"can retrieve a bundle packets" in {
val obj = MultiPacketCollector(List(packet1, packet2))
obj.Bundle match {
case Some(MultiPacketBundle(list)) =>
list.size mustEqual 2
list.head mustEqual packet1
list(1) mustEqual packet2
case _ =>
ko
}
}
"can retrieve a bundle of potential packets" in {
val obj1 = new MultiPacketCollector()
obj1.Bundle match {
case Some(_) =>
ko
case _ => ;
}
val obj2 = MultiPacketCollector(List(packet1, packet2))
obj2.Bundle match {
case None =>
ko
case Some(MultiPacketBundle(list)) =>
list.size mustEqual 2
list.head mustEqual packet1
list(1) mustEqual packet2
}
}
"clear packets after being asked to bundle" in {
val list = List(packet1, packet2)
val obj = MultiPacketCollector(list)
obj.Bundle match {
case Some(MultiPacketBundle(bundle)) =>
bundle mustEqual list
case _ =>
ko
}
obj.Bundle match {
case Some(MultiPacketBundle(_)) =>
ko
case _ =>
ok
}
}
"add a packet" in {
val obj = new MultiPacketCollector()
obj.Add(packet1)
obj.Bundle match {
case Some(MultiPacketBundle(list)) =>
list.size mustEqual 1
list.head mustEqual packet1
case _ =>
ko
}
}
"add packets" in {
val obj = new MultiPacketCollector()
obj.Add(List(packet1, packet2))
obj.Bundle match {
case Some(MultiPacketBundle(list)) =>
list.size mustEqual 2
list.head mustEqual packet1
list(1) mustEqual packet2
case _ =>
ko
}
}
"concatenate bundles (1)" in {
val obj1 = new MultiPacketCollector()
obj1.Add(List(packet1, packet2))
obj1.Bundle match {
case Some(MultiPacketBundle(bundle1)) =>
val obj2 = MultiPacketCollector(bundle1)
obj2.Add(packet3)
obj2.Bundle match {
case Some(MultiPacketBundle(list)) =>
list.size mustEqual 3
list.head mustEqual packet1
list(1) mustEqual packet2
list(2) mustEqual packet3
case _ =>
ko
}
case _ =>
ko
}
}
"concatenate bundles (2)" in {
val obj1 = new MultiPacketCollector()
obj1.Add(List(packet1, packet2))
obj1.Bundle match {
case Some(MultiPacketBundle(bundle1)) =>
val obj2 = new MultiPacketCollector()
obj2.Add(packet3)
obj2.Add(bundle1)
obj2.Bundle match {
case Some(MultiPacketBundle(list)) =>
list.size mustEqual 3
list.head mustEqual packet3
list(1) mustEqual packet1
list(2) mustEqual packet2
case _ =>
ko
}
case _ =>
ko
}
}
}
}

View file

@ -0,0 +1,47 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet.control._
import org.specs2.specification.core.Fragment
import scodec.bits._
class MultiPacketExTest extends Specification {
val strings = Vector(
hex"00",
hex"01 41",
hex"01 41" ++ hex"02 4142",
hex"fe" ++ ByteVector.fill(0xfe)(0x41),
hex"ffff00" ++ ByteVector.fill(0xff)(0x41),
hex"ff0001" ++ ByteVector.fill(0x100)(0x41),
hex"ff ffff ffff 0000" ++ ByteVector.fill(0x0000ffff)(0x41),
hex"ff ffff 0000 0100" ++ ByteVector.fill(0x00010000)(0x41)
)
val packets = Vector(
MultiPacketEx(Vector(ByteVector.empty)),
MultiPacketEx(Vector(hex"41")),
MultiPacketEx(Vector(hex"41", hex"4142")),
MultiPacketEx(Vector(ByteVector.fill(0xfe)(0x41))),
MultiPacketEx(Vector(ByteVector.fill(0xff)(0x41))),
MultiPacketEx(Vector(ByteVector.fill(0x100)(0x41))),
MultiPacketEx(Vector(ByteVector.fill(0x0000ffff)(0x41))),
MultiPacketEx(Vector(ByteVector.fill(0x00010000)(0x41)))
)
"decode" in {
Fragment.foreach(strings.indices) { i =>
"test " + i ! { MultiPacketEx.decode(strings { i }.bits).require.value mustEqual packets { i } }
}
}
"encode" in {
Fragment.foreach(packets.indices) { i =>
"test " + i ! { MultiPacketEx.encode(packets { i }).require.toByteVector mustEqual strings { i } }
}
}
"sizeCodec description" in {
MultiPacketEx.sizeCodec.toString mustEqual "variable-bit unsigned integer"
}
}

View file

@ -0,0 +1,41 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class MultiPacketTest extends Specification {
val string =
hex"00 03 04 00 15 13 23 3A 00 09 03 E3 00 19 16 6D 56 05 68 05 40 A0 EF 45 00 15 0E 44 00 A0 A2 41 00 00 0F 88 00 06 E4 C0 60 00 00 00 15 E4 32 40 74 72 61 69 6E 69 6E 67 5F 77 65 61 70 6F 6E 73 30 31 13 BD 68 05 53 F6 EF 90 D1 6E 03 14 FE 78 8C 20 1C C0 00 00 1F 00 09 03 E4 6D 56 05 68 05 40 A0 EF 45 00 15 0E 44 30 89 A1 41 00 00 0F 8A 01 00 04 18 EF 80"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case MultiPacket(data) =>
data.size mustEqual 4
data(0) mustEqual hex"00151323"
data(
1
) mustEqual hex"000903e30019166d5605680540a0ef4500150e4400a0a24100000f880006e4c06000000015e43240747261696e696e675f776561706f6e733031"
data(2) mustEqual hex"bd680553f6ef90d16e0314fe788c201cc00000"
data(3) mustEqual hex"000903e46d5605680540a0ef4500150e443089a14100000f8a01000418ef80"
case _ =>
ko
}
}
"encode" in {
val msg = MultiPacket(
Vector(
hex"00151323",
hex"000903e30019166d5605680540a0ef4500150e4400a0a24100000f880006e4c06000000015e43240747261696e696e675f776561706f6e733031",
hex"bd680553f6ef90d16e0314fe788c201cc00000",
hex"000903e46d5605680540a0ef4500150e443089a14100000f8a01000418ef80"
)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,82 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control.RelatedA
import scodec.bits._
class RelatedATest extends Specification {
val string0 = hex"00 11 01 04"
val string1 = hex"00 12 01 04"
val string2 = hex"00 13 01 04"
val string3 = hex"00 14 01 04"
"decode (0)" in {
PacketCoding.DecodePacket(string0).require match {
case RelatedA(slot, subslot) =>
slot mustEqual 0
subslot mustEqual 260
case _ =>
ko
}
}
"decode (1)" in {
PacketCoding.DecodePacket(string1).require match {
case RelatedA(slot, subslot) =>
slot mustEqual 1
subslot mustEqual 260
case _ =>
ko
}
}
"decode (2)" in {
PacketCoding.DecodePacket(string2).require match {
case RelatedA(slot, subslot) =>
slot mustEqual 2
subslot mustEqual 260
case _ =>
ko
}
}
"decode (3)" in {
PacketCoding.DecodePacket(string3).require match {
case RelatedA(slot, subslot) =>
slot mustEqual 3
subslot mustEqual 260
case _ =>
ko
}
}
"encode (0)" in {
val pkt = RelatedA(0, 260)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string0
}
"encode (1)" in {
val pkt = RelatedA(1, 260)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string1
}
"encode (2)" in {
val pkt = RelatedA(2, 260)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string2
}
"encode (3)" in {
val pkt = RelatedA(3, 260)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string3
}
"encode (n)" in {
RelatedA(4, 260) must throwA[IllegalArgumentException]
}
}

View file

@ -0,0 +1,82 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control.RelatedB
import scodec.bits._
class RelatedBTest extends Specification {
val string0 = hex"00 15 01 04"
val string1 = hex"00 16 01 04"
val string2 = hex"00 17 01 04"
val string3 = hex"00 18 01 04"
"decode (0)" in {
PacketCoding.DecodePacket(string0).require match {
case RelatedB(slot, subslot) =>
slot mustEqual 0
subslot mustEqual 260
case _ =>
ko
}
}
"decode (1)" in {
PacketCoding.DecodePacket(string1).require match {
case RelatedB(slot, subslot) =>
slot mustEqual 1
subslot mustEqual 260
case _ =>
ko
}
}
"decode (2)" in {
PacketCoding.DecodePacket(string2).require match {
case RelatedB(slot, subslot) =>
slot mustEqual 2
subslot mustEqual 260
case _ =>
ko
}
}
"decode (3)" in {
PacketCoding.DecodePacket(string3).require match {
case RelatedB(slot, subslot) =>
slot mustEqual 3
subslot mustEqual 260
case _ =>
ko
}
}
"encode (0)" in {
val pkt = RelatedB(0, 260)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string0
}
"encode (1)" in {
val pkt = RelatedB(1, 260)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string1
}
"encode (2)" in {
val pkt = RelatedB(2, 260)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string2
}
"encode (3)" in {
val pkt = RelatedB(3, 260)
val msg = PacketCoding.EncodePacket(pkt).require.toByteVector
msg mustEqual string3
}
"encode (n)" in {
RelatedB(4, 260) must throwA[IllegalArgumentException]
}
}

View file

@ -0,0 +1,79 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import org.specs2.specification.core.Fragment
import scodec.bits._
import scodec.codecs.uint16
class SlottedMetaPacketTest extends Specification {
val string = hex"00 09 00 00 00194302484C36563130433F" ++
hex"4C6835316369774A0000000018FABE0C" ++
hex"00000000000000000000000001000000" ++
hex"020000006B7BD8288C6469666671756F" ++
hex"7469656E740000000000440597570065" ++
hex"006C0063006F006D006500200074006F" ++
hex"00200050006C0061006E006500740053" ++
hex"0069006400650021002000018667656D" ++
hex"696E690100040001459E2540377540"
def createMetaPacket(slot: Int, subslot: Int, rest: ByteVector) =
hex"00" ++
ControlPacketOpcode.codec
.encode(
ControlPacketOpcode(ControlPacketOpcode.SlottedMetaPacket0.id + slot)
)
.require
.toByteVector ++ uint16.encode(subslot).require.toByteVector ++ rest
"decode as the base slot and subslot" in {
PacketCoding.DecodePacket(string).require match {
case SlottedMetaPacket(slot, subslot, rest) =>
slot mustEqual 0
subslot mustEqual 0
rest mustEqual string.drop(4)
case _ =>
ko
}
}
"decode as an arbitrary slot and subslot" in {
val maxSlots = ControlPacketOpcode.SlottedMetaPacket7.id - ControlPacketOpcode.SlottedMetaPacket0.id
// create all possible SlottedMetaPackets
Fragment.foreach(0 to maxSlots) { i =>
"slot " + i ! {
val subslot = 12323
val pkt = createMetaPacket(i, subslot, ByteVector.empty)
PacketCoding.DecodePacket(pkt).require match {
case SlottedMetaPacket(slot, subslotDecoded, rest) =>
// XXX: there isn't a simple solution to Slot0 and Slot4 be aliases of each other structurally
// This is probably best left to higher layers
//slot mustEqual i % 4 // this is seen at 0x00A3FBFA
slot mustEqual i
subslotDecoded mustEqual subslot
rest mustEqual ByteVector.empty // empty in this case
case _ =>
ko
}
}
}
}
"encode" in {
val encoded = PacketCoding.EncodePacket(SlottedMetaPacket(0, 0x1000, ByteVector.empty)).require
val encoded2 = PacketCoding.EncodePacket(SlottedMetaPacket(3, 0xffff, hex"414243")).require
val encoded3 = PacketCoding.EncodePacket(SlottedMetaPacket(7, 0, hex"00")).require
encoded.toByteVector mustEqual createMetaPacket(0, 0x1000, ByteVector.empty)
encoded2.toByteVector mustEqual createMetaPacket(3, 0xffff, hex"414243")
encoded3.toByteVector mustEqual createMetaPacket(7, 0, hex"00")
PacketCoding.EncodePacket(SlottedMetaPacket(8, 0, hex"00")).require must throwA[AssertionError]
PacketCoding.EncodePacket(SlottedMetaPacket(-1, 0, hex"00")).require must throwA[AssertionError]
PacketCoding.EncodePacket(SlottedMetaPacket(0, 0x10000, hex"00")).require must throwA[IllegalArgumentException]
}
}

View file

@ -0,0 +1,26 @@
// Copyright (c) 2017 PSForever
package control
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.control._
import scodec.bits._
class TeardownConnectionTest extends Specification {
val string = hex"00 05 02 4F 57 17 00 06"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case TeardownConnection(nonce) =>
nonce mustEqual 391597826
case _ =>
ko
}
}
"encode" in {
val encoded = PacketCoding.EncodePacket(TeardownConnection(391597826)).require
encoded.toByteVector mustEqual string
}
}

View file

@ -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.PlanetSideGUID
import scodec.bits._
class ActionCancelMessageTest extends Specification {
val string = hex"22 201ee01a10"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ActionCancelMessage(player_guid, object_guid, unk) =>
player_guid mustEqual PlanetSideGUID(7712)
object_guid mustEqual PlanetSideGUID(6880)
unk mustEqual 1
case _ =>
ko
}
}
"encode" in {
val msg = ActionCancelMessage(PlanetSideGUID(7712), PlanetSideGUID(6880), 1)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -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 ActionProgressMessageTest extends Specification {
val string = hex"216000000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ActionProgressMessage(unk1, unk2) =>
unk1 mustEqual 6
unk2 mustEqual 0
case _ =>
ko
}
}
"encode" in {
val msg = ActionProgressMessage(6, 0L)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,60 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class ActionResultMessageTest extends Specification {
val string_pass = hex"1f 80"
val string_fail = hex"1f 0080000000"
"decode (pass)" in {
PacketCoding.DecodePacket(string_pass).require match {
case ActionResultMessage(okay, code) =>
okay mustEqual true
code mustEqual None
case _ =>
ko
}
}
"decode (fail)" in {
PacketCoding.DecodePacket(string_fail).require match {
case ActionResultMessage(okay, code) =>
okay mustEqual false
code mustEqual Some(1)
case _ =>
ko
}
}
"encode (pass, full)" in {
val msg = ActionResultMessage(true, None)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_pass
}
"encode (pass, minimal)" in {
val msg = ActionResultMessage.Pass
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_pass
}
"encode (fail, full)" in {
val msg = ActionResultMessage(false, Some(1))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_fail
}
"encode (fail, minimal)" in {
val msg = ActionResultMessage.Fail(1)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_fail
}
}

View file

@ -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.{ExoSuitType, PlanetSideGUID}
import scodec.bits._
class ArmorChangedMessageTest extends Specification {
val string = hex"3E 11 01 4C"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ArmorChangedMessage(player_guid, armor, subtype) =>
player_guid mustEqual PlanetSideGUID(273)
armor mustEqual ExoSuitType.MAX
subtype mustEqual 3
case _ =>
ko
}
}
"encode" in {
val msg = ArmorChangedMessage(PlanetSideGUID(273), ExoSuitType.MAX, 3)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,45 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideEmpire, Vector3}
import scodec.bits._
class AvatarDeadStateMessageTest extends Specification {
val string = hex"ad3c1260801c12608009f99861fb0741e040000010"
val string_invalid = hex"ad3c1260801c12608009f99861fb0741e0400000F0"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case AvatarDeadStateMessage(unk1, unk2, unk3, pos, unk4, unk5) =>
unk1 mustEqual DeadState.Dead
unk2 mustEqual 300000
unk3 mustEqual 300000
pos mustEqual Vector3(6552.617f, 4602.375f, 60.90625f)
unk4 mustEqual PlanetSideEmpire.VS
unk5 mustEqual true
case _ =>
ko
}
}
"decode (failure)" in {
PacketCoding.DecodePacket(string_invalid).isFailure mustEqual true
}
"encode" in {
val msg = AvatarDeadStateMessage(
DeadState.Dead,
300000,
300000,
Vector3(6552.617f, 4602.375f, 60.90625f),
PlanetSideEmpire.VS,
true
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class AvatarFirstTimeEventMessageTest extends Specification {
val string = hex"69 4b00 c000 01000000 9e 766973697465645f63657274696669636174696f6e5f7465726d696e616c"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case AvatarFirstTimeEventMessage(avatar_guid, object_guid, unk1, event_name) =>
avatar_guid mustEqual PlanetSideGUID(75)
object_guid mustEqual PlanetSideGUID(192)
unk1 mustEqual 1
event_name mustEqual "visited_certification_terminal"
case _ =>
ko
}
}
"encode" in {
val msg = AvatarFirstTimeEventMessage(PlanetSideGUID(75), PlanetSideGUID(192), 1, "visited_certification_terminal")
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{GrenadeState, PlanetSideGUID}
import scodec.bits._
class AvatarGrenadeStateMessageTest extends Specification {
val string = hex"A9 DA11 01"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case AvatarGrenadeStateMessage(player_guid, state) =>
player_guid mustEqual PlanetSideGUID(4570)
state mustEqual GrenadeState.Primed
case _ =>
ko
}
}
"encode" in {
val msg = AvatarGrenadeStateMessage(PlanetSideGUID(4570), GrenadeState.Primed)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class AvatarImplantMessageTest extends Specification {
val string = hex"58 630C 68 80"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case AvatarImplantMessage(player_guid, unk1, unk2, implant) =>
player_guid mustEqual PlanetSideGUID(3171)
unk1 mustEqual ImplantAction.Activation
unk2 mustEqual 1
implant mustEqual 1
case _ =>
ko
}
}
"encode" in {
val msg = AvatarImplantMessage(PlanetSideGUID(3171), ImplantAction.Activation, 1, 1)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -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 AvatarJumpMessageTest extends Specification {
val string = hex"35 80"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case AvatarJumpMessage(state) =>
state mustEqual true
case _ =>
ko
}
}
"encode" in {
val msg = AvatarJumpMessage(true)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,50 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class AvatarSearchCriteriaMessageTest extends Specification {
val string = hex"64 C604 00 00 00 00 00 00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case AvatarSearchCriteriaMessage(unk1, unk2) =>
unk1 mustEqual PlanetSideGUID(1222)
unk2.length mustEqual 6
unk2.head mustEqual 0
unk2(1) mustEqual 0
unk2(2) mustEqual 0
unk2(3) mustEqual 0
unk2(4) mustEqual 0
unk2(5) mustEqual 0
case _ =>
ko
}
}
"encode" in {
val msg = AvatarSearchCriteriaMessage(PlanetSideGUID(1222), List(0, 0, 0, 0, 0, 0))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
"encode (failure; wrong number of list entries)" in {
val msg = AvatarSearchCriteriaMessage(PlanetSideGUID(1222), List(0))
PacketCoding.EncodePacket(msg).isSuccessful mustEqual false
}
"encode (failure; list number too big)" in {
val msg = AvatarSearchCriteriaMessage(PlanetSideGUID(1222), List(0, 0, 0, 0, 0, 256))
PacketCoding.EncodePacket(msg).isSuccessful mustEqual false
}
"encode (failure; list number too small)" in {
val msg = AvatarSearchCriteriaMessage(PlanetSideGUID(1222), List(0, 0, 0, -1, 0, 0))
PacketCoding.EncodePacket(msg).isSuccessful mustEqual false
}
}

View file

@ -0,0 +1,80 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class AvatarStatisticsMessageTest extends Specification {
val string_long = hex"7F 4 00000000 0"
val string_complex =
hex"7F 01 3C 40 20 00 00 00 C0 00 00 00 00 00 00 00 20 00 00 00 20 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00"
"decode (long)" in {
PacketCoding.DecodePacket(string_long).require match {
case AvatarStatisticsMessage(unk, stats) =>
unk mustEqual 2
stats.unk1 mustEqual None
stats.unk2 mustEqual None
stats.unk3.length mustEqual 1
stats.unk3.head mustEqual 0
case _ =>
ko
}
}
"decode (complex)" in {
PacketCoding.DecodePacket(string_complex).require match {
case AvatarStatisticsMessage(unk, stats) =>
unk mustEqual 0
stats.unk1 mustEqual Some(1)
stats.unk2 mustEqual Some(572)
stats.unk3.length mustEqual 8
stats.unk3.head mustEqual 1
stats.unk3(1) mustEqual 6
stats.unk3(2) mustEqual 0
stats.unk3(3) mustEqual 1
stats.unk3(4) mustEqual 1
stats.unk3(5) mustEqual 2
stats.unk3(6) mustEqual 0
stats.unk3(7) mustEqual 0
case _ =>
ko
}
}
"encode (long)" in {
val msg = AvatarStatisticsMessage(2, Statistics(0L))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_long
}
"encode (complex)" in {
val msg = AvatarStatisticsMessage(0, Statistics(1, 572, List[Long](1, 6, 0, 1, 1, 2, 0, 0)))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_complex
}
"encode (failure; long; missing value)" in {
val msg = AvatarStatisticsMessage(0, Statistics(None, None, List(0L)))
PacketCoding.EncodePacket(msg).isFailure mustEqual true
}
"encode (failure; complex; missing value (5-bit))" in {
val msg = AvatarStatisticsMessage(0, Statistics(None, Some(572), List[Long](1, 6, 0, 1, 1, 2, 0, 0)))
PacketCoding.EncodePacket(msg).isFailure mustEqual true
}
"encode (failure; complex; missing value (11-bit))" in {
val msg = AvatarStatisticsMessage(0, Statistics(Some(1), None, List[Long](1, 6, 0, 1, 1, 2, 0, 0)))
PacketCoding.EncodePacket(msg).isFailure mustEqual true
}
"encode (failure; complex; wrong number of list entries)" in {
val msg = AvatarStatisticsMessage(0, Statistics(Some(1), None, List[Long](1, 6, 0, 1)))
PacketCoding.EncodePacket(msg).isFailure mustEqual true
}
}

View file

@ -0,0 +1,49 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class AvatarVehicleTimerMessageTest extends Specification {
val string = hex"57bd16866d65646b69740500000000"
val string2 = hex"57971b84667572794800000080"
"decode medkit" in {
PacketCoding.DecodePacket(string).require match {
case AvatarVehicleTimerMessage(player_guid, text, time, u1) =>
player_guid mustEqual PlanetSideGUID(5821)
text mustEqual "medkit"
time mustEqual 5
u1 mustEqual false
case _ =>
ko
}
}
"decode fury" in {
PacketCoding.DecodePacket(string2).require match {
case AvatarVehicleTimerMessage(player_guid, text, time, u1) =>
player_guid mustEqual PlanetSideGUID(7063)
text mustEqual "fury"
time mustEqual 72
u1 mustEqual true
case _ =>
ko
}
}
"encode medkit" in {
val msg = AvatarVehicleTimerMessage(PlanetSideGUID(5821), "medkit", 5, false)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
"encode fury" in {
val msg = AvatarVehicleTimerMessage(PlanetSideGUID(7063), "fury", 72, true)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string2
}
}

View file

@ -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.PlanetSideGUID
import scodec.bits._
class BattleExperienceMessageTest extends Specification {
val string = hex"B4 8A0A E7030000 00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case BattleExperienceMessage(player_guid, experience, unk) =>
player_guid mustEqual PlanetSideGUID(2698)
experience mustEqual 999
unk mustEqual 0
case _ =>
ko
}
}
"encode" in {
val msg = BattleExperienceMessage(PlanetSideGUID(2698), 999, 0)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,336 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class BattleplanMessageTest extends Specification {
val string_start =
hex"b3 3a197902 94 59006500740041006e006f0074006800650072004600610069006c0075007200650041006c007400 0000 01 e0"
val string_stop =
hex"b3 3a197902 94 59006500740041006e006f0074006800650072004600610069006c0075007200650041006c007400 0000 01 f0"
val string_line =
hex"b3 85647702 8c 4f0075007400730074006100620075006c006f0075007300 0a00 20 2aba2b4aae8bd2aba334aae8dd2aca3b4ab28fd2aca414ab29152aca474ab292d2ada4d4ab69452ada534ab695d2ada594ab696d2ada5d4ab697d2ada614ab698d2ada654ab699d2ada694ab69ad2aea6d4aba9bd2aea714aba9cd2aea754aba9dd2aea794aba9ed"
val string_style = hex"b3856477028c4f0075007400730074006100620075006c006f00750073000a00031d22aba2f4aae8cd"
val string_message =
hex"b3 85647702 8c 4f0075007400730074006100620075006c006f0075007300 0a00 01 6aba2b5011c0480065006c006c006f00200041007500720061007800690073002100"
//0xb3856477028c4f0075007400730074006100620075006c006f00750073000a000130
"decode (start)" in {
PacketCoding.DecodePacket(string_start).require match {
case BattleplanMessage(char_id, player_name, zone_id, diagrams) =>
char_id mustEqual 41490746
player_name mustEqual "YetAnotherFailureAlt"
zone_id mustEqual 0
diagrams.size mustEqual 1
//0
diagrams.head.action mustEqual DiagramActionCode.StartDrawing
diagrams.head.stroke.isDefined mustEqual false
case _ =>
ko
}
}
"decode (end)" in {
PacketCoding.DecodePacket(string_stop).require match {
case BattleplanMessage(char_id, player_name, zone_id, diagrams) =>
char_id mustEqual 41490746
player_name mustEqual "YetAnotherFailureAlt"
zone_id mustEqual 0
diagrams.size mustEqual 1
//0
diagrams.head.action mustEqual DiagramActionCode.StopDrawing
diagrams.head.stroke.isDefined mustEqual false
case _ =>
ko
}
}
"decode (stop)" in {
PacketCoding.DecodePacket(string_line).require match {
case BattleplanMessage(char_id, player_name, zone_id, diagrams) =>
char_id mustEqual 41378949
player_name mustEqual "Outstabulous"
zone_id mustEqual 10
diagrams.size mustEqual 32
//0
diagrams.head.action mustEqual DiagramActionCode.Vertex
diagrams.head.stroke.isDefined mustEqual true
diagrams.head.stroke.get.isInstanceOf[Vertex] mustEqual true
diagrams.head.stroke.get.asInstanceOf[Vertex].x mustEqual 7512.0f
diagrams.head.stroke.get.asInstanceOf[Vertex].y mustEqual 6312.0f
//1
diagrams(1).action mustEqual DiagramActionCode.Vertex
diagrams(1).stroke.get.asInstanceOf[Vertex].x mustEqual 7512.0f
diagrams(1).stroke.get.asInstanceOf[Vertex].y mustEqual 6328.0f
//2
diagrams(2).action mustEqual DiagramActionCode.Vertex
diagrams(2).stroke.get.asInstanceOf[Vertex].x mustEqual 7512.0f
diagrams(2).stroke.get.asInstanceOf[Vertex].y mustEqual 6344.0f
//3
diagrams(3).action mustEqual DiagramActionCode.Vertex
diagrams(3).stroke.get.asInstanceOf[Vertex].x mustEqual 7512.0f
diagrams(3).stroke.get.asInstanceOf[Vertex].y mustEqual 6360.0f
//4
diagrams(4).action mustEqual DiagramActionCode.Vertex
diagrams(4).stroke.get.asInstanceOf[Vertex].x mustEqual 7520.0f
diagrams(4).stroke.get.asInstanceOf[Vertex].y mustEqual 6376.0f
//5
diagrams(5).action mustEqual DiagramActionCode.Vertex
diagrams(5).stroke.get.asInstanceOf[Vertex].x mustEqual 7520.0f
diagrams(5).stroke.get.asInstanceOf[Vertex].y mustEqual 6392.0f
//6
diagrams(6).action mustEqual DiagramActionCode.Vertex
diagrams(6).stroke.get.asInstanceOf[Vertex].x mustEqual 7520.0f
diagrams(6).stroke.get.asInstanceOf[Vertex].y mustEqual 6400.0f
//7
diagrams(7).action mustEqual DiagramActionCode.Vertex
diagrams(7).stroke.get.asInstanceOf[Vertex].x mustEqual 7520.0f
diagrams(7).stroke.get.asInstanceOf[Vertex].y mustEqual 6416.0f
//8
diagrams(8).action mustEqual DiagramActionCode.Vertex
diagrams(8).stroke.get.asInstanceOf[Vertex].x mustEqual 7520.0f
diagrams(8).stroke.get.asInstanceOf[Vertex].y mustEqual 6424.0f
//9
diagrams(9).action mustEqual DiagramActionCode.Vertex
diagrams(9).stroke.get.asInstanceOf[Vertex].x mustEqual 7520.0f
diagrams(9).stroke.get.asInstanceOf[Vertex].y mustEqual 6440.0f
//10
diagrams(10).action mustEqual DiagramActionCode.Vertex
diagrams(10).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(10).stroke.get.asInstanceOf[Vertex].y mustEqual 6448.0f
//11
diagrams(11).action mustEqual DiagramActionCode.Vertex
diagrams(11).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(11).stroke.get.asInstanceOf[Vertex].y mustEqual 6464.0f
//12
diagrams(12).action mustEqual DiagramActionCode.Vertex
diagrams(12).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(12).stroke.get.asInstanceOf[Vertex].y mustEqual 6472.0f
//13
diagrams(13).action mustEqual DiagramActionCode.Vertex
diagrams(13).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(13).stroke.get.asInstanceOf[Vertex].y mustEqual 6488.0f
//14
diagrams(14).action mustEqual DiagramActionCode.Vertex
diagrams(14).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(14).stroke.get.asInstanceOf[Vertex].y mustEqual 6496.0f
//15
diagrams(15).action mustEqual DiagramActionCode.Vertex
diagrams(15).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(15).stroke.get.asInstanceOf[Vertex].y mustEqual 6504.0f
//16
diagrams(16).action mustEqual DiagramActionCode.Vertex
diagrams(16).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(16).stroke.get.asInstanceOf[Vertex].y mustEqual 6512.0f
//17
diagrams(17).action mustEqual DiagramActionCode.Vertex
diagrams(17).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(17).stroke.get.asInstanceOf[Vertex].y mustEqual 6520.0f
//18
diagrams(18).action mustEqual DiagramActionCode.Vertex
diagrams(18).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(18).stroke.get.asInstanceOf[Vertex].y mustEqual 6528.0f
//19
diagrams(19).action mustEqual DiagramActionCode.Vertex
diagrams(19).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(19).stroke.get.asInstanceOf[Vertex].y mustEqual 6536.0f
//20
diagrams(20).action mustEqual DiagramActionCode.Vertex
diagrams(20).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(20).stroke.get.asInstanceOf[Vertex].y mustEqual 6544.0f
//21
diagrams(21).action mustEqual DiagramActionCode.Vertex
diagrams(21).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(21).stroke.get.asInstanceOf[Vertex].y mustEqual 6552.0f
//22
diagrams(22).action mustEqual DiagramActionCode.Vertex
diagrams(22).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(22).stroke.get.asInstanceOf[Vertex].y mustEqual 6560.0f
//23
diagrams(23).action mustEqual DiagramActionCode.Vertex
diagrams(23).stroke.get.asInstanceOf[Vertex].x mustEqual 7528.0f
diagrams(23).stroke.get.asInstanceOf[Vertex].y mustEqual 6568.0f
//24
diagrams(24).action mustEqual DiagramActionCode.Vertex
diagrams(24).stroke.get.asInstanceOf[Vertex].x mustEqual 7536.0f
diagrams(24).stroke.get.asInstanceOf[Vertex].y mustEqual 6576.0f
//25
diagrams(25).action mustEqual DiagramActionCode.Vertex
diagrams(25).stroke.get.asInstanceOf[Vertex].x mustEqual 7536.0f
diagrams(25).stroke.get.asInstanceOf[Vertex].y mustEqual 6584.0f
//26
diagrams(26).action mustEqual DiagramActionCode.Vertex
diagrams(26).stroke.get.asInstanceOf[Vertex].x mustEqual 7536.0f
diagrams(26).stroke.get.asInstanceOf[Vertex].y mustEqual 6592.0f
//27
diagrams(27).action mustEqual DiagramActionCode.Vertex
diagrams(27).stroke.get.asInstanceOf[Vertex].x mustEqual 7536.0f
diagrams(27).stroke.get.asInstanceOf[Vertex].y mustEqual 6600.0f
//28
diagrams(28).action mustEqual DiagramActionCode.Vertex
diagrams(28).stroke.get.asInstanceOf[Vertex].x mustEqual 7536.0f
diagrams(28).stroke.get.asInstanceOf[Vertex].y mustEqual 6608.0f
//29
diagrams(29).action mustEqual DiagramActionCode.Vertex
diagrams(29).stroke.get.asInstanceOf[Vertex].x mustEqual 7536.0f
diagrams(29).stroke.get.asInstanceOf[Vertex].y mustEqual 6616.0f
//30
diagrams(30).action mustEqual DiagramActionCode.Vertex
diagrams(30).stroke.get.asInstanceOf[Vertex].x mustEqual 7536.0f
diagrams(30).stroke.get.asInstanceOf[Vertex].y mustEqual 6624.0f
//31
diagrams(31).action mustEqual DiagramActionCode.Vertex
diagrams(31).stroke.get.asInstanceOf[Vertex].x mustEqual 7536.0f
diagrams(31).stroke.get.asInstanceOf[Vertex].y mustEqual 6632.0f
case _ =>
ko
}
}
"decode (style)" in {
PacketCoding.DecodePacket(string_style).require match {
case BattleplanMessage(char_id, player_name, zone_id, diagrams) =>
char_id mustEqual 41378949
player_name mustEqual "Outstabulous"
zone_id mustEqual 10
diagrams.size mustEqual 3
//0
diagrams.head.action mustEqual DiagramActionCode.Style
diagrams.head.stroke.isDefined mustEqual true
diagrams.head.stroke.get.isInstanceOf[Style] mustEqual true
diagrams.head.stroke.get.asInstanceOf[Style].thickness mustEqual 3.0f
diagrams.head.stroke.get.asInstanceOf[Style].color mustEqual 2
//1
diagrams(1).action mustEqual DiagramActionCode.Vertex
diagrams(1).stroke.get.asInstanceOf[Vertex].x mustEqual 7512.0f
diagrams(1).stroke.get.asInstanceOf[Vertex].y mustEqual 6328.0f
//2
diagrams(2).action mustEqual DiagramActionCode.Vertex
diagrams(2).stroke.get.asInstanceOf[Vertex].x mustEqual 7512.0f
diagrams(2).stroke.get.asInstanceOf[Vertex].y mustEqual 6344.0f
case _ =>
ko
}
}
"decode (message)" in {
PacketCoding.DecodePacket(string_message).require match {
case BattleplanMessage(char_id, player_name, zone_id, diagrams) =>
char_id mustEqual 41378949
player_name mustEqual "Outstabulous"
zone_id mustEqual 10
diagrams.size mustEqual 1
//0
diagrams.head.action mustEqual DiagramActionCode.DrawString
diagrams.head.stroke.isDefined mustEqual true
diagrams.head.stroke.get.isInstanceOf[DrawString] mustEqual true
diagrams.head.stroke.get.asInstanceOf[DrawString].x mustEqual 7512.0f
diagrams.head.stroke.get.asInstanceOf[DrawString].y mustEqual 6312.0f
diagrams.head.stroke.get.asInstanceOf[DrawString].color mustEqual 2
diagrams.head.stroke.get.asInstanceOf[DrawString].channel mustEqual 0
diagrams.head.stroke.get.asInstanceOf[DrawString].message mustEqual "Hello Auraxis!"
case _ =>
ko
}
}
"encode (start)" in {
val msg = BattleplanMessage(
41490746,
"YetAnotherFailureAlt",
0,
BattleDiagramAction(DiagramActionCode.StartDrawing) ::
Nil
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_start
}
"encode (stop)" in {
val msg = BattleplanMessage(
41490746,
"YetAnotherFailureAlt",
0,
BattleDiagramAction(DiagramActionCode.StopDrawing) ::
Nil
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_stop
}
"encode (line)" in {
val msg = BattleplanMessage(
41378949,
"Outstabulous",
10,
BattleDiagramAction.vertex(7512.0f, 6312.0f) ::
BattleDiagramAction.vertex(7512.0f, 6328.0f) ::
BattleDiagramAction.vertex(7512.0f, 6344.0f) ::
BattleDiagramAction.vertex(7512.0f, 6360.0f) ::
BattleDiagramAction.vertex(7520.0f, 6376.0f) ::
BattleDiagramAction.vertex(7520.0f, 6392.0f) ::
BattleDiagramAction.vertex(7520.0f, 6400.0f) ::
BattleDiagramAction.vertex(7520.0f, 6416.0f) ::
BattleDiagramAction.vertex(7520.0f, 6424.0f) ::
BattleDiagramAction.vertex(7520.0f, 6440.0f) ::
BattleDiagramAction.vertex(7528.0f, 6448.0f) ::
BattleDiagramAction.vertex(7528.0f, 6464.0f) ::
BattleDiagramAction.vertex(7528.0f, 6472.0f) ::
BattleDiagramAction.vertex(7528.0f, 6488.0f) ::
BattleDiagramAction.vertex(7528.0f, 6496.0f) ::
BattleDiagramAction.vertex(7528.0f, 6504.0f) ::
BattleDiagramAction.vertex(7528.0f, 6512.0f) ::
BattleDiagramAction.vertex(7528.0f, 6520.0f) ::
BattleDiagramAction.vertex(7528.0f, 6528.0f) ::
BattleDiagramAction.vertex(7528.0f, 6536.0f) ::
BattleDiagramAction.vertex(7528.0f, 6544.0f) ::
BattleDiagramAction.vertex(7528.0f, 6552.0f) ::
BattleDiagramAction.vertex(7528.0f, 6560.0f) ::
BattleDiagramAction.vertex(7528.0f, 6568.0f) ::
BattleDiagramAction.vertex(7536.0f, 6576.0f) ::
BattleDiagramAction.vertex(7536.0f, 6584.0f) ::
BattleDiagramAction.vertex(7536.0f, 6592.0f) ::
BattleDiagramAction.vertex(7536.0f, 6600.0f) ::
BattleDiagramAction.vertex(7536.0f, 6608.0f) ::
BattleDiagramAction.vertex(7536.0f, 6616.0f) ::
BattleDiagramAction.vertex(7536.0f, 6624.0f) ::
BattleDiagramAction.vertex(7536.0f, 6632.0f) ::
Nil
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_line
}
"encode (style)" in {
val msg = BattleplanMessage(
41378949,
"Outstabulous",
10,
BattleDiagramAction.style(3.0f, 2) ::
BattleDiagramAction.vertex(7512.0f, 6328.0f) ::
BattleDiagramAction.vertex(7512.0f, 6344.0f) ::
Nil
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_style
}
"encode (message)" in {
val msg = BattleplanMessage(
41378949,
"Outstabulous",
10,
BattleDiagramAction.drawString(7512.0f, 6312.0f, 2, 0, "Hello Auraxis!") :: Nil
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_message
}
}

View file

@ -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 BeginZoningMessageTest extends Specification {
val string = hex"43" //yes, just the opcode
"decode" in {
PacketCoding.DecodePacket(string).require match {
case BeginZoningMessage() =>
ok
case _ =>
ko
}
}
"encode" in {
val msg = BeginZoningMessage()
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,125 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{SpawnGroup, Vector3}
import scodec.bits._
class BindPlayerMessageTest extends Specification {
val string_standard = hex"16028004000000000000000000000000000000"
val string_ams = hex"16 05 8440616D73 08 28000000 00000000 00000 00000 0000"
val string_tech = hex"16 01 8b40746563685f706c616e74 d4 28000000 38000000 00064 012b1 a044"
val string_akkan = hex"16048440616d7388100000001400000214e171a8e33024"
"decode (standard)" in {
PacketCoding.DecodePacket(string_standard).require match {
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
action mustEqual BindStatus.Unbind
bindDesc mustEqual ""
unk1 mustEqual false
logging mustEqual false
unk2 mustEqual SpawnGroup.BoundAMS
unk3 mustEqual 0
unk4 mustEqual 0
pos mustEqual Vector3.Zero
case _ =>
ko
}
}
"decode (ams)" in {
PacketCoding.DecodePacket(string_ams).require match {
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
action mustEqual BindStatus.Unavailable
bindDesc mustEqual "@ams"
unk1 mustEqual false
logging mustEqual false
unk2 mustEqual SpawnGroup.AMS
unk3 mustEqual 10
unk4 mustEqual 0
pos mustEqual Vector3.Zero
case _ =>
ko
}
}
"decode (tech)" in {
PacketCoding.DecodePacket(string_tech).require match {
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
action mustEqual BindStatus.Bind
bindDesc mustEqual "@tech_plant"
unk1 mustEqual true
logging mustEqual true
unk2 mustEqual SpawnGroup.BoundFacility
unk3 mustEqual 10
unk4 mustEqual 14
pos mustEqual Vector3(4610.0f, 6292, 69.625f)
case _ =>
ko
}
}
"decode (akkan)" in {
PacketCoding.DecodePacket(string_akkan).require match {
case BindPlayerMessage(action, bindDesc, unk1, logging, unk2, unk3, unk4, pos) =>
action mustEqual BindStatus.Available
bindDesc mustEqual "@ams"
unk1 mustEqual true
logging mustEqual false
unk2 mustEqual SpawnGroup.AMS
unk3 mustEqual 4
unk4 mustEqual 5
pos mustEqual Vector3(2673.039f, 4423.547f, 39.1875f)
case _ =>
ko
}
}
"encode (standard)" in {
val msg = BindPlayerMessage.Standard
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_standard
}
"encode (ams)" in {
val msg = BindPlayerMessage(BindStatus.Unavailable, "@ams", false, false, SpawnGroup.AMS, 10, 0, Vector3.Zero)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_ams
}
"encode (tech)" in {
val msg = BindPlayerMessage(
BindStatus.Bind,
"@tech_plant",
true,
true,
SpawnGroup.BoundFacility,
10,
14,
Vector3(4610.0f, 6292, 69.625f)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_tech
}
"encode (akkan)" in {
val msg = BindPlayerMessage(
BindStatus.Available,
"@ams",
true,
false,
SpawnGroup.AMS,
4,
5,
Vector3(2673.039f, 4423.547f, 39.1875f)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_akkan
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class BroadcastWarpgateUpdateMessageTest extends Specification {
val string = hex"D9 0D 00 01 00 20"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case BroadcastWarpgateUpdateMessage(continent_guid, building_guid, state1, state2, state3) =>
continent_guid mustEqual 13
building_guid mustEqual 1
state1 mustEqual false
state2 mustEqual false
state3 mustEqual true
case _ =>
ko
}
}
"encode" in {
val msg = BroadcastWarpgateUpdateMessage(13, 1, false, false, true)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,50 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.Vector3
import scodec.bits._
class BugReportMessageTest extends Specification {
val string =
hex"89 03000000 0F000000 8B4465632020322032303039 1 1 0 19 6C511 656B1 7A11 830610062006300 843100320033003400"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case BugReportMessage(major, minor, date, btype, repeat, unk, zone, loc, summary, desc) =>
major mustEqual 3
minor mustEqual 15
date mustEqual "Dec 2 2009"
btype mustEqual BugType.GAMEPLAY
repeat mustEqual true
zone mustEqual 25
loc.x mustEqual 674.84375f
loc.y mustEqual 726.78906f
loc.z mustEqual 69.90625f
summary mustEqual "abc"
desc mustEqual "1234"
case _ =>
ko
}
}
"encode" in {
val msg = BugReportMessage(
3,
15,
"Dec 2 2009",
BugType.GAMEPLAY,
true,
0,
25,
Vector3(674.84375f, 726.78906f, 69.90625f),
"abc",
"1234"
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,93 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideEmpire, PlanetSideGeneratorState}
import scodec.bits._
class BuildingInfoUpdateMessageTest extends Specification {
val string = hex"a0 04 00 09 00 16 00 00 00 00 80 00 00 00 17 00 00 00 00 00 00 40"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case BuildingInfoUpdateMessage(
continent_guid,
building_guid,
ntu_level,
is_hacked,
empire_hack,
hack_time_remaining,
empire_own,
unk1,
unk1x,
generator_state,
spawn_tubes_normal,
force_dome_active,
lattice_benefit,
unk3,
unk4,
unk5,
unk6,
unk7,
unk7x,
boost_spawn_pain,
boost_generator_pain
) =>
continent_guid mustEqual 4
building_guid mustEqual 9
ntu_level mustEqual 1
is_hacked mustEqual false
empire_hack mustEqual PlanetSideEmpire.NEUTRAL
hack_time_remaining mustEqual 0
empire_own mustEqual PlanetSideEmpire.NC
unk1 mustEqual 0
unk1x mustEqual None
generator_state mustEqual PlanetSideGeneratorState.Normal
spawn_tubes_normal mustEqual true
force_dome_active mustEqual false
lattice_benefit mustEqual 28
unk3 mustEqual 0
unk4.size mustEqual 0
unk4.isEmpty mustEqual true
unk5 mustEqual 0
unk6 mustEqual false
unk7 mustEqual 8
unk7x mustEqual None
boost_spawn_pain mustEqual false
boost_generator_pain mustEqual false
case _ =>
ko
}
}
"encode" in {
val msg = BuildingInfoUpdateMessage(
4,
9,
1,
false,
PlanetSideEmpire.NEUTRAL,
0,
PlanetSideEmpire.NC,
0,
None,
PlanetSideGeneratorState.Normal,
true,
false,
28,
0,
Nil,
0,
false,
8,
None,
false,
false
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,64 @@
// Copyright (c) 2020 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class ChainLashMessageTest extends Specification {
val string1 = hex"c5 cafe708880df81e910100000043060"
val string2 = hex"c5 5282e910100000093050"
"decode (1)" in {
PacketCoding.DecodePacket(string1).require match {
case ChainLashMessage(u1a, u1b, u2, u3) =>
u1a.isEmpty mustEqual true
u1b.contains(Vector3(7673.164f, 544.1328f, 14.984375f)) mustEqual true
u2 mustEqual 466
u3 mustEqual List(PlanetSideGUID(1603))
case _ =>
ko
}
}
"decode (2)" in {
PacketCoding.DecodePacket(string2).require match {
case ChainLashMessage(u1a, u1b, u2, u3) =>
u1a.contains(PlanetSideGUID(1445)) mustEqual true
u1b.isEmpty mustEqual true
u2 mustEqual 466
u3 mustEqual List(PlanetSideGUID(1427))
case _ =>
ko
}
}
"encode (1)" in {
val msg = ChainLashMessage(Vector3(7673.164f, 544.1328f, 14.984375f), 466, List(PlanetSideGUID(1603)))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string1
}
"encode (2)" in {
val msg = ChainLashMessage(PlanetSideGUID(1445), 466, List(PlanetSideGUID(1427)))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string2
}
"encode (fail; 1)" in {
ChainLashMessage(
Some(PlanetSideGUID(1445)),
Some(Vector3(7673.164f, 544.1328f, 14.984375f)),
466,
List(PlanetSideGUID(1427))
) must throwA[AssertionError]
}
"encode (fail; 2)" in {
ChainLashMessage(None, None, 466, List(PlanetSideGUID(1427))) must throwA[AssertionError]
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class ChangeAmmoMessageTest extends Specification {
val string = hex"47 4E00 00000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ChangeAmmoMessage(item_guid, unk1) =>
item_guid mustEqual PlanetSideGUID(78)
unk1 mustEqual 0
case _ =>
ko
}
}
"encode" in {
val msg = ChangeAmmoMessage(PlanetSideGUID(78), 0)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class ChangeFireModeMessageTest extends Specification {
val string = hex"46 4C0020"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ChangeFireModeMessage(item_guid, fire_mode) =>
item_guid mustEqual PlanetSideGUID(76)
fire_mode mustEqual 1
case _ =>
ko
}
}
"encode" in {
val msg = ChangeFireModeMessage(PlanetSideGUID(76), 1)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class ChangeFireStateMessage_StartTest extends Specification {
val string = hex"39 4C00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ChangeFireStateMessage_Start(item_guid) =>
item_guid mustEqual PlanetSideGUID(76)
case _ =>
ko
}
}
"encode" in {
val msg = ChangeFireStateMessage_Start(PlanetSideGUID(76))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class ChangeFireStateMessage_StopTest extends Specification {
val string = hex"3A 4C00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ChangeFireStateMessage_Stop(item_guid) =>
item_guid mustEqual PlanetSideGUID(76)
case _ =>
ko
}
}
"encode" in {
val msg = ChangeFireStateMessage_Stop(PlanetSideGUID(76))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class ChangeShortcutBankMessageTest extends Specification {
val string = hex"29 4B00 20"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ChangeShortcutBankMessage(player_guid, bank) =>
player_guid mustEqual PlanetSideGUID(75)
bank mustEqual 2
case _ =>
ko
}
}
"encode" in {
val msg = ChangeShortcutBankMessage(PlanetSideGUID(75), 2)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -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, CharacterVoice, 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 CharacterVoice.Voice5
gender mustEqual CharacterGender.Female
faction mustEqual PlanetSideEmpire.NC
case _ =>
ko
}
}
"encode" in {
val msg =
CharacterCreateRequestMessage("TestChar", 50, CharacterVoice.Voice5, CharacterGender.Female, PlanetSideEmpire.NC)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -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.PlanetSideGUID
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
}
}

View file

@ -0,0 +1,71 @@
// Copyright (c) 2017 PSForever
package game
import net.psforever.objects.avatar.Certification
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class CharacterKnowledgeMessageTest extends Specification {
val string = hex"ec cc637a02 45804600720061006e006b0065006e00740061006e006b0003c022dc0008f01800"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case CharacterKnowledgeMessage(char_id, Some(info)) =>
char_id mustEqual 41575372L
info mustEqual CharacterKnowledgeInfo(
"Frankentank",
Set(
Certification.StandardAssault,
Certification.ArmoredAssault1,
Certification.MediumAssault,
Certification.ReinforcedExoSuit,
Certification.Harasser,
Certification.Engineering,
Certification.GroundSupport,
Certification.AgileExoSuit,
Certification.AIMAX,
Certification.StandardExoSuit,
Certification.AAMAX,
Certification.ArmoredAssault2
),
15,
0,
PlanetSideGUID(12)
)
case _ =>
ko
}
}
"encode" in {
val msg = CharacterKnowledgeMessage(
41575372L,
CharacterKnowledgeInfo(
"Frankentank",
Set(
Certification.StandardAssault,
Certification.ArmoredAssault1,
Certification.MediumAssault,
Certification.ReinforcedExoSuit,
Certification.Harasser,
Certification.Engineering,
Certification.GroundSupport,
Certification.AgileExoSuit,
Certification.AIMAX,
Certification.StandardExoSuit,
Certification.AAMAX,
Certification.ArmoredAssault2
),
15,
0,
PlanetSideGUID(12)
)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -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 CharacterNoRecordMessageTest extends Specification {
val string = hex"13 00400000" //we have no record of this packet, so here's something fake that works
"decode" in {
PacketCoding.DecodePacket(string).require match {
case CharacterNoRecordMessage(unk) =>
unk mustEqual 16384
case _ =>
ko
}
}
"encode" in {
val msg = CharacterNoRecordMessage(16384)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -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 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
}
}

View file

@ -0,0 +1,56 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.ChatMessageType
import scodec.bits._
class ChatMsgTest extends Specification {
val string_local = hex"12 1A C000 83610062006300"
val string_tell = hex"12 20 C180640065006600 83610062006300"
"decode" in {
PacketCoding.DecodePacket(string_local).require match {
case ChatMsg(messagetype, has_wide_contents, recipient, contents, note_contents) =>
messagetype mustEqual ChatMessageType.CMT_OPEN
has_wide_contents mustEqual true
recipient mustEqual ""
contents mustEqual "abc"
note_contents mustEqual None
case _ =>
ko
}
PacketCoding.DecodePacket(string_tell).require match {
case ChatMsg(messagetype, has_wide_contents, recipient, contents, note_contents) =>
messagetype mustEqual ChatMessageType.CMT_TELL
has_wide_contents mustEqual true
recipient mustEqual "def"
contents mustEqual "abc"
note_contents mustEqual None
case _ =>
ko
}
}
"encode" in {
val msg_local = ChatMsg(ChatMessageType.CMT_OPEN, true, "", "abc", None)
val pkt_local = PacketCoding.EncodePacket(msg_local).require.toByteVector
pkt_local mustEqual string_local
val msg_tell = ChatMsg(ChatMessageType.CMT_TELL, true, "def", "abc", None)
val pkt_tell = PacketCoding.EncodePacket(msg_tell).require.toByteVector
pkt_tell mustEqual string_tell
}
"allow and disallow note" in {
ChatMsg(ChatMessageType.CMT_ARMOR, false, "DontCare", "DontCare", Some("Should be here")) must throwA[
AssertionError
]
ChatMsg(ChatMessageType.CMT_NOTE, false, "DontCare", "DontCare", None) must throwA[AssertionError]
}
}

View file

@ -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.PlanetSideGUID
import scodec.bits._
class ChildObjectStateMessageTest extends Specification {
val string = hex"1E 640B 06 47"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ChildObjectStateMessage(object_guid, pitch, yaw) =>
object_guid mustEqual PlanetSideGUID(2916)
pitch mustEqual 343.125f
yaw mustEqual 160.3125f
case _ =>
ko
}
}
"encode" in {
val msg = ChildObjectStateMessage(PlanetSideGUID(2916), 343.125f, 160.3125f)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -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 ConnectToWorldMessageTest extends Specification {
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 _ =>
ko
}
}
"encode" in {
val msg = ConnectToWorldMessage("gemini", "64.37.158.69", 30012)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,34 @@
// Copyright (c) 2017 PSForever
package game
import net.psforever.packet._
import net.psforever.packet.game._
import org.specs2.mutable._
import scodec.bits._
class ConnectToWorldRequestMessageTest extends Specification {
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 {
case ConnectToWorldRequestMessage(serverName, token, majorVersion, minorVersion, revision, buildDate, unk) =>
serverName mustEqual "gemini"
token mustEqual ""
majorVersion mustEqual 0
minorVersion mustEqual 0
revision mustEqual 0
buildDate mustEqual ""
unk mustEqual 0
case _ =>
ko
}
}
"encode" in {
val msg = ConnectToWorldRequestMessage("gemini", "", 0, 0, 0, "", 0)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideEmpire
import scodec.bits._
class ContinentalLockUpdateMessageTest extends Specification {
val string = hex"A8 16 00 40"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ContinentalLockUpdateMessage(continent_guid, empire) =>
continent_guid mustEqual 22
empire mustEqual PlanetSideEmpire.NC
case _ =>
ko
}
}
"encode" in {
val msg = ContinentalLockUpdateMessage(22, PlanetSideEmpire.NC)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,122 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{ImplantType, PlanetSideGUID}
import scodec.bits._
class CreateShortcutMessageTest extends Specification {
val stringMedkit = hex"28 7210 01 00 90 C0 6D65646B6974 80 80"
val stringMacro =
hex"28 4C05 08 00 B1 C0 73686F72746375745F6D6163726F 83 4E00 5400 5500 9B 2F00 7000 6C00 6100 7400 6F00 6F00 6E00 2000 4900 6E00 6300 6F00 6D00 6900 6E00 6700 2000 4E00 5400 5500 2000 7300 7000 6100 6D00 2100"
val stringRemove = hex"28 4C05 01 00 00"
"decode (medkit)" in {
PacketCoding.DecodePacket(stringMedkit).require match {
case CreateShortcutMessage(player_guid, slot, unk, addShortcut, shortcut) =>
player_guid mustEqual PlanetSideGUID(4210)
slot mustEqual 1
unk mustEqual 0
addShortcut mustEqual true
shortcut.isDefined mustEqual true
shortcut.get.purpose mustEqual 0
shortcut.get.tile mustEqual "medkit"
shortcut.get.effect1 mustEqual ""
shortcut.get.effect2 mustEqual ""
case _ =>
ko
}
}
"decode (macro)" in {
PacketCoding.DecodePacket(stringMacro).require match {
case CreateShortcutMessage(player_guid, slot, unk, addShortcut, shortcut) =>
player_guid mustEqual PlanetSideGUID(1356)
slot mustEqual 8
unk mustEqual 0
addShortcut mustEqual true
shortcut.isDefined mustEqual true
shortcut.get.purpose mustEqual 1
shortcut.get.tile mustEqual "shortcut_macro"
shortcut.get.effect1 mustEqual "NTU"
shortcut.get.effect2 mustEqual "/platoon Incoming NTU spam!"
case _ =>
ko
}
}
"decode (remove)" in {
PacketCoding.DecodePacket(stringRemove).require match {
case CreateShortcutMessage(player_guid, slot, unk, addShortcut, shortcut) =>
player_guid mustEqual PlanetSideGUID(1356)
slot mustEqual 1
unk mustEqual 0
addShortcut mustEqual false
shortcut.isDefined mustEqual false
case _ =>
ko
}
}
"encode (medkit)" in {
val msg = CreateShortcutMessage(PlanetSideGUID(4210), 1, 0, true, Some(Shortcut(0, "medkit")))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringMedkit
}
"encode (macro)" in {
val msg = CreateShortcutMessage(
PlanetSideGUID(1356),
8,
0,
true,
Some(Shortcut(1, "shortcut_macro", "NTU", "/platoon Incoming NTU spam!"))
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringMacro
}
"encode (remove)" in {
val msg = CreateShortcutMessage(PlanetSideGUID(1356), 1, 0, false)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringRemove
}
"macro" in {
val MACRO: Some[Shortcut] = Shortcut.MACRO("NTU", "/platoon Incoming NTU spam!")
MACRO.get.purpose mustEqual 1
MACRO.get.tile mustEqual "shortcut_macro"
MACRO.get.effect1 mustEqual "NTU"
MACRO.get.effect2 mustEqual "/platoon Incoming NTU spam!"
}
"presets" in {
ImplantType.AudioAmplifier.shortcut.purpose mustEqual 2
ImplantType.AudioAmplifier.shortcut.tile mustEqual "audio_amplifier"
ImplantType.DarklightVision.shortcut.purpose mustEqual 2
ImplantType.DarklightVision.shortcut.tile mustEqual "darklight_vision"
ImplantType.Targeting.shortcut.purpose mustEqual 2
ImplantType.Targeting.shortcut.tile mustEqual "targeting"
Shortcut.Medkit.get.purpose mustEqual 0
Shortcut.Medkit.get.tile mustEqual "medkit"
ImplantType.MeleeBooster.shortcut.purpose mustEqual 2
ImplantType.MeleeBooster.shortcut.tile mustEqual "melee_booster"
ImplantType.PersonalShield.shortcut.purpose mustEqual 2
ImplantType.PersonalShield.shortcut.tile mustEqual "personal_shield"
ImplantType.RangeMagnifier.shortcut.purpose mustEqual 2
ImplantType.RangeMagnifier.shortcut.tile mustEqual "range_magnifier"
ImplantType.AdvancedRegen.shortcut.purpose mustEqual 2
ImplantType.AdvancedRegen.shortcut.tile mustEqual "advanced_regen"
ImplantType.SecondWind.shortcut.purpose mustEqual 2
ImplantType.SecondWind.shortcut.tile mustEqual "second_wind"
ImplantType.SilentRun.shortcut.purpose mustEqual 2
ImplantType.SilentRun.shortcut.tile mustEqual "silent_run"
ImplantType.Surge.shortcut.purpose mustEqual 2
ImplantType.Surge.shortcut.tile mustEqual "surge"
}
}

View file

@ -0,0 +1,350 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class DamageFeedbackMessageTest extends Specification {
val string = hex"7b 3d842f610b2040000000"
val string_2 = hex"7B 5E5826D8001DC0400000"
"decode (string 1)" in {
PacketCoding.DecodePacket(string).require match {
case DamageFeedbackMessage(unk1, unk2, unk2a, unk2b, unk2c, unk3, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) =>
unk1 mustEqual 3
unk2 mustEqual true
unk2a.contains(PlanetSideGUID(2913)) mustEqual true
unk2b.isEmpty mustEqual true
unk2c.isEmpty mustEqual true
unk3 mustEqual true
unk3a.contains(PlanetSideGUID(2913)) mustEqual true
unk3b.isEmpty mustEqual true
unk3c.isEmpty mustEqual true
unk3d.isEmpty mustEqual true
unk4 mustEqual 1
unk5 mustEqual 2
unk6 mustEqual 0
case _ =>
ko
}
}
"decode (string 2)" in {
PacketCoding.DecodePacket(string_2).require match {
case DamageFeedbackMessage(unk1, unk2, unk2a, unk2b, unk2c, unk3, unk3a, unk3b, unk3c, unk3d, unk4, unk5, unk6) =>
unk1 mustEqual 5
unk2 mustEqual true
unk2a.contains(PlanetSideGUID(2454)) mustEqual true
unk2b.isEmpty mustEqual true
unk2c.isEmpty mustEqual true
unk3 mustEqual false
unk3a.contains(PlanetSideGUID(216)) mustEqual true
unk3b.isEmpty mustEqual true
unk3c.isEmpty mustEqual true
unk3d.isEmpty mustEqual true
unk4 mustEqual 0
unk5 mustEqual 750
unk6 mustEqual 0
case _ =>
ko
}
}
"encode (string 1)" in {
val msg = DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
"encode (string 2)" in {
val msg = DamageFeedbackMessage(
5,
true,
Some(PlanetSideGUID(2454)),
None,
None,
false,
Some(PlanetSideGUID(216)),
None,
None,
None,
0,
750,
0
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_2
}
"assert catches" in {
//unk2: no parameters
DamageFeedbackMessage(
3,
true,
None,
None,
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
//unk2: two exclusive parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
Some("error"),
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
Some(5),
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
None,
Some("error"),
Some(5),
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
//unk2: all parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
Some("error"),
Some(5),
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
//unk2: mismatched flag for strings
DamageFeedbackMessage(
3,
true,
None,
None,
Some(5),
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
false,
None,
Some("error"),
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
//unk3: no parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
None,
None,
None,
None,
1,
2,
0
) must throwA[AssertionError]
//unk3: two exclusive parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
Some("error"),
None,
None,
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
None,
Some(5),
None,
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
None,
Some("error"),
Some(5),
Some(1),
1,
2,
0
) must throwA[AssertionError]
//unk3: all parameters
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
Some("error"),
Some(5),
None,
1,
2,
0
) must throwA[AssertionError]
//unk3: mismatched fields
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
Some(PlanetSideGUID(2913)),
None,
None,
Some(5),
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
None,
Some("Error"),
None,
None,
1,
2,
0
) must throwA[AssertionError]
//unk3: mismatched flag for strings
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
true,
None,
None,
Some(5),
None,
1,
2,
0
) must throwA[AssertionError]
DamageFeedbackMessage(
3,
true,
Some(PlanetSideGUID(2913)),
None,
None,
false,
None,
Some("error"),
None,
None,
1,
2,
0
) must throwA[AssertionError]
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2019 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class DamageMessageTest extends Specification {
val string = hex"0b610b02610b00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DamageMessage(guid1, unk1, guid2, unk2) =>
guid1 mustEqual PlanetSideGUID(2913)
unk1 mustEqual 2
guid2 mustEqual PlanetSideGUID(2913)
unk2 mustEqual false
case _ =>
ko
}
}
"encode" in {
val msg = DamageMessage(PlanetSideGUID(2913), 2, PlanetSideGUID(2913), false)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package game
import net.psforever.types.Vector3
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class DamageWithPositionMessageTest extends Specification {
val string = hex"A6 11 6C2D7 65535 CA16"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DamageWithPositionMessage(unk, pos) =>
unk mustEqual 17
pos.x mustEqual 3674.8438f
pos.y mustEqual 2726.789f
pos.z mustEqual 91.15625f
case _ =>
ko
}
}
"encode" in {
val msg = DamageWithPositionMessage(17, Vector3(3674.8438f, 2726.789f, 91.15625f))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2020 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class DataChallengeMessageRespTest extends Specification {
val string = hex"948673616d706c6501000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DataChallengeMessageResp(attribute, value) =>
attribute mustEqual "sample"
value mustEqual 1L
case _ =>
ko
}
}
"encode" in {
val msg = DataChallengeMessageResp("sample", 1L)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2020 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class DataChallengeMessageTest extends Specification {
val string = hex"938673616d706c6501000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DataChallengeMessage(attribute, value) =>
attribute mustEqual "sample"
value mustEqual 1L
case _ =>
ko
}
}
"encode" in {
val msg = DataChallengeMessage("sample", 1L)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class DelayedPathMountMsgTest extends Specification {
val string = hex"5a f50583044680"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DelayedPathMountMsg(player_guid, vehicle_guid, u3, u4) =>
player_guid mustEqual PlanetSideGUID(1525)
vehicle_guid mustEqual PlanetSideGUID(1155)
u3 mustEqual 70
u4 mustEqual true
case _ =>
ko
}
}
"encode" in {
val msg = DelayedPathMountMsg(PlanetSideGUID(1525), PlanetSideGUID(1155), 70, true)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,52 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class DensityLevelUpdateMessageTest extends Specification {
val string = hex"cd 0100 1f4e 000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DensityLevelUpdateMessage(zone_id, building_id, unk) =>
zone_id mustEqual 1
building_id mustEqual 19999
unk.length mustEqual 8
unk.head mustEqual 0
unk(1) mustEqual 0
unk(2) mustEqual 0
unk(3) mustEqual 0
unk(4) mustEqual 0
unk(5) mustEqual 0
unk(6) mustEqual 0
unk(7) mustEqual 0
case _ =>
ko
}
}
"encode" in {
val msg = DensityLevelUpdateMessage(1, 19999, List(0, 0, 0, 0, 0, 0, 0, 0))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
"encode (failure; wrong number of list entries)" in {
val msg = DensityLevelUpdateMessage(1, 19999, List(0))
PacketCoding.EncodePacket(msg).isSuccessful mustEqual false
}
"encode (failure; list number too big)" in {
val msg = DensityLevelUpdateMessage(1, 19999, List(0, 0, 0, 0, 0, 0, 0, 8))
PacketCoding.EncodePacket(msg).isSuccessful mustEqual false
}
"encode (failure; list number too small)" in {
val msg = DensityLevelUpdateMessage(1, 19999, List(0, 0, 0, 0, 0, -1, 0, 0))
PacketCoding.EncodePacket(msg).isSuccessful mustEqual false
}
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class DeployObjectMessageTest extends Specification {
val string = hex"5d 740b e8030000 a644b 6e3c6 7e18 00 00 3f 01000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DeployObjectMessage(guid, unk1, pos, orient, unk2) =>
guid mustEqual PlanetSideGUID(2932)
unk1 mustEqual 1000L
pos mustEqual Vector3(5769.297f, 3192.8594f, 97.96875f)
orient mustEqual Vector3.z(272.8125f)
unk2 mustEqual 1L
case _ =>
ko
}
}
"encode" in {
val msg = DeployObjectMessage(
PlanetSideGUID(2932),
1000L,
Vector3(5769.297f, 3192.8594f, 97.96875f),
Vector3.z(272.8125f),
1L
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{DriveState, PlanetSideGUID, Vector3}
import scodec.bits._
class DeployRequestMessageTest extends Specification {
val string = hex"4b 4b00 7c01 40 0cf73b52aa6a9300"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DeployRequestMessage(player_guid, vehicle_guid, deploy_state, unk2, unk3, pos) =>
player_guid mustEqual PlanetSideGUID(75)
vehicle_guid mustEqual PlanetSideGUID(380)
deploy_state mustEqual DriveState.Deploying
unk2 mustEqual 0
unk3 mustEqual false
pos.x mustEqual 4060.1953f
pos.y mustEqual 2218.8281f
pos.z mustEqual 155.32812f
case _ =>
ko
}
}
"encode" in {
val msg = DeployRequestMessage(
PlanetSideGUID(75),
PlanetSideGUID(380),
DriveState.Deploying,
0,
false,
Vector3(4060.1953f, 2218.8281f, 155.32812f)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,44 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game.{DeployableIcon, DeployableInfo, DeployableObjectsInfoMessage, DeploymentAction}
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class DeployableObjectsInfoMessageTest extends Specification {
val string = hex"76 00 80 00 00 31 85 41 CF D3 7E B3 34 00 E6 30 48" //this was a TRAP @ Ogma, Forseral
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DeployableObjectsInfoMessage(action, list) =>
action mustEqual DeploymentAction.Dismiss
list.size mustEqual 1
//0
list.head.object_guid mustEqual PlanetSideGUID(2659)
list.head.icon mustEqual DeployableIcon.TRAP
list.head.pos.x mustEqual 3572.4453f
list.head.pos.y mustEqual 3277.9766f
list.head.pos.z mustEqual 114.0f
list.head.player_guid mustEqual PlanetSideGUID(2502)
case _ =>
ko
}
}
"encode" in {
val msg = DeployableObjectsInfoMessage(
DeploymentAction.Dismiss,
DeployableInfo(
PlanetSideGUID(2659),
DeployableIcon.TRAP,
Vector3(3572.4453f, 3277.9766f, 114.0f),
PlanetSideGUID(2502)
)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,59 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideEmpire
import scodec.bits._
class DestroyDisplayMessageTest extends Specification {
val string =
hex"81 87 41006E00670065006C006C006F00 35BCD801 8 F201 9207 0A 0 48004D00460049004300 B18ED901 00" // Angello-VS (???) HMFIC-TR
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DestroyDisplayMessage(
killer,
killer_charId,
killer_empire,
killer_inVehicle,
unk,
method,
victim,
victim_charId,
victim_empire,
victim_inVehicle
) =>
killer mustEqual "Angello"
killer_charId mustEqual 30981173
killer_empire mustEqual PlanetSideEmpire.VS
killer_inVehicle mustEqual false
unk mustEqual 121
method mustEqual 969
victim mustEqual "HMFIC"
victim_charId mustEqual 31035057
victim_empire mustEqual PlanetSideEmpire.TR
victim_inVehicle mustEqual false
case _ =>
ko
}
}
"encode" in {
val msg = DestroyDisplayMessage(
"Angello",
30981173,
PlanetSideEmpire.VS,
false,
121,
969,
"HMFIC",
31035057,
PlanetSideEmpire.TR,
false
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,38 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class DestroyMessageTest extends Specification {
val string = hex"0C 74 09 74 09 00 00 06 35 3C FF D7 26 08"
"DestroyMessage" should {
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DestroyMessage(unk1, unk2, unk3, pos) =>
unk1 mustEqual PlanetSideGUID(2420)
unk2 mustEqual PlanetSideGUID(2420)
unk3 mustEqual PlanetSideGUID(0)
pos mustEqual Vector3(1642.0469f, 4091.6172f, 32.59375f)
case _ =>
ko
}
}
"encode" in {
val msg = DestroyMessage(
PlanetSideGUID(2420),
PlanetSideGUID(2420),
PlanetSideGUID(0),
Vector3(1642.0469f, 4091.6172f, 32.59375f)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}
}

View file

@ -0,0 +1,33 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class DisconnectMessageTest extends Specification {
val string = hex"B7 85 46 69 72 73 74 86 53 65 63 6F 6E 64 8E 46 69 72 73 74 20 26 20 73 65 63 6F 6E 64"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DisconnectMessage(unk1, unk2, unk3) =>
unk1 mustEqual "First"
unk2 mustEqual "Second"
unk3 mustEqual "First & second"
case _ =>
ko
}
}
"encode" in {
val msg = DisconnectMessage("First", "Second", "First & second")
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
"comparison" in {
DisconnectMessage("First") mustEqual DisconnectMessage("First", "", "")
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class DismountBuildingMsgTest extends Specification {
val string = hex"7C 4B00 2E00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DismountBuildingMsg(player_guid, building_guid) =>
player_guid mustEqual PlanetSideGUID(75)
building_guid mustEqual PlanetSideGUID(46)
case _ =>
ko
}
}
"encode" in {
val msg = DismountBuildingMsg(PlanetSideGUID(75), PlanetSideGUID(46))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,30 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
import net.psforever.types.{BailType, PlanetSideGUID}
class DismountVehicleMsgTest extends Specification {
val string = hex"0F C609 00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DismountVehicleMsg(player_guid, bailType, wasKickedByDriver) =>
player_guid mustEqual PlanetSideGUID(2502)
bailType mustEqual BailType.Normal
wasKickedByDriver mustEqual false
case _ =>
ko
}
}
"encode" in {
val msg = DismountVehicleMsg(PlanetSideGUID(2502), BailType.Normal, false)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,30 @@
// Copyright (c) 2017 PSForever
package game
import net.psforever.types.{MeritCommendation, PlanetSideGUID}
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class DisplayedAwardMessageTest extends Specification {
val string = hex"D1 9F06 A6010000 3 0"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DisplayedAwardMessage(player_guid, ribbon, bar) =>
player_guid mustEqual PlanetSideGUID(1695)
ribbon mustEqual MeritCommendation.TwoYearVS
bar mustEqual RibbonBarsSlot.TermOfService
case _ =>
ko
}
}
"encode" in {
val msg = DisplayedAwardMessage(PlanetSideGUID(1695), MeritCommendation.TwoYearVS, RibbonBarsSlot.TermOfService)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class DropItemMessageTest extends Specification {
val string = hex"37 4C00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DropItemMessage(item_guid) =>
item_guid mustEqual PlanetSideGUID(76)
case _ =>
ko
}
}
"encode" in {
val msg = DropItemMessage(PlanetSideGUID(76))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,43 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class DroppodFreefallingMessageTest extends Specification {
val string =
hex"68 220e 00e0b245 00c06145 00a08744 00000000 00000000 ffff79c4 0740b245 22c66145 00608144 00 67 3f 00 00 3f"
"DroppodFreefallingMessage" should {
"decode" in {
PacketCoding.DecodePacket(string).require match {
case DroppodFreefallingMessage(guid, pos, vel, pos2, orientation1, orientation2) =>
guid mustEqual PlanetSideGUID(3618)
pos mustEqual Vector3(5724, 3612, 1085)
vel mustEqual Vector3(0, 0, -999.99994f)
pos2 mustEqual Vector3(5704.0034f, 3612.3833f, 1035.0f)
orientation1 mustEqual Vector3(0, 70.3125f, 272.8125f)
orientation2 mustEqual Vector3(0, 0, 272.8125f)
case _ =>
ko
}
}
"encode" in {
val msg = DroppodFreefallingMessage(
PlanetSideGUID(3618),
Vector3(5724, 3612, 1085),
Vector3(0, 0, -999.99994f),
Vector3(5704.0034f, 3612.3833f, 1035.0f),
Vector3(0, 70.3125f, 272.8125f),
Vector3(0, 0, 272.8125f)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{EmoteType, PlanetSideGUID}
import scodec.bits._
class EmoteMsgTest extends Specification {
val string = hex"25 4B00 15"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case EmoteMsg(avatar_guid, emote) =>
avatar_guid mustEqual PlanetSideGUID(75)
emote mustEqual EmoteType.Thumbsdown
case _ =>
ko
}
}
"encode" in {
val msg = EmoteMsg(PlanetSideGUID(75), EmoteType.Thumbsdown)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -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 ExperienceAddedMessageTest extends Specification {
val string = hex"B8 04 03"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case ExperienceAddedMessage(exp, unk) =>
exp mustEqual 260 //0x104
unk mustEqual true
case _ =>
ko
}
}
"encode" in {
val msg = ExperienceAddedMessage(260)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class FacilityBenefitShieldChargeRequestMessageTest extends Specification {
val string = hex"C2 4C00"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case FacilityBenefitShieldChargeRequestMessage(guid) =>
guid mustEqual PlanetSideGUID(76)
case _ =>
ko
}
}
"encode" in {
val msg = FacilityBenefitShieldChargeRequestMessage(PlanetSideGUID(76))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,54 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{LoadoutType, PlanetSideGUID}
import scodec.bits._
class FavoritesMessageTest extends Specification {
val stringVehicles = hex"60 5C 84 02 20 5300 6B00 7900 6700 7500 6100 7200 6400"
val stringInfantry = hex"60 2C 03 82 34 4100 6700 6900 6C00 6500 2000 2800 6200 6100 7300 6900 6300 2900 20"
"decode (for infantry)" in {
PacketCoding.DecodePacket(stringInfantry).require match {
case FavoritesMessage(list, player_guid, line, label, armor) =>
list mustEqual LoadoutType.Infantry
player_guid mustEqual PlanetSideGUID(3760)
line mustEqual 0
label mustEqual "Agile (basic)"
armor.isDefined mustEqual true
armor.get mustEqual 1
case _ =>
ko
}
}
"encode (for infantry)" in {
val msg = FavoritesMessage(LoadoutType.Infantry, PlanetSideGUID(3760), 0, "Agile (basic)", 1)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringInfantry
}
"decode (for vehicles)" in {
PacketCoding.DecodePacket(stringVehicles).require match {
case FavoritesMessage(list, player_guid, line, label, armor) =>
list mustEqual LoadoutType.Vehicle
player_guid mustEqual PlanetSideGUID(4210)
line mustEqual 0
label mustEqual "Skyguard"
armor.isDefined mustEqual false
case _ =>
ko
}
}
"encode (for vehicles)" in {
val msg = FavoritesMessage(LoadoutType.Vehicle, PlanetSideGUID(4210), 0, "Skyguard")
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringVehicles
}
}

View file

@ -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.{LoadoutType, PlanetSideGUID}
import scodec.bits._
class FavoritesRequestTest extends Specification {
val stringInfantry = hex"5E 4B00 1187 4500 7800 6100 6D00 7000 6C00 6500"
"decode (for infantry)" in {
PacketCoding.DecodePacket(stringInfantry).require match {
case FavoritesRequest(player_guid, list, action, line, label) =>
player_guid mustEqual PlanetSideGUID(75)
list mustEqual LoadoutType.Infantry
action mustEqual FavoritesAction.Save
line mustEqual 1
label.isDefined mustEqual true
label.get mustEqual "Example"
case _ =>
ko
}
}
"encode (for infantry)" in {
val msg = FavoritesRequest(PlanetSideGUID(75), LoadoutType.Infantry, FavoritesAction.Save, 1, Some("Example"))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringInfantry
}
}

View file

@ -0,0 +1,63 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class FireHintMessageTest extends Specification {
val string = hex"a1 0117 23cd63f1d7480d 000077ff9d1d00"
val string2 = hex"a1 080e 65af5705074411 0000cffee0fc7b08899f5580"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case FireHintMessage(weapon_guid, pos, u1, u2, u3, u4, u5) =>
weapon_guid mustEqual PlanetSideGUID(5889)
pos mustEqual Vector3(3482.2734f, 3642.4922f, 53.125f)
u1 mustEqual 0
u2 mustEqual 65399
u3 mustEqual 7581
u4 mustEqual 0
u5 mustEqual None
case _ =>
ko
}
}
"decode string2" in {
PacketCoding.DecodePacket(string2).require match {
case FireHintMessage(weapon_guid, pos, u1, u2, u3, u4, u5) =>
weapon_guid mustEqual PlanetSideGUID(3592)
pos mustEqual Vector3(2910.789f, 3744.875f, 69.0625f)
u1 mustEqual 0
u2 mustEqual 65231
u3 mustEqual 64736
u4 mustEqual 3
u5 mustEqual Some(Vector3(21.5f, -6.8125f, 2.65625f))
case _ =>
ko
}
}
"encode" in {
val msg = FireHintMessage(PlanetSideGUID(5889), Vector3(3482.2734f, 3642.4922f, 53.125f), 0, 65399, 7581, 0)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
"encode string2" in {
val msg = FireHintMessage(
PlanetSideGUID(3592),
Vector3(2910.789f, 3744.875f, 69.0625f),
0,
65231,
64736,
3,
Some(Vector3(21.5f, -6.8125f, 2.65625f))
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string2
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class FriendsRequestTest extends Specification {
val string = hex"72 3 0A0 46004A0048004E004300"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case FriendsRequest(action, friend) =>
action mustEqual 1
friend.length mustEqual 5
friend mustEqual "FJHNC"
case _ =>
ko
}
}
"encode" in {
val msg = FriendsRequest(1, "FJHNC")
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,104 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class FriendsResponseTest extends Specification {
val stringOneFriend = hex"73 61 8C 60 4B007500720074004800650063007400690063002D004700 00"
val stringManyFriends =
hex"73 01 AC 48 4100 6E00 6700 6500 6C00 6C00 6F00 2D00 5700 47 00 7400 6800 6500 7000 6800 6100 7400 7400 7000 6800 7200 6F00 6700 6700 46 80 4B00 6900 6D00 7000 6F00 7300 7300 6900 6200 6C00 6500 3100 3200 45 00 5A00 6500 6100 7200 7400 6800 6C00 6900 6E00 6700 46 00 4B00 7500 7200 7400 4800 6500 6300 7400 6900 6300 2D00 4700 00"
val stringShort = hex"73 81 80"
"decode (one friend)" in {
PacketCoding.DecodePacket(stringOneFriend).require match {
case FriendsResponse(action, unk2, unk3, unk4, list) =>
action mustEqual FriendAction.UpdateFriend
unk2 mustEqual 0
unk3 mustEqual true
unk4 mustEqual true
list.size mustEqual 1
list.head.name mustEqual "KurtHectic-G"
list.head.online mustEqual false
case _ =>
ko
}
}
"decode (multiple friends)" in {
PacketCoding.DecodePacket(stringManyFriends).require match {
case FriendsResponse(action, unk2, unk3, unk4, list) =>
action mustEqual FriendAction.InitializeFriendList
unk2 mustEqual 0
unk3 mustEqual true
unk4 mustEqual true
list.size mustEqual 5
list.head.name mustEqual "Angello-W"
list.head.online mustEqual false
list(1).name mustEqual "thephattphrogg"
list(1).online mustEqual false
list(2).name mustEqual "Kimpossible12"
list(2).online mustEqual false
list(3).name mustEqual "Zearthling"
list(3).online mustEqual false
list(4).name mustEqual "KurtHectic-G"
list(4).online mustEqual false
case _ =>
ko
}
}
"decode (short)" in {
PacketCoding.DecodePacket(stringShort).require match {
case FriendsResponse(action, unk2, unk3, unk4, list) =>
action mustEqual FriendAction.InitializeIgnoreList
unk2 mustEqual 0
unk3 mustEqual true
unk4 mustEqual true
list.size mustEqual 0
case _ =>
ko
}
}
"encode (one friend)" in {
val msg = FriendsResponse(
FriendAction.UpdateFriend,
0,
true,
true,
Friend("KurtHectic-G", false) ::
Nil
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringOneFriend
}
"encode (multiple friends)" in {
val msg = FriendsResponse(
FriendAction.InitializeFriendList,
0,
true,
true,
Friend("Angello-W", false) ::
Friend("thephattphrogg", false) ::
Friend("Kimpossible12", false) ::
Friend("Zearthling", false) ::
Friend("KurtHectic-G", false) ::
Nil
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringManyFriends
}
"encode (short)" in {
val msg = FriendsResponse(FriendAction.InitializeIgnoreList, 0, true, true)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringShort
}
}

View file

@ -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 GenericActionMessageTest extends Specification {
val string = hex"A7 94"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case GenericActionMessage(action) =>
action mustEqual 37
case _ =>
ko
}
}
"encode" in {
val msg = GenericActionMessage(37)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,59 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class GenericCollisionMsgTest extends Specification {
//TODO find a better test later
val string =
hex"3C 92C00000190000001B2A8010932CEF505C70946F00000000000000000000000017725EBC6D6A058000000000000000000000000000003F8FF45140"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case GenericCollisionMsg(unk1, p, t, php, thp, pv, tv, ppos, tpos, unk2, unk3, unk4) =>
unk1 mustEqual 2
p mustEqual PlanetSideGUID(75)
t mustEqual PlanetSideGUID(0)
php mustEqual 100
thp mustEqual 0
pv.x mustEqual 32.166428f
pv.y mustEqual 23.712547f
pv.z mustEqual -0.012802706f
tv.x mustEqual 0.0f
tv.z mustEqual 0.0f
tv.x mustEqual 0.0f
ppos.x mustEqual 3986.7266f
ppos.y mustEqual 2615.3672f
ppos.z mustEqual 90.625f
tpos.x mustEqual 0.0f
tpos.y mustEqual 0.0f
tpos.z mustEqual 0.0f
unk2 mustEqual 0L
unk3 mustEqual 0L
unk4 mustEqual 1171341310L
case _ =>
ko
}
}
"encode" in {
val msg = GenericCollisionMsg(
2,
PlanetSideGUID(75),
PlanetSideGUID(0),
100,
0,
Vector3(32.166428f, 23.712547f, -0.012802706f),
Vector3(0.0f, 0.0f, 0.0f),
Vector3(3986.7266f, 2615.3672f, 90.625f),
Vector3(0.0f, 0.0f, 0.0f),
0L,
0L,
1171341310L
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class GenericObjectActionMessageTest extends Specification {
val string = hex"56 B501 24"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case GenericObjectActionMessage(object_guid, action) =>
object_guid mustEqual PlanetSideGUID(437)
action mustEqual 9
case _ =>
ko
}
}
"encode" in {
val msg = GenericObjectActionMessage(PlanetSideGUID(437), 9)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class GenericObjectStateMsgTest extends Specification {
val string = hex"1D 6401 10000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case GenericObjectStateMsg(object_guid, state) =>
object_guid mustEqual PlanetSideGUID(356)
state mustEqual 16
case _ =>
ko
}
}
"encode" in {
val msg = GenericObjectStateMsg(PlanetSideGUID(356), 16)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,34 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class HackMessageTest extends Specification {
// Record 62 in PSCap-hack-door-tower.gcap
val string = hex"54 000105c3800000202fc04200000000"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case HackMessage(unk1, target_guid, player_guid, progress, unk5, hack_state, unk7) =>
unk1 mustEqual 0
target_guid mustEqual PlanetSideGUID(1024)
player_guid mustEqual PlanetSideGUID(3607)
progress mustEqual 0
unk5 mustEqual 3212836864L
hack_state mustEqual HackState.Start
unk7 mustEqual 8L
case _ =>
ko
}
}
"encode" in {
val msg = HackMessage(0, PlanetSideGUID(1024), PlanetSideGUID(3607), 0, 3212836864L, HackState.Start, 8L)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class HitHintTest extends Specification {
val string = hex"0A 460B 0100"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case HitHint(source, player) =>
source mustEqual PlanetSideGUID(2886)
player mustEqual PlanetSideGUID(1)
case _ =>
ko
}
}
"encode" in {
val msg = HitHint(PlanetSideGUID(2886), PlanetSideGUID(1))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,76 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class HitMessageTest extends Specification {
val string_hitgeneric = hex"09 09E9A70200"
val string_hitobj = hex"09 99292705F4B1FB9514585F08BDD3D454CC5EE80300"
"decode (generic)" in {
PacketCoding.DecodePacket(string_hitgeneric).require match {
case HitMessage(seq_time, projectile_guid, unk1, hit_info, unk2, unk3, unk4) =>
seq_time mustEqual 777
projectile_guid mustEqual PlanetSideGUID(40102)
unk1 mustEqual 0
hit_info mustEqual None
unk2 mustEqual true
unk3 mustEqual false
unk4 mustEqual None
case _ =>
ko
}
}
"decode (object)" in {
PacketCoding.DecodePacket(string_hitobj).require match {
case HitMessage(seq_time, projectile_guid, unk1, hit_info, unk2, unk3, unk4) =>
seq_time mustEqual 153
projectile_guid mustEqual PlanetSideGUID(40100)
unk1 mustEqual 0
hit_info mustEqual Some(
HitInfo(
Vector3(3672.9766f, 2729.8594f, 92.34375f),
Vector3(3679.5156f, 2722.6172f, 92.796875f),
Some(PlanetSideGUID(372))
)
)
unk2 mustEqual true
unk3 mustEqual false
unk4 mustEqual None
case _ =>
ko
}
}
"encode (generic)" in {
val msg_hitgeneric = HitMessage(777, PlanetSideGUID(40102), 0, None, true, false, None)
val pkt_hitgeneric = PacketCoding.EncodePacket(msg_hitgeneric).require.toByteVector
pkt_hitgeneric mustEqual string_hitgeneric
}
"encode (object)" in {
val msg_hitobj = HitMessage(
153,
PlanetSideGUID(40100),
0,
Some(
HitInfo(
Vector3(3672.9766f, 2729.8594f, 92.34375f),
Vector3(3679.5156f, 2722.6172f, 92.796875f),
Some(PlanetSideGUID(372))
)
),
true,
false,
None
)
val pkt_hitobj = PacketCoding.EncodePacket(msg_hitobj).require.toByteVector
pkt_hitobj mustEqual string_hitobj
}
}

View file

@ -0,0 +1,97 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class HotSpotUpdateMessageTest extends Specification {
val stringClear = hex"9F 0500 1 000"
val stringOne = hex"9F 0500 1 010 002E9 00145 80000 0"
val stringTwo = hex"9F 0500 5 020 00D07 008CA 80000 00BEA 004C4 80000"
val stringThree = hex"9F 0A00 4 030 00FC8 00F0A 80000 002E9 00BEA 80000 00FC8 00BEA 80000 0"
"decode (clear)" in {
PacketCoding.DecodePacket(stringClear).require match {
case HotSpotUpdateMessage(continent_id, unk, spots) =>
continent_id mustEqual 5
unk mustEqual 1
spots.size mustEqual 0
case _ =>
ko
}
}
"decode (one)" in {
PacketCoding.DecodePacket(stringOne).require match {
case HotSpotUpdateMessage(continent_id, unk, spots) =>
continent_id mustEqual 5
unk mustEqual 1
spots.size mustEqual 1
spots.head mustEqual HotSpotInfo(4700.0f, 2600.0f, 64.0f)
case _ =>
ko
}
}
"decode (two)" in {
PacketCoding.DecodePacket(stringTwo).require match {
case HotSpotUpdateMessage(continent_id, unk, spots) =>
continent_id mustEqual 5
unk mustEqual 5
spots.size mustEqual 2
spots.head mustEqual HotSpotInfo(4000.0f, 5400.0f, 64.0f)
spots(1) mustEqual HotSpotInfo(5500.0f, 2200.0f, 64.0f)
case _ =>
ko
}
}
"decode (three)" in {
PacketCoding.DecodePacket(stringThree).require match {
case HotSpotUpdateMessage(continent_id, unk, spots) =>
continent_id mustEqual 10
unk mustEqual 4
spots.size mustEqual 3
spots.head mustEqual HotSpotInfo(4600.0f, 5600.0f, 64.0f)
spots(1) mustEqual HotSpotInfo(4700.0f, 5500.0f, 64.0f)
spots(2) mustEqual HotSpotInfo(4600.0f, 5500.0f, 64.0f)
case _ =>
ko
}
}
"encode (clear)" in {
val msg = HotSpotUpdateMessage(5, 1, Nil)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringClear
}
"encode (one)" in {
val msg = HotSpotUpdateMessage(5, 1, List(HotSpotInfo(4700.0f, 2600.0f, 64.0f)))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringOne
}
"encode (two)" in {
val msg =
HotSpotUpdateMessage(5, 5, List(HotSpotInfo(4000.0f, 5400.0f, 64.0f), HotSpotInfo(5500.0f, 2200.0f, 64.0f)))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringTwo
}
"encode (three)" in {
val msg = HotSpotUpdateMessage(
10,
4,
List(
HotSpotInfo(4600.0f, 5600.0f, 64.0f),
HotSpotInfo(4700.0f, 5500.0f, 64.0f),
HotSpotInfo(4600.0f, 5500.0f, 64.0f)
)
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual stringThree
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class InventoryStateMessageTest extends Specification {
val string = hex"38 5C0B 00 3C02 B20000000 0"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case InventoryStateMessage(object_guid, unk, inv_guid, value) =>
object_guid mustEqual PlanetSideGUID(2908)
unk mustEqual 0
inv_guid mustEqual PlanetSideGUID(2800)
value mustEqual 200
case _ =>
ko
}
}
"encode" in {
val msg = InventoryStateMessage(PlanetSideGUID(2908), 0, PlanetSideGUID(2800), 200)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,77 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, TransactionType}
import scodec.bits._
class ItemTransactionMessageTest extends Specification {
val string_buy = hex"44 4C03 4000110070756E6973686572000000"
val string_sell = hex"44 5303 60001000004E00"
val string_forget = hex"44 BA00 600011006861726173736572000000"
"decode (buy)" in {
PacketCoding.DecodePacket(string_buy).require match {
case ItemTransactionMessage(terminal_guid, transaction_type, item_page, item_name, unk1, item_guid) =>
terminal_guid mustEqual PlanetSideGUID(844)
transaction_type mustEqual TransactionType.Buy
item_page mustEqual 0
item_name mustEqual "punisher"
unk1 mustEqual 0
item_guid mustEqual PlanetSideGUID(0)
case _ =>
ko
}
}
"decode (sell)" in {
PacketCoding.DecodePacket(string_sell).require match {
case ItemTransactionMessage(terminal_guid, transaction_type, item_page, item_name, unk1, item_guid) =>
terminal_guid mustEqual PlanetSideGUID(851)
transaction_type mustEqual TransactionType.Sell
item_page mustEqual 0
item_name mustEqual ""
unk1 mustEqual 0
item_guid mustEqual PlanetSideGUID(78)
case _ =>
ko
}
}
"decode (forget)" in {
PacketCoding.DecodePacket(string_forget).require match {
case ItemTransactionMessage(terminal_guid, transaction_type, item_page, item_name, unk1, item_guid) =>
terminal_guid mustEqual PlanetSideGUID(186)
transaction_type mustEqual TransactionType.Sell
item_page mustEqual 0
item_name mustEqual "harasser"
unk1 mustEqual 0
item_guid mustEqual PlanetSideGUID(0)
case _ =>
ko
}
}
"encode (buy)" in {
val msg_buy = ItemTransactionMessage(PlanetSideGUID(844), TransactionType.Buy, 0, "punisher", 0, PlanetSideGUID(0))
val pkt_buy = PacketCoding.EncodePacket(msg_buy).require.toByteVector
pkt_buy mustEqual string_buy
}
"encode (sell)" in {
val msg_sell = ItemTransactionMessage(PlanetSideGUID(851), TransactionType.Sell, 0, "", 0, PlanetSideGUID(78))
val pkt_sell = PacketCoding.EncodePacket(msg_sell).require.toByteVector
pkt_sell mustEqual string_sell
}
"encode (forget)" in {
val msg_forget =
ItemTransactionMessage(PlanetSideGUID(186), TransactionType.Sell, 0, "harasser", 0, PlanetSideGUID(0))
val pkt_forget = PacketCoding.EncodePacket(msg_forget).require.toByteVector
pkt_forget mustEqual string_forget
}
}

View file

@ -0,0 +1,44 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, TransactionType}
import scodec.bits._
class ItemTransactionResultMessageTest extends Specification {
//these are paried packets come from the same capture
val string_request = hex"44 DD 03 40 00 11 40 73 75 70 70 72 65 73 73 6F 72 00 00 00"
val string_result = hex"45 DD 03 50 00"
"decode" in {
PacketCoding.DecodePacket(string_result).require match {
case ItemTransactionResultMessage(terminal_guid, transaction_type, is_success, error_code) =>
terminal_guid mustEqual PlanetSideGUID(989)
transaction_type mustEqual TransactionType.Buy
is_success mustEqual true
error_code mustEqual 0
case default =>
ko
}
}
"encode" in {
val msg = ItemTransactionResultMessage(PlanetSideGUID(989), TransactionType.Buy, true, 0)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_result
}
"proper reply" in {
try {
val request = PacketCoding.DecodePacket(string_request).require.asInstanceOf[ItemTransactionMessage]
val result = PacketCoding.DecodePacket(string_result).require.asInstanceOf[ItemTransactionResultMessage]
request.terminal_guid mustEqual result.terminal_guid
request.transaction_type mustEqual result.transaction_type
} catch {
case e: Exception =>
ko
}
}
}

View file

@ -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 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
}
}

View file

@ -0,0 +1,40 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideGUID, Vector3}
import scodec.bits._
class LashMessageTest extends Specification {
val string = hex"4f644a82e2c297a738a1ed0b01b886c0"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case LashMessage(seq_time, player, victim, bullet, pos, unk1) =>
seq_time mustEqual 356
player mustEqual PlanetSideGUID(2858)
victim mustEqual PlanetSideGUID(2699)
bullet mustEqual PlanetSideGUID(40030)
pos mustEqual Vector3(5903.7656f, 3456.5156f, 111.53125f)
unk1 mustEqual 0
case _ =>
ko
}
}
"encode" in {
val msg = LashMessage(
356,
PlanetSideGUID(2858),
PlanetSideGUID(2699),
PlanetSideGUID(40030),
Vector3(5903.7656f, 3456.5156f, 111.53125f),
0
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,31 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class LoadMapMessageTest extends Specification {
val string = hex"31 85 6D61703130 83 7A3130 0FA0 19000000 F6 F1 60 86 80"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case LoadMapMessage(map_name, nav_map_name, unk1, unk2, weapons_unlocked, unk3) =>
map_name mustEqual "map10"
nav_map_name mustEqual "z10"
unk1 mustEqual 40975
unk2 mustEqual 25
weapons_unlocked mustEqual true
unk3 mustEqual 230810349
case _ =>
ko
}
}
"encode" in {
val msg = LoadMapMessage("map10", "z10", 40975, 25, true, 230810349)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,123 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class LoginMessageTest extends Specification {
val string_password = hex"0x01030000000f0000008b4465632020322032303039408061816154000000"
val string_token =
hex"0x01030000000f0000008b4465632020322032303039a0a0a0a0a121212121a1a1a1a222222222a2a2a2a323232323a3a3a3a424240040806154000000"
"LoginMessage" should {
"decode (username)" in {
PacketCoding.DecodePacket(string_password).require match {
case LoginMessage(majorVersion, minorVersion, buildDate, username, password, token, revision) =>
majorVersion mustEqual 3
minorVersion mustEqual 15
buildDate mustEqual "Dec 2 2009"
username mustEqual "a"
password mustEqual Some("a")
token mustEqual None
revision mustEqual 84
case _ =>
ko
}
}
"decode (token)" in {
PacketCoding.DecodePacket(string_token).require match {
case LoginMessage(majorVersion, minorVersion, buildDate, username, password, token, revision) =>
majorVersion mustEqual 3
minorVersion mustEqual 15
buildDate mustEqual "Dec 2 2009"
username mustEqual "a"
password mustEqual None
token mustEqual Some("AAAABBBBCCCCDDDDEEEEFFFFGGGGHHH")
revision mustEqual 84
case _ =>
ko
}
}
"encode (username)" in {
val msg = LoginMessage(
3,
15,
"Dec 2 2009",
"a",
Some("a"),
None,
84
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_password
}
}
"encode (token)" in {
val msg = LoginMessage(
3,
15,
"Dec 2 2009",
"a",
None,
Some("AAAABBBBCCCCDDDDEEEEFFFFGGGGHHH"),
84
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_token
}
"encode (both?)" in {
LoginMessage(
3,
15,
"Dec 2 2009",
"a",
Some("a"),
Some("AAAABBBBCCCCDDDDEEEEFFFFGGGGHHH"),
84
) must throwA[IllegalArgumentException]
}
"encode (majorVersion == -1)" in {
LoginMessage(
-1,
15,
"Dec 2 2009",
"a",
Some("a"),
None,
84
) must throwA[IllegalArgumentException]
}
"encode (minorVersion == -1)" in {
LoginMessage(
3,
-1,
"Dec 2 2009",
"a",
Some("a"),
None,
84
) must throwA[IllegalArgumentException]
}
"encode (revision == -1)" in {
LoginMessage(
3,
15,
"Dec 2 2009",
"a",
Some("a"),
None,
-1
) must throwA[IllegalArgumentException]
}
}

View file

@ -0,0 +1,81 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.packet.game.LoginRespMessage._
import scodec.bits._
class LoginRespMessageTest extends Specification {
/// NOTE: the token is a C-string, meaning that the 18FABE0C junk seems like uninitialized memory due to memcpy, but
/// not memset
//val original = hex"02 4861484C64597A73305641536A6B73520000000018FABE0C0000000000000000" ++
// hex"00000000 01000000 02000000 6B7BD828 8C4169666671756F7469656E74 00000000 00"
val string = hex"02 4861484C64597A73305641536A6B735200000000000000000000000000000000" ++
hex"00000000 01000000 02000000 6B7BD828 8C4169666671756F7469656E74 00000000 00"
val string_priv = hex"02 4861484C64597A73305641536A6B735200000000000000000000000000000000" ++
hex"00000000 01000000 02000000 6B7BD828 8C4169666671756F7469656E74 11270000 80"
"encode" in {
val msg = LoginRespMessage(
"HaHLdYzs0VASjksR",
LoginError.Success,
StationError.AccountActive,
StationSubscriptionStatus.Active,
685276011,
"Aiffquotient",
0
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
"encode with privilege" in {
val msg = LoginRespMessage(
"HaHLdYzs0VASjksR",
LoginError.Success,
StationError.AccountActive,
StationSubscriptionStatus.Active,
685276011,
"Aiffquotient",
10001
)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string_priv
}
"decode" in {
PacketCoding.DecodePacket(string).require match {
case LoginRespMessage(token, error, stationError, subscription, unk, username, priv) =>
token mustEqual "HaHLdYzs0VASjksR"
error mustEqual LoginError.Success
stationError mustEqual StationError.AccountActive
subscription mustEqual StationSubscriptionStatus.Active
unk mustEqual 685276011
username mustEqual "Aiffquotient"
priv mustEqual 0
case _ =>
ko
}
}
"decode with privilege" in {
PacketCoding.DecodePacket(string_priv).require match {
case LoginRespMessage(token, error, stationError, subscription, unk, username, priv) =>
token mustEqual "HaHLdYzs0VASjksR"
error mustEqual LoginError.Success
stationError mustEqual StationError.AccountActive
subscription mustEqual StationSubscriptionStatus.Active
unk mustEqual 685276011
username mustEqual "Aiffquotient"
priv mustEqual 10001
case _ =>
ko
}
}
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.types.PlanetSideGUID
import scodec.bits._
class LootItemMessageTest extends Specification {
val string = hex"6C DD0D 5C14"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case LootItemMessage(item_guid, target_guid) =>
item_guid mustEqual PlanetSideGUID(3549)
target_guid mustEqual PlanetSideGUID(5212)
case _ =>
ko
}
}
"encode" in {
val msg = LootItemMessage(PlanetSideGUID(3549), PlanetSideGUID(5212))
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

View file

@ -0,0 +1,30 @@
// Copyright (c) 2017 PSForever
package game
import org.specs2.mutable._
import net.psforever.packet._
import net.psforever.packet.game._
import scodec.bits._
class MailMessageTest extends Specification {
//we've never received this packet before so this whole test is faked
val string = hex"F1 86466174654A489250726 96F72697479204D61696C2054657374 8E48656C6C6F204175726178697321"
"decode" in {
PacketCoding.DecodePacket(string).require match {
case MailMessage(sender, subject, msg) =>
sender mustEqual "FateJH"
subject mustEqual "Priority Mail Test"
msg mustEqual "Hello Auraxis!"
case _ =>
ko
}
}
"encode" in {
val msg = MailMessage("FateJH", "Priority Mail Test", "Hello Auraxis!")
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
pkt mustEqual string
}
}

Some files were not shown because too many files have changed in this diff Show more