update sbt & dependencies

removed kamon because it is not being used
This commit is contained in:
Jakob Gillich 2023-03-26 12:39:08 +00:00
parent 53e3f9a08d
commit ea91251002
No known key found for this signature in database
GPG key ID: FD8BF52DB8452C91
5 changed files with 377 additions and 318 deletions

View file

@ -3,7 +3,7 @@ import xerial.sbt.pack.PackPlugin._
lazy val psforeverSettings = Seq( lazy val psforeverSettings = Seq(
organization := "net.psforever", organization := "net.psforever",
version := "1.0.2-SNAPSHOT", version := "1.0.2-SNAPSHOT",
scalaVersion := "2.13.3", scalaVersion := "2.13.10",
Global / cancelable := false, Global / cancelable := false,
semanticdbEnabled := true, semanticdbEnabled := true,
semanticdbVersion := scalafixSemanticdb.revision, semanticdbVersion := scalafixSemanticdb.revision,
@ -40,53 +40,50 @@ lazy val psforeverSettings = Seq(
classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat, classLoaderLayeringStrategy := ClassLoaderLayeringStrategy.Flat,
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots", resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots",
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor" % "2.6.17", "com.typesafe.akka" %% "akka-actor" % "2.6.20",
"com.typesafe.akka" %% "akka-slf4j" % "2.6.17", "com.typesafe.akka" %% "akka-slf4j" % "2.6.20",
"com.typesafe.akka" %% "akka-protobuf-v3" % "2.6.17", "com.typesafe.akka" %% "akka-protobuf-v3" % "2.6.20",
"com.typesafe.akka" %% "akka-stream" % "2.6.17", "com.typesafe.akka" %% "akka-stream" % "2.6.20",
"com.typesafe.akka" %% "akka-testkit" % "2.6.17" % "test", "com.typesafe.akka" %% "akka-testkit" % "2.6.20" % "test",
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.17", "com.typesafe.akka" %% "akka-actor-typed" % "2.6.20",
"com.typesafe.akka" %% "akka-actor-testkit-typed" % "2.6.17" % "test", "com.typesafe.akka" %% "akka-actor-testkit-typed" % "2.6.20" % "test",
"com.typesafe.akka" %% "akka-slf4j" % "2.6.17", "com.typesafe.akka" %% "akka-slf4j" % "2.6.20",
"com.typesafe.akka" %% "akka-cluster-typed" % "2.6.17", "com.typesafe.akka" %% "akka-cluster-typed" % "2.6.20",
"com.typesafe.akka" %% "akka-coordination" % "2.6.17", "com.typesafe.akka" %% "akka-coordination" % "2.6.20",
"com.typesafe.akka" %% "akka-cluster-tools" % "2.6.17", "com.typesafe.akka" %% "akka-cluster-tools" % "2.6.20",
"com.typesafe.akka" %% "akka-http" % "10.2.6", "com.typesafe.akka" %% "akka-http" % "10.2.6",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.4", "com.typesafe.scala-logging" %% "scala-logging" % "3.9.4",
"org.specs2" %% "specs2-core" % "4.13.0" % "test", "org.specs2" %% "specs2-core" % "4.20.0" % "test",
"org.scalatest" %% "scalatest" % "3.2.10" % "test", "org.scalatest" %% "scalatest" % "3.2.15" % "test",
"org.scodec" %% "scodec-core" % "1.11.9", "org.scodec" %% "scodec-core" % "1.11.9",
"ch.qos.logback" % "logback-classic" % "1.2.6", "ch.qos.logback" % "logback-classic" % "1.2.6",
"org.log4s" %% "log4s" % "1.10.0", "org.log4s" %% "log4s" % "1.10.0",
"org.fusesource.jansi" % "jansi" % "2.4.0", "org.fusesource.jansi" % "jansi" % "2.4.0",
"org.scoverage" %% "scalac-scoverage-plugin" % "1.4.2",
"com.github.nscala-time" %% "nscala-time" % "2.30.0", "com.github.nscala-time" %% "nscala-time" % "2.30.0",
"com.github.t3hnar" %% "scala-bcrypt" % "4.3.0", "com.github.t3hnar" %% "scala-bcrypt" % "4.3.0",
"org.scala-graph" %% "graph-core" % "1.13.3", "org.scala-graph" %% "graph-core" % "1.13.3",
"io.kamon" %% "kamon-bundle" % "2.3.1",
"io.kamon" %% "kamon-apm-reporter" % "2.3.1",
"org.json4s" %% "json4s-native" % "4.0.3", "org.json4s" %% "json4s-native" % "4.0.3",
"io.getquill" %% "quill-jasync-postgres" % "3.12.0", "io.getquill" %% "quill-jasync-postgres" % "3.18.0",
"org.flywaydb" % "flyway-core" % "8.0.3", "org.flywaydb" % "flyway-core" % "9.0.0",
"org.postgresql" % "postgresql" % "42.3.1", "org.postgresql" % "postgresql" % "42.3.1",
"com.typesafe" % "config" % "1.4.1", "com.typesafe" % "config" % "1.4.1",
"com.github.pureconfig" %% "pureconfig" % "0.17.0", "com.github.pureconfig" %% "pureconfig" % "0.17.0",
"com.beachape" %% "enumeratum" % "1.7.0", "com.beachape" %% "enumeratum" % "1.7.0",
"joda-time" % "joda-time" % "2.10.13",
"commons-io" % "commons-io" % "2.11.0", "commons-io" % "commons-io" % "2.11.0",
"com.github.scopt" %% "scopt" % "4.0.1", "com.github.scopt" %% "scopt" % "4.1.0",
"io.sentry" % "sentry-logback" % "5.3.0", "io.sentry" % "sentry-logback" % "6.16.0",
"io.circe" %% "circe-core" % "0.14.1", "io.circe" %% "circe-core" % "0.14.5",
"io.circe" %% "circe-generic" % "0.14.1", "io.circe" %% "circe-generic" % "0.14.5",
"io.circe" %% "circe-parser" % "0.14.1", "io.circe" %% "circe-parser" % "0.14.5",
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4", "org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.4",
"org.bouncycastle" % "bcprov-jdk15on" % "1.69" "org.bouncycastle" % "bcprov-jdk15on" % "1.69"
), ),
dependencyOverrides ++= Seq( dependencyOverrides ++= Seq(
"com.github.jasync-sql" % "jasync-postgresql" % "1.1.7" "com.github.jasync-sql" % "jasync-postgresql" % "1.1.7",
), "org.scala-lang.modules" %% "scala-java8-compat" % "1.0.2"
)
// TODO(chord): remove exclusion when SessionActor is refactored: https://github.com/psforever/PSF-LoginServer/issues/279 // TODO(chord): remove exclusion when SessionActor is refactored: https://github.com/psforever/PSF-LoginServer/issues/279
coverageExcludedPackages := "net\\.psforever\\.actors\\.session\\.SessionActor.*" // coverageExcludedPackages := "net\\.psforever\\.actors\\.session\\.SessionActor.*"
) )
lazy val psforever = (project in file(".")) lazy val psforever = (project in file("."))

View file

@ -1 +1 @@
sbt.version = 1.4.5 sbt.version = 1.8.2

View file

@ -1,8 +1,7 @@
logLevel := Level.Warn logLevel := Level.Warn
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.14") addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.17")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.1") addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.7")
addSbtPlugin("io.kamon" % "sbt-kanela-runner" % "2.0.12") addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.3")
addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.3") addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.0")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.3") addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.10.4")
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.31")

View file

