2023-05-21 04:45:35 +00:00
|
|
|
//import xerial.sbt.pack.PackPlugin._
|
2020-01-13 22:59:24 +00:00
|
|
|
|
2020-08-23 01:26:06 +00:00
|
|
|
lazy val psforeverSettings = Seq(
|
2016-05-03 08:04:36 +00:00
|
|
|
organization := "net.psforever",
|
2016-08-05 22:11:46 +00:00
|
|
|
version := "1.0.2-SNAPSHOT",
|
2023-07-10 00:35:07 +00:00
|
|
|
scalaVersion := "2.13.10",
|
ChatActor
This removes roughly 1k LOC from WorldSessionActor and moves
them to a new ChatActor. That was the initial goal anyway, but it
wasn't that simple. There was no clear location to put this new actor,
I didn't want to put it in pslogin since it isn't part of the "login server"
(and neither is WSA). But since the new actor would have to talk to
WSA and common does not depend on pslogin, I had a choice of
putting more actors in pslogin or putting everything in common. I
chose the latter.
ChatActor and SessionActor (formerly WorldSessionActor) now live
in `common/actors/session`. Since WSA also depends on other
actors in pslogin, most of the pslogin code was moved to either
common/login or common/util. PsLogin as the main entry point
remains in pslogin since having the main code compile to a library
has some advantages, and it will allow us to produce binaries
for distinct login/world servers in the future if desired. For a second
take, I'd suggest moving common to /src in the root directory.
This change is enabled by a new immutable `Zone` object that is
passed from SessionActor to ChatActor. Most of its members are
still mutable references, and the code at the moment does depend
on this being the case. Changes to the session object in
SessionActor are forwarded through a SetZone message to
ChatActor. As we split out more code into actors, we could
use EventBus or typed Topic's instead.
Also included is a reworked ChatService that was converted to a
typed actor and uses the built-in Receptionist facility for service
discovery. By receiving the session object from ChatActor, it can
be much smarter about who to send messages to, rather than
sending all messages to everyone and having them figure it out.
But as this session object is not updated, it can only use static
properties like player name and faction and not fluid properties
like position.
The following chat commands were added:
command, note, gmbroadcast, [nc|tr|vs|broadcast, gmtell, gmpopup
and !whitetext
2020-07-11 10:50:29 +00:00
|
|
|
Global / cancelable := false,
|
2020-07-14 03:54:05 +00:00
|
|
|
semanticdbEnabled := true,
|
|
|
|
|
semanticdbVersion := scalafixSemanticdb.revision,
|
|
|
|
|
scalacOptions := Seq(
|
|
|
|
|
"-unchecked",
|
|
|
|
|
"-feature",
|
|
|
|
|
"-deprecation",
|
|
|
|
|
"-encoding",
|
|
|
|
|
"utf8",
|
|
|
|
|
"-language:postfixOps",
|
|
|
|
|
"-Wunused:imports",
|
|
|
|
|
"-Xmacro-settings:materialize-derivations"
|
|
|
|
|
),
|
2020-01-08 13:33:25 +00:00
|
|
|
// Quiet test options
|
|
|
|
|
// https://github.com/etorreborre/specs2/blob/8305db76c5084e4b3ce5827ce23117f6fb6beee4/common/shared/src/main/scala/org/specs2/main/Report.scala#L94
|
|
|
|
|
// https://etorreborre.github.io/specs2/guide/SPECS2-2.4.17/org.specs2.guide.Runners.html
|
2023-05-21 04:45:35 +00:00
|
|
|
QuietTest / testOptions += Tests.Argument(TestFrameworks.Specs2, "showOnly", "x!"),
|
2020-01-08 13:33:25 +00:00
|
|
|
// http://www.scalatest.org/user_guide/using_the_runner
|
2023-05-21 04:45:35 +00:00
|
|
|
QuietTest / testOptions += Tests.Argument(TestFrameworks.ScalaTest, "-oCEHILMNOPQRX"),
|
2019-10-21 20:29:36 +00:00
|
|
|
// Trick taken from https://groups.google.com/d/msg/scala-user/mxV9ok7J_Eg/kt-LnsrD0bkJ
|
2020-01-08 13:33:25 +00:00
|
|
|
// scaladoc flags: https://github.com/scala/scala/blob/2.11.x/src/scaladoc/scala/tools/nsc/doc/Settings.scala
|
2023-05-21 04:45:35 +00:00
|
|
|
Compile / doc / scalacOptions ++= Seq(
|
2019-10-21 20:29:36 +00:00
|
|
|
"-groups",
|
2020-07-14 03:54:05 +00:00
|
|
|
"-doc-title",
|
|
|
|
|
"PSF-LoginServer - ",
|
|
|
|
|
"-doc-version",
|
|
|
|
|
"master",
|
2019-10-21 20:29:36 +00:00
|
|
|
// For non unidoc builds, you may need bd.getName before the template parameter
|
2020-07-14 03:54:05 +00:00
|
|
|
"-doc-source-url",
|
|
|
|
|
"https://github.com/psforever/PSF-LoginServer/blob/master/€{FILE_PATH}.scala",
|
|
|
|
|
"-sourcepath",
|
|
|
|
|
baseDirectory.value.getAbsolutePath // needed for scaladoc relative source paths
|
|
|
|
|
),
|
2020-05-11 13:24:10 +00:00
|
|
|
classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat,
|
2016-02-05 08:19:13 +00:00
|
|
|
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots",
|
2016-07-27 02:31:54 +00:00
|
|
|
libraryDependencies ++= Seq(
|
2023-07-12 00:26:38 +00:00
|
|
|
// Akka 2.8+ is BSL licensed, do not upgrade
|
|
|
|
|
"com.typesafe.akka" %% "akka-actor" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-slf4j" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-protobuf-v3" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-stream" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-testkit" % "2.6.20" % "test",
|
|
|
|
|
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-actor-testkit-typed" % "2.6.20" % "test",
|
|
|
|
|
"com.typesafe.akka" %% "akka-slf4j" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-cluster-typed" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-coordination" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-cluster-tools" % "2.6.20",
|
|
|
|
|
"com.typesafe.akka" %% "akka-http" % "10.2.10",
|
2023-07-11 22:43:48 +00:00
|
|
|
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.5",
|
2023-03-26 12:39:08 +00:00
|
|
|
"org.specs2" %% "specs2-core" % "4.20.0" % "test",
|
|
|
|
|
"org.scalatest" %% "scalatest" % "3.2.15" % "test",
|
2023-07-11 22:43:48 +00:00
|
|
|
"org.scodec" %% "scodec-core" % "1.11.10",
|
|
|
|
|
"ch.qos.logback" % "logback-classic" % "1.2.12",
|
2021-05-19 12:37:40 +00:00
|
|
|
"org.log4s" %% "log4s" % "1.10.0",
|
2021-11-01 15:22:13 +00:00
|
|
|
"org.fusesource.jansi" % "jansi" % "2.4.0",
|
2023-07-11 22:43:48 +00:00
|
|
|
"com.github.nscala-time" %% "nscala-time" % "2.32.0",
|
2020-09-01 18:21:16 +00:00
|
|
|
"com.github.t3hnar" %% "scala-bcrypt" % "4.3.0",
|
2023-07-11 22:43:48 +00:00
|
|
|
"org.scala-graph" %% "graph-core" % "1.13.5",
|
|
|
|
|
"io.kamon" %% "kamon-bundle" % "2.6.1",
|
|
|
|
|
"io.kamon" %% "kamon-apm-reporter" % "2.6.0",
|
|
|
|
|
"org.json4s" %% "json4s-native" % "4.0.6",
|
2023-03-26 12:39:08 +00:00
|
|
|
"io.getquill" %% "quill-jasync-postgres" % "3.18.0",
|
2023-07-11 22:43:48 +00:00
|
|
|
"org.flywaydb" % "flyway-core" % "9.16.0",
|
|
|
|
|
"org.postgresql" % "postgresql" % "42.5.4",
|
|
|
|
|
"com.typesafe" % "config" % "1.4.2",
|
|
|
|
|
"com.github.pureconfig" %% "pureconfig" % "0.17.4",
|
|
|
|
|
"com.beachape" %% "enumeratum" % "1.7.2",
|
|
|
|
|
"commons-io" % "commons-io" % "2.13.0",
|
2023-03-26 12:39:08 +00:00
|
|
|
"com.github.scopt" %% "scopt" % "4.1.0",
|
2023-07-11 22:43:48 +00:00
|
|
|
"io.sentry" % "sentry-logback" % "6.19.0",
|
2023-03-26 12:39:08 +00:00
|
|
|
"io.circe" %% "circe-core" % "0.14.5",
|
|
|
|
|
"io.circe" %% "circe-generic" % "0.14.5",
|
|
|
|
|
"io.circe" %% "circe-parser" % "0.14.5",
|
2021-09-29 00:58:58 +00:00
|
|
|
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4",
|
2023-07-11 22:43:48 +00:00
|
|
|
"org.bouncycastle" % "bcprov-jdk15on" % "1.70"
|
2020-07-23 14:31:53 +00:00
|
|
|
),
|
2022-07-06 01:03:02 +00:00
|
|
|
dependencyOverrides ++= Seq(
|
2023-07-11 22:43:48 +00:00
|
|
|
"com.github.jasync-sql" % "jasync-postgresql" % "1.2.3",
|
2023-03-26 12:39:08 +00:00
|
|
|
"org.scala-lang.modules" %% "scala-java8-compat" % "1.0.2"
|
|
|
|
|
)
|
2020-07-23 14:31:53 +00:00
|
|
|
// TODO(chord): remove exclusion when SessionActor is refactored: https://github.com/psforever/PSF-LoginServer/issues/279
|
2023-03-26 12:39:08 +00:00
|
|
|
// coverageExcludedPackages := "net\\.psforever\\.actors\\.session\\.SessionActor.*"
|
2016-02-05 08:19:13 +00:00
|
|
|
)
|
|
|
|
|
|
2020-08-23 01:26:06 +00:00
|
|
|
lazy val psforever = (project in file("."))
|
2020-07-14 03:54:05 +00:00
|
|
|
.configs(QuietTest)
|
2020-08-23 01:26:06 +00:00
|
|
|
.settings(psforeverSettings: _*)
|
2020-07-14 03:54:05 +00:00
|
|
|
.settings(
|
2020-08-23 01:26:06 +00:00
|
|
|
name := "psforever",
|
2020-01-08 13:33:25 +00:00
|
|
|
// Copy all tests from Test -> QuietTest (we're only changing the run options)
|
|
|
|
|
inConfig(QuietTest)(Defaults.testTasks)
|
2020-07-14 03:54:05 +00:00
|
|
|
)
|
2016-02-05 08:19:13 +00:00
|
|
|
|
2020-08-23 01:26:06 +00:00
|
|
|
lazy val server = (project in file("server"))
|
2020-07-14 03:54:05 +00:00
|
|
|
.configs(QuietTest)
|
2020-08-23 01:26:06 +00:00
|
|
|
.enablePlugins(PackPlugin)
|
|
|
|
|
.settings(psforeverSettings: _*)
|
2020-07-14 03:54:05 +00:00
|
|
|
.settings(
|
2020-08-23 01:26:06 +00:00
|
|
|
name := "server",
|
|
|
|
|
// ActorTests have specific timing requirements and will be flaky if run in parallel
|
2023-05-21 04:45:35 +00:00
|
|
|
Test / parallelExecution := false,
|
2020-01-08 13:33:25 +00:00
|
|
|
// Copy all tests from Test -> QuietTest (we're only changing the run options)
|
2020-08-23 01:26:06 +00:00
|
|
|
inConfig(QuietTest)(Defaults.testTasks),
|
|
|
|
|
packMain := Map("psforever-server" -> "net.psforever.server.Server"),
|
|
|
|
|
packArchivePrefix := "psforever-server",
|
|
|
|
|
packJvmOpts := Map("psforever-server" -> Seq("-Dstacktrace.app.packages=net.psforever")),
|
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 15:04:06 +00:00
|
|
|
packExtraClasspath := Map("psforever-server" -> Seq("${PROG_HOME}/config")),
|
2023-05-21 04:45:35 +00:00
|
|
|
packResourceDir += ((psforever / baseDirectory).value / "config" -> "config")
|
2020-07-14 03:54:05 +00:00
|
|
|
)
|
2020-08-23 01:26:06 +00:00
|
|
|
.dependsOn(psforever)
|
2020-01-08 13:33:25 +00:00
|
|
|
|
2020-07-14 03:54:05 +00:00
|
|
|
lazy val decodePackets = (project in file("tools/decode-packets"))
|
|
|
|
|
.enablePlugins(PackPlugin)
|
2020-08-23 01:26:06 +00:00
|
|
|
.settings(psforeverSettings: _*)
|
2020-07-14 03:54:05 +00:00
|
|
|
.settings(
|
2020-08-23 01:26:06 +00:00
|
|
|
packMain := Map("psforever-decode-packets" -> "net.psforever.tools.decodePackets.DecodePackets")
|
2020-07-14 03:54:05 +00:00
|
|
|
)
|
2020-08-23 01:26:06 +00:00
|
|
|
.dependsOn(psforever)
|
2020-06-09 22:32:02 +00:00
|
|
|
|
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 15:04:06 +00:00
|
|
|
lazy val client = (project in file("tools/client"))
|
|
|
|
|
.enablePlugins(PackPlugin)
|
|
|
|
|
.settings(psforeverSettings: _*)
|
|
|
|
|
.dependsOn(psforever)
|
|
|
|
|
|
2020-01-08 13:33:25 +00:00
|
|
|
// Special test configuration for really quiet tests (used in CI)
|
2020-07-22 15:28:09 +00:00
|
|
|
lazy val QuietTest = config("quiet") extend Test
|
2020-08-23 19:27:02 +00:00
|
|
|
|
|
|
|
|
lazy val docs = (project in file("docs"))
|
|
|
|
|
.settings(psforeverSettings: _*)
|
2023-10-08 15:52:50 +00:00
|
|
|
//.enablePlugins(ScalaUnidocPlugin)
|
2020-08-23 19:27:02 +00:00
|
|
|
.settings(
|
|
|
|
|
name := "psforever"
|
|
|
|
|
)
|
|
|
|
|
.aggregate(psforever, server, decodePackets)
|