2020-07-14 05:54:05 +02:00
|
|
|
package net.psforever.pslogin
|
Networking
The game uses a UDP-based protocol. Unlike TCP, UDP does not guarantee that
packets arrive, or that they arrive in the correct order. For this reason,
the game protocol implements those features using the following:
* All packets have a sequence number that is utilized for reordering
* Important packets are wrapped in a SlottedMetaPacket with a subslot number
* RelatedA packets ae used to request lost packets using the subslot number
* RelatedB packets are used to confirm received SlottedMetaPackets
All of these go both ways, server <-> client. We used to only partially
implement these features: Outgoing packet bundles used SMPs and could be
resent, but not all packets were bundled and there was no logic for requesting
lost packets from the client and there was no packet reordering, which resulted
in dire consequences in the case of packet loss (zoning failures, crashes and many
other odd bugs). This patch addresses all of these issues.
* Packet bundling: Packets are now automatically bundled and sent as
SlottedMetaPackets using a recurring timer. All manual bundling functionality
was removed.
* Packet reordering: Incoming packets, if received out of order, are stashed and
reordered. The maximum wait time for reordering is 20ms.
* Packet requesting: Missing SlottedMetaPackets are requested from the client.
* PacketCoding refactor: Dropped confusing packet container types. Fixes #5.
* Crypto rewrite: PSCrypto is based on a ancient buggy version of cryptopp.
Updating to a current version was not possible because it removed the
MD5-MAC algorithm. For more details, see Md5Mac.scala.
This patch replaces PSCrypto with native Scala code.
* Added two new actors:
* SocketActor: A simple typed UDP socket actor
* MiddlewareActor: The old session pipeline greatly simplified into a
typed actor that does most of the things mentioned above.
* Begun work on a headless client
* Fixed anniversary gun breaking stamina regen
* Resolved a few sentry errors
2020-09-17 17:04:06 +02:00
|
|
|
/*
|
2020-07-14 05:54:05 +02:00
|
|
|
|
2019-12-13 03:00:55 -05:00
|
|
|
import actor.base.ActorTest
|
2017-12-05 00:37:24 -05:00
|
|
|
import akka.actor.{ActorRef, Props}
|
|
|
|
|
import akka.testkit.TestProbe
|
Networking
The game uses a UDP-based protocol. Unlike TCP, UDP does not guarantee that
packets arrive, or that they arrive in the correct order. For this reason,
the game protocol implements those features using the following:
* All packets have a sequence number that is utilized for reordering
* Important packets are wrapped in a SlottedMetaPacket with a subslot number
* RelatedA packets ae used to request lost packets using the subslot number
* RelatedB packets are used to confirm received SlottedMetaPackets
All of these go both ways, server <-> client. We used to only partially
implement these features: Outgoing packet bundles used SMPs and could be
resent, but not all packets were bundled and there was no logic for requesting
lost packets from the client and there was no packet reordering, which resulted
in dire consequences in the case of packet loss (zoning failures, crashes and many
other odd bugs). This patch addresses all of these issues.
* Packet bundling: Packets are now automatically bundled and sent as
SlottedMetaPackets using a recurring timer. All manual bundling functionality
was removed.
* Packet reordering: Incoming packets, if received out of order, are stashed and
reordered. The maximum wait time for reordering is 20ms.
* Packet requesting: Missing SlottedMetaPackets are requested from the client.
* PacketCoding refactor: Dropped confusing packet container types. Fixes #5.
* Crypto rewrite: PSCrypto is based on a ancient buggy version of cryptopp.
Updating to a current version was not possible because it removed the
MD5-MAC algorithm. For more details, see Md5Mac.scala.
This patch replaces PSCrypto with native Scala code.
* Added two new actors:
* SocketActor: A simple typed UDP socket actor
* MiddlewareActor: The old session pipeline greatly simplified into a
typed actor that does most of the things mentioned above.
* Begun work on a headless client
* Fixed anniversary gun breaking stamina regen
* Resolved a few sentry errors
2020-09-17 17:04:06 +02:00
|
|
|
import net.psforever.actors.net.MiddlewareActor
|
2020-08-01 12:25:03 +02:00
|
|
|
import net.psforever.objects.avatar.Certification
|
Networking
The game uses a UDP-based protocol. Unlike TCP, UDP does not guarantee that
packets arrive, or that they arrive in the correct order. For this reason,
the game protocol implements those features using the following:
* All packets have a sequence number that is utilized for reordering
* Important packets are wrapped in a SlottedMetaPacket with a subslot number
* RelatedA packets ae used to request lost packets using the subslot number
* RelatedB packets are used to confirm received SlottedMetaPackets
All of these go both ways, server <-> client. We used to only partially
implement these features: Outgoing packet bundles used SMPs and could be
resent, but not all packets were bundled and there was no logic for requesting
lost packets from the client and there was no packet reordering, which resulted
in dire consequences in the case of packet loss (zoning failures, crashes and many
other odd bugs). This patch addresses all of these issues.
* Packet bundling: Packets are now automatically bundled and sent as
SlottedMetaPackets using a recurring timer. All manual bundling functionality
was removed.
* Packet reordering: Incoming packets, if received out of order, are stashed and
reordered. The maximum wait time for reordering is 20ms.
* Packet requesting: Missing SlottedMetaPackets are requested from the client.
* PacketCoding refactor: Dropped confusing packet container types. Fixes #5.
* Crypto rewrite: PSCrypto is based on a ancient buggy version of cryptopp.
Updating to a current version was not possible because it removed the
MD5-MAC algorithm. For more details, see Md5Mac.scala.
This patch replaces PSCrypto with native Scala code.
* Added two new actors:
* SocketActor: A simple typed UDP socket actor
* MiddlewareActor: The old session pipeline greatly simplified into a
typed actor that does most of the things mentioned above.
* Begun work on a headless client
* Fixed anniversary gun breaking stamina regen
* Resolved a few sentry errors
2020-09-17 17:04:06 +02:00
|
|
|
import net.psforever.packet.control.{ControlSync, SlottedMetaPacket}
|
|
|
|
|
import net.psforever.packet.{GamePacketOpcode, PacketCoding}
|
2017-12-05 00:37:24 -05:00
|
|
|
import net.psforever.packet.game._
|
2018-03-14 18:53:19 -04:00
|
|
|
import net.psforever.packet.game.objectcreate.ObjectClass
|
|
|
|
|
import net.psforever.types._
|
2017-12-05 00:37:24 -05:00
|
|
|
import scodec.bits._
|
|
|
|
|
|
|
|
|
|
import scala.concurrent.duration._
|
|
|
|
|
class PacketCodingActor1Test extends ActorTest {
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"construct" in {
|
Networking
The game uses a UDP-based protocol. Unlike TCP, UDP does not guarantee that
packets arrive, or that they arrive in the correct order. For this reason,
the game protocol implements those features using the following:
* All packets have a sequence number that is utilized for reordering
* Important packets are wrapped in a SlottedMetaPacket with a subslot number
* RelatedA packets ae used to request lost packets using the subslot number
* RelatedB packets are used to confirm received SlottedMetaPackets
All of these go both ways, server <-> client. We used to only partially
implement these features: Outgoing packet bundles used SMPs and could be
resent, but not all packets were bundled and there was no logic for requesting
lost packets from the client and there was no packet reordering, which resulted
in dire consequences in the case of packet loss (zoning failures, crashes and many
other odd bugs). This patch addresses all of these issues.
* Packet bundling: Packets are now automatically bundled and sent as
SlottedMetaPackets using a recurring timer. All manual bundling functionality
was removed.
* Packet reordering: Incoming packets, if received out of order, are stashed and
reordered. The maximum wait time for reordering is 20ms.
* Packet requesting: Missing SlottedMetaPackets are requested from the client.
* PacketCoding refactor: Dropped confusing packet container types. Fixes #5.
* Crypto rewrite: PSCrypto is based on a ancient buggy version of cryptopp.
Updating to a current version was not possible because it removed the
MD5-MAC algorithm. For more details, see Md5Mac.scala.
This patch replaces PSCrypto with native Scala code.
* Added two new actors:
* SocketActor: A simple typed UDP socket actor
* MiddlewareActor: The old session pipeline greatly simplified into a
typed actor that does most of the things mentioned above.
* Begun work on a headless client
* Fixed anniversary gun breaking stamina regen
* Resolved a few sentry errors
2020-09-17 17:04:06 +02:00
|
|
|
system.actorOf(Props[MiddlewareActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
//just construct without failing
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActor4Test extends ActorTest {
|
|
|
|
|
val string_hex = RawPacket(hex"2A 9F05 D405 86")
|
2020-01-08 01:17:23 -05:00
|
|
|
val string_obj = ObjectAttachMessage(PlanetSideGUID(1439), PlanetSideGUID(1492), 6)
|
2017-12-05 00:37:24 -05:00
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"translate r-originating game packet into l-facing hexadecimal data" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
2019-12-13 03:00:55 -05:00
|
|
|
val msg = MDCGamePacket(PacketCoding.CreateGamePacket(0, string_obj))
|
2017-12-05 00:37:24 -05:00
|
|
|
probe2 ! msg
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply1 = receiveOne(300 milli) //we get a MdcMsg message back
|
2017-12-05 00:37:24 -05:00
|
|
|
probe2 ! reply1 //by feeding the MdcMsg into the actor, we get normal output on the probe
|
|
|
|
|
probe1.expectMsg(string_hex)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActor5Test extends ActorTest {
|
|
|
|
|
val string_hex = RawPacket(hex"2A 9F05 D405 86")
|
2020-01-08 01:17:23 -05:00
|
|
|
val string_obj = ObjectAttachMessage(PlanetSideGUID(1439), PlanetSideGUID(1492), 6)
|
2017-12-05 00:37:24 -05:00
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"translate l-originating hexadecimal data into r-facing game packet" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
pca ! string_hex
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply = probe1.receiveOne(300 milli)
|
2017-12-05 00:37:24 -05:00
|
|
|
reply match {
|
|
|
|
|
case GamePacket(_, _, msg) => ;
|
|
|
|
|
assert(msg == string_obj)
|
|
|
|
|
case _ =>
|
|
|
|
|
assert(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActor6Test extends ActorTest {
|
2020-01-08 01:17:23 -05:00
|
|
|
val string_obj = ObjectAttachMessage(PlanetSideGUID(1439), PlanetSideGUID(1492), 6)
|
2017-12-05 00:37:24 -05:00
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"permit l-originating game packet to pass through as an r-facing game packet" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
val msg = PacketCoding.CreateGamePacket(0, string_obj)
|
|
|
|
|
pca ! msg
|
|
|
|
|
probe1.expectMsg(msg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActor7Test extends ActorTest {
|
2020-07-14 05:54:05 +02:00
|
|
|
val string_hex = RawPacket(
|
|
|
|
|
hex"0007 5268 0000004D 00000052 0000004D 0000007C 0000004D 0000000000000276 0000000000000275"
|
|
|
|
|
)
|
2017-12-05 00:37:24 -05:00
|
|
|
val string_obj = ControlSync(21096, 0x4d, 0x52, 0x4d, 0x7c, 0x4d, 0x276, 0x275)
|
|
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"translate r-originating control packet into l-facing hexadecimal data" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
2019-12-13 03:00:55 -05:00
|
|
|
val msg = MDCControlPacket(PacketCoding.CreateControlPacket(string_obj))
|
2017-12-05 00:37:24 -05:00
|
|
|
probe2 ! msg
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply1 = receiveOne(300 milli) //we get a MdcMsg message back
|
2017-12-05 00:37:24 -05:00
|
|
|
probe2 ! reply1 //by feeding the MdcMsg into the actor, we get normal output on the probe
|
|
|
|
|
probe1.expectMsg(string_hex)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActor8Test extends ActorTest {
|
2020-07-14 05:54:05 +02:00
|
|
|
val string_hex = RawPacket(
|
|
|
|
|
hex"0007 5268 0000004D 00000052 0000004D 0000007C 0000004D 0000000000000276 0000000000000275"
|
|
|
|
|
)
|
2017-12-05 00:37:24 -05:00
|
|
|
val string_obj = ControlSync(21096, 0x4d, 0x52, 0x4d, 0x7c, 0x4d, 0x276, 0x275)
|
|
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"translate l-originating hexadecimal data into r-facing control packet" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
pca ! string_hex
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply = probe1.receiveOne(300 milli)
|
2017-12-05 00:37:24 -05:00
|
|
|
reply match {
|
|
|
|
|
case ControlPacket(_, msg) => ;
|
|
|
|
|
assert(msg == string_obj)
|
|
|
|
|
case _ =>
|
|
|
|
|
assert(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActor9Test extends ActorTest {
|
|
|
|
|
val string_obj = ControlSync(21096, 0x4d, 0x52, 0x4d, 0x7c, 0x4d, 0x276, 0x275)
|
|
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"permit l-originating control packet to pass through as an r-facing control packet" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
val msg = PacketCoding.CreateControlPacket(string_obj)
|
|
|
|
|
pca ! msg
|
|
|
|
|
probe1.expectMsg(msg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorATest extends ActorTest {
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"permit l-originating unhandled message to pass through as an r-facing unhandled message" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
pca ! "unhandled message"
|
|
|
|
|
probe1.expectMsg("unhandled message")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorBTest extends ActorTest {
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"permit r-originating unhandled message to pass through as an l-facing unhandled message" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
probe2 ! "unhandled message"
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply1 = receiveOne(300 milli) //we get a MdcMsg message back
|
2017-12-05 00:37:24 -05:00
|
|
|
probe2 ! reply1 //by feeding the MdcMsg into the actor, we get normal output on the probe
|
|
|
|
|
probe1.expectMsg("unhandled message")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorCTest extends ActorTest {
|
2020-07-14 05:54:05 +02:00
|
|
|
val string_hex =
|
|
|
|
|
hex"D5 0B 00 00 00 01 0A E4 0C 02 48 70 75 72 63 68 61 73 65 5F 65 78 65 6D 70 74 5F 76 73 80 92 70 75 72 63 68 61 73 65 5F 65 78 65 6D 70 74 5F 74 72 80 92 70 75 72 63 68 61 73 65 5F 65 78 65 6D 70 74 5F 6E 63 80 11 00 01 14 A4 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 12 00 01 14 A4 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 13 00 01 14 A4 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 14 00 01 14 A4 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 15 00 01 14 A4 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 16 00 01 14 A4 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 1D 00 15 0A 60 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 54 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 76 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 87 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 C7 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 C8 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 26 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 52 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 AD 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B0 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B9 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 CE 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 D6 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 2C 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 82 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 83 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B9 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 CA 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 61 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 9B 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 DA 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 1E 00 15 0A 60 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 54 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 76 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 87 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 C7 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 C8 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 26 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 52 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 AD 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B0 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B9 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 CE 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 D6 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 2C 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 82 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 83 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B9 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 CA 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 61 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 9B 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 DA 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 1F 00 15 0A 60 04 02 1C 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 54 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 76 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 87 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 C7 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 C8 00 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 26 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 52 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 AD 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B0 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B9 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 CE 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 D6 20 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 2C 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 82 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 83 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 B9 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 CA 40 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 61 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 9B 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66 61 6C 73 65 DA 60 20 10 E0 61 6C 6C 6F 77 65 64 85 66
|
2017-12-05 00:37:24 -05:00
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"should split r-originating hexadecimal data if it is larger than the MTU limit" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
val msg = RawPacket(string_hex)
|
|
|
|
|
probe2 ! msg
|
|
|
|
|
receiveN(4)
|
|
|
|
|
//msg4.foreach(str => { probe2 ! str })
|
|
|
|
|
//probe1.receiveN(4)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorDTest extends ActorTest {
|
|
|
|
|
val string_obj = PropertyOverrideMessage(
|
|
|
|
|
List(
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(
|
|
|
|
|
0,
|
|
|
|
|
GamePropertyTarget(
|
|
|
|
|
GamePropertyTarget.game_properties,
|
|
|
|
|
List(
|
|
|
|
|
"purchase_exempt_vs" -> "",
|
|
|
|
|
"purchase_exempt_tr" -> "",
|
|
|
|
|
"purchase_exempt_nc" -> ""
|
|
|
|
|
)
|
2017-12-05 00:37:24 -05:00
|
|
|
)
|
|
|
|
|
),
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(17, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(18, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(19, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(20, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(21, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(22, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(
|
|
|
|
|
29,
|
|
|
|
|
List(
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aurora, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.battlewagon, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.flail, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.galaxy_gunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lasher, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.liberator, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lightgunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.maelstrom, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.magrider, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.mini_chaingun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.prowler, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.r_shotgun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.thunderer, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vanguard, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vulture, "allowed" -> "false")
|
|
|
|
|
)
|
2017-12-05 00:37:24 -05:00
|
|
|
),
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(
|
|
|
|
|
30,
|
|
|
|
|
List(
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aurora, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.battlewagon, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.flail, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.galaxy_gunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lasher, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.liberator, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lightgunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.maelstrom, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.magrider, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.mini_chaingun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.prowler, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.r_shotgun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.thunderer, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vanguard, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vulture, "allowed" -> "false")
|
|
|
|
|
)
|
2017-12-05 00:37:24 -05:00
|
|
|
),
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(
|
|
|
|
|
31,
|
|
|
|
|
List(
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aurora, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.battlewagon, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.flail, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.galaxy_gunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lasher, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.liberator, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lightgunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.maelstrom, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.magrider, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.mini_chaingun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.prowler, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.r_shotgun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.thunderer, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vanguard, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vulture, "allowed" -> "false")
|
|
|
|
|
)
|
2017-12-05 00:37:24 -05:00
|
|
|
),
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(
|
|
|
|
|
32,
|
|
|
|
|
List(
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aurora, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.battlewagon, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.flail, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.galaxy_gunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lasher, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.liberator, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lightgunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.maelstrom, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.magrider, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.mini_chaingun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.prowler, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.r_shotgun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.thunderer, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vanguard, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vulture, "allowed" -> "false")
|
|
|
|
|
)
|
|
|
|
|
)
|
2017-12-05 00:37:24 -05:00
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"should split r-originating game packet if it is larger than the MTU limit" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2017-12-05 00:37:24 -05:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
2019-12-13 03:00:55 -05:00
|
|
|
val msg = MDCGamePacket(PacketCoding.CreateGamePacket(0, string_obj))
|
2017-12-05 00:37:24 -05:00
|
|
|
probe2 ! msg
|
|
|
|
|
receiveN(4)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-14 18:53:19 -04:00
|
|
|
class PacketCodingActorETest extends ActorTest {
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"unwind l-originating hexadecimal data into multiple r-facing packets (MultiPacket -> 2 PlayerStateMessageUpstream)" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val string_hex = RawPacket(
|
|
|
|
|
hex"00 03 18 BD E8 04 5C 02 60 E3 F9 19 0E C1 41 27 00 04 02 60 20 0C 58 0B 20 00 00 18 BD E8 04 86 02 62 13 F9 19 0E D8 40 4D 00 04 02 60 20 0C 78 0A 80 00 00"
|
|
|
|
|
)
|
|
|
|
|
val string_obj1 = GamePacket(
|
|
|
|
|
GamePacketOpcode.PlayerStateMessageUpstream,
|
|
|
|
|
0,
|
|
|
|
|
PlayerStateMessageUpstream(
|
|
|
|
|
PlanetSideGUID(1256),
|
|
|
|
|
Vector3(3076.7188f, 4734.1094f, 56.390625f),
|
|
|
|
|
Some(Vector3(4.0625f, 4.59375f, 0.0f)),
|
|
|
|
|
36.5625f,
|
|
|
|
|
-2.8125f,
|
|
|
|
|
0.0f,
|
|
|
|
|
866,
|
|
|
|
|
0,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
178,
|
|
|
|
|
0
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
val string_obj2 = GamePacket(
|
|
|
|
|
GamePacketOpcode.PlayerStateMessageUpstream,
|
|
|
|
|
0,
|
|
|
|
|
PlayerStateMessageUpstream(
|
|
|
|
|
PlanetSideGUID(1256),
|
|
|
|
|
Vector3(3077.0469f, 4734.258f, 56.390625f),
|
|
|
|
|
Some(Vector3(5.5f, 1.1875f, 0.0f)),
|
|
|
|
|
36.5625f,
|
|
|
|
|
-2.8125f,
|
|
|
|
|
0.0f,
|
|
|
|
|
867,
|
|
|
|
|
0,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
168,
|
|
|
|
|
0
|
|
|
|
|
)
|
|
|
|
|
)
|
2018-03-14 18:53:19 -04:00
|
|
|
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2018-03-14 18:53:19 -04:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
pca ! string_hex
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply = probe1.receiveN(2, 400 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
assert(reply.head == string_obj1)
|
|
|
|
|
assert(reply(1) == string_obj2)
|
2020-05-26 19:50:54 -04:00
|
|
|
probe1.expectNoMessage(300 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorFTest extends ActorTest {
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"unwind l-originating hexadecimal data into an r-facing packet (MultiPacket -> RelatedB + GenericObjectStateMsg)" in {
|
|
|
|
|
val string_hex = RawPacket(hex"00 03 04 00 15 02 98 0B 00 09 0C 0A 1D F2 00 10 00 00 00")
|
2020-07-14 05:54:05 +02:00
|
|
|
val string_obj =
|
|
|
|
|
GamePacket(GamePacketOpcode.GenericObjectStateMsg, 0, GenericObjectStateMsg(PlanetSideGUID(242), 16))
|
2018-03-14 18:53:19 -04:00
|
|
|
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2018-03-14 18:53:19 -04:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
pca ! string_hex
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply = probe1.receiveN(1, 400 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
assert(reply.head == string_obj)
|
|
|
|
|
//the RelatedB message - 00 15 02 98 - is consumed by pca
|
2020-05-26 19:50:54 -04:00
|
|
|
probe1.expectNoMessage(300 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorGTest extends ActorTest {
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"unwind l-originating hexadecimal data into an r-facing packet (MultiPacketEx -> RelatedA + GenericObjectStateMsg)" in {
|
|
|
|
|
val string_hex = RawPacket(hex"00 19 04 00 11 02 98 0B 00 09 0C 0A 1D F2 00 10 00 00 00")
|
2020-07-14 05:54:05 +02:00
|
|
|
val string_obj =
|
|
|
|
|
GamePacket(GamePacketOpcode.GenericObjectStateMsg, 0, GenericObjectStateMsg(PlanetSideGUID(242), 16))
|
2018-03-14 18:53:19 -04:00
|
|
|
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2018-03-14 18:53:19 -04:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
pca ! string_hex
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply = probe1.receiveN(1, 400 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
assert(reply.head == string_obj)
|
|
|
|
|
//the RelatedA message - 00 11 02 98 - is consumed by pca; should see error log message in console
|
2020-05-26 19:50:54 -04:00
|
|
|
probe1.expectNoMessage(300 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorHTest extends ActorTest {
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"unwind l-originating hexadecimal data into two r-facing packets (SlottedMetaPacket/MultiPacketEx -> 2 ObjectDeleteMessage)" in {
|
|
|
|
|
val string_hex = RawPacket(hex"00 09 0A E1 00 19 04 19 4F 04 40 04 19 51 04 40")
|
2020-07-14 05:54:05 +02:00
|
|
|
val string_obj1 =
|
|
|
|
|
GamePacket(GamePacketOpcode.ObjectDeleteMessage, 0, ObjectDeleteMessage(PlanetSideGUID(1103), 2))
|
|
|
|
|
val string_obj2 =
|
|
|
|
|
GamePacket(GamePacketOpcode.ObjectDeleteMessage, 0, ObjectDeleteMessage(PlanetSideGUID(1105), 2))
|
|
|
|
|
|
|
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2018-03-14 18:53:19 -04:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
pca ! string_hex
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply = probe1.receiveN(2, 400 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
assert(reply.head == string_obj1)
|
|
|
|
|
assert(reply(1) == string_obj2)
|
2020-05-26 19:50:54 -04:00
|
|
|
probe1.expectNoMessage(300 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorITest extends ActorTest {
|
2018-05-28 20:39:35 -04:00
|
|
|
import net.psforever.packet.game.objectcreate._
|
2020-07-14 05:54:05 +02:00
|
|
|
val pos: PlacementData = PlacementData(Vector3.Zero, Vector3.Zero)
|
|
|
|
|
val app: Int => CharacterAppearanceData = CharacterAppearanceData(
|
|
|
|
|
BasicCharacterData(
|
|
|
|
|
"IlllIIIlllIlIllIlllIllI",
|
|
|
|
|
PlanetSideEmpire.VS,
|
|
|
|
|
CharacterGender.Female,
|
|
|
|
|
41,
|
|
|
|
|
CharacterVoice.Voice1
|
|
|
|
|
),
|
2018-05-28 20:39:35 -04:00
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
ExoSuitType.Standard,
|
|
|
|
|
"",
|
|
|
|
|
0,
|
|
|
|
|
false,
|
2020-07-14 05:54:05 +02:00
|
|
|
2.8125f,
|
|
|
|
|
0f,
|
2018-05-28 20:39:35 -04:00
|
|
|
true,
|
|
|
|
|
GrenadeState.None,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
2018-10-07 23:34:06 -04:00
|
|
|
None,
|
2018-05-28 20:39:35 -04:00
|
|
|
RibbonBars()
|
|
|
|
|
)
|
2020-07-14 05:54:05 +02:00
|
|
|
var char: Option[Int] => DetailedCharacterData = DetailedCharacterData(
|
2018-05-28 20:39:35 -04:00
|
|
|
0,
|
|
|
|
|
0,
|
2020-07-14 05:54:05 +02:00
|
|
|
100,
|
|
|
|
|
100,
|
2018-05-28 20:39:35 -04:00
|
|
|
50,
|
2020-07-14 05:54:05 +02:00
|
|
|
100,
|
|
|
|
|
100,
|
2018-11-21 20:00:33 -05:00
|
|
|
None,
|
2020-07-14 05:54:05 +02:00
|
|
|
List(
|
2020-08-01 12:25:03 +02:00
|
|
|
Certification.StandardAssault,
|
|
|
|
|
Certification.MediumAssault,
|
|
|
|
|
Certification.ATV,
|
|
|
|
|
Certification.Harasser,
|
|
|
|
|
Certification.StandardExoSuit,
|
|
|
|
|
Certification.AgileExoSuit,
|
|
|
|
|
Certification.ReinforcedExoSuit
|
2020-07-14 05:54:05 +02:00
|
|
|
),
|
2018-05-28 20:39:35 -04:00
|
|
|
List(),
|
|
|
|
|
List(),
|
|
|
|
|
List.empty,
|
|
|
|
|
None
|
|
|
|
|
)
|
|
|
|
|
val obj = DetailedPlayerData(pos, app, char, InventoryData(Nil), DrawnSlot.None)
|
2019-11-29 11:14:25 -05:00
|
|
|
//println(s"${PacketCoding.EncodePacket(ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj))}")
|
2020-01-08 01:17:23 -05:00
|
|
|
val pkt = MultiPacketBundle(List(ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj)))
|
2020-07-14 05:54:05 +02:00
|
|
|
val string_hex =
|
|
|
|
|
hex"00090000186c060000bc84b000000000000000000002040000097049006c006c006c004900490049006c006c006c0049006c0049006c006c0049006c006c006c0049006c006c00490084524000000000000000000000000000000020000007f00703fffffffffffffffffffffffffffffffc000000000000000000000000000000000000000190019000640000000000c800c80000000000000000000000000000000000000001c00042c54686c7000000000000000000000000000000000000000000000000000000000000100000000400e0"
|
2018-05-28 20:39:35 -04:00
|
|
|
|
2018-03-14 18:53:19 -04:00
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"bundle an r-originating packet into an l-facing SlottedMetaPacket byte stream data (SlottedMetaPacket)" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2018-03-14 18:53:19 -04:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
probe2 ! pkt
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply1 = receiveN(1, 400 milli) //we get a MdcMsg message back
|
2018-03-14 18:53:19 -04:00
|
|
|
probe1.receiveN(1, 200 milli) //flush contents
|
2020-07-14 05:54:05 +02:00
|
|
|
probe2 ! reply1.head //by feeding the MdcMsg into the actor, we get normal output on the probe
|
2018-05-21 08:25:11 -04:00
|
|
|
probe1.receiveOne(300 milli) match {
|
2018-03-14 18:53:19 -04:00
|
|
|
case RawPacket(data) =>
|
|
|
|
|
assert(data == string_hex)
|
Networking
The game uses a UDP-based protocol. Unlike TCP, UDP does not guarantee that
packets arrive, or that they arrive in the correct order. For this reason,
the game protocol implements those features using the following:
* All packets have a sequence number that is utilized for reordering
* Important packets are wrapped in a SlottedMetaPacket with a subslot number
* RelatedA packets ae used to request lost packets using the subslot number
* RelatedB packets are used to confirm received SlottedMetaPackets
All of these go both ways, server <-> client. We used to only partially
implement these features: Outgoing packet bundles used SMPs and could be
resent, but not all packets were bundled and there was no logic for requesting
lost packets from the client and there was no packet reordering, which resulted
in dire consequences in the case of packet loss (zoning failures, crashes and many
other odd bugs). This patch addresses all of these issues.
* Packet bundling: Packets are now automatically bundled and sent as
SlottedMetaPackets using a recurring timer. All manual bundling functionality
was removed.
* Packet reordering: Incoming packets, if received out of order, are stashed and
reordered. The maximum wait time for reordering is 20ms.
* Packet requesting: Missing SlottedMetaPackets are requested from the client.
* PacketCoding refactor: Dropped confusing packet container types. Fixes #5.
* Crypto rewrite: PSCrypto is based on a ancient buggy version of cryptopp.
Updating to a current version was not possible because it removed the
MD5-MAC algorithm. For more details, see Md5Mac.scala.
This patch replaces PSCrypto with native Scala code.
* Added two new actors:
* SocketActor: A simple typed UDP socket actor
* MiddlewareActor: The old session pipeline greatly simplified into a
typed actor that does most of the things mentioned above.
* Begun work on a headless client
* Fixed anniversary gun breaking stamina regen
* Resolved a few sentry errors
2020-09-17 17:04:06 +02:00
|
|
|
PacketCoding.decodePacket(data).require match {
|
2020-07-14 05:54:05 +02:00
|
|
|
case _: SlottedMetaPacket =>
|
2018-03-14 18:53:19 -04:00
|
|
|
assert(true)
|
|
|
|
|
case _ =>
|
|
|
|
|
assert(false)
|
|
|
|
|
}
|
|
|
|
|
case e =>
|
|
|
|
|
assert(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorJTest extends ActorTest {
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"bundle r-originating packets into a number of MTU-acceptable l-facing byte streams (1 packets into 1)" in {
|
|
|
|
|
val pkt = MultiPacketBundle(
|
2020-07-14 05:54:05 +02:00
|
|
|
List(
|
|
|
|
|
ObjectDeleteMessage(PlanetSideGUID(1103), 2),
|
|
|
|
|
ObjectDeleteMessage(PlanetSideGUID(1105), 2),
|
|
|
|
|
ObjectDeleteMessage(PlanetSideGUID(1107), 2)
|
|
|
|
|
)
|
2018-03-14 18:53:19 -04:00
|
|
|
)
|
|
|
|
|
val string_hex = hex"00090000001904194f044004195104400419530440"
|
|
|
|
|
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2018-03-14 18:53:19 -04:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
probe2 ! pkt
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply1 = receiveN(1, 400 milli) //we get a MdcMsg message back
|
2018-03-14 18:53:19 -04:00
|
|
|
probe1.receiveN(1, 200 milli) //flush contents
|
2020-07-14 05:54:05 +02:00
|
|
|
probe2 ! reply1.head //by feeding the MdcMsg into the actor, we get normal output on the probe
|
2018-05-21 08:25:11 -04:00
|
|
|
probe1.receiveOne(300 milli) match {
|
2018-03-14 18:53:19 -04:00
|
|
|
case RawPacket(data) =>
|
|
|
|
|
assert(data == string_hex)
|
|
|
|
|
case e =>
|
|
|
|
|
assert(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorKTest extends ActorTest {
|
|
|
|
|
import net.psforever.packet.game.objectcreate._
|
2020-07-14 05:54:05 +02:00
|
|
|
val pos: PlacementData = PlacementData(Vector3.Zero, Vector3.Zero)
|
|
|
|
|
val aa: Int => CharacterAppearanceA = CharacterAppearanceA(
|
2018-10-17 12:26:25 -04:00
|
|
|
BasicCharacterData(
|
|
|
|
|
"IlllIIIlllIlIllIlllIllI",
|
|
|
|
|
PlanetSideEmpire.VS,
|
|
|
|
|
CharacterGender.Female,
|
|
|
|
|
41,
|
|
|
|
|
CharacterVoice.Voice1
|
|
|
|
|
),
|
2019-03-03 08:23:30 -05:00
|
|
|
CommonFieldData(
|
|
|
|
|
PlanetSideEmpire.VS,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
true,
|
|
|
|
|
None,
|
|
|
|
|
false,
|
|
|
|
|
None,
|
|
|
|
|
None,
|
2020-01-08 01:17:23 -05:00
|
|
|
PlanetSideGUID(0)
|
2019-03-03 08:23:30 -05:00
|
|
|
),
|
2018-05-28 20:39:35 -04:00
|
|
|
ExoSuitType.Standard,
|
2018-10-17 12:26:25 -04:00
|
|
|
0,
|
|
|
|
|
41605313L,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
65535
|
|
|
|
|
)
|
2020-07-14 05:54:05 +02:00
|
|
|
val ab: (Boolean, Int) => CharacterAppearanceB = CharacterAppearanceB(
|
2018-10-17 12:26:25 -04:00
|
|
|
0L,
|
2018-05-28 20:39:35 -04:00
|
|
|
"",
|
|
|
|
|
0,
|
|
|
|
|
false,
|
2018-10-17 12:26:25 -04:00
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
2020-07-14 05:54:05 +02:00
|
|
|
2.8125f,
|
|
|
|
|
0f,
|
2018-10-17 12:26:25 -04:00
|
|
|
false,
|
2018-05-28 20:39:35 -04:00
|
|
|
GrenadeState.None,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
2018-10-17 12:26:25 -04:00
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
None
|
|
|
|
|
)
|
|
|
|
|
|
2020-07-14 05:54:05 +02:00
|
|
|
val app: Int => CharacterAppearanceData = CharacterAppearanceData(
|
|
|
|
|
aa,
|
|
|
|
|
ab,
|
2018-05-28 20:39:35 -04:00
|
|
|
RibbonBars()
|
|
|
|
|
)
|
2020-07-14 05:54:05 +02:00
|
|
|
val ba: DetailedCharacterA = DetailedCharacterA(
|
|
|
|
|
0L,
|
|
|
|
|
0L,
|
2018-10-17 12:26:25 -04:00
|
|
|
0L,
|
|
|
|
|
0L,
|
2020-07-14 05:54:05 +02:00
|
|
|
0L,
|
|
|
|
|
100,
|
|
|
|
|
100,
|
2018-10-17 12:26:25 -04:00
|
|
|
false,
|
2018-03-14 18:53:19 -04:00
|
|
|
50,
|
2018-10-17 12:26:25 -04:00
|
|
|
32831L,
|
2020-07-14 05:54:05 +02:00
|
|
|
100,
|
|
|
|
|
100,
|
2018-11-21 20:00:33 -05:00
|
|
|
None,
|
2020-07-14 05:54:05 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0L,
|
2018-10-17 12:26:25 -04:00
|
|
|
List(0, 0, 0, 0, 0, 0),
|
|
|
|
|
List(
|
2020-08-01 12:25:03 +02:00
|
|
|
Certification.StandardAssault,
|
|
|
|
|
Certification.MediumAssault,
|
|
|
|
|
Certification.ATV,
|
|
|
|
|
Certification.Harasser,
|
|
|
|
|
Certification.StandardExoSuit,
|
|
|
|
|
Certification.AgileExoSuit,
|
|
|
|
|
Certification.ReinforcedExoSuit
|
2018-10-17 12:26:25 -04:00
|
|
|
)
|
|
|
|
|
)
|
2020-07-14 05:54:05 +02:00
|
|
|
val bb: (Long, Option[Int]) => DetailedCharacterB = DetailedCharacterB(
|
2018-10-17 12:26:25 -04:00
|
|
|
None,
|
|
|
|
|
Nil,
|
2020-07-14 05:54:05 +02:00
|
|
|
Nil,
|
|
|
|
|
Nil,
|
2018-10-17 12:26:25 -04:00
|
|
|
List(
|
|
|
|
|
"xpe_sanctuary_help",
|
|
|
|
|
"xpe_th_firemodes",
|
|
|
|
|
"used_beamer",
|
|
|
|
|
"map13"
|
|
|
|
|
),
|
|
|
|
|
Nil,
|
2020-07-14 05:54:05 +02:00
|
|
|
0L,
|
|
|
|
|
0L,
|
|
|
|
|
0L,
|
|
|
|
|
0L,
|
|
|
|
|
0L,
|
2018-10-17 12:26:25 -04:00
|
|
|
Some(DCDExtra2(0, 0)),
|
2020-07-14 05:54:05 +02:00
|
|
|
Nil,
|
|
|
|
|
Nil,
|
|
|
|
|
false,
|
2018-05-28 20:39:35 -04:00
|
|
|
None
|
2018-03-14 18:53:19 -04:00
|
|
|
)
|
2020-07-14 05:54:05 +02:00
|
|
|
val char: Option[Int] => DetailedCharacterData =
|
|
|
|
|
(pad_length: Option[Int]) => DetailedCharacterData(ba, bb(ba.bep, pad_length))(pad_length)
|
2018-05-28 20:39:35 -04:00
|
|
|
val obj = DetailedPlayerData(pos, app, char, InventoryData(Nil), DrawnSlot.None)
|
2018-03-14 18:53:19 -04:00
|
|
|
val list = List(
|
2020-01-08 01:17:23 -05:00
|
|
|
ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), obj),
|
|
|
|
|
ObjectDeleteMessage(PlanetSideGUID(1103), 2),
|
|
|
|
|
ObjectDeleteMessage(PlanetSideGUID(1105), 2),
|
|
|
|
|
ObjectCreateDetailedMessage(0x79, PlanetSideGUID(175), obj),
|
|
|
|
|
ObjectCreateDetailedMessage(0x79, PlanetSideGUID(275), obj),
|
|
|
|
|
ObjectDeleteMessage(PlanetSideGUID(1107), 2)
|
2018-03-14 18:53:19 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"bundle r-originating packets into a number of MTU-acceptable l-facing byte streams (6 packets into 2)" in {
|
|
|
|
|
val pkt = MultiPacketBundle(list)
|
|
|
|
|
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2018-03-14 18:53:19 -04:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
probe2 ! pkt
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply1 = receiveN(2, 400 milli)
|
2018-03-14 18:53:19 -04:00
|
|
|
probe1.receiveN(1, 200 milli) //flush contents
|
2020-07-14 05:54:05 +02:00
|
|
|
probe2 ! reply1.head //by feeding the MdcMsg into the actor, we get normal output on the probe
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply3 = probe1.receiveOne(300 milli).asInstanceOf[RawPacket]
|
2018-03-14 18:53:19 -04:00
|
|
|
|
|
|
|
|
pca ! reply3 //reconstruct original three packets from the first bundle
|
2018-05-21 08:25:11 -04:00
|
|
|
val reply4 = probe1.receiveN(3, 400 milli)
|
2020-07-14 05:54:05 +02:00
|
|
|
var i = 0
|
|
|
|
|
reply4.foreach {
|
2018-03-14 18:53:19 -04:00
|
|
|
case GamePacket(_, _, packet) =>
|
|
|
|
|
assert(packet == list(i))
|
|
|
|
|
i += 1
|
|
|
|
|
case _ =>
|
|
|
|
|
assert(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class PacketCodingActorLTest extends ActorTest {
|
|
|
|
|
val string_obj = PropertyOverrideMessage(
|
|
|
|
|
List(
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(
|
|
|
|
|
0,
|
|
|
|
|
GamePropertyTarget(
|
|
|
|
|
GamePropertyTarget.game_properties,
|
|
|
|
|
List(
|
|
|
|
|
"purchase_exempt_vs" -> "",
|
|
|
|
|
"purchase_exempt_tr" -> "",
|
|
|
|
|
"purchase_exempt_nc" -> ""
|
|
|
|
|
)
|
2018-03-14 18:53:19 -04:00
|
|
|
)
|
|
|
|
|
),
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(17, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(18, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(19, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(20, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(21, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(22, GamePropertyTarget(ObjectClass.katana, "allowed" -> "false")),
|
|
|
|
|
GamePropertyScope(
|
|
|
|
|
29,
|
|
|
|
|
List(
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aurora, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.battlewagon, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.flail, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.galaxy_gunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lasher, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.liberator, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lightgunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.maelstrom, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.magrider, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.mini_chaingun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.prowler, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.r_shotgun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.thunderer, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vanguard, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vulture, "allowed" -> "false")
|
|
|
|
|
)
|
2018-03-14 18:53:19 -04:00
|
|
|
),
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(
|
|
|
|
|
30,
|
|
|
|
|
List(
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aurora, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.battlewagon, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.flail, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.galaxy_gunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lasher, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.liberator, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lightgunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.maelstrom, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.magrider, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.mini_chaingun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.prowler, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.r_shotgun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.thunderer, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vanguard, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vulture, "allowed" -> "false")
|
|
|
|
|
)
|
2018-03-14 18:53:19 -04:00
|
|
|
),
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(
|
|
|
|
|
31,
|
|
|
|
|
List(
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aurora, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.battlewagon, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.flail, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.galaxy_gunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lasher, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.liberator, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lightgunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.maelstrom, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.magrider, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.mini_chaingun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.prowler, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.r_shotgun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.thunderer, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vanguard, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vulture, "allowed" -> "false")
|
|
|
|
|
)
|
2018-03-14 18:53:19 -04:00
|
|
|
),
|
2020-07-14 05:54:05 +02:00
|
|
|
GamePropertyScope(
|
|
|
|
|
32,
|
|
|
|
|
List(
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aphelion_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.aurora, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.battlewagon, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.colossus_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.flail, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.galaxy_gunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lasher, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.liberator, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.lightgunship, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.maelstrom, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.magrider, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.mini_chaingun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_flight, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.peregrine_gunner, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.prowler, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.r_shotgun, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.thunderer, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vanguard, "allowed" -> "false"),
|
|
|
|
|
GamePropertyTarget(ObjectClass.vulture, "allowed" -> "false")
|
|
|
|
|
)
|
|
|
|
|
)
|
2018-03-14 18:53:19 -04:00
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
"PacketCodingActor" should {
|
|
|
|
|
"split, rather than bundle, r-originating packets into a number of MTU-acceptable l-facing byte streams" in {
|
2020-07-14 05:54:05 +02:00
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = system.actorOf(Props(classOf[MDCTestProbe], probe1), "mdc-probe")
|
2020-08-01 12:25:03 +02:00
|
|
|
val pca: ActorRef = system.actorOf(Props[PacketCodingActor](), "pca")
|
2018-03-14 18:53:19 -04:00
|
|
|
pca ! HelloFriend(135, List(probe2).iterator)
|
|
|
|
|
probe1.receiveOne(100 milli) //consume
|
|
|
|
|
|
|
|
|
|
val msg = MultiPacketBundle(List(string_obj))
|
|
|
|
|
pca ! msg
|
|
|
|
|
receiveN(4)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-05 00:37:24 -05:00
|
|
|
object PacketCodingActorTest {
|
|
|
|
|
//decoy
|
|
|
|
|
}
|
Networking
The game uses a UDP-based protocol. Unlike TCP, UDP does not guarantee that
packets arrive, or that they arrive in the correct order. For this reason,
the game protocol implements those features using the following:
* All packets have a sequence number that is utilized for reordering
* Important packets are wrapped in a SlottedMetaPacket with a subslot number
* RelatedA packets ae used to request lost packets using the subslot number
* RelatedB packets are used to confirm received SlottedMetaPackets
All of these go both ways, server <-> client. We used to only partially
implement these features: Outgoing packet bundles used SMPs and could be
resent, but not all packets were bundled and there was no logic for requesting
lost packets from the client and there was no packet reordering, which resulted
in dire consequences in the case of packet loss (zoning failures, crashes and many
other odd bugs). This patch addresses all of these issues.
* Packet bundling: Packets are now automatically bundled and sent as
SlottedMetaPackets using a recurring timer. All manual bundling functionality
was removed.
* Packet reordering: Incoming packets, if received out of order, are stashed and
reordered. The maximum wait time for reordering is 20ms.
* Packet requesting: Missing SlottedMetaPackets are requested from the client.
* PacketCoding refactor: Dropped confusing packet container types. Fixes #5.
* Crypto rewrite: PSCrypto is based on a ancient buggy version of cryptopp.
Updating to a current version was not possible because it removed the
MD5-MAC algorithm. For more details, see Md5Mac.scala.
This patch replaces PSCrypto with native Scala code.
* Added two new actors:
* SocketActor: A simple typed UDP socket actor
* MiddlewareActor: The old session pipeline greatly simplified into a
typed actor that does most of the things mentioned above.
* Begun work on a headless client
* Fixed anniversary gun breaking stamina regen
* Resolved a few sentry errors
2020-09-17 17:04:06 +02:00
|
|
|
|
|
|
|
|
*/
|