@ -5,6 +5,8 @@ import java.nio.file.Paths
import java.util.Locale import java.util.Locale
import java.util.UUID.randomUUID import java.util.UUID.randomUUID
import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicLong
import scala.concurrent.Future
import scala.concurrent.Await
import akka.actor.ActorSystem import akka.actor.ActorSystem
import akka.actor.typed.ActorRef import akka.actor.typed.ActorRef
@ -13,7 +15,6 @@ import akka.{actor => classic}
import ch.qos.logback.classic.LoggerContext import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.joran.JoranConfigurator import ch.qos.logback.classic.joran.JoranConfigurator
import io.sentry.{Sentry, SentryOptions} import io.sentry.{Sentry, SentryOptions}
import kamon.Kamon
import net.psforever.actors.net.{LoginActor, MiddlewareActor, SocketActor} import net.psforever.actors.net.{LoginActor, MiddlewareActor, SocketActor}
import net.psforever.actors.session.SessionActor import net.psforever.actors.session.SessionActor
import net.psforever.login.psadmin.PsAdminActor import net.psforever.login.psadmin.PsAdminActor
@ -37,6 +38,7 @@ import scopt.OParser
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
import net.psforever.packet.PlanetSidePacket import net.psforever.packet.PlanetSidePacket
import net.psforever.services.hart.HartService import net.psforever.services.hart.HartService
import scala.concurrent.duration.Duration
object Server { object Server {
private val logger = org.log4s.getLogger private val logger = org.log4s.getLogger
@ -80,11 +82,6 @@ object Server {
case None => InetAddress.getByName(Config.app.bind) // address from config case None => InetAddress.getByName(Config.app.bind) // address from config
} }
if (Config.app.kamon.enable) {
logger.info("Starting Kamon")
Kamon.init()
}
if (Config.app.sentry.enable) { if (Config.app.sentry.enable) {
logger.info(s"Enabling Sentry") logger.info(s"Enabling Sentry")
val options = new SentryOptions() val options = new SentryOptions()
@ -110,8 +107,9 @@ object Server {
} }
val session = (ref: ActorRef[MiddlewareActor.Command], info: InetSocketAddress, connectionId: String) => { val session = (ref: ActorRef[MiddlewareActor.Command], info: InetSocketAddress, connectionId: String) => {
Behaviors.setup[PlanetSidePacket](context => { Behaviors.setup[PlanetSidePacket](context => {
val uuid = randomUUID().toString val uuid = randomUUID().toString
val actor = context.actorOf(classic.Props(new SessionActor(ref, connectionId, Session.getNewId())), s"session-$uuid") val actor =
context.actorOf(classic.Props(new SessionActor(ref, connectionId, Session.getNewId())), s"session-$uuid")
Behaviors.receiveMessage(message => { Behaviors.receiveMessage(message => {
actor ! message actor ! message
Behaviors.same Behaviors.same
@ -119,7 +117,7 @@ object Server {
}) })
} }
val zones = Zones.zones ++ Seq(Zone.Nowhere) val zones = Zones.zones ++ Seq(Zone.Nowhere)
val serviceManager = ServiceManager.boot val serviceManager = ServiceManager.boot
serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService](), "accountIntermediary") serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService](), "accountIntermediary")
serviceManager ! ServiceManager.Register(classic.Props[GalaxyService](), "galaxy") serviceManager ! ServiceManager.Register(classic.Props[GalaxyService](), "galaxy")
@ -156,6 +154,8 @@ object Server {
// TODO: clean up active sessions and close resources safely // TODO: clean up active sessions and close resources safely
logger.info("Login server now shutting down...") logger.info("Login server now shutting down...")
} }
Await.ready(Future.never, Duration.Inf)
} }
def flyway(args: CliConfig): Flyway = { def flyway(args: CliConfig): Flyway = {
@ -228,6 +228,7 @@ object Server {
} }
sealed trait AuthoritativeCounter { sealed trait AuthoritativeCounter {
/** the id accumulator */ /** the id accumulator */
private val masterIdKeyRing: AtomicLong = new AtomicLong(0L) private val masterIdKeyRing: AtomicLong = new AtomicLong(0L)

View file

@ -257,26 +257,26 @@ object AvatarActor {
} }
/** /**
* Transform from encoded inventory data as a CLOB - character large object - into individual items. * Transform from encoded inventory data as a CLOB - character large object - into individual items.
* Install those items into positions in a target container * Install those items into positions in a target container
* in the same positions in which they were previously recorded.<br> * in the same positions in which they were previously recorded.<br>
* <br> * <br>
* There is no guarantee that the structure of the retained container data encoded in the CLOB * There is no guarantee that the structure of the retained container data encoded in the CLOB
* will fit the current dimensions of the container. * will fit the current dimensions of the container.
* No tests are performed. * No tests are performed.
* A partial decompression of the CLOB may occur. * A partial decompression of the CLOB may occur.
* @param container the container in which to place the pieces of equipment produced from the CLOB * @param container the container in which to place the pieces of equipment produced from the CLOB
* @param clob the inventory data in string form * @param clob the inventory data in string form
* @param log a reference to a logging context * @param log a reference to a logging context
* @param restoreAmmo by default, when `false`, use the maximum ammunition for all ammunition boixes and for all tools; * @param restoreAmmo by default, when `false`, use the maximum ammunition for all ammunition boixes and for all tools;
* if `true`, load the last saved ammunition count for all ammunition boxes and for all tools * if `true`, load the last saved ammunition count for all ammunition boxes and for all tools
*/ */
def buildContainedEquipmentFromClob( def buildContainedEquipmentFromClob(
container: Container, container: Container,
clob: String, clob: String,
log: org.log4s.Logger, log: org.log4s.Logger,
restoreAmmo: Boolean = false restoreAmmo: Boolean = false
): Unit = { ): Unit = {
clob.split("/").filter(_.trim.nonEmpty).foreach { value => clob.split("/").filter(_.trim.nonEmpty).foreach { value =>
val (objectType, objectIndex, objectId, ammoData) = value.split(",") match { val (objectType, objectIndex, objectId, ammoData) = value.split(",") match {
case Array(a, b: String, c: String) => (a, b.toInt, c.toInt, None) case Array(a, b: String, c: String) => (a, b.toInt, c.toInt, None)
@ -293,8 +293,8 @@ object AvatarActor {
ammoData foreach { toolAmmo => ammoData foreach { toolAmmo =>
toolAmmo.split("_").drop(1).foreach { value => toolAmmo.split("_").drop(1).foreach { value =>
val (ammoSlots, ammoTypeIndex, ammoBoxDefinition, ammoCount) = value.split("-") match { val (ammoSlots, ammoTypeIndex, ammoBoxDefinition, ammoCount) = value.split("-") match {
case Array(a: String, b: String, c: String) => (a.toInt, b.toInt, c.toInt, None) case Array(a: String, b: String, c: String) => (a.toInt, b.toInt, c.toInt, None)
case Array(a: String, b: String, c: String, d:String) => (a.toInt, b.toInt, c.toInt, Some(d.toInt)) case Array(a: String, b: String, c: String, d: String) => (a.toInt, b.toInt, c.toInt, Some(d.toInt))
} }
val fireMode = tool.AmmoSlots(ammoSlots) val fireMode = tool.AmmoSlots(ammoSlots)
fireMode.AmmoTypeIndex = ammoTypeIndex fireMode.AmmoTypeIndex = ammoTypeIndex
@ -340,11 +340,11 @@ object AvatarActor {
* @return the resulting text data that represents object to time mappings * @return the resulting text data that represents object to time mappings
*/ */
def buildCooldownsFromClob( def buildCooldownsFromClob(
clob: String, clob: String,
cooldownDurations: Map[BasicDefinition,FiniteDuration], cooldownDurations: Map[BasicDefinition, FiniteDuration],
log: org.log4s.Logger log: org.log4s.Logger
): Map[String, LocalDateTime] = { ): Map[String, LocalDateTime] = {
val now = LocalDateTime.now() val now = LocalDateTime.now()
val cooldowns: mutable.Map[String, LocalDateTime] = mutable.Map() val cooldowns: mutable.Map[String, LocalDateTime] = mutable.Map()
clob.split("/").filter(_.trim.nonEmpty).foreach { value => clob.split("/").filter(_.trim.nonEmpty).foreach { value =>
value.split(",") match { value.split(",") match {
@ -385,7 +385,7 @@ object AvatarActor {
val factionName: String = faction.toString.toLowerCase val factionName: String = faction.toString.toLowerCase
val name = item match { val name = item match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.nchev_scattercannon | case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.nchev_scattercannon |
GlobalDefinitions.vshev_quasar => GlobalDefinitions.vshev_quasar =>
s"${factionName}hev_antipersonnel" s"${factionName}hev_antipersonnel"
case GlobalDefinitions.trhev_pounder | GlobalDefinitions.nchev_falcon | GlobalDefinitions.vshev_comet => case GlobalDefinitions.trhev_pounder | GlobalDefinitions.nchev_falcon | GlobalDefinitions.vshev_comet =>
s"${factionName}hev_antivehicular" s"${factionName}hev_antivehicular"
@ -402,12 +402,12 @@ object AvatarActor {
if (name.matches("(tr|nc|vs)hev_.+") && Config.app.game.sharedMaxCooldown) { if (name.matches("(tr|nc|vs)hev_.+") && Config.app.game.sharedMaxCooldown) {
val faction = name.take(2) val faction = name.take(2)
(if (faction.equals("nc")) { (if (faction.equals("nc")) {
Seq(GlobalDefinitions.nchev_scattercannon, GlobalDefinitions.nchev_falcon, GlobalDefinitions.nchev_sparrow) Seq(GlobalDefinitions.nchev_scattercannon, GlobalDefinitions.nchev_falcon, GlobalDefinitions.nchev_sparrow)
} else if (faction.equals("vs")) { } else if (faction.equals("vs")) {
Seq(GlobalDefinitions.vshev_quasar, GlobalDefinitions.vshev_comet, GlobalDefinitions.vshev_starfire) Seq(GlobalDefinitions.vshev_quasar, GlobalDefinitions.vshev_comet, GlobalDefinitions.vshev_starfire)
} else { } else {
Seq(GlobalDefinitions.trhev_dualcycler, GlobalDefinitions.trhev_pounder, GlobalDefinitions.trhev_burster) Seq(GlobalDefinitions.trhev_dualcycler, GlobalDefinitions.trhev_pounder, GlobalDefinitions.trhev_burster)
}).zip( }).zip(
Seq(s"${faction}hev_antipersonnel", s"${faction}hev_antivehicular", s"${faction}hev_antiaircraft") Seq(s"${faction}hev_antipersonnel", s"${faction}hev_antivehicular", s"${faction}hev_antiaircraft")
) )
} else { } else {
@ -461,7 +461,6 @@ object AvatarActor {
} }
} }
def displayLookingForSquad(session: Session, state: Int): Unit = { def displayLookingForSquad(session: Session, state: Int): Unit = {
val player = session.player val player = session.player
session.zone.AvatarEvents ! AvatarServiceMessage( session.zone.AvatarEvents ! AvatarServiceMessage(
@ -477,7 +476,10 @@ object AvatarActor {
* @param func functionality that is called upon discovery of the character * @param func functionality that is called upon discovery of the character
* @return if found, the discovered avatar, the avatar's account id, and the avatar's faction affiliation * @return if found, the discovered avatar, the avatar's account id, and the avatar's faction affiliation
*/ */
def getLiveAvatarForFunc(name: String, func: (Long,String,Int)=>Unit): Option[(Avatar, Long, PlanetSideEmpire.Value)] = { def getLiveAvatarForFunc(
name: String,
func: (Long, String, Int) => Unit
): Option[(Avatar, Long, PlanetSideEmpire.Value)] = {
if (name.nonEmpty) { if (name.nonEmpty) {
LivePlayerList.WorldPopulation({ case (_, a) => a.name.equals(name) }).headOption match { LivePlayerList.WorldPopulation({ case (_, a) => a.name.equals(name) }).headOption match {
case Some(otherAvatar) => case Some(otherAvatar) =>
@ -500,7 +502,10 @@ object AvatarActor {
* otherwise, always returns `None` as if no avatar was discovered * otherwise, always returns `None` as if no avatar was discovered
* (the query is probably still in progress) * (the query is probably still in progress)
*/ */
def getAvatarForFunc(name: String, func: (Long,String,Int)=>Unit): Option[(Avatar, Long, PlanetSideEmpire.Value)] = { def getAvatarForFunc(
name: String,
func: (Long, String, Int) => Unit
): Option[(Avatar, Long, PlanetSideEmpire.Value)] = {
getLiveAvatarForFunc(name, func).orElse { getLiveAvatarForFunc(name, func).orElse {
if (name.nonEmpty) { if (name.nonEmpty) {
import ctx._ import ctx._
@ -527,7 +532,7 @@ object AvatarActor {
* @param name unique character name * @param name unique character name
* @param faction the faction affiliation * @param faction the faction affiliation
*/ */
def formatForOtherFunc(func: (Long,String)=>Unit)(charId: Long, name: String, faction: Int): Unit = { def formatForOtherFunc(func: (Long, String) => Unit)(charId: Long, name: String, faction: Int): Unit = {
func(charId, name) func(charId, name)
} }
@ -540,9 +545,11 @@ object AvatarActor {
*/ */
def onlineIfNotIgnored(onlinePlayerName: String, observerName: String): Boolean = { def onlineIfNotIgnored(onlinePlayerName: String, observerName: String): Boolean = {
val onlinePlayerNameLower = onlinePlayerName.toLowerCase() val onlinePlayerNameLower = onlinePlayerName.toLowerCase()
LivePlayerList.WorldPopulation({ case (_, a) => a.name.toLowerCase().equals(onlinePlayerNameLower) }).headOption match { LivePlayerList
.WorldPopulation({ case (_, a) => a.name.toLowerCase().equals(onlinePlayerNameLower) })
.headOption match {
case Some(onlinePlayer) => onlineIfNotIgnored(onlinePlayer, observerName) case Some(onlinePlayer) => onlineIfNotIgnored(onlinePlayer, observerName)
case _ => false case _ => false
} }
} }
@ -556,9 +563,9 @@ object AvatarActor {
*/ */
def onlineIfNotIgnoredEitherWay(observer: Avatar, onlinePlayerName: String): Boolean = { def onlineIfNotIgnoredEitherWay(observer: Avatar, onlinePlayerName: String): Boolean = {
LivePlayerList.WorldPopulation({ case (_, a) => a.name.equals(onlinePlayerName) }) match { LivePlayerList.WorldPopulation({ case (_, a) => a.name.equals(onlinePlayerName) }) match {
case Nil => false //weird case, but ... case Nil => false //weird case, but ...
case onlinePlayer :: Nil => onlineIfNotIgnoredEitherWay(onlinePlayer, observer) case onlinePlayer :: Nil => onlineIfNotIgnoredEitherWay(onlinePlayer, observer)
case _ => throw new Exception("only trying to find two players, but too many matching search results!") case _ => throw new Exception("only trying to find two players, but too many matching search results!")
} }
} }
@ -598,24 +605,25 @@ object AvatarActor {
import ctx._ import ctx._
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
val out: Promise[persistence.Savedplayer] = Promise() val out: Promise[persistence.Savedplayer] = Promise()
val queryResult = ctx.run(query[persistence.Savedplayer].filter { _.avatarId == lift(avatarId) }) val queryResult = ctx.run(query[persistence.Savedplayer].filter { _.avatarId == lift(avatarId) })
queryResult.onComplete { queryResult.onComplete {
case Success(data) if data.nonEmpty => case Success(data) if data.nonEmpty =>
out.completeWith(Future(data.head)) out.completeWith(Future(data.head))
case _ => case _ =>
ctx.run(query[persistence.Savedplayer] ctx.run(
.insert( query[persistence.Savedplayer]
_.avatarId -> lift(avatarId), .insert(
_.px -> lift(0), _.avatarId -> lift(avatarId),
_.py -> lift(0), _.px -> lift(0),
_.pz -> lift(0), _.py -> lift(0),
_.orientation -> lift(0), _.pz -> lift(0),
_.zoneNum -> lift(0), _.orientation -> lift(0),
_.health -> lift(0), _.zoneNum -> lift(0),
_.armor -> lift(0), _.health -> lift(0),
_.exosuitNum -> lift(0), _.armor -> lift(0),
_.loadout -> lift("") _.exosuitNum -> lift(0),
) _.loadout -> lift("")
)
) )
out.completeWith(Future(persistence.Savedplayer(avatarId, 0, 0, 0, 0, 0, 0, 0, 0, ""))) out.completeWith(Future(persistence.Savedplayer(avatarId, 0, 0, 0, 0, 0, 0, 0, 0, "")))
} }
@ -684,24 +692,25 @@ object AvatarActor {
import ctx._ import ctx._
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
val out: Promise[Int] = Promise() val out: Promise[Int] = Promise()
val avatarId = player.avatar.id val avatarId = player.avatar.id
val position = player.Position val position = player.Position
val queryResult = ctx.run(query[persistence.Savedplayer].filter { _.avatarId == lift(avatarId) }) val queryResult = ctx.run(query[persistence.Savedplayer].filter { _.avatarId == lift(avatarId) })
queryResult.onComplete { queryResult.onComplete {
case Success(results) if results.nonEmpty => case Success(results) if results.nonEmpty =>
ctx.run(query[persistence.Savedplayer] ctx.run(
.filter { _.avatarId == lift(avatarId) } query[persistence.Savedplayer]
.update( .filter { _.avatarId == lift(avatarId) }
_.px -> lift((position.x * 1000).toInt), .update(
_.py -> lift((position.y * 1000).toInt), _.px -> lift((position.x * 1000).toInt),
_.pz -> lift((position.z * 1000).toInt), _.py -> lift((position.y * 1000).toInt),
_.orientation -> lift((player.Orientation.z * 1000).toInt), _.pz -> lift((position.z * 1000).toInt),
_.zoneNum -> lift(player.Zone.Number), _.orientation -> lift((player.Orientation.z * 1000).toInt),
_.health -> lift(health), _.zoneNum -> lift(player.Zone.Number),
_.armor -> lift(player.Armor), _.health -> lift(health),
_.exosuitNum -> lift(player.ExoSuit.id), _.armor -> lift(player.Armor),
_.loadout -> lift(buildClobFromPlayerLoadout(player)) _.exosuitNum -> lift(player.ExoSuit.id),
) _.loadout -> lift(buildClobFromPlayerLoadout(player))
)
) )
out.completeWith(Future(1)) out.completeWith(Future(1))
case _ => case _ =>
@ -722,20 +731,21 @@ object AvatarActor {
import ctx._ import ctx._
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
val out: Promise[Int] = Promise() val out: Promise[Int] = Promise()
val avatarId = player.avatar.id val avatarId = player.avatar.id
val position = player.Position val position = player.Position
val queryResult = ctx.run(query[persistence.Savedplayer].filter { _.avatarId == lift(avatarId) }) val queryResult = ctx.run(query[persistence.Savedplayer].filter { _.avatarId == lift(avatarId) })
queryResult.onComplete { queryResult.onComplete {
case Success(results) if results.nonEmpty => case Success(results) if results.nonEmpty =>
ctx.run(query[persistence.Savedplayer] ctx.run(
.filter { _.avatarId == lift(avatarId) } query[persistence.Savedplayer]
.update( .filter { _.avatarId == lift(avatarId) }
_.px -> lift((position.x * 1000).toInt), .update(
_.py -> lift((position.y * 1000).toInt), _.px -> lift((position.x * 1000).toInt),
_.pz -> lift((position.z * 1000).toInt), _.py -> lift((position.y * 1000).toInt),
_.orientation -> lift((player.Orientation.z * 1000).toInt), _.pz -> lift((position.z * 1000).toInt),
_.zoneNum -> lift(player.Zone.Number) _.orientation -> lift((player.Orientation.z * 1000).toInt),
) _.zoneNum -> lift(player.Zone.Number)
)
) )
out.completeWith(Future(1)) out.completeWith(Future(1))
case _ => case _ =>
@ -757,19 +767,20 @@ object AvatarActor {
import ctx._ import ctx._
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
val out: Promise[persistence.Savedavatar] = Promise() val out: Promise[persistence.Savedavatar] = Promise()
val queryResult = ctx.run(query[persistence.Savedavatar].filter { _.avatarId == lift(avatarId) }) val queryResult = ctx.run(query[persistence.Savedavatar].filter { _.avatarId == lift(avatarId) })
queryResult.onComplete { queryResult.onComplete {
case Success(data) if data.nonEmpty => case Success(data) if data.nonEmpty =>
out.completeWith(Future(data.head)) out.completeWith(Future(data.head))
case _ => case _ =>
val now = LocalDateTime.now() val now = LocalDateTime.now()
ctx.run(query[persistence.Savedavatar] ctx.run(
.insert( query[persistence.Savedavatar]
_.avatarId -> lift(avatarId), .insert(
_.forgetCooldown -> lift(now), _.avatarId -> lift(avatarId),
_.purchaseCooldowns -> lift(""), _.forgetCooldown -> lift(now),
_.useCooldowns -> lift("") _.purchaseCooldowns -> lift(""),
) _.useCooldowns -> lift("")
)
) )
out.completeWith(Future(persistence.Savedavatar(avatarId, now, "", ""))) out.completeWith(Future(persistence.Savedavatar(avatarId, now, "", "")))
} }
@ -788,16 +799,17 @@ object AvatarActor {
import ctx._ import ctx._
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
val out: Promise[Int] = Promise() val out: Promise[Int] = Promise()
val avatarId = avatar.id val avatarId = avatar.id
val queryResult = ctx.run(query[persistence.Savedavatar].filter { _.avatarId == lift(avatarId) }) val queryResult = ctx.run(query[persistence.Savedavatar].filter { _.avatarId == lift(avatarId) })
queryResult.onComplete { queryResult.onComplete {
case Success(results) if results.nonEmpty => case Success(results) if results.nonEmpty =>
ctx.run(query[persistence.Savedavatar] ctx.run(
.filter { _.avatarId == lift(avatarId) } query[persistence.Savedavatar]
.update( .filter { _.avatarId == lift(avatarId) }
_.purchaseCooldowns -> lift(buildClobfromCooldowns(avatar.cooldowns.purchase)), .update(
_.useCooldowns -> lift(buildClobfromCooldowns(avatar.cooldowns.use)) _.purchaseCooldowns -> lift(buildClobfromCooldowns(avatar.cooldowns.purchase)),
) _.useCooldowns -> lift(buildClobfromCooldowns(avatar.cooldowns.use))
)
) )
out.completeWith(Future(1)) out.completeWith(Future(1))
case _ => case _ =>
@ -959,12 +971,13 @@ class AvatarActor(
deleted.headOption match { deleted.headOption match {
case Some(a) if !a.deleted => case Some(a) if !a.deleted =>
val flagDeletion = for { val flagDeletion = for {
_ <- ctx.run(query[persistence.Avatar] _ <- ctx.run(
.filter(_.id == lift(id)) query[persistence.Avatar]
.update( .filter(_.id == lift(id))
_.deleted -> lift(true), .update(
_.lastModified -> lift(LocalDateTime.now()) _.deleted -> lift(true),
) _.lastModified -> lift(LocalDateTime.now())
)
) )
} yield () } yield ()
flagDeletion.onComplete { flagDeletion.onComplete {
@ -1008,11 +1021,12 @@ class AvatarActor(
case LoginAvatar(replyTo) => case LoginAvatar(replyTo) =>
import ctx._ import ctx._
val avatarId = avatar.id val avatarId = avatar.id
ctx.run( ctx
query[persistence.Avatar] .run(
.filter(_.id == lift(avatarId)) query[persistence.Avatar]
.map { c => (c.created, c.lastLogin) } .filter(_.id == lift(avatarId))
) .map { c => (c.created, c.lastLogin) }
)
.onComplete { .onComplete {
case Success(value) if value.nonEmpty => case Success(value) if value.nonEmpty =>
val (created, lastLogin) = value.head val (created, lastLogin) = value.head
@ -1031,12 +1045,12 @@ class AvatarActor(
persistence.Certification(Certification.ATV.value, avatarId), persistence.Certification(Certification.ATV.value, avatarId),
persistence.Certification(Certification.Harasser.value, avatarId) persistence.Certification(Certification.Harasser.value, avatarId)
) )
).foreach(c => query[persistence.Certification].insert(c)) ).foreach(c => query[persistence.Certification].insertValue(c))
) )
_ <- ctx.run( _ <- ctx.run(
liftQuery( liftQuery(
List(persistence.Shortcut(avatarId, 0, 0, "medkit")) List(persistence.Shortcut(avatarId, 0, 0, "medkit"))
).foreach(c => query[persistence.Shortcut].insert(c)) ).foreach(c => query[persistence.Shortcut].insertValue(c))
) )
} yield true } yield true
inits.onComplete { inits.onComplete {
@ -1109,13 +1123,14 @@ class AvatarActor(
val replace = certification.replaces.intersect(avatar.certifications) val replace = certification.replaces.intersect(avatar.certifications)
Future Future
.sequence(replace.map(cert => { .sequence(replace.map(cert => {
ctx.run( ctx
query[persistence.Certification] .run(
.filter(_.avatarId == lift(avatar.id)) query[persistence.Certification]
.filter(_.id == lift(cert.value)) .filter(_.avatarId == lift(avatar.id))
.delete .filter(_.id == lift(cert.value))
) .delete
.map(_ => cert) )
.map(_ => cert)
})) }))
.onComplete { .onComplete {
case Failure(exception) => case Failure(exception) =>
@ -1129,10 +1144,11 @@ class AvatarActor(
PlanetsideAttributeMessage(session.get.player.GUID, 25, cert.value) PlanetsideAttributeMessage(session.get.player.GUID, 25, cert.value)
) )
} }
ctx.run( ctx
query[persistence.Certification] .run(
.insert(_.id -> lift(certification.value), _.avatarId -> lift(avatar.id)) query[persistence.Certification]
) .insert(_.id -> lift(certification.value), _.avatarId -> lift(avatar.id))
)
.onComplete { .onComplete {
case Failure(exception) => case Failure(exception) =>
log.error(exception)("db failure") log.error(exception)("db failure")
@ -1180,13 +1196,14 @@ class AvatarActor(
avatar.certifications avatar.certifications
.intersect(requiredByCert) .intersect(requiredByCert)
.map(cert => { .map(cert => {
ctx.run( ctx
query[persistence.Certification] .run(
.filter(_.avatarId == lift(avatar.id)) query[persistence.Certification]
.filter(_.id == lift(cert.value)) .filter(_.avatarId == lift(avatar.id))
.delete .filter(_.id == lift(cert.value))
) .delete
.map(_ => cert) )
.map(_ => cert)
}) })
) )
.onComplete { .onComplete {
@ -1329,25 +1346,26 @@ class AvatarActor(
index match { index match {
case Some(_index) => case Some(_index) =>
import ctx._ import ctx._
ctx.run( ctx
query[persistence.Implant] .run(
.filter(_.name == lift(definition.Name)) query[persistence.Implant]
.filter(_.avatarId == lift(avatar.id)) .filter(_.name == lift(definition.Name))
.delete .filter(_.avatarId == lift(avatar.id))
) .delete
.onComplete { )
case Success(_) => .onComplete {
replaceAvatar(avatar.copy(implants = avatar.implants.updated(_index, None))) case Success(_) =>
sessionActor ! SessionActor.SendResponse( replaceAvatar(avatar.copy(implants = avatar.implants.updated(_index, None)))
AvatarImplantMessage(session.get.player.GUID, ImplantAction.Remove, _index, 0) sessionActor ! SessionActor.SendResponse(
) AvatarImplantMessage(session.get.player.GUID, ImplantAction.Remove, _index, 0)
sessionActor ! SessionActor.SendResponse( )
ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = true) sessionActor ! SessionActor.SendResponse(
) ItemTransactionResultMessage(terminalGuid, TransactionType.Sell, success = true)
context.self ! ResetImplants() )
sessionActor ! SessionActor.CharSaved context.self ! ResetImplants()
case Failure(exception) => log.error(exception)("db failure") sessionActor ! SessionActor.CharSaved
} case Failure(exception) => log.error(exception)("db failure")
}
case None => case None =>
log.warn("attempted to sell implant but could not find slot") log.warn("attempted to sell implant but could not find slot")
@ -1462,23 +1480,25 @@ class AvatarActor(
case UpdatePurchaseTime(definition, time) => case UpdatePurchaseTime(definition, time) =>
var newTimes = avatar.cooldowns.purchase var newTimes = avatar.cooldowns.purchase
AvatarActor.resolveSharedPurchaseTimeNames(AvatarActor.resolvePurchaseTimeName(avatar.faction, definition)).foreach { AvatarActor
case (item, name) => .resolveSharedPurchaseTimeNames(AvatarActor.resolvePurchaseTimeName(avatar.faction, definition))
Avatar.purchaseCooldowns.get(item) match { .foreach {
case Some(cooldown) => case (item, name) =>
//only send for items with cooldowns Avatar.purchaseCooldowns.get(item) match {
newTimes = newTimes.updated(name, time) case Some(cooldown) =>
updatePurchaseTimer( //only send for items with cooldowns
name, newTimes = newTimes.updated(name, time)
cooldown.toSeconds, updatePurchaseTimer(
item match { name,
case _: KitDefinition => false cooldown.toSeconds,
case _ => true item match {
} case _: KitDefinition => false
) case _ => true
case _ => ; }
} )
} case _ => ;
}
}
avatarCopy(avatar.copy(cooldowns = avatar.cooldowns.copy(purchase = newTimes))) avatarCopy(avatar.copy(cooldowns = avatar.cooldowns.copy(purchase = newTimes)))
Behaviors.same Behaviors.same
@ -1675,14 +1695,16 @@ class AvatarActor(
Behaviors.same Behaviors.same
case SetRibbon(ribbon, bar) => case SetRibbon(ribbon, bar) =>
val decor = avatar.decoration val decor = avatar.decoration
val previousRibbonBars = decor.ribbonBars val previousRibbonBars = decor.ribbonBars
val useRibbonBars = Seq(previousRibbonBars.upper, previousRibbonBars.middle, previousRibbonBars.lower) val useRibbonBars = Seq(previousRibbonBars.upper, previousRibbonBars.middle, previousRibbonBars.lower)
.indexWhere { _ == ribbon } match { .indexWhere { _ == ribbon } match {
case -1 => previousRibbonBars case -1 => previousRibbonBars
case n => AvatarActor.changeRibbons(previousRibbonBars, MeritCommendation.None, RibbonBarSlot(n)) case n => AvatarActor.changeRibbons(previousRibbonBars, MeritCommendation.None, RibbonBarSlot(n))
} }
replaceAvatar(avatar.copy(decoration = decor.copy(ribbonBars = AvatarActor.changeRibbons(useRibbonBars, ribbon, bar)))) replaceAvatar(
avatar.copy(decoration = decor.copy(ribbonBars = AvatarActor.changeRibbons(useRibbonBars, ribbon, bar)))
)
val player = session.get.player val player = session.get.player
val zone = player.Zone val zone = player.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! AvatarServiceMessage(
@ -1706,9 +1728,11 @@ class AvatarActor(
case _ => false case _ => false
}) })
if (isDifferentShortcut) { if (isDifferentShortcut) {
if (!isMacroShortcut && avatar.shortcuts.flatten.exists { if (
a => AvatarShortcut.equals(shortcut, a) !isMacroShortcut && avatar.shortcuts.flatten.exists { a =>
}) { AvatarShortcut.equals(shortcut, a)
}
) {
//duplicate implant or medkit found //duplicate implant or medkit found
if (shortcut.isInstanceOf[Shortcut.Implant]) { if (shortcut.isInstanceOf[Shortcut.Implant]) {
//duplicate implant //duplicate implant
@ -1716,11 +1740,17 @@ class AvatarActor(
case Some(existingShortcut: AvatarShortcut) => case Some(existingShortcut: AvatarShortcut) =>
//redraw redundant shortcut slot with existing shortcut //redraw redundant shortcut slot with existing shortcut
sessionActor ! SessionActor.SendResponse( sessionActor ! SessionActor.SendResponse(
CreateShortcutMessage(session.get.player.GUID, slot + 1, Some(AvatarShortcut.convert(existingShortcut))) CreateShortcutMessage(
session.get.player.GUID,
slot + 1,
Some(AvatarShortcut.convert(existingShortcut))
)
) )
case _ => case _ =>
//blank shortcut slot //blank shortcut slot
sessionActor ! SessionActor.SendResponse(CreateShortcutMessage(session.get.player.GUID, slot + 1, None)) sessionActor ! SessionActor.SendResponse(
CreateShortcutMessage(session.get.player.GUID, slot + 1, None)
)
} }
} }
} else { } else {
@ -1743,7 +1773,7 @@ class AvatarActor(
.filter(_.slot == lift(slot)) .filter(_.slot == lift(slot))
.update( .update(
_.purpose -> lift(shortcut.code), _.purpose -> lift(shortcut.code),
_.tile -> lift(shortcut.tile), _.tile -> lift(shortcut.tile),
_.effect1 -> Option(lift(optEffect1)), _.effect1 -> Option(lift(optEffect1)),
_.effect2 -> Option(lift(optEffect2)) _.effect2 -> Option(lift(optEffect2))
) )
@ -1752,11 +1782,11 @@ class AvatarActor(
ctx.run( ctx.run(
query[persistence.Shortcut].insert( query[persistence.Shortcut].insert(
_.avatarId -> lift(avatar.id.toLong), _.avatarId -> lift(avatar.id.toLong),
_.slot -> lift(slot), _.slot -> lift(slot),
_.purpose -> lift(shortcut.code), _.purpose -> lift(shortcut.code),
_.tile -> lift(shortcut.tile), _.tile -> lift(shortcut.tile),
_.effect1 -> Option(lift(optEffect1)), _.effect1 -> Option(lift(optEffect1)),
_.effect2 -> Option(lift(optEffect2)) _.effect2 -> Option(lift(optEffect2))
) )
) )
} }
@ -1771,10 +1801,11 @@ class AvatarActor(
avatar.shortcuts.lift(slot).flatten match { avatar.shortcuts.lift(slot).flatten match {
case None => ; case None => ;
case Some(_) => case Some(_) =>
ctx.run(query[persistence.Shortcut] ctx.run(
.filter(_.avatarId == lift(avatar.id.toLong)) query[persistence.Shortcut]
.filter(_.slot == lift(slot)) .filter(_.avatarId == lift(avatar.id.toLong))
.delete .filter(_.slot == lift(slot))
.delete
) )
avatar.shortcuts.update(slot, None) avatar.shortcuts.update(slot, None)
} }
@ -1803,12 +1834,16 @@ class AvatarActor(
val result = for { val result = for {
//log this login //log this login
_ <- ctx.run(query[persistence.Avatar].filter(_.id == lift(avatarId)) _ <- ctx.run(
.update(_.lastLogin -> lift(LocalDateTime.now())) query[persistence.Avatar]
.filter(_.id == lift(avatarId))
.update(_.lastLogin -> lift(LocalDateTime.now()))
) )
//log this choice of faction (no empire switching) //log this choice of faction (no empire switching)
_ <- ctx.run(query[persistence.Account].filter(_.id == lift(accountId)) _ <- ctx.run(
.update(_.lastFactionId -> lift(avatar.faction.id)) query[persistence.Account]
.filter(_.id == lift(accountId))
.update(_.lastFactionId -> lift(avatar.faction.id))
) )
//retrieve avatar data //retrieve avatar data
loadouts <- initializeAllLoadouts() loadouts <- initializeAllLoadouts()
@ -1887,11 +1922,12 @@ class AvatarActor(
val p = Promise[Unit]() val p = Promise[Unit]()
import ctx._ import ctx._
ctx.run( ctx
query[persistence.Avatar] .run(
.filter(_.id == lift(avatar.id)) query[persistence.Avatar]
.update(_.cosmetics -> lift(Some(Cosmetic.valuesToObjectCreateValue(cosmetics)): Option[Int])) .filter(_.id == lift(avatar.id))
) .update(_.cosmetics -> lift(Some(Cosmetic.valuesToObjectCreateValue(cosmetics)): Option[Int]))
)
.onComplete { .onComplete {
case Success(_) => case Success(_) =>
val zone = session.get.zone val zone = session.get.zone
@ -2177,6 +2213,7 @@ class AvatarActor(
secondsSinceLastLogin secondsSinceLastLogin
) )
) )
/** After the user has selected a character to load from the "character select screen," /** After the user has selected a character to load from the "character select screen,"
* the temporary global unique identifiers used for that screen are stripped from the underlying `Player` object that was selected. * the temporary global unique identifiers used for that screen are stripped from the underlying `Player` object that was selected.
* Characters that were not selected may be destroyed along with their temporary GUIDs. * Characters that were not selected may be destroyed along with their temporary GUIDs.
@ -2471,42 +2508,45 @@ class AvatarActor(
val locker = Avatar.makeLocker() val locker = Avatar.makeLocker()
saveLockerFunc = storeLocker saveLockerFunc = storeLocker
val out = Promise[LockerContainer]() val out = Promise[LockerContainer]()
ctx.run(query[persistence.Locker].filter(_.avatarId == lift(charId))) ctx
.run(query[persistence.Locker].filter(_.avatarId == lift(charId)))
.onComplete { .onComplete {
case Success(entry) if entry.nonEmpty => case Success(entry) if entry.nonEmpty =>
AvatarActor.buildContainedEquipmentFromClob(locker, entry.head.items, log, restoreAmmo = true) AvatarActor.buildContainedEquipmentFromClob(locker, entry.head.items, log, restoreAmmo = true)
out.completeWith(Future(locker)) out.completeWith(Future(locker))
case Success(_) => case Success(_) =>
//no locker, or maybe default empty locker? //no locker, or maybe default empty locker?
ctx.run(query[persistence.Locker].insert(_.avatarId -> lift(avatar.id), _.items -> lift(""))) ctx
.onComplete { .run(query[persistence.Locker].insert(_.avatarId -> lift(avatar.id), _.items -> lift("")))
_ => out.completeWith(Future(locker)) .onComplete { _ =>
} out.completeWith(Future(locker))
case Failure(e) => }
saveLockerFunc = doNotStoreLocker case Failure(e) =>
log.error(e)("db failure") saveLockerFunc = doNotStoreLocker
out.tryFailure(e) log.error(e)("db failure")
} out.tryFailure(e)
}
out.future out.future
} }
def loadFriendList(avatarId: Long): Future[List[AvatarFriend]] = { def loadFriendList(avatarId: Long): Future[List[AvatarFriend]] = {
import ctx._ import ctx._
val out: Promise[List[AvatarFriend]] = Promise() val out: Promise[List[AvatarFriend]] = Promise()
val queryResult = ctx.run( val queryResult = ctx.run(
query[persistence.Friend].filter { _.avatarId == lift(avatarId) } query[persistence.Friend]
.filter { _.avatarId == lift(avatarId) }
.join(query[persistence.Avatar]) .join(query[persistence.Avatar])
.on { case (friend, avatar) => friend.charId == avatar.id } .on { case (friend, avatar) => friend.charId == avatar.id }
.map { case (_, avatar) => (avatar.id, avatar.name, avatar.factionId) } .map { case (_, avatar) => (avatar.id, avatar.name, avatar.factionId) }
) )
queryResult.onComplete { queryResult.onComplete {
case Success(list) => case Success(list) =>
out.completeWith(Future( out.completeWith(
list.map { case (id, name, faction) => AvatarFriend(id, name, PlanetSideEmpire(faction)) }.toList Future(
)) list.map { case (id, name, faction) => AvatarFriend(id, name, PlanetSideEmpire(faction)) }.toList
)
)
case _ => case _ =>
out.completeWith(Future(List.empty[AvatarFriend])) out.completeWith(Future(List.empty[AvatarFriend]))
} }
@ -2518,16 +2558,19 @@ class AvatarActor(
val out: Promise[List[AvatarIgnored]] = Promise() val out: Promise[List[AvatarIgnored]] = Promise()
val queryResult = ctx.run( val queryResult = ctx.run(
query[persistence.Ignored].filter { _.avatarId == lift(avatarId) } query[persistence.Ignored]
.filter { _.avatarId == lift(avatarId) }
.join(query[persistence.Avatar]) .join(query[persistence.Avatar])
.on { case (friend, avatar) => friend.charId == avatar.id } .on { case (friend, avatar) => friend.charId == avatar.id }
.map { case (_, avatar) => (avatar.id, avatar.name) } .map { case (_, avatar) => (avatar.id, avatar.name) }
) )
queryResult.onComplete { queryResult.onComplete {
case Success(list) => case Success(list) =>
out.completeWith(Future( out.completeWith(
list.map { case (id, name) => AvatarIgnored(id, name) }.toList Future(
)) list.map { case (id, name) => AvatarIgnored(id, name) }.toList
)
)
case _ => case _ =>
out.completeWith(Future(List.empty[AvatarIgnored])) out.completeWith(Future(List.empty[AvatarIgnored]))
} }
@ -2539,14 +2582,16 @@ class AvatarActor(
val out: Promise[Array[Option[AvatarShortcut]]] = Promise() val out: Promise[Array[Option[AvatarShortcut]]] = Promise()
val queryResult = ctx.run( val queryResult = ctx.run(
query[persistence.Shortcut].filter { _.avatarId == lift(avatarId) } query[persistence.Shortcut]
.filter { _.avatarId == lift(avatarId) }
.map { shortcut => (shortcut.slot, shortcut.purpose, shortcut.tile, shortcut.effect1, shortcut.effect2) } .map { shortcut => (shortcut.slot, shortcut.purpose, shortcut.tile, shortcut.effect1, shortcut.effect2) }
) )
val output = Array.fill[Option[AvatarShortcut]](64)(None) val output = Array.fill[Option[AvatarShortcut]](64)(None)
queryResult.onComplete { queryResult.onComplete {
case Success(list) => case Success(list) =>
list.foreach { case (slot, purpose, tile, effect1, effect2) => list.foreach {
output.update(slot, Some(AvatarShortcut(purpose, tile, effect1.getOrElse(""), effect2.getOrElse("")))) case (slot, purpose, tile, effect1, effect2) =>
output.update(slot, Some(AvatarShortcut(purpose, tile, effect1.getOrElse(""), effect2.getOrElse(""))))
} }
out.completeWith(Future(output)) out.completeWith(Future(output))
case Failure(e) => case Failure(e) =>
@ -2597,7 +2642,7 @@ class AvatarActor(
cooldown.toSeconds - secondsSincePurchase, cooldown.toSeconds - secondsSincePurchase,
obj match { obj match {
case _: KitDefinition => false case _: KitDefinition => false
case _ => true case _ => true
} }
) )
@ -2648,7 +2693,7 @@ class AvatarActor(
case MemberAction.RemoveFriend => getAvatarForFunc(name, formatForOtherFunc(memberActionRemoveFriend)) case MemberAction.RemoveFriend => getAvatarForFunc(name, formatForOtherFunc(memberActionRemoveFriend))
case MemberAction.AddIgnoredPlayer => getAvatarForFunc(name, memberActionAddIgnored) case MemberAction.AddIgnoredPlayer => getAvatarForFunc(name, memberActionAddIgnored)
case MemberAction.RemoveIgnoredPlayer => getAvatarForFunc(name, formatForOtherFunc(memberActionRemoveIgnored)) case MemberAction.RemoveIgnoredPlayer => getAvatarForFunc(name, formatForOtherFunc(memberActionRemoveIgnored))
case _ => ; case _ => ;
} }
} }
} }
@ -2658,15 +2703,17 @@ class AvatarActor(
* @return a list of `Friends` suitable for putting into a packet * @return a list of `Friends` suitable for putting into a packet
*/ */
def transformFriendsList(): List[GameFriend] = { def transformFriendsList(): List[GameFriend] = {
avatar.people.friend.map { f => GameFriend(f.name, f.online)} avatar.people.friend.map { f => GameFriend(f.name, f.online) }
} }
/** /**
* Transform the ignored players list in a list of packet entities. * Transform the ignored players list in a list of packet entities.
* @return a list of `Friends` suitable for putting into a packet * @return a list of `Friends` suitable for putting into a packet
*/ */
def transformIgnoredList(): List[GameFriend] = { def transformIgnoredList(): List[GameFriend] = {
avatar.people.ignored.map { f => GameFriend(f.name, f.online)} avatar.people.ignored.map { f => GameFriend(f.name, f.online) }
} }
/** /**
* Reload the list of friend players or ignored players for the client. * Reload the list of friend players or ignored players for the client.
* This does not update any player's online status, but merely reloads current states. * This does not update any player's online status, but merely reloads current states.
@ -2674,7 +2721,7 @@ class AvatarActor(
* (either `InitializeFriendList` or `InitializeIgnoreList`, hopefully) * (either `InitializeFriendList` or `InitializeIgnoreList`, hopefully)
* @param listFunc transformation function that produces data suitable for a game paket * @param listFunc transformation function that produces data suitable for a game paket
*/ */
def memberActionListManagement(action: MemberAction.Value, listFunc: ()=>List[GameFriend]): Unit = { def memberActionListManagement(action: MemberAction.Value, listFunc: () => List[GameFriend]): Unit = {
FriendsResponse.packetSequence(action, listFunc()).foreach { msg => FriendsResponse.packetSequence(action, listFunc()).foreach { msg =>
sessionActor ! SessionActor.SendResponse(msg) sessionActor ! SessionActor.SendResponse(msg)
} }
@ -2693,16 +2740,20 @@ class AvatarActor(
case Some(_) => ; case Some(_) => ;
case None => case None =>
import ctx._ import ctx._
ctx.run(query[persistence.Friend] ctx.run(
.insert( query[persistence.Friend]
_.avatarId -> lift(avatar.id.toLong), .insert(
_.charId -> lift(charId) _.avatarId -> lift(avatar.id.toLong),
) _.charId -> lift(charId)
)
) )
val isOnline = onlineIfNotIgnoredEitherWay(avatar, name) val isOnline = onlineIfNotIgnoredEitherWay(avatar, name)
replaceAvatar(avatar.copy( replaceAvatar(
people = people.copy(friend = people.friend :+ AvatarFriend(charId, name, PlanetSideEmpire(faction), isOnline)) avatar.copy(
)) people =
people.copy(friend = people.friend :+ AvatarFriend(charId, name, PlanetSideEmpire(faction), isOnline))
)
)
sessionActor ! SessionActor.SendResponse(FriendsResponse(MemberAction.AddFriend, GameFriend(name, isOnline))) sessionActor ! SessionActor.SendResponse(FriendsResponse(MemberAction.AddFriend, GameFriend(name, isOnline)))
sessionActor ! SessionActor.CharSaved sessionActor ! SessionActor.CharSaved
} }
@ -2724,17 +2775,17 @@ class AvatarActor(
) )
case None => ; case None => ;
} }
ctx.run(query[persistence.Friend] ctx.run(
.filter(_.avatarId == lift(avatar.id)) query[persistence.Friend]
.filter(_.charId == lift(charId)) .filter(_.avatarId == lift(avatar.id))
.delete .filter(_.charId == lift(charId))
.delete
) )
sessionActor ! SessionActor.SendResponse(FriendsResponse(MemberAction.RemoveFriend, GameFriend(name))) sessionActor ! SessionActor.SendResponse(FriendsResponse(MemberAction.RemoveFriend, GameFriend(name)))
sessionActor ! SessionActor.CharSaved sessionActor ! SessionActor.CharSaved
} }
/** /**
*
* @param name unique character name * @param name unique character name
* @return if the avatar is found, that avatar's unique identifier and the avatar's faction affiliation * @return if the avatar is found, that avatar's unique identifier and the avatar's faction affiliation
*/ */
@ -2752,11 +2803,13 @@ class AvatarActor(
case None => case None =>
(None, false) (None, false)
} }
replaceAvatar(avatar.copy( replaceAvatar(
people = people.copy( avatar.copy(
friend = people.friend.filterNot { _.name.equals(name) } :+ otherFriend.copy(online = online) people = people.copy(
friend = people.friend.filterNot { _.name.equals(name) } :+ otherFriend.copy(online = online)
)
) )
)) )
sessionActor ! SessionActor.SendResponse(FriendsResponse(MemberAction.UpdateFriend, GameFriend(name, online))) sessionActor ! SessionActor.SendResponse(FriendsResponse(MemberAction.UpdateFriend, GameFriend(name, online)))
out out
case None => case None =>
@ -2782,16 +2835,19 @@ class AvatarActor(
case Some(_) => ; case Some(_) => ;
case None => case None =>
import ctx._ import ctx._
ctx.run(query[persistence.Ignored] ctx.run(
.insert( query[persistence.Ignored]
_.avatarId -> lift(avatar.id.toLong), .insert(
_.charId -> lift(charId) _.avatarId -> lift(avatar.id.toLong),
) _.charId -> lift(charId)
)
) )
replaceAvatar( replaceAvatar(
avatar.copy(people = people.copy(ignored = people.ignored :+ AvatarIgnored(charId, name))) avatar.copy(people = people.copy(ignored = people.ignored :+ AvatarIgnored(charId, name)))
) )
sessionActor ! SessionActor.UpdateIgnoredPlayers(FriendsResponse(MemberAction.AddIgnoredPlayer, GameFriend(name))) sessionActor ! SessionActor.UpdateIgnoredPlayers(
FriendsResponse(MemberAction.AddIgnoredPlayer, GameFriend(name))
)
sessionActor ! SessionActor.CharSaved sessionActor ! SessionActor.CharSaved
} }
} }
@ -2814,31 +2870,34 @@ class AvatarActor(
) )
case None => ; case None => ;
} }
ctx.run(query[persistence.Ignored] ctx.run(
.filter(_.avatarId == lift(avatar.id.toLong)) query[persistence.Ignored]
.filter(_.charId == lift(charId)) .filter(_.avatarId == lift(avatar.id.toLong))
.delete .filter(_.charId == lift(charId))
.delete
)
sessionActor ! SessionActor.UpdateIgnoredPlayers(
FriendsResponse(MemberAction.RemoveIgnoredPlayer, GameFriend(name))
) )
sessionActor ! SessionActor.UpdateIgnoredPlayers(FriendsResponse(MemberAction.RemoveIgnoredPlayer, GameFriend(name)))
sessionActor ! SessionActor.CharSaved sessionActor ! SessionActor.CharSaved
} }
def setBep(bep: Long, modifier: ExperienceType): Unit = { def setBep(bep: Long, modifier: ExperienceType): Unit = {
import ctx._ import ctx._
val current = BattleRank.withExperience(avatar.bep).value val current = BattleRank.withExperience(avatar.bep).value
val next = BattleRank.withExperience(bep).value val next = BattleRank.withExperience(bep).value
lazy val br24 = BattleRank.BR24.value lazy val br24 = BattleRank.BR24.value
val result = for { val result = for {
r <- ctx.run(query[persistence.Avatar].filter(_.id == lift(avatar.id)).update(_.bep -> lift(bep))) r <- ctx.run(query[persistence.Avatar].filter(_.id == lift(avatar.id)).update(_.bep -> lift(bep)))
} yield r } yield r
result.onComplete { result.onComplete {
case Success(_) => case Success(_) =>
val sess = session.get val sess = session.get
val zone = sess.zone val zone = sess.zone
val zoneId = zone.id val zoneId = zone.id
val events = zone.AvatarEvents val events = zone.AvatarEvents
val player = sess.player val player = sess.player
val pguid = player.GUID val pguid = player.GUID
val localModifier = modifier val localModifier = modifier
sessionActor ! SessionActor.SendResponse(BattleExperienceMessage(pguid, bep, localModifier)) sessionActor ! SessionActor.SendResponse(BattleExperienceMessage(pguid, bep, localModifier))
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(pguid, 17, bep)) events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(pguid, 17, bep))
@ -2854,15 +2913,18 @@ class AvatarActor(
val implants = avatar.implants.zipWithIndex.map { val implants = avatar.implants.zipWithIndex.map {
case (implant, index) => case (implant, index) =>
if (index >= BattleRank.withExperience(bep).implantSlots && implant.isDefined) { if (index >= BattleRank.withExperience(bep).implantSlots && implant.isDefined) {
ctx.run( ctx
query[persistence.Implant] .run(
.filter(_.name == lift(implant.get.definition.Name)) query[persistence.Implant]
.filter(_.avatarId == lift(avatar.id)) .filter(_.name == lift(implant.get.definition.Name))
.delete .filter(_.avatarId == lift(avatar.id))
) .delete
)
.onComplete { .onComplete {
case Success(_) => case Success(_) =>
sessionActor ! SessionActor.SendResponse(AvatarImplantMessage(pguid, ImplantAction.Remove, index, 0)) sessionActor ! SessionActor.SendResponse(
AvatarImplantMessage(pguid, ImplantAction.Remove, index, 0)
)
case Failure(exception) => case Failure(exception) =>
log.error(exception)("db failure") log.error(exception)("db failure")
} }
@ -2895,22 +2957,22 @@ class AvatarActor(
def updateKillsDeathsAssists(kdaStat: KDAStat): Unit = { def updateKillsDeathsAssists(kdaStat: KDAStat): Unit = {
avatar.scorecard.rate(kdaStat) avatar.scorecard.rate(kdaStat)
val exp = kdaStat.experienceEarned val exp = kdaStat.experienceEarned
val _session = session.get val _session = session.get
val zone = _session.zone val zone = _session.zone
val player = _session.player val player = _session.player
kdaStat match { kdaStat match {
case kill: Kill => case kill: Kill =>
val _ = PlayerSource(player) val _ = PlayerSource(player)
(kill.info.interaction.cause match { (kill.info.interaction.cause match {
case pr: ProjectileReason => pr.projectile.mounted_in.map { a => zone.GUID(a._1) } case pr: ProjectileReason => pr.projectile.mounted_in.map { a => zone.GUID(a._1) }
case _ => None case _ => None
}) match { }) match {
case Some(Some(_: Vitality)) => case Some(Some(_: Vitality)) =>
//zone.actor ! ZoneActor.RewardOurSupporters(playerSource, obj.History, kill, exp) //zone.actor ! ZoneActor.RewardOurSupporters(playerSource, obj.History, kill, exp)
case _ => ; case _ => ;
} }
//zone.actor ! ZoneActor.RewardOurSupporters(playerSource, player.History, kill, exp) //zone.actor ! ZoneActor.RewardOurSupporters(playerSource, player.History, kill, exp)
case _: Death => case _: Death =>
player.Zone.AvatarEvents ! AvatarServiceMessage( player.Zone.AvatarEvents ! AvatarServiceMessage(
player.Name, player.Name,