mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-19 18:44:45 +00:00
Building persistence
Buildings will now persist their faction in the database. At least that's what I want you to believe this change is. What it actually is: A rework of InterstellarCluster and groundwork for further reworks. InterstellarClusterService: This is the old InterstellarCluster, but as a service (it has always been one in secret). It was converted to a typed actor and it now handles all spawn point requests. ZoneActor: Basically ZoneControl, but as a typed actor. It's more of a stub right now, the eventual goal is to have it own the `Zone` object rather than the other way around. BuildingActor: BuildingControl, but as a typed actor. Also includes some minor improvements to ChatActor and sets SupervisorStrategy.restart for all typed actors (which is the default for classic actors, but not for typed actors - we may want to get more sophisticated here in the future).
This commit is contained in:
parent
4634dffe00
commit
3345e56b38
|
|
@ -81,7 +81,7 @@ The Login and World servers require PostgreSQL for persistence.
|
|||
The default database is named `psforever` and the credentials are
|
||||
`psforever:psforever`. To change these, create a configuration file at
|
||||
`config/psforever.conf`. For configuration options and their defaults, see
|
||||
[`application.conf`](/pslogin/src/main/resources/application.conf). This database user will need
|
||||
[`application.conf`](/common/src/main/resources/application.conf). The database user will need
|
||||
ALL access to tables, sequences, and functions.
|
||||
The permissions required can be summarized by the SQL below.
|
||||
Loading this in requires access to a graphical tool such as [pgAdmin](https://www.pgadmin.org/download/) (highly recommended) or a PostgreSQL terminal (`psql`) for advanced users.
|
||||
|
|
|
|||
|
|
@ -89,9 +89,8 @@ lazy val psloginPackSettings = Seq(
|
|||
packMain := Map("ps-login" -> "net.psforever.pslogin.PsLogin"),
|
||||
packArchivePrefix := "pslogin",
|
||||
packExtraClasspath := Map("ps-login" -> Seq("${PROG_HOME}/pscrypto-lib", "${PROG_HOME}/config")),
|
||||
packResourceDir += (baseDirectory.value / "pscrypto-lib" -> "pscrypto-lib"),
|
||||
packResourceDir += (baseDirectory.value / "config" -> "config"),
|
||||
packResourceDir += (baseDirectory.value / "pslogin/src/main/resources" -> "config")
|
||||
packResourceDir += (baseDirectory.value / "pscrypto-lib" -> "pscrypto-lib"),
|
||||
packResourceDir += (baseDirectory.value / "config" -> "config")
|
||||
)
|
||||
|
||||
lazy val root = (project in file("."))
|
||||
|
|
@ -142,4 +141,4 @@ lazy val decodePackets = (project in file("tools/decode-packets"))
|
|||
lazy val decodePacketsPackSettings = Seq(packMain := Map("psf-decode-packets" -> "DecodePackets"))
|
||||
|
||||
// Special test configuration for really quiet tests (used in CI)
|
||||
lazy val QuietTest = config("quiet") extend (Test)
|
||||
lazy val QuietTest = config("quiet") extend Test
|
||||
|
|
|
|||
|
|
@ -58,6 +58,15 @@ database {
|
|||
# The SSL configuration of the database connection.
|
||||
# One of: disable prefer require verify-full
|
||||
sslmode = prefer
|
||||
|
||||
# The maximum number of active connections.
|
||||
maxActiveConnections = 5
|
||||
}
|
||||
|
||||
# Enable non-standard game properties
|
||||
game {
|
||||
# Allow instant action to AMS
|
||||
instant-action-ams = no
|
||||
}
|
||||
|
||||
anti-cheat {
|
||||
|
|
@ -110,5 +119,13 @@ kamon {
|
|||
apm.api-key = ""
|
||||
}
|
||||
|
||||
include "akka"
|
||||
include "dispatchers"
|
||||
sentry {
|
||||
# Enables submission of warnings and errors to Sentry
|
||||
enable = no
|
||||
|
||||
# Sentry DSN (Data Source Name)
|
||||
dsn = ""
|
||||
}
|
||||
|
||||
include "akka.conf"
|
||||
include "dispatchers.conf"
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package net.psforever.actors.commands
|
||||
|
||||
import akka.actor.typed.ActorRef
|
||||
import net.psforever.objects.NtuContainer
|
||||
|
||||
object NtuCommand {
|
||||
|
||||
trait Command
|
||||
|
||||
/** Message for announcing it has nanites it can offer the recipient.
|
||||
*
|
||||
* @param source the nanite container recognized as the sender
|
||||
*/
|
||||
final case class Offer(source: NtuContainer) extends Command
|
||||
|
||||
/** Message for asking for nanites from the recipient.
|
||||
*
|
||||
* @param amount the amount of nanites requested
|
||||
*/
|
||||
final case class Request(amount: Int, replyTo: ActorRef[Grant]) extends Command
|
||||
|
||||
/** Response for transferring nanites to a recipient.
|
||||
*
|
||||
* @param source the nanite container recognized as the sender
|
||||
* @param amount the nanites transferred in this package
|
||||
*/
|
||||
final case class Grant(source: NtuContainer, amount: Int)
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,175 @@
|
|||
package net.psforever.actors.zone
|
||||
|
||||
import akka.actor.typed.receptionist.Receptionist
|
||||
import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer}
|
||||
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
|
||||
import akka.{actor => classic}
|
||||
import net.psforever.actors.commands.NtuCommand
|
||||
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.persistence
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
import net.psforever.util.Database._
|
||||
import services.galaxy.{GalaxyAction, GalaxyServiceMessage}
|
||||
import services.local.{LocalAction, LocalServiceMessage}
|
||||
import services.{InterstellarClusterService, ServiceManager}
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
object BuildingActor {
|
||||
def apply(zone: Zone, building: Building): Behavior[Command] =
|
||||
Behaviors
|
||||
.supervise[Command] {
|
||||
Behaviors.withStash(100) { buffer =>
|
||||
Behaviors.setup(context => new BuildingActor(context, buffer, zone, building).start())
|
||||
}
|
||||
}
|
||||
.onFailure[Exception](SupervisorStrategy.restart)
|
||||
|
||||
sealed trait Command
|
||||
|
||||
private case class ReceptionistListing(listing: Receptionist.Listing) extends Command
|
||||
|
||||
private case class ServiceManagerLookupResult(result: ServiceManager.LookupResult) extends Command
|
||||
|
||||
final case class SetFaction(faction: PlanetSideEmpire.Value) extends Command
|
||||
|
||||
// TODO remove
|
||||
// Changes to building objects should go through BuildingActor
|
||||
// Once they do, we won't need this anymore
|
||||
final case class MapUpdate() extends Command
|
||||
|
||||
final case class Ntu(command: NtuCommand.Command) extends Command
|
||||
}
|
||||
|
||||
class BuildingActor(
|
||||
context: ActorContext[BuildingActor.Command],
|
||||
buffer: StashBuffer[BuildingActor.Command],
|
||||
zone: Zone,
|
||||
building: Building
|
||||
) {
|
||||
|
||||
import BuildingActor._
|
||||
|
||||
private[this] val log = org.log4s.getLogger
|
||||
var galaxyService: Option[classic.ActorRef] = None
|
||||
var interstellarCluster: Option[ActorRef[InterstellarClusterService.Command]] = None
|
||||
|
||||
context.system.receptionist ! Receptionist.Find(
|
||||
InterstellarClusterService.InterstellarClusterServiceKey,
|
||||
context.messageAdapter[Receptionist.Listing](ReceptionistListing)
|
||||
)
|
||||
|
||||
ServiceManager.serviceManager ! ServiceManager.LookupFromTyped(
|
||||
"galaxy",
|
||||
context.messageAdapter[ServiceManager.LookupResult](ServiceManagerLookupResult)
|
||||
)
|
||||
|
||||
def start(): Behavior[Command] = {
|
||||
Behaviors.receiveMessage {
|
||||
case ReceptionistListing(InterstellarClusterService.InterstellarClusterServiceKey.Listing(listings)) =>
|
||||
interstellarCluster = listings.headOption
|
||||
postStartBehaviour()
|
||||
|
||||
case ServiceManagerLookupResult(ServiceManager.LookupResult(request, endpoint)) =>
|
||||
request match {
|
||||
case "galaxy" => galaxyService = Some(endpoint)
|
||||
}
|
||||
postStartBehaviour()
|
||||
|
||||
case other =>
|
||||
buffer.stash(other)
|
||||
Behaviors.same
|
||||
}
|
||||
}
|
||||
|
||||
def postStartBehaviour(): Behavior[Command] = {
|
||||
(galaxyService, interstellarCluster) match {
|
||||
case (Some(galaxyService), Some(interstellarCluster)) =>
|
||||
buffer.unstashAll(active(galaxyService, interstellarCluster))
|
||||
case _ =>
|
||||
Behaviors.same
|
||||
}
|
||||
}
|
||||
|
||||
def active(
|
||||
galaxyService: classic.ActorRef,
|
||||
interstellarCluster: ActorRef[InterstellarClusterService.Command]
|
||||
): Behavior[Command] = {
|
||||
Behaviors.receiveMessagePartial {
|
||||
case SetFaction(faction) =>
|
||||
import ctx._
|
||||
ctx
|
||||
.run(
|
||||
query[persistence.Building]
|
||||
.filter(_.localId == lift(building.MapId))
|
||||
.filter(_.zoneId == lift(zone.Number))
|
||||
)
|
||||
.onComplete {
|
||||
case Success(res) =>
|
||||
res.headOption match {
|
||||
case Some(_) =>
|
||||
ctx
|
||||
.run(
|
||||
query[persistence.Building]
|
||||
.filter(_.localId == lift(building.MapId))
|
||||
.filter(_.zoneId == lift(zone.Number))
|
||||
.update(_.factionId -> lift(building.Faction.id))
|
||||
)
|
||||
.onComplete {
|
||||
case Success(_) =>
|
||||
case Failure(e) => log.error(e.getMessage)
|
||||
}
|
||||
case _ =>
|
||||
ctx
|
||||
.run(
|
||||
query[persistence.Building]
|
||||
.insert(
|
||||
_.localId -> lift(building.MapId),
|
||||
_.factionId -> lift(building.Faction.id),
|
||||
_.zoneId -> lift(zone.Number)
|
||||
)
|
||||
)
|
||||
.onComplete {
|
||||
case Success(_) =>
|
||||
case Failure(e) => log.error(e.getMessage)
|
||||
}
|
||||
}
|
||||
case Failure(e) => log.error(e.getMessage)
|
||||
}
|
||||
building.Faction = faction
|
||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.SetEmpire(building.GUID, faction))
|
||||
Behaviors.same
|
||||
|
||||
case MapUpdate() =>
|
||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||
Behaviors.same
|
||||
|
||||
case Ntu(msg) =>
|
||||
ntu(msg)
|
||||
}
|
||||
}
|
||||
|
||||
def ntu(msg: NtuCommand.Command): Behavior[Command] = {
|
||||
import NtuCommand._
|
||||
val ntuBuilding = building match {
|
||||
case b: WarpGate => b
|
||||
case _ => return Behaviors.unhandled
|
||||
}
|
||||
|
||||
msg match {
|
||||
case Offer(source) =>
|
||||
case Request(amount, replyTo) =>
|
||||
ntuBuilding match {
|
||||
case warpGate: WarpGate => replyTo ! Grant(warpGate, if (warpGate.Active) amount else 0)
|
||||
case _ => return Behaviors.unhandled
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behaviors.same
|
||||
}
|
||||
|
||||
}
|
||||
124
common/src/main/scala/net/psforever/actors/zone/ZoneActor.scala
Normal file
124
common/src/main/scala/net/psforever/actors/zone/ZoneActor.scala
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
package net.psforever.actors.zone
|
||||
|
||||
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
|
||||
import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors}
|
||||
import net.psforever.objects.ballistics.SourceEntry
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.serverobject.structures.StructureType
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.objects.{ConstructionItem, PlanetSideGameObject, Player, Vehicle}
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||
import scala.collection.mutable.ListBuffer
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import net.psforever.util.Database._
|
||||
import net.psforever.persistence
|
||||
import scala.util.{Failure, Success}
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
object ZoneActor {
|
||||
def apply(zone: Zone): Behavior[Command] =
|
||||
Behaviors
|
||||
.supervise[Command] {
|
||||
Behaviors.setup(context => new ZoneActor(context, zone))
|
||||
}
|
||||
.onFailure[Exception](SupervisorStrategy.restart)
|
||||
|
||||
sealed trait Command
|
||||
|
||||
final case class GetZone(replyTo: ActorRef[ZoneResponse]) extends Command
|
||||
|
||||
final case class ZoneResponse(zone: Zone)
|
||||
|
||||
final case class AddPlayer(player: Player) extends Command
|
||||
|
||||
final case class RemovePlayer(player: Player) extends Command
|
||||
|
||||
final case class DropItem(item: Equipment, position: Vector3, orientation: Vector3) extends Command
|
||||
|
||||
final case class PickupItem(guid: PlanetSideGUID) extends Command
|
||||
|
||||
final case class BuildDeployable(obj: PlanetSideGameObject with Deployable, withTool: ConstructionItem)
|
||||
extends Command
|
||||
|
||||
final case class DismissDeployable(obj: PlanetSideGameObject with Deployable) extends Command
|
||||
|
||||
final case class SpawnVehicle(vehicle: Vehicle) extends Command
|
||||
|
||||
final case class DespawnVehicle(vehicle: Vehicle) extends Command
|
||||
|
||||
final case class HotSpotActivity(defender: SourceEntry, attacker: SourceEntry, location: Vector3) extends Command
|
||||
|
||||
// TODO remove
|
||||
// Changes to zone objects should go through ZoneActor
|
||||
// Once they do, we won't need this anymore
|
||||
final case class ZoneMapUpdate() extends Command
|
||||
|
||||
}
|
||||
|
||||
class ZoneActor(context: ActorContext[ZoneActor.Command], zone: Zone)
|
||||
extends AbstractBehavior[ZoneActor.Command](context) {
|
||||
|
||||
import ZoneActor._
|
||||
import ctx._
|
||||
|
||||
private[this] val log = org.log4s.getLogger
|
||||
val players: ListBuffer[Player] = ListBuffer()
|
||||
|
||||
zone.actor = context.self
|
||||
zone.init(context.toClassic)
|
||||
|
||||
ctx.run(query[persistence.Building].filter(_.zoneId == lift(zone.Number))).onComplete {
|
||||
case Success(buildings) =>
|
||||
buildings.foreach { building =>
|
||||
zone.BuildingByMapId(building.localId) match {
|
||||
case Some(b) => b.Faction = PlanetSideEmpire(building.factionId)
|
||||
case None => // TODO this happens during testing, need a way to not always persist during tests
|
||||
}
|
||||
|
||||
}
|
||||
case Failure(e) => log.error(e.getMessage)
|
||||
}
|
||||
|
||||
override def onMessage(msg: Command): Behavior[Command] = {
|
||||
msg match {
|
||||
case GetZone(replyTo) =>
|
||||
replyTo ! ZoneResponse(zone)
|
||||
|
||||
case AddPlayer(player) =>
|
||||
players.addOne(player)
|
||||
|
||||
case RemovePlayer(player) =>
|
||||
players.filterInPlace(p => p.CharId == player.CharId)
|
||||
|
||||
case DropItem(item, position, orientation) =>
|
||||
zone.Ground ! Zone.Ground.DropItem(item, position, orientation)
|
||||
|
||||
case PickupItem(guid) =>
|
||||
zone.Ground ! Zone.Ground.PickupItem(guid)
|
||||
|
||||
case BuildDeployable(obj, tool) =>
|
||||
zone.Deployables ! Zone.Deployable.Build(obj, tool)
|
||||
|
||||
case DismissDeployable(obj) =>
|
||||
zone.Deployables ! Zone.Deployable.Dismiss(obj)
|
||||
|
||||
case SpawnVehicle(vehicle) =>
|
||||
zone.Transport ! Zone.Vehicle.Spawn(vehicle)
|
||||
|
||||
case DespawnVehicle(vehicle) =>
|
||||
zone.Transport ! Zone.Vehicle.Despawn(vehicle)
|
||||
|
||||
case HotSpotActivity(defender, attacker, location) =>
|
||||
zone.Activity ! Zone.HotSpot.Activity(defender, attacker, location)
|
||||
|
||||
case ZoneMapUpdate() =>
|
||||
zone.Buildings
|
||||
.filter(_._2.BuildingType == StructureType.Facility)
|
||||
.values
|
||||
.foreach(_.Actor ! BuildingActor.MapUpdate())
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
|
@ -140,7 +140,7 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
|||
def accountLogin(username: String, password: String): Unit = {
|
||||
import ctx._
|
||||
val newToken = this.generateToken()
|
||||
|
||||
log.info("accountLogin")
|
||||
val result = for {
|
||||
// backwards compatibility: prefer exact match first, then try lowercase
|
||||
accountsExact <- ctx.run(query[persistence.Account].filter(_.username == lift(username)))
|
||||
|
|
@ -171,6 +171,7 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
login <- accountOption match {
|
||||
case Some(account) =>
|
||||
log.info(s"$account")
|
||||
(account.inactive, password.isBcrypted(account.passhash)) match {
|
||||
case (false, true) =>
|
||||
accountIntermediary ! StoreAccountData(newToken, new Account(account.id, account.username, account.gm))
|
||||
|
|
|
|||
|
|
@ -1,27 +1,40 @@
|
|||
package net.psforever.login.psadmin
|
||||
|
||||
import akka.actor.typed.receptionist.Receptionist
|
||||
import akka.actor.{Actor, ActorRef}
|
||||
import net.psforever.objects.zones.InterstellarCluster
|
||||
|
||||
import services.{InterstellarClusterService, ServiceManager}
|
||||
import scala.collection.mutable.Map
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
|
||||
class CmdListPlayers(args: Array[String], services: Map[String, ActorRef]) extends Actor {
|
||||
private[this] val log = org.log4s.getLogger(self.path.name)
|
||||
|
||||
override def preStart = {
|
||||
services { "cluster" } ! InterstellarCluster.ListPlayers()
|
||||
ServiceManager.receptionist ! Receptionist.Find(
|
||||
InterstellarClusterService.InterstellarClusterServiceKey,
|
||||
context.self
|
||||
)
|
||||
}
|
||||
|
||||
override def receive = {
|
||||
case InterstellarCluster.PlayerList(players) =>
|
||||
case InterstellarClusterService.InterstellarClusterServiceKey.Listing(listings) =>
|
||||
listings.head ! InterstellarClusterService.GetPlayers(context.self)
|
||||
|
||||
case InterstellarClusterService.PlayersResponse(players) =>
|
||||
val data = Map[String, Any]()
|
||||
data { "player_count" } = players.size
|
||||
data { "player_list" } = Array[String]()
|
||||
data {
|
||||
"player_count"
|
||||
} = players.size
|
||||
data {
|
||||
"player_list"
|
||||
} = Array[String]()
|
||||
|
||||
if (players.isEmpty) {
|
||||
context.parent ! CommandGoodResponse("No players currently online!", data)
|
||||
} else {
|
||||
data { "player_list" } = players
|
||||
data {
|
||||
"player_list"
|
||||
} = players
|
||||
context.parent ! CommandGoodResponse(s"${players.length} players online\n", data)
|
||||
}
|
||||
case default => log.error(s"Unexpected message $default")
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package net.psforever.objects
|
||||
|
||||
import akka.actor.{Actor, ActorRef}
|
||||
import net.psforever.actors.commands.NtuCommand
|
||||
import net.psforever.objects.serverobject.transfer.{TransferBehavior, TransferContainer}
|
||||
|
||||
object Ntu {
|
||||
|
|
@ -9,77 +10,81 @@ object Ntu {
|
|||
|
||||
/**
|
||||
* Message for a `sender` announcing it has nanites it can offer the recipient.
|
||||
*
|
||||
* @param src the nanite container recognized as the sender
|
||||
*/
|
||||
final case class Offer(src : NtuContainer)
|
||||
final case class Offer(src: NtuContainer)
|
||||
|
||||
/**
|
||||
* Message for a `sender` asking for nanites from the recipient.
|
||||
*
|
||||
* @param min a minimum amount of nanites requested;
|
||||
* if 0, the `sender` has no expectations
|
||||
* @param max the amount of nanites required to not make further requests;
|
||||
* if 0, the `sender` is full and the message is for clean up operations
|
||||
*/
|
||||
final case class Request(min : Int, max : Int)
|
||||
final case class Request(min: Int, max: Int)
|
||||
|
||||
/**
|
||||
* Message for transferring nanites to a recipient.
|
||||
* @param src the nanite container recognized as the sender
|
||||
*
|
||||
* @param src the nanite container recognized as the sender
|
||||
* @param amount the nanites transferred in this package
|
||||
*/
|
||||
final case class Grant(src : NtuContainer, amount : Int)
|
||||
final case class Grant(src: NtuContainer, amount: Int)
|
||||
}
|
||||
|
||||
trait NtuContainer extends TransferContainer {
|
||||
def NtuCapacitor : Int
|
||||
def NtuCapacitor: Int
|
||||
|
||||
def NtuCapacitor_=(value: Int) : Int
|
||||
def NtuCapacitor_=(value: Int): Int
|
||||
|
||||
def Definition : NtuContainerDefinition
|
||||
def Definition: NtuContainerDefinition
|
||||
}
|
||||
|
||||
trait CommonNtuContainer extends NtuContainer {
|
||||
private var ntuCapacitor : Int = 0
|
||||
private var ntuCapacitor: Int = 0
|
||||
|
||||
def NtuCapacitor : Int = ntuCapacitor
|
||||
def NtuCapacitor: Int = ntuCapacitor
|
||||
|
||||
def NtuCapacitor_=(value: Int) : Int = {
|
||||
def NtuCapacitor_=(value: Int): Int = {
|
||||
ntuCapacitor = scala.math.max(0, scala.math.min(value, Definition.MaxNtuCapacitor))
|
||||
NtuCapacitor
|
||||
}
|
||||
|
||||
def Definition : NtuContainerDefinition
|
||||
def Definition: NtuContainerDefinition
|
||||
}
|
||||
|
||||
trait NtuContainerDefinition {
|
||||
private var maxNtuCapacitor : Int = 0
|
||||
private var maxNtuCapacitor: Int = 0
|
||||
|
||||
def MaxNtuCapacitor : Int = maxNtuCapacitor
|
||||
def MaxNtuCapacitor: Int = maxNtuCapacitor
|
||||
|
||||
def MaxNtuCapacitor_=(max: Int) : Int = {
|
||||
def MaxNtuCapacitor_=(max: Int): Int = {
|
||||
maxNtuCapacitor = max
|
||||
MaxNtuCapacitor
|
||||
}
|
||||
}
|
||||
|
||||
trait NtuStorageBehavior extends Actor {
|
||||
def NtuStorageObject : NtuContainer = null
|
||||
def NtuStorageObject: NtuContainer = null
|
||||
|
||||
def storageBehavior : Receive = {
|
||||
def storageBehavior: Receive = {
|
||||
case Ntu.Offer(src) => HandleNtuOffer(sender, src)
|
||||
|
||||
case Ntu.Grant(_, 0) | Ntu.Request(0, 0) | TransferBehavior.Stopping() => StopNtuBehavior(sender)
|
||||
|
||||
case Ntu.Request(min, max) => HandleNtuRequest(sender, min, max)
|
||||
|
||||
case Ntu.Grant(src, amount) => HandleNtuGrant(sender, src, amount)
|
||||
case Ntu.Grant(src, amount) => HandleNtuGrant(sender, src, amount)
|
||||
case NtuCommand.Grant(src, amount) => HandleNtuGrant(sender, src, amount)
|
||||
}
|
||||
|
||||
def HandleNtuOffer(sender : ActorRef, src : NtuContainer) : Unit
|
||||
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit
|
||||
|
||||
def StopNtuBehavior(sender : ActorRef) : Unit
|
||||
def StopNtuBehavior(sender: ActorRef): Unit
|
||||
|
||||
def HandleNtuRequest(sender : ActorRef, min : Int, max : Int) : Unit
|
||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit
|
||||
|
||||
def HandleNtuGrant(sender : ActorRef, src : NtuContainer, amount : Int) : Unit
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit
|
||||
}
|
||||
|
|
|
|||
|
|
@ -498,7 +498,7 @@ class PlayerControl(player: Player) extends Actor with JammableBehavior with Dam
|
|||
val (interface, slotNumber) = player.VehicleSeated match {
|
||||
case Some(mech_guid) =>
|
||||
(
|
||||
zone.Map.TerminalToInterface.get(mech_guid.guid),
|
||||
zone.map.TerminalToInterface.get(mech_guid.guid),
|
||||
if (!player.Implants.exists({ case (implantType, _, _) => implantType == implant_type })) {
|
||||
//no duplicates
|
||||
player.InstallImplant(implant)
|
||||
|
|
@ -547,7 +547,7 @@ class PlayerControl(player: Player) extends Actor with JammableBehavior with Dam
|
|||
val (interface, slotNumber) = player.VehicleSeated match {
|
||||
case Some(mech_guid) =>
|
||||
(
|
||||
zone.Map.TerminalToInterface.get(mech_guid.guid),
|
||||
zone.map.TerminalToInterface.get(mech_guid.guid),
|
||||
player.UninstallImplant(implant_type)
|
||||
)
|
||||
case None =>
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
player: Player
|
||||
): Boolean = {
|
||||
val zone = obj.Zone
|
||||
zone.Map.TerminalToInterface.get(obj.GUID.guid) match {
|
||||
zone.map.TerminalToInterface.get(obj.GUID.guid) match {
|
||||
case Some(interface_guid) =>
|
||||
(zone.GUID(interface_guid) match {
|
||||
case Some(interface) => !interface.Destroyed
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.serverobject.resourcesilo
|
|||
|
||||
import akka.actor.{Actor, ActorRef}
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
import net.psforever.objects.serverobject.transfer.TransferBehavior
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
|
|
@ -10,7 +11,6 @@ import net.psforever.objects.{Ntu, NtuContainer, NtuStorageBehavior}
|
|||
import net.psforever.types.PlanetSideEmpire
|
||||
import services.Service
|
||||
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import services.local.{LocalAction, LocalServiceMessage}
|
||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
|
@ -18,59 +18,69 @@ import scala.concurrent.duration._
|
|||
|
||||
/**
|
||||
* An `Actor` that handles messages being dispatched to a specific `Resource Silo`.
|
||||
*
|
||||
* @param resourceSilo the `Resource Silo` object being governed
|
||||
*/
|
||||
class ResourceSiloControl(resourceSilo: ResourceSilo) extends Actor with FactionAffinityBehavior.Check with NtuStorageBehavior {
|
||||
class ResourceSiloControl(resourceSilo: ResourceSilo)
|
||||
extends Actor
|
||||
with FactionAffinityBehavior.Check
|
||||
with NtuStorageBehavior {
|
||||
def FactionObject: FactionAffinity = resourceSilo
|
||||
private[this] val log = org.log4s.getLogger
|
||||
var panelAnimationFunc : Int=>Unit = PanelAnimation
|
||||
|
||||
private[this] val log = org.log4s.getLogger
|
||||
var panelAnimationFunc: Int => Unit = PanelAnimation
|
||||
|
||||
def receive: Receive = {
|
||||
case "startup" =>
|
||||
// todo: This is just a temporary solution to drain NTU over time. When base object destruction is properly implemented NTU should be deducted when base objects repair themselves
|
||||
// context.system.scheduler.schedule(5 second, 5 second, self, ResourceSilo.UpdateChargeLevel(-1))
|
||||
// context.system.scheduler.schedule(5 second, 5 second, self, ResourceSilo.UpdateChargeLevel(-1))
|
||||
context.become(Processing)
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
def Processing : Receive = checkBehavior
|
||||
.orElse(storageBehavior)
|
||||
.orElse {
|
||||
case CommonMessages.Use(player, _) =>
|
||||
if(resourceSilo.Faction == PlanetSideEmpire.NEUTRAL || player.Faction == resourceSilo.Faction) {
|
||||
resourceSilo.Zone.Vehicles.find(v => v.PassengerInSeat(player).contains(0)) match {
|
||||
case Some(vehicle) =>
|
||||
context.system.scheduler.scheduleOnce(delay = 1000 milliseconds, vehicle.Actor, TransferBehavior.Discharging(Ntu.Nanites))
|
||||
case _ =>
|
||||
def Processing: Receive =
|
||||
checkBehavior
|
||||
.orElse(storageBehavior)
|
||||
.orElse {
|
||||
case CommonMessages.Use(player, _) =>
|
||||
if (resourceSilo.Faction == PlanetSideEmpire.NEUTRAL || player.Faction == resourceSilo.Faction) {
|
||||
resourceSilo.Zone.Vehicles.find(v => v.PassengerInSeat(player).contains(0)) match {
|
||||
case Some(vehicle) =>
|
||||
context.system.scheduler.scheduleOnce(
|
||||
delay = 1000 milliseconds,
|
||||
vehicle.Actor,
|
||||
TransferBehavior.Discharging(Ntu.Nanites)
|
||||
)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
||||
LowNtuWarning(enabled)
|
||||
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
||||
LowNtuWarning(enabled)
|
||||
|
||||
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
||||
UpdateChargeLevel(amount)
|
||||
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
||||
UpdateChargeLevel(amount)
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
def LowNtuWarning(enabled : Boolean) : Unit = {
|
||||
def LowNtuWarning(enabled: Boolean): Unit = {
|
||||
resourceSilo.LowNtuWarningOn = enabled
|
||||
log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to $enabled")
|
||||
val building = resourceSilo.Owner
|
||||
val zone = building.Zone
|
||||
val zone = building.Zone
|
||||
building.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
zone.Id,
|
||||
AvatarAction.PlanetsideAttribute(building.GUID, 47, if(resourceSilo.LowNtuWarningOn) 1 else 0)
|
||||
AvatarAction.PlanetsideAttribute(building.GUID, 47, if (resourceSilo.LowNtuWarningOn) 1 else 0)
|
||||
)
|
||||
}
|
||||
|
||||
def UpdateChargeLevel(amount: Int) : Unit = {
|
||||
val siloChargeBeforeChange = resourceSilo.NtuCapacitor
|
||||
def UpdateChargeLevel(amount: Int): Unit = {
|
||||
val siloChargeBeforeChange = resourceSilo.NtuCapacitor
|
||||
val siloDisplayBeforeChange = resourceSilo.CapacitorDisplay
|
||||
val building = resourceSilo.Owner.asInstanceOf[Building]
|
||||
val zone = building.Zone
|
||||
val building = resourceSilo.Owner.asInstanceOf[Building]
|
||||
val zone = building.Zone
|
||||
|
||||
// Increase if positive passed in or decrease charge level if negative number is passed in
|
||||
resourceSilo.NtuCapacitor += amount
|
||||
|
|
@ -80,67 +90,65 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) extends Actor with Faction
|
|||
|
||||
// Only send updated capacitor display value to all clients if it has actually changed
|
||||
if (resourceSilo.CapacitorDisplay != siloDisplayBeforeChange) {
|
||||
log.trace(s"Silo ${resourceSilo.GUID} NTU bar level has changed from $siloDisplayBeforeChange to ${resourceSilo.CapacitorDisplay}")
|
||||
resourceSilo.Owner.Actor ! Building.SendMapUpdate(all_clients = true)
|
||||
log.trace(
|
||||
s"Silo ${resourceSilo.GUID} NTU bar level has changed from $siloDisplayBeforeChange to ${resourceSilo.CapacitorDisplay}"
|
||||
)
|
||||
resourceSilo.Owner.Actor ! BuildingActor.MapUpdate()
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
zone.Id,
|
||||
AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)
|
||||
)
|
||||
building.Actor ! Building.SendMapUpdate(all_clients = true)
|
||||
building.Actor ! BuildingActor.MapUpdate()
|
||||
}
|
||||
val ntuIsLow = resourceSilo.NtuCapacitor.toFloat / resourceSilo.Definition.MaxNtuCapacitor.toFloat < 0.2f
|
||||
if (resourceSilo.LowNtuWarningOn && !ntuIsLow) {
|
||||
LowNtuWarning(enabled = false)
|
||||
}
|
||||
else if (!resourceSilo.LowNtuWarningOn && ntuIsLow) {
|
||||
} else if (!resourceSilo.LowNtuWarningOn && ntuIsLow) {
|
||||
LowNtuWarning(enabled = true)
|
||||
}
|
||||
if (resourceSilo.NtuCapacitor == 0 && siloChargeBeforeChange > 0) {
|
||||
// Oops, someone let the base run out of power. Shut it all down.
|
||||
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttribute(building.GUID, 48, 1))
|
||||
building.Faction = PlanetSideEmpire.NEUTRAL
|
||||
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.SetEmpire(building.GUID, PlanetSideEmpire.NEUTRAL))
|
||||
building.TriggerZoneMapUpdate()
|
||||
}
|
||||
else if (siloChargeBeforeChange == 0 && resourceSilo.NtuCapacitor > 0) {
|
||||
building.Actor ! BuildingActor.SetFaction(PlanetSideEmpire.NEUTRAL)
|
||||
} else if (siloChargeBeforeChange == 0 && resourceSilo.NtuCapacitor > 0) {
|
||||
// Power restored. Reactor Online. Sensors Online. Weapons Online. All systems nominal.
|
||||
//todo: Check generator is online before starting up
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
zone.Id,
|
||||
AvatarAction.PlanetsideAttribute(building.GUID, 48, 0)
|
||||
)
|
||||
building.TriggerZoneMapUpdate()
|
||||
building.Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The silo will agree to offers until its nanite capacitor is completely full.
|
||||
*/
|
||||
def HandleNtuOffer(sender : ActorRef, src : NtuContainer) : Unit = {
|
||||
sender ! (if(resourceSilo.NtuCapacitor < resourceSilo.MaxNtuCapacitor) {
|
||||
Ntu.Request(0, resourceSilo.MaxNtuCapacitor - resourceSilo.NtuCapacitor)
|
||||
}
|
||||
else {
|
||||
StopNtuBehavior(sender)
|
||||
Ntu.Request(0, 0)
|
||||
})
|
||||
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = {
|
||||
sender ! (if (resourceSilo.NtuCapacitor < resourceSilo.MaxNtuCapacitor) {
|
||||
Ntu.Request(0, resourceSilo.MaxNtuCapacitor - resourceSilo.NtuCapacitor)
|
||||
} else {
|
||||
StopNtuBehavior(sender)
|
||||
Ntu.Request(0, 0)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the animation trigger and attempt the stop animation.
|
||||
*/
|
||||
def StopNtuBehavior(sender : ActorRef) : Unit = {
|
||||
def StopNtuBehavior(sender: ActorRef): Unit = {
|
||||
panelAnimationFunc = PanelAnimation
|
||||
panelAnimationFunc(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
*
|
||||
* @param sender na
|
||||
* @param min a minimum amount of nanites requested;
|
||||
* @param max the amount of nanites required to not make further requests;
|
||||
* @param min a minimum amount of nanites requested;
|
||||
* @param max the amount of nanites required to not make further requests;
|
||||
*/
|
||||
def HandleNtuRequest(sender : ActorRef, min : Int, max : Int) : Unit = {
|
||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit = {
|
||||
val originalAmount = resourceSilo.NtuCapacitor
|
||||
UpdateChargeLevel(-min)
|
||||
sender ! Ntu.Grant(resourceSilo, originalAmount - resourceSilo.NtuCapacitor)
|
||||
|
|
@ -149,8 +157,8 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) extends Actor with Faction
|
|||
/**
|
||||
* Accept nanites into the silo capacitor and set the animation state.
|
||||
*/
|
||||
def HandleNtuGrant(sender : ActorRef, src : NtuContainer, amount : Int) : Unit = {
|
||||
if(amount != 0) {
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit = {
|
||||
if (amount != 0) {
|
||||
val originalAmount = resourceSilo.NtuCapacitor
|
||||
UpdateChargeLevel(amount)
|
||||
panelAnimationFunc(resourceSilo.NtuCapacitor - originalAmount)
|
||||
|
|
@ -162,19 +170,20 @@ class ResourceSiloControl(resourceSilo: ResourceSilo) extends Actor with Faction
|
|||
* When charging from another source of nanites, the silo's panels will glow
|
||||
* and a particle affect will traverse towards the panels from about ten meters in front of the silo.
|
||||
* These effects are both controlled by thee same packet.
|
||||
*
|
||||
* @param trigger if positive, activate the animation;
|
||||
* if negative or zero, disable the animation
|
||||
*/
|
||||
def PanelAnimation(trigger : Int) : Unit = {
|
||||
def PanelAnimation(trigger: Int): Unit = {
|
||||
val zone = resourceSilo.Zone
|
||||
zone.VehicleEvents ! VehicleServiceMessage(
|
||||
zone.Id,
|
||||
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, resourceSilo.GUID, 49, if(trigger > 0) 1 else 0)
|
||||
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, resourceSilo.GUID, 49, if (trigger > 0) 1 else 0)
|
||||
) // panel glow on & orb particles on
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing this turn.
|
||||
*/
|
||||
def SkipPanelAnimation(trigger : Int) : Unit = { }
|
||||
def SkipPanelAnimation(trigger: Int): Unit = {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package net.psforever.objects.serverobject.structures
|
|||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||
import net.psforever.objects.{Default, GlobalDefinitions, Player}
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.serverobject.generator.Generator
|
||||
|
|
@ -13,18 +14,19 @@ import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
|||
import net.psforever.objects.serverobject.terminals.CaptureTerminal
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.{Additional1, Additional2, Additional3}
|
||||
import net.psforever.packet.game.BuildingInfoUpdateMessage
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState, Vector3}
|
||||
import scalax.collection.{Graph, GraphEdge}
|
||||
import services.Service
|
||||
import services.local.{LocalAction, LocalServiceMessage}
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
|
||||
class Building(
|
||||
private val name: String,
|
||||
private val building_guid: Int,
|
||||
private val map_id: Int,
|
||||
private val zone: Zone,
|
||||
private val buildingType: StructureType.Value,
|
||||
private val buildingType: StructureType,
|
||||
private val buildingDefinition: BuildingDefinition
|
||||
) extends AmenityOwner {
|
||||
|
||||
|
|
@ -71,7 +73,8 @@ class Building(
|
|||
} else if (IsCapitol) {
|
||||
UpdateForceDomeStatus()
|
||||
}
|
||||
TriggerZoneMapUpdate()
|
||||
// FIXME null check is a bad idea but tests rely on it
|
||||
if (Zone.actor != null) Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
Faction
|
||||
}
|
||||
|
||||
|
|
@ -126,10 +129,6 @@ class Building(
|
|||
}
|
||||
}
|
||||
|
||||
def TriggerZoneMapUpdate(): Unit = {
|
||||
if (Actor != Default.Actor) Actor ! Building.TriggerZoneMapUpdate(Zone.Number)
|
||||
}
|
||||
|
||||
def UpdateForceDomeStatus(): Unit = {
|
||||
if (IsCapitol) {
|
||||
val originalStatus = ForceDomeActive
|
||||
|
|
@ -155,7 +154,7 @@ class Building(
|
|||
Zone.Id,
|
||||
LocalAction.UpdateForceDomeStatus(Service.defaultPlayerGUID, GUID, ForceDomeActive)
|
||||
)
|
||||
Actor ! Building.SendMapUpdate(all_clients = true)
|
||||
Actor ! BuildingActor.MapUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -171,27 +170,7 @@ class Building(
|
|||
}
|
||||
}
|
||||
|
||||
def Info: (
|
||||
Int,
|
||||
Boolean,
|
||||
PlanetSideEmpire.Value,
|
||||
Long,
|
||||
PlanetSideEmpire.Value,
|
||||
Long,
|
||||
Option[Additional1],
|
||||
PlanetSideGeneratorState.Value,
|
||||
Boolean,
|
||||
Boolean,
|
||||
Int,
|
||||
Int,
|
||||
List[Additional2],
|
||||
Long,
|
||||
Boolean,
|
||||
Int,
|
||||
Option[Additional3],
|
||||
Boolean,
|
||||
Boolean
|
||||
) = {
|
||||
def infoUpdateMessage(): BuildingInfoUpdateMessage = {
|
||||
val ntuLevel: Int = NtuLevel
|
||||
//if we have a capture terminal, get the hack status & time (in milliseconds) from control console if it exists
|
||||
val (hacking, hackingFaction, hackTime): (Boolean, PlanetSideEmpire.Value, Long) = CaptureTerminal match {
|
||||
|
|
@ -264,31 +243,33 @@ class Building(
|
|||
}
|
||||
}
|
||||
}
|
||||
//out
|
||||
(
|
||||
|
||||
BuildingInfoUpdateMessage(
|
||||
Zone.Number,
|
||||
MapId,
|
||||
ntuLevel,
|
||||
hacking,
|
||||
hackingFaction,
|
||||
hackTime,
|
||||
if (ntuLevel > 0) Faction else PlanetSideEmpire.NEUTRAL,
|
||||
0, //!! Field != 0 will cause malformed packet. See class def.
|
||||
0, // Field != 0 will cause malformed packet
|
||||
None,
|
||||
generatorState,
|
||||
spawnTubesNormal,
|
||||
ForceDomeActive,
|
||||
forceDomeActive,
|
||||
latticeBenefit,
|
||||
48, //cavern_benefit; !! Field > 0 will cause malformed packet. See class def.
|
||||
Nil, //unk4
|
||||
0, //unk5
|
||||
false, //unk6
|
||||
8, //!! unk7 Field != 8 will cause malformed packet. See class def.
|
||||
None, //unk7x
|
||||
boostSpawnPain, //boost_spawn_pain
|
||||
boostGeneratorPain //boost_generator_pain
|
||||
48, // cavern benefit
|
||||
Nil, // unk4,
|
||||
0, // unk5
|
||||
false, // unk6
|
||||
8, // unk7 Field != 8 will cause malformed packet
|
||||
None, // unk7x
|
||||
boostSpawnPain,
|
||||
boostGeneratorPain
|
||||
)
|
||||
}
|
||||
|
||||
def BuildingType: StructureType.Value = buildingType
|
||||
def BuildingType: StructureType = buildingType
|
||||
|
||||
override def Zone_=(zone: Zone): Zone = Zone //building never leaves zone after being set in constructor
|
||||
|
||||
|
|
@ -307,58 +288,51 @@ object Building {
|
|||
GUID = net.psforever.types.PlanetSideGUID(0)
|
||||
}
|
||||
|
||||
def apply(name: String, guid: Int, map_id: Int, zone: Zone, buildingType: StructureType.Value): Building = {
|
||||
def apply(name: String, guid: Int, map_id: Int, zone: Zone, buildingType: StructureType): Building = {
|
||||
new Building(name, guid, map_id, zone, buildingType, GlobalDefinitions.building)
|
||||
}
|
||||
|
||||
def Structure(
|
||||
buildingType: StructureType.Value,
|
||||
buildingType: StructureType,
|
||||
location: Vector3,
|
||||
rotation: Vector3,
|
||||
definition: BuildingDefinition
|
||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): Building = {
|
||||
import akka.actor.Props
|
||||
val obj = new Building(name, guid, map_id, zone, buildingType, definition)
|
||||
obj.Position = location
|
||||
obj.Orientation = rotation
|
||||
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$map_id-$buildingType-building")
|
||||
obj.Actor = context.spawn(BuildingActor(zone, obj), s"$map_id-$buildingType-building").toClassic
|
||||
obj
|
||||
}
|
||||
|
||||
def Structure(
|
||||
buildingType: StructureType.Value,
|
||||
buildingType: StructureType,
|
||||
location: Vector3
|
||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): Building = {
|
||||
import akka.actor.Props
|
||||
|
||||
val obj = new Building(name, guid, map_id, zone, buildingType, GlobalDefinitions.building)
|
||||
obj.Position = location
|
||||
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$map_id-$buildingType-building")
|
||||
obj.Actor = context.spawn(BuildingActor(zone, obj), s"$map_id-$buildingType-building").toClassic
|
||||
obj
|
||||
}
|
||||
|
||||
def Structure(
|
||||
buildingType: StructureType.Value
|
||||
buildingType: StructureType
|
||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): Building = {
|
||||
import akka.actor.Props
|
||||
val obj = new Building(name, guid, map_id, zone, buildingType, GlobalDefinitions.building)
|
||||
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$map_id-$buildingType-building")
|
||||
obj.Actor = context.spawn(BuildingActor(zone, obj), s"$map_id-$buildingType-building").toClassic
|
||||
obj
|
||||
}
|
||||
|
||||
def Structure(
|
||||
buildingType: StructureType.Value,
|
||||
buildingType: StructureType,
|
||||
buildingDefinition: BuildingDefinition,
|
||||
location: Vector3
|
||||
)(name: String, guid: Int, id: Int, zone: Zone, context: ActorContext): Building = {
|
||||
import akka.actor.Props
|
||||
val obj = new Building(name, guid, id, zone, buildingType, buildingDefinition)
|
||||
obj.Position = location
|
||||
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$id-$buildingType-building")
|
||||
context.spawn(BuildingActor(zone, obj), s"$id-$buildingType-building").toClassic
|
||||
obj
|
||||
}
|
||||
|
||||
final case class AmenityStateChange(obj: Amenity)
|
||||
final case class SendMapUpdate(all_clients: Boolean)
|
||||
final case class TriggerZoneMapUpdate(zone_num: Int)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.structures
|
||||
|
||||
import akka.actor.{Actor, ActorRef}
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
import net.psforever.objects.serverobject.generator.Generator
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.zones.InterstellarCluster
|
||||
import net.psforever.packet.game.BuildingInfoUpdateMessage
|
||||
import services.ServiceManager
|
||||
import services.ServiceManager.Lookup
|
||||
import services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage, GalaxyServiceResponse}
|
||||
|
||||
class BuildingControl(building: Building) extends Actor with FactionAffinityBehavior.Check {
|
||||
def FactionObject: FactionAffinity = building
|
||||
var galaxyService: ActorRef = ActorRef.noSender
|
||||
var interstellarCluster: ActorRef = ActorRef.noSender
|
||||
private[this] val log = org.log4s.getLogger
|
||||
|
||||
override def preStart = {
|
||||
log.trace(s"Starting BuildingControl for ${building.GUID} / ${building.MapId}")
|
||||
ServiceManager.serviceManager ! Lookup("galaxy")
|
||||
ServiceManager.serviceManager ! Lookup("cluster")
|
||||
}
|
||||
|
||||
def receive: Receive =
|
||||
checkBehavior.orElse {
|
||||
case ServiceManager.LookupResult("galaxy", endpoint) =>
|
||||
galaxyService = endpoint
|
||||
log.trace("BuildingControl: Building " + building.GUID + " Got galaxy service " + endpoint)
|
||||
case ServiceManager.LookupResult("cluster", endpoint) =>
|
||||
interstellarCluster = endpoint
|
||||
log.trace("BuildingControl: Building " + building.GUID + " Got interstellar cluster service " + endpoint)
|
||||
|
||||
case FactionAffinity.ConvertFactionAffinity(faction) =>
|
||||
val originalAffinity = building.Faction
|
||||
if (originalAffinity != (building.Faction = faction)) {
|
||||
building.Amenities.foreach(_.Actor forward FactionAffinity.ConfirmFactionAffinity())
|
||||
}
|
||||
sender ! FactionAffinity.AssertFactionAffinity(building, faction)
|
||||
|
||||
case Building.AmenityStateChange(obj: SpawnTube) =>
|
||||
if (building.Amenities.contains(obj)) {
|
||||
SendMapUpdate(allClients = true)
|
||||
}
|
||||
|
||||
case Building.AmenityStateChange(obj: Generator) =>
|
||||
if (building.Amenities.contains(obj)) {
|
||||
SendMapUpdate(allClients = true)
|
||||
}
|
||||
|
||||
case Building.TriggerZoneMapUpdate(zone_num: Int) =>
|
||||
if (interstellarCluster != ActorRef.noSender) interstellarCluster ! InterstellarCluster.ZoneMapUpdate(zone_num)
|
||||
|
||||
case Building.SendMapUpdate(all_clients: Boolean) =>
|
||||
SendMapUpdate(all_clients)
|
||||
|
||||
case _ =>
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param allClients na
|
||||
*/
|
||||
def SendMapUpdate(allClients: Boolean): Unit = {
|
||||
val zoneNumber = building.Zone.Number
|
||||
val buildingNumber = building.MapId
|
||||
log.trace(s"sending BuildingInfoUpdateMessage update - zone=$zoneNumber, building=$buildingNumber")
|
||||
val (
|
||||
ntuLevel,
|
||||
isHacked,
|
||||
empireHack,
|
||||
hackTimeRemaining,
|
||||
controllingEmpire,
|
||||
unk1,
|
||||
unk1x,
|
||||
generatorState,
|
||||
spawnTubesNormal,
|
||||
forceDomeActive,
|
||||
latticeBenefit,
|
||||
cavernBenefit,
|
||||
unk4,
|
||||
unk5,
|
||||
unk6,
|
||||
unk7,
|
||||
unk7x,
|
||||
boostSpawnPain,
|
||||
boostGeneratorPain
|
||||
) = building.Info
|
||||
val msg = BuildingInfoUpdateMessage(
|
||||
zoneNumber,
|
||||
buildingNumber,
|
||||
ntuLevel,
|
||||
isHacked,
|
||||
empireHack,
|
||||
hackTimeRemaining,
|
||||
controllingEmpire,
|
||||
unk1,
|
||||
unk1x,
|
||||
generatorState,
|
||||
spawnTubesNormal,
|
||||
forceDomeActive,
|
||||
latticeBenefit,
|
||||
cavernBenefit,
|
||||
unk4,
|
||||
unk5,
|
||||
unk6,
|
||||
unk7,
|
||||
unk7x,
|
||||
boostSpawnPain,
|
||||
boostGeneratorPain
|
||||
)
|
||||
|
||||
if (allClients) {
|
||||
if (galaxyService != ActorRef.noSender) galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(msg))
|
||||
} else {
|
||||
// Fake a GalaxyServiceResponse response back to just the sender
|
||||
sender ! GalaxyServiceResponse("", GalaxyResponse.MapUpdate(msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.structures
|
||||
|
||||
/**
|
||||
* An `Enumeration` of the kinds of building structures found in the game.
|
||||
* This is merely a kludge for more a future, more complicated internal object that handles base operations.
|
||||
*/
|
||||
object StructureType extends Enumeration {
|
||||
type Type = Value
|
||||
import enumeratum.{EnumEntry, Enum}
|
||||
|
||||
val Bridge, // technically, a "bridge section"
|
||||
Building, // generic
|
||||
Bunker, // low accessible ground cover
|
||||
Facility, // large base
|
||||
Platform, // outdoor amenities disconnected from a proper base like the vehicle spawn pads in sanctuary
|
||||
Tower, // also called field towers: watchtower, air tower, gun tower
|
||||
WarpGate // transport point between zones
|
||||
= Value
|
||||
sealed trait StructureType extends EnumEntry
|
||||
|
||||
object StructureType extends Enum[StructureType] {
|
||||
val values = findValues
|
||||
|
||||
case object Bridge extends StructureType // technically, a "bridge section"
|
||||
case object Building extends StructureType // generic
|
||||
case object Bunker extends StructureType // low accessible ground cover
|
||||
case object Facility extends StructureType // large base
|
||||
case object Platform
|
||||
extends StructureType // outdoor amenities disconnected from a proper base like the vehicle spawn pads in sanctuary
|
||||
case object Tower extends StructureType // also called field towers: watchtower, air tower, gun tower
|
||||
case object WarpGate extends StructureType // transport point between zones
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ import akka.actor.ActorContext
|
|||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.{GlobalDefinitions, NtuContainer, SpawnPoint}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.{Additional1, Additional2, Additional3}
|
||||
import net.psforever.packet.game.BuildingInfoUpdateMessage
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGeneratorState, Vector3}
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
|
|
@ -20,28 +22,10 @@ class WarpGate(name: String, building_guid: Int, map_id: Int, zone: Zone, buildi
|
|||
/** what faction views this warp gate as a broadcast gate */
|
||||
private var broadcast: mutable.Set[PlanetSideEmpire.Value] = mutable.Set.empty[PlanetSideEmpire.Value]
|
||||
|
||||
override def Info: (
|
||||
Int,
|
||||
Boolean,
|
||||
PlanetSideEmpire.Value,
|
||||
Long,
|
||||
PlanetSideEmpire.Value,
|
||||
Long,
|
||||
Option[Additional1],
|
||||
PlanetSideGeneratorState.Value,
|
||||
Boolean,
|
||||
Boolean,
|
||||
Int,
|
||||
Int,
|
||||
List[Additional2],
|
||||
Long,
|
||||
Boolean,
|
||||
Int,
|
||||
Option[Additional3],
|
||||
Boolean,
|
||||
Boolean
|
||||
) = {
|
||||
(
|
||||
override def infoUpdateMessage(): BuildingInfoUpdateMessage = {
|
||||
BuildingInfoUpdateMessage(
|
||||
Zone.Number,
|
||||
MapId,
|
||||
0,
|
||||
false,
|
||||
PlanetSideEmpire.NEUTRAL,
|
||||
|
|
@ -179,19 +163,17 @@ object WarpGate {
|
|||
}
|
||||
|
||||
def Structure(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): WarpGate = {
|
||||
import akka.actor.Props
|
||||
val obj = new WarpGate(name, guid, map_id, zone, GlobalDefinitions.warpgate)
|
||||
obj.Actor = context.actorOf(Props(classOf[WarpGateControl], obj), name = s"$map_id-$guid-gate")
|
||||
obj.Actor = context.spawn(BuildingActor(zone, obj), name = s"$map_id-$guid-gate").toClassic
|
||||
obj
|
||||
}
|
||||
|
||||
def Structure(
|
||||
location: Vector3
|
||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): WarpGate = {
|
||||
import akka.actor.Props
|
||||
val obj = new WarpGate(name, guid, map_id, zone, GlobalDefinitions.warpgate)
|
||||
obj.Position = location
|
||||
obj.Actor = context.actorOf(Props(classOf[WarpGateControl], obj), name = s"$map_id-$guid-gate")
|
||||
obj.Actor = context.spawn(BuildingActor(zone, obj), name = s"$map_id-$guid-gate").toClassic
|
||||
obj
|
||||
}
|
||||
|
||||
|
|
@ -199,10 +181,9 @@ object WarpGate {
|
|||
location: Vector3,
|
||||
buildingDefinition: WarpGateDefinition
|
||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): WarpGate = {
|
||||
import akka.actor.Props
|
||||
val obj = new WarpGate(name, guid, map_id, zone, buildingDefinition)
|
||||
obj.Position = location
|
||||
obj.Actor = context.actorOf(Props(classOf[WarpGateControl], obj), name = s"$map_id-$guid-gate")
|
||||
obj.Actor = context.spawn(BuildingActor(zone, obj), name = s"$map_id-$guid-gate").toClassic
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.serverobject.structures
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import net.psforever.objects.{Ntu, NtuContainer, NtuStorageBehavior}
|
||||
|
||||
class WarpGateControl(gate : WarpGate) extends BuildingControl(gate)
|
||||
with NtuStorageBehavior {
|
||||
override def receive : Receive = storageBehavior.orElse(super.receive)
|
||||
|
||||
/**
|
||||
* Warp gates don't need to respond to offers.
|
||||
*/
|
||||
def HandleNtuOffer(sender : ActorRef, src : NtuContainer) : Unit = {}
|
||||
|
||||
/**
|
||||
* Warp gates don't need to stop.
|
||||
*/
|
||||
def StopNtuBehavior(sender : ActorRef) : Unit = {}
|
||||
|
||||
/**
|
||||
* When processing a request, the only important consideration is whether the warp gate is active.
|
||||
* @param sender na
|
||||
* @param min a minimum amount of nanites requested;
|
||||
* @param max the amount of nanites required to not make further requests;
|
||||
*/
|
||||
def HandleNtuRequest(sender : ActorRef, min : Int, max : Int) : Unit = {
|
||||
sender ! Ntu.Grant(gate, if (gate.Active) min else 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Warp gates doesn't need additional nanites.
|
||||
* For the sake of not letting any go to waste, it will give back those nanites for free.
|
||||
*/
|
||||
def HandleNtuGrant(sender : ActorRef, src : NtuContainer, amount : Int) : Unit = {
|
||||
sender ! Ntu.Grant(gate, amount)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
package net.psforever.objects.vehicles
|
||||
|
||||
import akka.actor.{ActorRef, Cancellable}
|
||||
import net.psforever.actors.commands.NtuCommand
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
import net.psforever.objects.serverobject.deploy.Deployment
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||
import net.psforever.objects.serverobject.structures.WarpGate
|
||||
|
|
@ -10,21 +12,22 @@ import net.psforever.objects.{NtuContainer, _}
|
|||
import net.psforever.types.DriveState
|
||||
import services.Service
|
||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration._
|
||||
|
||||
trait AntTransferBehavior extends TransferBehavior
|
||||
with NtuStorageBehavior {
|
||||
var ntuChargingTick : Cancellable = Default.Cancellable
|
||||
var panelAnimationFunc : ()=>Unit = NoCharge
|
||||
trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||
var ntuChargingTick: Cancellable = Default.Cancellable
|
||||
var panelAnimationFunc: () => Unit = NoCharge
|
||||
|
||||
def TransferMaterial = Ntu.Nanites
|
||||
def ChargeTransferObject : Vehicle with NtuContainer
|
||||
|
||||
def antBehavior : Receive = storageBehavior.orElse(transferBehavior)
|
||||
def ChargeTransferObject: Vehicle with NtuContainer
|
||||
|
||||
def ActivatePanelsForChargingEvent(vehicle : NtuContainer) : Unit = {
|
||||
def antBehavior: Receive = storageBehavior.orElse(transferBehavior)
|
||||
|
||||
def ActivatePanelsForChargingEvent(vehicle: NtuContainer): Unit = {
|
||||
val zone = vehicle.Zone
|
||||
zone.VehicleEvents ! VehicleServiceMessage(
|
||||
zone.Id,
|
||||
|
|
@ -33,7 +36,7 @@ trait AntTransferBehavior extends TransferBehavior
|
|||
}
|
||||
|
||||
/** Charging */
|
||||
def StartNtuChargingEvent(vehicle : NtuContainer) : Unit = {
|
||||
def StartNtuChargingEvent(vehicle: NtuContainer): Unit = {
|
||||
val zone = vehicle.Zone
|
||||
zone.VehicleEvents ! VehicleServiceMessage(
|
||||
zone.Id,
|
||||
|
|
@ -41,8 +44,8 @@ trait AntTransferBehavior extends TransferBehavior
|
|||
) // orb particle effect on
|
||||
}
|
||||
|
||||
def UpdateNtuUI(vehicle : Vehicle with NtuContainer) : Unit = {
|
||||
if(vehicle.Seats.values.exists(_.isOccupied)) {
|
||||
def UpdateNtuUI(vehicle: Vehicle with NtuContainer): Unit = {
|
||||
if (vehicle.Seats.values.exists(_.isOccupied)) {
|
||||
val display = scala.math.ceil(vehicle.NtuCapacitorScaled).toLong
|
||||
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
|
||||
vehicle.Actor.toString,
|
||||
|
|
@ -51,76 +54,82 @@ trait AntTransferBehavior extends TransferBehavior
|
|||
}
|
||||
}
|
||||
|
||||
def HandleChargingEvent(target : TransferContainer) : Boolean = {
|
||||
def HandleChargingEvent(target: TransferContainer): Boolean = {
|
||||
ntuChargingTick.cancel
|
||||
val obj = ChargeTransferObject
|
||||
//log.trace(s"NtuCharging: Vehicle $guid is charging NTU capacitor.")
|
||||
if(obj.NtuCapacitor < obj.Definition.MaxNtuCapacitor) {
|
||||
if (obj.NtuCapacitor < obj.Definition.MaxNtuCapacitor) {
|
||||
//charging
|
||||
panelAnimationFunc = InitialCharge
|
||||
transferTarget = Some(target)
|
||||
transferEvent = TransferBehavior.Event.Charging
|
||||
val (min, max) = target match {
|
||||
case _ : WarpGate =>
|
||||
target match {
|
||||
case _: WarpGate =>
|
||||
//ANTs would charge from 0-100% in roughly 75s on live (https://www.youtube.com/watch?v=veOWToR2nSk&feature=youtu.be&t=1194)
|
||||
val ntuMax = obj.Definition.MaxNtuCapacitor - obj.NtuCapacitor
|
||||
val ntuMin = scala.math.min(obj.Definition.MaxNtuCapacitor/75, ntuMax)
|
||||
(ntuMin, ntuMax)
|
||||
val max = obj.Definition.MaxNtuCapacitor - obj.NtuCapacitor
|
||||
target.Actor ! BuildingActor.Ntu(
|
||||
NtuCommand.Request(scala.math.min(obj.Definition.MaxNtuCapacitor / 75, max), context.self)
|
||||
)
|
||||
case _ =>
|
||||
(0, 0)
|
||||
}
|
||||
target.Actor ! Ntu.Request(min, max)
|
||||
ntuChargingTick = context.system.scheduler.scheduleOnce(delay = 1000 milliseconds, self, TransferBehavior.Charging(TransferMaterial)) // Repeat until fully charged, or minor delay
|
||||
|
||||
ntuChargingTick = context.system.scheduler.scheduleOnce(
|
||||
delay = 1000 milliseconds,
|
||||
self,
|
||||
TransferBehavior.Charging(TransferMaterial)
|
||||
) // Repeat until fully charged, or minor delay
|
||||
true
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Fully charged
|
||||
TryStopChargingEvent(obj)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
def ReceiveAndDepositUntilFull(vehicle : Vehicle, amount : Int) : Boolean = {
|
||||
def ReceiveAndDepositUntilFull(vehicle: Vehicle, amount: Int): Boolean = {
|
||||
val isNotFull = (vehicle.NtuCapacitor += amount) < vehicle.Definition.MaxNtuCapacitor
|
||||
UpdateNtuUI(vehicle)
|
||||
isNotFull
|
||||
}
|
||||
|
||||
/** Discharging */
|
||||
def HandleDischargingEvent(target : TransferContainer) : Boolean = {
|
||||
def HandleDischargingEvent(target: TransferContainer): Boolean = {
|
||||
//log.trace(s"NtuDischarging: Vehicle $guid is discharging NTU into silo $silo_guid")
|
||||
val obj = ChargeTransferObject
|
||||
if(obj.NtuCapacitor > 0) {
|
||||
if (obj.NtuCapacitor > 0) {
|
||||
panelAnimationFunc = InitialDischarge
|
||||
transferTarget = Some(target)
|
||||
transferEvent = TransferBehavior.Event.Discharging
|
||||
target.Actor ! Ntu.Offer(obj)
|
||||
ntuChargingTick.cancel
|
||||
ntuChargingTick = context.system.scheduler.scheduleOnce(delay = 1000 milliseconds, self, TransferBehavior.Discharging(TransferMaterial))
|
||||
ntuChargingTick = context.system.scheduler.scheduleOnce(
|
||||
delay = 1000 milliseconds,
|
||||
self,
|
||||
TransferBehavior.Discharging(TransferMaterial)
|
||||
)
|
||||
true
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
TryStopChargingEvent(obj)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
def NoCharge() : Unit = {}
|
||||
def NoCharge(): Unit = {}
|
||||
|
||||
def InitialCharge() : Unit = {
|
||||
def InitialCharge(): Unit = {
|
||||
panelAnimationFunc = NoCharge
|
||||
val obj = ChargeTransferObject
|
||||
ActivatePanelsForChargingEvent(obj)
|
||||
StartNtuChargingEvent(obj)
|
||||
}
|
||||
|
||||
def InitialDischarge() : Unit = {
|
||||
def InitialDischarge(): Unit = {
|
||||
panelAnimationFunc = NoCharge
|
||||
ActivatePanelsForChargingEvent(ChargeTransferObject)
|
||||
}
|
||||
|
||||
def WithdrawAndTransmit(vehicle : Vehicle, maxRequested : Int) : Any = {
|
||||
val chargeable = ChargeTransferObject
|
||||
def WithdrawAndTransmit(vehicle: Vehicle, maxRequested: Int): Any = {
|
||||
val chargeable = ChargeTransferObject
|
||||
var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), maxRequested)
|
||||
chargeable.NtuCapacitor -= chargeToDeposit
|
||||
UpdateNtuUI(chargeable)
|
||||
|
|
@ -128,27 +137,34 @@ trait AntTransferBehavior extends TransferBehavior
|
|||
}
|
||||
|
||||
/** Stopping */
|
||||
override def TryStopChargingEvent(container : TransferContainer) : Unit = {
|
||||
override def TryStopChargingEvent(container: TransferContainer): Unit = {
|
||||
val vehicle = ChargeTransferObject
|
||||
ntuChargingTick.cancel
|
||||
if(transferEvent != TransferBehavior.Event.None) {
|
||||
if(vehicle.DeploymentState == DriveState.Deployed) {
|
||||
if (transferEvent != TransferBehavior.Event.None) {
|
||||
if (vehicle.DeploymentState == DriveState.Deployed) {
|
||||
//turning off glow/orb effects on ANT doesn't seem to work when deployed. Try to undeploy ANT first
|
||||
vehicle.Actor ! Deployment.TryUndeploy(DriveState.Undeploying)
|
||||
ntuChargingTick = context.system.scheduler.scheduleOnce(250 milliseconds, self, TransferBehavior.Stopping())
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//vehicle is not deployed; just do cleanup
|
||||
val vguid = vehicle.GUID
|
||||
val zone = vehicle.Zone
|
||||
val vguid = vehicle.GUID
|
||||
val zone = vehicle.Zone
|
||||
val zoneId = zone.Id
|
||||
val events = zone.VehicleEvents
|
||||
if(transferEvent == TransferBehavior.Event.Charging) {
|
||||
events ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 52, 0L)) // panel glow off
|
||||
events ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 49, 0L)) // orb particle effect off
|
||||
}
|
||||
else if(transferEvent == TransferBehavior.Event.Discharging) {
|
||||
events ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 52, 0L)) // panel glow off
|
||||
if (transferEvent == TransferBehavior.Event.Charging) {
|
||||
events ! VehicleServiceMessage(
|
||||
zoneId,
|
||||
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 52, 0L)
|
||||
) // panel glow off
|
||||
events ! VehicleServiceMessage(
|
||||
zoneId,
|
||||
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 49, 0L)
|
||||
) // orb particle effect off
|
||||
} else if (transferEvent == TransferBehavior.Event.Discharging) {
|
||||
events ! VehicleServiceMessage(
|
||||
zoneId,
|
||||
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 52, 0L)
|
||||
) // panel glow off
|
||||
}
|
||||
}
|
||||
panelAnimationFunc = NoCharge
|
||||
|
|
@ -156,39 +172,37 @@ trait AntTransferBehavior extends TransferBehavior
|
|||
}
|
||||
}
|
||||
|
||||
def StopNtuBehavior(sender : ActorRef) : Unit = TryStopChargingEvent(ChargeTransferObject)
|
||||
def StopNtuBehavior(sender: ActorRef): Unit = TryStopChargingEvent(ChargeTransferObject)
|
||||
|
||||
def HandleNtuOffer(sender : ActorRef, src : NtuContainer) : Unit = { }
|
||||
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = {}
|
||||
|
||||
def HandleNtuRequest(sender : ActorRef, min : Int, max : Int) : Unit = {
|
||||
if(transferEvent == TransferBehavior.Event.Discharging) {
|
||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit = {
|
||||
if (transferEvent == TransferBehavior.Event.Discharging) {
|
||||
val chargeable = ChargeTransferObject
|
||||
val chargeToDeposit = if(min == 0) {
|
||||
val chargeToDeposit = if (min == 0) {
|
||||
transferTarget match {
|
||||
case Some(silo : ResourceSilo) =>
|
||||
case Some(silo: ResourceSilo) =>
|
||||
// Silos would charge from 0-100% in roughly 105s on live (~20%-100% https://youtu.be/veOWToR2nSk?t=1402)
|
||||
scala.math.min(scala.math.min(silo.MaxNtuCapacitor / 105, chargeable.NtuCapacitor), max)
|
||||
case _ =>
|
||||
0
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
scala.math.min(min, chargeable.NtuCapacitor)
|
||||
}
|
||||
// var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), max)
|
||||
// var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), max)
|
||||
chargeable.NtuCapacitor -= chargeToDeposit
|
||||
UpdateNtuUI(chargeable)
|
||||
sender ! Ntu.Grant(chargeable, chargeToDeposit)
|
||||
}
|
||||
}
|
||||
|
||||
def HandleNtuGrant(sender : ActorRef, src : NtuContainer, amount : Int) : Unit = {
|
||||
if(transferEvent == TransferBehavior.Event.Charging) {
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit = {
|
||||
if (transferEvent == TransferBehavior.Event.Charging) {
|
||||
val obj = ChargeTransferObject
|
||||
if(ReceiveAndDepositUntilFull(obj, amount)) {
|
||||
if (ReceiveAndDepositUntilFull(obj, amount)) {
|
||||
panelAnimationFunc()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
TryStopChargingEvent(obj)
|
||||
sender ! Ntu.Request(0, 0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,228 +0,0 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.zones
|
||||
|
||||
import akka.actor.{Actor, Props}
|
||||
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.Random
|
||||
|
||||
/**
|
||||
* The root of the universe of one-continent planets, codified by the game's "Interstellar Map."
|
||||
* Constructs each zone and thus instigates the construction of every server object in the game world.
|
||||
* The nanite flow connecting all of these `Zone`s is called the "Intercontinental Lattice."<br>
|
||||
* <br>
|
||||
* The process of "construction" and "initialization" and "configuration" are referenced at this level.
|
||||
* These concepts are not the same thing;
|
||||
* the distinction is important.
|
||||
* "Construction" and "instantiation" of the cluster merely produces the "facade" of the different `Zone` entities.
|
||||
* In such a `List`, every built `Zone` is capable of being a destination on the "Intercontinental lattice."
|
||||
* "Initialization" and "configuration" of the cluster refers to the act of completing the "Intercontinental Lattice"
|
||||
* by connecting different terminus warp gates together.
|
||||
* Other activities involve event management and managing wide-reaching and factional attributes.
|
||||
* @param zones a `List` of continental `Zone` arenas
|
||||
*/
|
||||
class InterstellarCluster(zones: List[Zone]) extends Actor {
|
||||
private[this] val log = org.log4s.getLogger
|
||||
val recallRandom = new Random()
|
||||
log.info("Starting interplanetary cluster ...")
|
||||
|
||||
/**
|
||||
* Create a `ZoneActor` for each `Zone`.
|
||||
* That `Actor` is sent a packet that would start the construction of the `Zone`'s server objects.
|
||||
* The process is maintained this way to allow every planet to be created and configured in separate stages.
|
||||
*/
|
||||
override def preStart(): Unit = {
|
||||
super.preStart()
|
||||
for (zone <- zones) {
|
||||
log.info(s"Built continent ${zone.Id}")
|
||||
zone.Actor = context.actorOf(Props(classOf[ZoneActor], zone), s"${zone.Id}-actor")
|
||||
zone.Actor ! Zone.Init()
|
||||
}
|
||||
}
|
||||
|
||||
def receive: Receive = {
|
||||
case InterstellarCluster.GetWorld(zoneId) =>
|
||||
log.info(s"Asked to find $zoneId")
|
||||
recursiveFindWorldInCluster(zones.iterator, _.Id == zoneId) match {
|
||||
case Some(continent) =>
|
||||
sender ! InterstellarCluster.GiveWorld(zoneId, continent)
|
||||
case None =>
|
||||
log.error(s"Requested zone $zoneId could not be found")
|
||||
}
|
||||
|
||||
case InterstellarCluster.RequestClientInitialization() =>
|
||||
zones.foreach(zone => { sender ! Zone.ClientInitialization(zone.ClientInitialization()) })
|
||||
sender ! InterstellarCluster.ClientInitializationComplete() //will be processed after all Zones
|
||||
|
||||
case msg @ Zone.Lattice.RequestSpawnPoint(zone_number, _, _, _) =>
|
||||
recursiveFindWorldInCluster(zones.iterator, _.Number == zone_number) match {
|
||||
case Some(zone) =>
|
||||
zone.Actor forward msg
|
||||
|
||||
case None => //zone_number does not exist
|
||||
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, None)
|
||||
}
|
||||
case InterstellarCluster.ListPlayers() =>
|
||||
var players: List[String] = List()
|
||||
|
||||
for (zone <- zones) {
|
||||
val zonePlayers = zone.Players
|
||||
for (player <- zonePlayers) {
|
||||
players ::= player.name
|
||||
}
|
||||
}
|
||||
sender ! InterstellarCluster.PlayerList(players)
|
||||
|
||||
case InterstellarCluster.GetZoneIds() =>
|
||||
sender ! InterstellarCluster.ZoneIds(zones.map(_.Number))
|
||||
|
||||
case msg @ Zone.Lattice.RequestSpecificSpawnPoint(zone_number, _, _, _) =>
|
||||
recursiveFindWorldInCluster(zones.iterator, _.Number == zone_number) match {
|
||||
case Some(zone) =>
|
||||
zone.Actor forward msg
|
||||
|
||||
case None => //zone_number does not exist
|
||||
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, None)
|
||||
}
|
||||
case InterstellarCluster.ZoneMapUpdate(zone_num: Int) =>
|
||||
val zone = zones.find(x => x.Number == zone_num).get
|
||||
zone.Buildings
|
||||
.filter(_._2.BuildingType == StructureType.Facility)
|
||||
.values
|
||||
.foreach(b => b.Actor ! Building.SendMapUpdate(all_clients = true))
|
||||
|
||||
case Zoning.InstantAction.Request(faction) =>
|
||||
val interests = zones.flatMap { zone =>
|
||||
//TODO zone.Locked.contains(faction)
|
||||
zone.HotSpotData
|
||||
.collect { case spot if zone.Players.nonEmpty => (zone, spot) }
|
||||
} /* ignore zones without existing population */
|
||||
if (interests.nonEmpty) {
|
||||
val (withAllies, onlyEnemies) = interests
|
||||
.map {
|
||||
case (zone, spot) =>
|
||||
(
|
||||
zone,
|
||||
spot,
|
||||
ZoneActor.FindLocalSpawnPointsInZone(zone, spot.DisplayLocation, faction, 0).getOrElse(Nil)
|
||||
)
|
||||
} /* pair hotspots and spawn points */
|
||||
.filter { case (_, _, spawns) => spawns.nonEmpty } /* faction spawns must exist */
|
||||
.sortBy({ case (_, spot, _) => spot.Activity.values.foldLeft(0)(_ + _.Heat) })(
|
||||
Ordering[Int].reverse
|
||||
) /* greatest > least */
|
||||
.partition { case (_, spot, _) => spot.ActivityBy().contains(faction) } /* us versus them */
|
||||
withAllies.headOption.orElse(onlyEnemies.headOption) match {
|
||||
case Some((zone, info, List(spawnPoint))) =>
|
||||
//one spawn
|
||||
val pos = info.DisplayLocation
|
||||
sender ! Zoning.InstantAction.Located(zone, pos, spawnPoint)
|
||||
case Some((zone, info, spawns)) =>
|
||||
//multiple spawn options
|
||||
val pos = info.DisplayLocation
|
||||
val spawnPoint = spawns.minBy(point => Vector3.DistanceSquared(point.Position, pos))
|
||||
sender ! Zoning.InstantAction.Located(zone, pos, spawnPoint)
|
||||
case None =>
|
||||
//no actionable hot spots
|
||||
sender ! Zoning.InstantAction.NotLocated()
|
||||
}
|
||||
} else {
|
||||
//never had any actionable hot spots
|
||||
sender ! Zoning.InstantAction.NotLocated()
|
||||
}
|
||||
|
||||
case Zoning.Recall.Request(faction, sanctuary_id) =>
|
||||
recursiveFindWorldInCluster(zones.iterator, _.Id.equals(sanctuary_id)) match {
|
||||
case Some(zone) =>
|
||||
//TODO zone full
|
||||
val width = zone.Map.Scale.width
|
||||
val height = zone.Map.Scale.height
|
||||
//xy-coordinates indicate sanctuary spawn bias:
|
||||
val spot = math.abs(scala.util.Random.nextInt() % sender.toString.hashCode % 4) match {
|
||||
case 0 => Vector3(width, height, 0) //NE
|
||||
case 1 => Vector3(width, 0, 0) //SE
|
||||
case 2 => Vector3.Zero //SW
|
||||
case 3 => Vector3(0, height, 0) //NW
|
||||
}
|
||||
ZoneActor.FindLocalSpawnPointsInZone(zone, spot, faction, 7).getOrElse(Nil) match {
|
||||
case Nil =>
|
||||
//no spawns
|
||||
sender ! Zoning.Recall.Denied("unavailable")
|
||||
case List(spawnPoint) =>
|
||||
//one spawn
|
||||
sender ! Zoning.Recall.Located(zone, spawnPoint)
|
||||
case spawnPoints =>
|
||||
//multiple spawn options
|
||||
val spawnPoint = spawnPoints(recallRandom.nextInt(spawnPoints.length))
|
||||
sender ! Zoning.Recall.Located(zone, spawnPoint)
|
||||
}
|
||||
case None =>
|
||||
sender ! Zoning.Recall.Denied("unavailable")
|
||||
}
|
||||
|
||||
case _ =>
|
||||
log.warn(s"InterstellarCluster received unknown message");
|
||||
}
|
||||
|
||||
/**
|
||||
* Search through the `List` of `Zone` entities and find the one with the matching designation.
|
||||
* @param iter an `Iterator` of `Zone` entities
|
||||
* @param predicate a condition to check against to determine when the appropriate `Zone` is discovered
|
||||
* @return the discovered `Zone`
|
||||
*/
|
||||
@tailrec private def recursiveFindWorldInCluster(iter: Iterator[Zone], predicate: Zone => Boolean): Option[Zone] = {
|
||||
if (!iter.hasNext) {
|
||||
None
|
||||
} else {
|
||||
val cont = iter.next
|
||||
if (predicate.apply(cont)) {
|
||||
Some(cont)
|
||||
} else {
|
||||
recursiveFindWorldInCluster(iter, predicate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object InterstellarCluster {
|
||||
|
||||
/**
|
||||
* Request a hard reference to a `Zone`.
|
||||
* @param zoneId the name of the `Zone`
|
||||
*/
|
||||
final case class GetWorld(zoneId: String)
|
||||
|
||||
/**
|
||||
* Provide a hard reference to a `Zone`.
|
||||
* @param zoneId the name of the `Zone`
|
||||
* @param zone the `Zone`
|
||||
*/
|
||||
final case class GiveWorld(zoneId: String, zone: Zone)
|
||||
|
||||
final case class ListPlayers()
|
||||
final case class PlayerList(players: List[String])
|
||||
|
||||
/**
|
||||
* Signal to the cluster that a new client needs to be initialized for all listed `Zone` destinations.
|
||||
* @see `Zone`
|
||||
*/
|
||||
final case class RequestClientInitialization()
|
||||
|
||||
/**
|
||||
* Return signal intended to inform the original sender that all `Zone`s have finished being initialized.
|
||||
* @see `WorldSessionActor`
|
||||
*/
|
||||
final case class ClientInitializationComplete()
|
||||
|
||||
/**
|
||||
* Requests that all buildings within a zone send a map update for the purposes of refreshing lattice benefits, such as when a base is hacked, changes faction or loses power
|
||||
* @see `BuildingInfoUpdateMessage`
|
||||
* @param zone_num the zone number to request building map updates for
|
||||
*/
|
||||
final case class ZoneMapUpdate(zone_num: Int)
|
||||
|
||||
final case class GetZoneIds()
|
||||
final case class ZoneIds(zoneIds: List[Int])
|
||||
}
|
||||
|
|
@ -16,10 +16,11 @@ import net.psforever.objects.guid.source.LimitedNumberSource
|
|||
import net.psforever.objects.inventory.Container
|
||||
import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition}
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, Building, WarpGate}
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, AmenityOwner, Building, StructureType, WarpGate}
|
||||
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||
import net.psforever.objects.serverobject.zipline.ZipLinePath
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
|
||||
import net.psforever.types.{DriveState, PlanetSideEmpire, PlanetSideGUID, SpawnGroup, Vector3}
|
||||
import org.log4s.Logger
|
||||
import services.avatar.AvatarService
|
||||
import services.local.LocalService
|
||||
import services.vehicle.VehicleService
|
||||
|
|
@ -33,6 +34,10 @@ import scalax.collection.GraphPredef._
|
|||
import scalax.collection.GraphEdge._
|
||||
|
||||
import scala.util.Try
|
||||
import akka.actor.typed
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.vehicles.UtilityType
|
||||
|
||||
/**
|
||||
* A server object representing the one-landmass planets as well as the individual subterranean caverns.<br>
|
||||
|
|
@ -45,20 +50,21 @@ import scala.util.Try
|
|||
* Static server objects originate from the `ZoneMap`.
|
||||
* Dynamic game objects originate from player characters.
|
||||
* (Write more later.)
|
||||
* @param zoneId the privileged name that can be used as the second parameter in the packet `LoadMapMessage`
|
||||
* @param zoneMap the map of server objects upon which this `Zone` is based
|
||||
*
|
||||
* @param zoneId the privileged name that can be used as the second parameter in the packet `LoadMapMessage`
|
||||
* @param map the map of server objects upon which this `Zone` is based
|
||||
* @param zoneNumber the numerical index of the `Zone` as it is recognized in a variety of packets;
|
||||
* also used by `LivePlayerList` to indicate a specific `Zone`
|
||||
* @see `ZoneMap`<br>
|
||||
* `LoadMapMessage`<br>
|
||||
* `LivePlayerList`
|
||||
*/
|
||||
class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
||||
class Zone(private val zoneId: String, val map: ZoneMap, zoneNumber: Int) {
|
||||
|
||||
/** Governs general synchronized external requests. */
|
||||
private var actor = Default.Actor
|
||||
var actor: typed.ActorRef[ZoneActor.Command] = _
|
||||
|
||||
/** Actor that handles SOI related functionality, for example if a player is in a SOI * */
|
||||
/** Actor that handles SOI related functionality, for example if a player is in a SOI */
|
||||
private var soi = Default.Actor
|
||||
|
||||
/** Used by the globally unique identifier system to coordinate requests. */
|
||||
|
|
@ -79,8 +85,7 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
|
||||
/**
|
||||
*/
|
||||
private val constructions: ListBuffer[PlanetSideGameObject with Deployable] =
|
||||
ListBuffer[PlanetSideGameObject with Deployable]()
|
||||
private val constructions: ListBuffer[PlanetSideGameObject with Deployable] = ListBuffer()
|
||||
|
||||
/**
|
||||
*/
|
||||
|
|
@ -106,8 +111,6 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
|
||||
private var lattice: Graph[Building, UnDiEdge] = Graph()
|
||||
|
||||
private var zipLinePaths: List[ZipLinePath] = List()
|
||||
|
||||
/** key - spawn zone id, value - buildings belonging to spawn zone */
|
||||
private var spawnGroups: Map[Building, List[SpawnPoint]] = PairMap[Building, List[SpawnPoint]]()
|
||||
|
||||
|
|
@ -155,31 +158,32 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
* Execution of this operation should be fail-safe.
|
||||
* The chances of failure should be mitigated or skipped.
|
||||
* A testing routine should be run after the fact on the results of the process.
|
||||
*
|
||||
* @see `ZoneActor.ZoneSetupCheck`
|
||||
* @param context a reference to an `ActorContext` necessary for `Props`
|
||||
*/
|
||||
def Init(implicit context: ActorContext): Unit = {
|
||||
def init(implicit context: ActorContext): Unit = {
|
||||
if (accessor == Default.Actor) {
|
||||
SetupNumberPools()
|
||||
accessor = context.actorOf(
|
||||
RandomPool(25).props(
|
||||
Props(classOf[UniqueNumberSystem], this.guid, UniqueNumberSystem.AllocateNumberPoolActors(this.guid))
|
||||
),
|
||||
s"$Id-uns"
|
||||
s"zone-$Id-uns"
|
||||
)
|
||||
ground = context.actorOf(Props(classOf[ZoneGroundActor], this, equipmentOnGround), s"$Id-ground")
|
||||
deployables = context.actorOf(Props(classOf[ZoneDeployableActor], this, constructions), s"$Id-deployables")
|
||||
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this, vehicles), s"$Id-vehicles")
|
||||
population = context.actorOf(Props(classOf[ZonePopulationActor], this, players, corpses), s"$Id-players")
|
||||
ground = context.actorOf(Props(classOf[ZoneGroundActor], this, equipmentOnGround), s"zone-$Id-ground")
|
||||
deployables = context.actorOf(Props(classOf[ZoneDeployableActor], this, constructions), s"zone-$Id-deployables")
|
||||
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this, vehicles), s"zone-$Id-vehicles")
|
||||
population = context.actorOf(Props(classOf[ZonePopulationActor], this, players, corpses), s"zone-$Id-players")
|
||||
projector = context.actorOf(
|
||||
Props(classOf[ZoneHotSpotDisplay], this, hotspots, 15 seconds, hotspotHistory, 60 seconds),
|
||||
s"$Id-hotspots"
|
||||
s"zone-$Id-hotspots"
|
||||
)
|
||||
soi = context.actorOf(Props(classOf[SphereOfInfluenceActor], this), s"$Id-soi")
|
||||
soi = context.actorOf(Props(classOf[SphereOfInfluenceActor], this), s"zone-$Id-soi")
|
||||
|
||||
avatarEvents = context.actorOf(Props(classOf[AvatarService], this), s"$Id-avatar-events")
|
||||
localEvents = context.actorOf(Props(classOf[LocalService], this), s"$Id-local-events")
|
||||
vehicleEvents = context.actorOf(Props(classOf[VehicleService], this), s"$Id-vehicle-events")
|
||||
avatarEvents = context.actorOf(Props(classOf[AvatarService], this), s"zone-$Id-avatar-events")
|
||||
localEvents = context.actorOf(Props(classOf[LocalService], this), s"zone-$Id-local-events")
|
||||
vehicleEvents = context.actorOf(Props(classOf[VehicleService], this), s"zone-$Id-vehicle-events")
|
||||
|
||||
implicit val guid: NumberPoolHub = this.guid //passed into builderObject.Build implicitly
|
||||
BuildLocalObjects(context, guid)
|
||||
|
|
@ -189,7 +193,118 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
AssignAmenities()
|
||||
CreateSpawnGroups()
|
||||
|
||||
zipLinePaths = Map.ZipLinePaths
|
||||
validate()
|
||||
}
|
||||
}
|
||||
|
||||
def validate(): Unit = {
|
||||
implicit val log: Logger = org.log4s.getLogger(s"zone/$Id/sanity")
|
||||
|
||||
//check bases
|
||||
map.ObjectToBuilding.values
|
||||
.toSet[Int]
|
||||
.foreach(building_id => {
|
||||
val target = Building(building_id)
|
||||
if (target.isEmpty) {
|
||||
log.error(s"expected a building for id #$building_id")
|
||||
} else if (!target.get.HasGUID) {
|
||||
log.error(s"building #$building_id was not registered")
|
||||
}
|
||||
})
|
||||
|
||||
//check base to object associations
|
||||
map.ObjectToBuilding.keys.foreach(object_guid =>
|
||||
if (guid(object_guid).isEmpty) {
|
||||
log.error(s"expected object id $object_guid to exist, but it did not")
|
||||
}
|
||||
)
|
||||
|
||||
//check door to lock association
|
||||
map.DoorToLock.foreach({
|
||||
case (doorGuid, lockGuid) =>
|
||||
validateObject(doorGuid, (x: PlanetSideGameObject) => x.isInstanceOf[serverobject.doors.Door], "door")
|
||||
validateObject(lockGuid, (x: PlanetSideGameObject) => x.isInstanceOf[serverobject.locks.IFFLock], "IFF lock")
|
||||
})
|
||||
|
||||
//check vehicle terminal to spawn pad association
|
||||
map.TerminalToSpawnPad.foreach({
|
||||
case (termGuid, padGuid) =>
|
||||
validateObject(
|
||||
termGuid,
|
||||
(x: PlanetSideGameObject) => x.isInstanceOf[serverobject.terminals.Terminal],
|
||||
"vehicle terminal"
|
||||
)
|
||||
validateObject(
|
||||
padGuid,
|
||||
(x: PlanetSideGameObject) => x.isInstanceOf[serverobject.pad.VehicleSpawnPad],
|
||||
"vehicle spawn pad"
|
||||
)
|
||||
})
|
||||
|
||||
//check implant terminal mech to implant terminal interface association
|
||||
map.TerminalToInterface.foreach({
|
||||
case (mechGuid, interfaceGuid) =>
|
||||
validateObject(
|
||||
mechGuid,
|
||||
(x: PlanetSideGameObject) => x.isInstanceOf[serverobject.implantmech.ImplantTerminalMech],
|
||||
"implant terminal mech"
|
||||
)
|
||||
validateObject(
|
||||
interfaceGuid,
|
||||
(o: PlanetSideGameObject) => o.isInstanceOf[serverobject.terminals.Terminal],
|
||||
"implant terminal interface"
|
||||
)
|
||||
})
|
||||
|
||||
//check manned turret to weapon association
|
||||
map.TurretToWeapon.foreach({
|
||||
case (turretGuid, weaponGuid) =>
|
||||
validateObject(
|
||||
turretGuid,
|
||||
(o: PlanetSideGameObject) => o.isInstanceOf[serverobject.turret.FacilityTurret],
|
||||
"facility turret mount"
|
||||
)
|
||||
if (
|
||||
validateObject(
|
||||
weaponGuid,
|
||||
(o: PlanetSideGameObject) => o.isInstanceOf[net.psforever.objects.Tool],
|
||||
"facility turret weapon"
|
||||
)
|
||||
) {
|
||||
if (GUID(weaponGuid).get.asInstanceOf[Tool].AmmoSlots.count(!_.Box.HasGUID) > 0) {
|
||||
log.error(s"expected weapon $weaponGuid has an unregistered ammunition unit")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover an object from a collection and perform any number of validating tests upon it.
|
||||
* If the object fails any tests, log an error.
|
||||
*
|
||||
* @param objectGuid the unique indentifier being checked against the `guid` access point
|
||||
* @param test a test for the discovered object;
|
||||
* expects at least `Type` checking
|
||||
* @param description an explanation of how the object, if not discovered, should be identified
|
||||
* @return `true` if the object was discovered and validates correctly;
|
||||
* `false` if the object failed any tests
|
||||
*/
|
||||
def validateObject(
|
||||
objectGuid: Int,
|
||||
test: PlanetSideGameObject => Boolean,
|
||||
description: String
|
||||
)(implicit log: Logger): Boolean = {
|
||||
try {
|
||||
if (!test(GUID(objectGuid).get)) {
|
||||
log.error(s"expected id $objectGuid to be a $description, but it was not")
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
log.error(s"expected a $description at id $objectGuid but no object is initialized - $e")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,42 +328,89 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
//guid.AddPool("l", (60001 to 65535).toList).Selector = new RandomSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to the primary `Actor` that governs this `Zone`.
|
||||
* @return an `ActorRef`
|
||||
* @see `ZoneActor`<br>
|
||||
* `Zone.Init`
|
||||
*/
|
||||
def Actor: ActorRef = actor
|
||||
|
||||
/**
|
||||
* Give this `Zone` an `Actor` that will govern its interactions sequentially.
|
||||
* @param zoneActor an `ActorRef` for this `Zone`;
|
||||
* will not overwrite any existing governance unless `noSender`
|
||||
* @return an `ActorRef`
|
||||
* @see `ZoneActor`
|
||||
*/
|
||||
def Actor_=(zoneActor: ActorRef): ActorRef = {
|
||||
if (actor == Default.Actor) {
|
||||
actor = zoneActor
|
||||
def findSpawns(
|
||||
faction: PlanetSideEmpire.Value,
|
||||
spawnGroups: Seq[SpawnGroup]
|
||||
): List[(AmenityOwner, Iterable[SpawnPoint])] = {
|
||||
val ams = spawnGroups.contains(SpawnGroup.AMS)
|
||||
val structures = spawnGroups.collect {
|
||||
case SpawnGroup.Facility =>
|
||||
StructureType.Facility
|
||||
case SpawnGroup.Tower =>
|
||||
StructureType.Tower
|
||||
case SpawnGroup.WarpGate =>
|
||||
StructureType.WarpGate
|
||||
case SpawnGroup.Sanctuary =>
|
||||
StructureType.Building
|
||||
}
|
||||
Actor
|
||||
|
||||
SpawnGroups()
|
||||
.filter {
|
||||
case (building, spawns) =>
|
||||
spawns.nonEmpty &&
|
||||
spawns.exists(_.Offline == false) &&
|
||||
structures.contains(building.BuildingType)
|
||||
}
|
||||
.filter {
|
||||
case (building, _) =>
|
||||
building match {
|
||||
case warpGate: WarpGate =>
|
||||
warpGate.Faction == faction || warpGate.Faction == PlanetSideEmpire.NEUTRAL || warpGate.Broadcast
|
||||
case building =>
|
||||
building.Faction == faction
|
||||
}
|
||||
}
|
||||
.map {
|
||||
case (building, spawns) =>
|
||||
(building, spawns.filter(!_.Offline))
|
||||
}
|
||||
.concat(
|
||||
(if (ams) Vehicles else List())
|
||||
.filter(vehicle =>
|
||||
vehicle.Definition == GlobalDefinitions.ams &&
|
||||
!vehicle.Destroyed &&
|
||||
vehicle.DeploymentState == DriveState.Deployed &&
|
||||
vehicle.Faction == faction
|
||||
)
|
||||
.map(vehicle =>
|
||||
(
|
||||
vehicle,
|
||||
vehicle.Utilities.values
|
||||
.filter(util => util.UtilType == UtilityType.ams_respawn_tube)
|
||||
.map(_().asInstanceOf[SpawnTube])
|
||||
)
|
||||
)
|
||||
)
|
||||
.toList
|
||||
|
||||
}
|
||||
|
||||
def findNearestSpawnPoints(
|
||||
faction: PlanetSideEmpire.Value,
|
||||
location: Vector3,
|
||||
spawnGroups: Seq[SpawnGroup]
|
||||
): Option[List[SpawnPoint]] = {
|
||||
findSpawns(faction, spawnGroups)
|
||||
.sortBy {
|
||||
case (spawn, _) =>
|
||||
Vector3.DistanceSquared(location, spawn.Position.xy)
|
||||
}
|
||||
.collectFirst {
|
||||
case (_, spawnPoints) if spawnPoints.nonEmpty =>
|
||||
spawnPoints.toList
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The privileged name that can be used as the second parameter in the packet `LoadMapMessage`.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
def Id: String = zoneId
|
||||
|
||||
/**
|
||||
* The map of server objects upon which this `Zone` is based
|
||||
* @return the map
|
||||
*/
|
||||
def Map: ZoneMap = zoneMap
|
||||
|
||||
/**
|
||||
* The numerical index of the `Zone` as it is recognized in a variety of packets.
|
||||
*
|
||||
* @return the abstract index position of this `Zone`
|
||||
*/
|
||||
def Number: Int = zoneNumber
|
||||
|
|
@ -268,7 +430,7 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
* @return synchronized reference to the globally unique identifier system
|
||||
*/
|
||||
def GUID(hub: NumberPoolHub): Boolean = {
|
||||
if (actor == Default.Actor && guid.Pools.values.foldLeft(0)(_ + _.Count) == 0) {
|
||||
if (actor == null && guid.Pools.values.foldLeft(0)(_ + _.Count) == 0) {
|
||||
import org.fusesource.jansi.Ansi.Color.RED
|
||||
import org.fusesource.jansi.Ansi.ansi
|
||||
println(
|
||||
|
|
@ -407,12 +569,12 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
lattice
|
||||
}
|
||||
|
||||
def ZipLinePaths: List[ZipLinePath] = {
|
||||
zipLinePaths
|
||||
def zipLinePaths: List[ZipLinePath] = {
|
||||
map.ZipLinePaths
|
||||
}
|
||||
|
||||
private def BuildLocalObjects(implicit context: ActorContext, guid: NumberPoolHub): Unit = {
|
||||
Map.LocalObjects.foreach({ builderObject =>
|
||||
map.LocalObjects.foreach({ builderObject =>
|
||||
builderObject.Build
|
||||
|
||||
val obj = guid(builderObject.Id)
|
||||
|
|
@ -426,7 +588,7 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
//guard against errors here, but don't worry about specifics; let ZoneActor.ZoneSetupCheck complain about problems
|
||||
val other: ListBuffer[IdentifiableEntity] = new ListBuffer[IdentifiableEntity]()
|
||||
//turret to weapon
|
||||
Map.TurretToWeapon.foreach({
|
||||
map.TurretToWeapon.foreach({
|
||||
case (turret_guid, weapon_guid) =>
|
||||
((GUID(turret_guid) match {
|
||||
case Some(obj: FacilityTurret) =>
|
||||
|
|
@ -456,7 +618,7 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
}
|
||||
|
||||
private def MakeBuildings(implicit context: ActorContext): PairMap[Int, Building] = {
|
||||
val buildingList = Map.LocalBuildings
|
||||
val buildingList = map.LocalBuildings
|
||||
val registrationKeys: Map[Int, Try[LoanedKey]] = buildingList.map {
|
||||
case ((_, building_guid: Int, _), _) =>
|
||||
(building_guid, guid.register(building_guid))
|
||||
|
|
@ -471,7 +633,7 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
}
|
||||
|
||||
private def AssignAmenities(): Unit = {
|
||||
Map.ObjectToBuilding.foreach({
|
||||
map.ObjectToBuilding.foreach({
|
||||
case (object_guid, building_id) =>
|
||||
(buildings.get(building_id), guid(object_guid)) match {
|
||||
case (Some(building), Some(amenity)) =>
|
||||
|
|
@ -498,7 +660,7 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
|||
}
|
||||
|
||||
private def MakeLattice(): Unit = {
|
||||
lattice ++= Map.LatticeLink.map {
|
||||
lattice ++= map.LatticeLink.map {
|
||||
case (source, target) =>
|
||||
val (sourceBuilding, targetBuilding) = (Building(source), Building(target)) match {
|
||||
case (Some(sBuilding), Some(tBuilding)) => (sBuilding, tBuilding)
|
||||
|
|
@ -650,12 +812,6 @@ object Zone {
|
|||
new Zone(id, map, number)
|
||||
}
|
||||
|
||||
/**
|
||||
* Message to initialize the `Zone`.
|
||||
* @see `Zone.Init(implicit ActorContext)`
|
||||
*/
|
||||
final case class Init()
|
||||
|
||||
object Population {
|
||||
|
||||
/**
|
||||
|
|
@ -730,79 +886,6 @@ object Zone {
|
|||
final case class Remove(player: Player)
|
||||
}
|
||||
|
||||
object Lattice {
|
||||
|
||||
/**
|
||||
* Message requesting that the current zone determine where a `player` can spawn.
|
||||
* @param zone_number this zone's numeric identifier
|
||||
* @param position the locality that the result should adhere
|
||||
* @param faction which empire's spawn options should be available
|
||||
* @param spawn_group the category of spawn points the request wants searched
|
||||
*/
|
||||
final case class RequestSpawnPoint(
|
||||
zone_number: Int,
|
||||
position: Vector3,
|
||||
faction: PlanetSideEmpire.Value,
|
||||
spawn_group: Int
|
||||
)
|
||||
|
||||
object RequestSpawnPoint {
|
||||
|
||||
/**
|
||||
* Overloaded constructor for `RequestSpawnPoint`.
|
||||
* @param zone_number this zone's numeric identifier
|
||||
* @param player the `Player` object
|
||||
* @param spawn_group the category of spawn points the request wants searched
|
||||
*/
|
||||
def apply(zone_number: Int, player: Player, spawn_group: Int): RequestSpawnPoint = {
|
||||
RequestSpawnPoint(zone_number, player.Position, player.Faction, spawn_group)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Message requesting a particular spawn point in the current zone.
|
||||
* @param zone_number this zone's numeric identifier
|
||||
* @param position the locality that the result should adhere
|
||||
* @param faction which empire's spawn options should be available
|
||||
* @param target the identifier of the spawn object
|
||||
*/
|
||||
final case class RequestSpecificSpawnPoint(
|
||||
zone_number: Int,
|
||||
position: Vector3,
|
||||
faction: PlanetSideEmpire.Value,
|
||||
target: PlanetSideGUID
|
||||
)
|
||||
|
||||
object RequestSpecificSpawnPoint {
|
||||
|
||||
/**
|
||||
* Overloaded constructor for `RequestSpecificSpawnPoint`.
|
||||
* @param zone_number this zone's numeric identifier
|
||||
* @param player the `Player` object
|
||||
* @param target the identifier of the spawn object
|
||||
*/
|
||||
def apply(zone_number: Int, player: Player, target: PlanetSideGUID): RequestSpecificSpawnPoint = {
|
||||
RequestSpecificSpawnPoint(zone_number, player.Position, player.Faction, target)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Message that returns a discovered spawn point to a request source.
|
||||
* @param zone_id the zone's text identifier
|
||||
* @param spawn_point the spawn point holding object
|
||||
*/
|
||||
final case class SpawnPoint(zone_id: String, spawn_point: net.psforever.objects.SpawnPoint)
|
||||
|
||||
/**
|
||||
* Message that informs a request source that a spawn point could not be discovered with the previous criteria.
|
||||
* @param zone_number this zone's numeric identifier
|
||||
* @param spawn_group the spawn point holding object;
|
||||
* if `None`, then the previous `zone_number` could not be found;
|
||||
* otherwise, no spawn points could be found in the zone
|
||||
*/
|
||||
final case class NoValidSpawnPoint(zone_number: Int, spawn_group: Option[Int])
|
||||
}
|
||||
|
||||
object Ground {
|
||||
final case class DropItem(item: Equipment, pos: Vector3, orient: Vector3)
|
||||
final case class ItemOnGround(item: Equipment, pos: Vector3, orient: Vector3)
|
||||
|
|
|
|||
|
|
@ -1,395 +0,0 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.zones
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject, SpawnPoint, Tool}
|
||||
import net.psforever.objects.serverobject.structures.{AmenityOwner, StructureType, WarpGate}
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.vehicles.UtilityType
|
||||
import net.psforever.types.{DriveState, PlanetSideEmpire, Vector3}
|
||||
import org.log4s.Logger
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param zone the `Zone` governed by this `Actor`
|
||||
*/
|
||||
class ZoneActor(zone: Zone) extends Actor {
|
||||
private[this] val log = org.log4s.getLogger
|
||||
|
||||
def receive: Receive = Init
|
||||
|
||||
def Init: Receive = {
|
||||
case Zone.Init() =>
|
||||
zone.Init
|
||||
ZoneSetupCheck()
|
||||
context.become(Processing)
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
def Processing: Receive = {
|
||||
//frwd to Population Actor
|
||||
case msg @ Zone.Population.Join =>
|
||||
zone.Population forward msg
|
||||
|
||||
case msg @ Zone.Population.Leave =>
|
||||
zone.Population forward msg
|
||||
|
||||
case msg @ Zone.Population.Spawn =>
|
||||
zone.Population forward msg
|
||||
|
||||
case msg @ Zone.Population.Release =>
|
||||
zone.Population forward msg
|
||||
|
||||
case msg @ Zone.Corpse.Add =>
|
||||
zone.Population forward msg
|
||||
|
||||
case msg @ Zone.Corpse.Remove =>
|
||||
zone.Population forward msg
|
||||
|
||||
//frwd to Ground Actor
|
||||
case msg @ Zone.Ground.DropItem =>
|
||||
zone.Ground forward msg
|
||||
|
||||
case msg @ Zone.Ground.PickupItem =>
|
||||
zone.Ground forward msg
|
||||
|
||||
//frwd to Deployable Actor
|
||||
case msg @ Zone.Deployable.Build =>
|
||||
zone.Deployables forward msg
|
||||
|
||||
case msg @ Zone.Deployable.Dismiss =>
|
||||
zone.Deployables forward msg
|
||||
|
||||
//frwd to Vehicle Actor
|
||||
case msg @ Zone.Vehicle.Spawn =>
|
||||
zone.Transport forward msg
|
||||
|
||||
case msg @ Zone.Vehicle.Despawn =>
|
||||
zone.Transport forward msg
|
||||
|
||||
//frwd to Projector actor
|
||||
case msg @ Zone.HotSpot.Activity =>
|
||||
zone.Activity forward msg
|
||||
|
||||
case msg @ Zone.HotSpot.UpdateNow =>
|
||||
zone.Activity forward msg
|
||||
|
||||
case msg @ Zone.HotSpot.ClearAll =>
|
||||
zone.Activity forward msg
|
||||
|
||||
//own
|
||||
case Zone.Lattice.RequestSpawnPoint(zone_number, position, faction, spawn_group) =>
|
||||
if (zone_number == zone.Number) {
|
||||
ZoneActor.FindLocalSpawnPointsInZone(zone, position, faction, spawn_group) match {
|
||||
case Some(Nil) | None =>
|
||||
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, Some(spawn_group))
|
||||
|
||||
case Some(List(tube)) =>
|
||||
sender ! Zone.Lattice.SpawnPoint(zone.Id, tube)
|
||||
|
||||
case Some(tubes) =>
|
||||
val tube = scala.util.Random.shuffle(tubes).head
|
||||
sender ! Zone.Lattice.SpawnPoint(zone.Id, tube)
|
||||
}
|
||||
} else { //wrong zone_number
|
||||
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, None)
|
||||
}
|
||||
|
||||
case Zone.Lattice.RequestSpecificSpawnPoint(zone_number, _, faction, target) =>
|
||||
if (zone_number == zone.Number) {
|
||||
//is our spawn point some other privileged vehicle?
|
||||
zone.Vehicles
|
||||
.collectFirst({
|
||||
case vehicle: SpawnPoint if vehicle.Faction == faction && vehicle.GUID == target =>
|
||||
Some(vehicle) //the vehicle itself is the spawn point
|
||||
case vehicle if vehicle.Faction == faction && vehicle.GUID == target =>
|
||||
vehicle.Utilities.values.find { util =>
|
||||
util().isInstanceOf[SpawnPoint]
|
||||
} match {
|
||||
case None =>
|
||||
None
|
||||
case Some(util) =>
|
||||
Some(util().asInstanceOf[SpawnTube]) //the vehicle's utility is the spawn point
|
||||
}
|
||||
})
|
||||
.orElse({
|
||||
//is our spawn point a building itself (like a warp gate)?
|
||||
val friendlySpawnGroups = zone.SpawnGroups().filter {
|
||||
case (building, _) =>
|
||||
building match {
|
||||
case wg: WarpGate =>
|
||||
building.Faction == faction || building.Faction == PlanetSideEmpire.NEUTRAL || wg.Broadcast
|
||||
case _ =>
|
||||
building.Faction == faction
|
||||
}
|
||||
}
|
||||
friendlySpawnGroups
|
||||
.collectFirst({
|
||||
case (building, points) if building.MapId == target.guid && points.nonEmpty =>
|
||||
scala.util.Random.shuffle(points).head
|
||||
})
|
||||
.orElse {
|
||||
//is our spawn a conventional amenity?
|
||||
friendlySpawnGroups.values.flatten.find { point => point.GUID == target }
|
||||
}
|
||||
}) match {
|
||||
case Some(point: SpawnPoint) =>
|
||||
sender ! Zone.Lattice.SpawnPoint(zone.Id, point)
|
||||
|
||||
case _ =>
|
||||
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, Some(target.guid))
|
||||
}
|
||||
} else { //wrong zone_number
|
||||
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, None)
|
||||
}
|
||||
|
||||
case msg =>
|
||||
log.warn(s"Received unexpected message - $msg")
|
||||
}
|
||||
|
||||
def ZoneSetupCheck(): Int = {
|
||||
import ZoneActor._
|
||||
val map = zone.Map
|
||||
def guid(id: Int) = zone.GUID(id)
|
||||
val slog = org.log4s.getLogger(s"zone/${zone.Id}/sanity")
|
||||
val errors = new AtomicInteger(0)
|
||||
val validateObject: (Int, PlanetSideGameObject => Boolean, String) => Boolean = ValidateObject(guid, slog, errors)
|
||||
|
||||
//check bases
|
||||
map.ObjectToBuilding.values
|
||||
.toSet[Int]
|
||||
.foreach(building_id => {
|
||||
val target = zone.Building(building_id)
|
||||
if (target.isEmpty) {
|
||||
slog.error(s"expected a building for id #$building_id")
|
||||
errors.incrementAndGet()
|
||||
} else if (!target.get.HasGUID) {
|
||||
slog.error(s"building #$building_id was not registered")
|
||||
errors.incrementAndGet()
|
||||
}
|
||||
})
|
||||
|
||||
//check base to object associations
|
||||
map.ObjectToBuilding.keys.foreach(object_guid =>
|
||||
if (guid(object_guid).isEmpty) {
|
||||
slog.error(s"expected object id $object_guid to exist, but it did not")
|
||||
errors.incrementAndGet()
|
||||
}
|
||||
)
|
||||
|
||||
//check door to lock association
|
||||
map.DoorToLock.foreach({
|
||||
case (door_guid, lock_guid) =>
|
||||
validateObject(door_guid, DoorCheck, "door")
|
||||
validateObject(lock_guid, LockCheck, "IFF lock")
|
||||
})
|
||||
|
||||
//check vehicle terminal to spawn pad association
|
||||
map.TerminalToSpawnPad.foreach({
|
||||
case (term_guid, pad_guid) =>
|
||||
validateObject(term_guid, TerminalCheck, "vehicle terminal")
|
||||
validateObject(pad_guid, VehicleSpawnPadCheck, "vehicle spawn pad")
|
||||
})
|
||||
|
||||
//check implant terminal mech to implant terminal interface association
|
||||
map.TerminalToInterface.foreach({
|
||||
case (mech_guid, interface_guid) =>
|
||||
validateObject(mech_guid, ImplantMechCheck, "implant terminal mech")
|
||||
validateObject(interface_guid, TerminalCheck, "implant terminal interface")
|
||||
})
|
||||
|
||||
//check manned turret to weapon association
|
||||
map.TurretToWeapon.foreach({
|
||||
case (turret_guid, weapon_guid) =>
|
||||
validateObject(turret_guid, FacilityTurretCheck, "facility turret mount")
|
||||
if (validateObject(weapon_guid, WeaponCheck, "facility turret weapon")) {
|
||||
if (guid(weapon_guid).get.asInstanceOf[Tool].AmmoSlots.count(!_.Box.HasGUID) > 0) {
|
||||
slog.error(s"expected weapon $weapon_guid has an unregistered ammunition unit")
|
||||
errors.incrementAndGet()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
//output number of errors
|
||||
errors.intValue()
|
||||
}
|
||||
}
|
||||
|
||||
object ZoneActor {
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param zone na
|
||||
* @param position na
|
||||
* @param faction na
|
||||
* @param spawn_group na
|
||||
* @return na
|
||||
*/
|
||||
def FindLocalSpawnPointsInZone(
|
||||
zone: Zone,
|
||||
position: Vector3,
|
||||
faction: PlanetSideEmpire.Value,
|
||||
spawn_group: Int
|
||||
): Option[List[SpawnPoint]] = {
|
||||
(if (spawn_group == 2) {
|
||||
FindVehicleSpawnPointsInZone(zone, position, faction)
|
||||
} else {
|
||||
FindBuildingSpawnPointsInZone(zone, position, faction, spawn_group)
|
||||
}).headOption match {
|
||||
case None | Some((_, Nil)) =>
|
||||
None
|
||||
case Some((_, tubes)) =>
|
||||
Some(tubes toList)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param zone na
|
||||
* @param position na
|
||||
* @param faction na
|
||||
* @return na
|
||||
*/
|
||||
private def FindVehicleSpawnPointsInZone(
|
||||
zone: Zone,
|
||||
position: Vector3,
|
||||
faction: PlanetSideEmpire.Value
|
||||
): List[(AmenityOwner, Iterable[SpawnTube])] = {
|
||||
val xy = position.xy
|
||||
//ams
|
||||
zone.Vehicles
|
||||
.filter(veh =>
|
||||
veh.Definition == GlobalDefinitions.ams &&
|
||||
!veh.Destroyed &&
|
||||
veh.DeploymentState == DriveState.Deployed &&
|
||||
veh.Faction == faction
|
||||
)
|
||||
.sortBy(veh => Vector3.DistanceSquared(xy, veh.Position.xy))
|
||||
.map(veh =>
|
||||
(
|
||||
veh,
|
||||
veh.Utilities.values
|
||||
.filter(util => util.UtilType == UtilityType.ams_respawn_tube)
|
||||
.map(_().asInstanceOf[SpawnTube])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param zone na
|
||||
* @param position na
|
||||
* @param faction na
|
||||
* @param spawn_group na
|
||||
* @return na
|
||||
*/
|
||||
private def FindBuildingSpawnPointsInZone(
|
||||
zone: Zone,
|
||||
position: Vector3,
|
||||
faction: PlanetSideEmpire.Value,
|
||||
spawn_group: Int
|
||||
): List[(AmenityOwner, Iterable[SpawnPoint])] = {
|
||||
val xy = position.xy
|
||||
//facilities, towers, warp gates, and other buildings
|
||||
val buildingTypeSet = if (spawn_group == 0) {
|
||||
Set(StructureType.Facility, StructureType.Tower, StructureType.Building)
|
||||
} else if (spawn_group == 6) {
|
||||
Set(StructureType.Tower)
|
||||
} else if (spawn_group == 7) {
|
||||
Set(StructureType.Facility, StructureType.Building)
|
||||
} else if (spawn_group == 12) {
|
||||
Set(StructureType.WarpGate)
|
||||
} else {
|
||||
Set.empty[StructureType.Value]
|
||||
}
|
||||
zone
|
||||
.SpawnGroups()
|
||||
.collect({
|
||||
case (building, spawns) if buildingTypeSet.contains(building.BuildingType) && (building match {
|
||||
case wg: WarpGate =>
|
||||
building.Faction == faction || building.Faction == PlanetSideEmpire.NEUTRAL || wg.Broadcast
|
||||
case _ =>
|
||||
building.Faction == faction && spawns.nonEmpty && spawns.exists(_.Offline == false)
|
||||
}) =>
|
||||
(building, spawns.filter(_.Offline == false))
|
||||
})
|
||||
.toSeq
|
||||
.sortBy({
|
||||
case (building, _) =>
|
||||
Vector3.DistanceSquared(xy, building.Position.xy)
|
||||
})
|
||||
.toList
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover an object from a collection and perform any number of validating tests upon it.
|
||||
* If the object fails any tests, log an error.
|
||||
* @param guid access to an association between unique numbers and objects using some of those unique numbers
|
||||
* @param elog a contraction of "error log;"
|
||||
* accepts `String` data
|
||||
* @param object_guid the unique indentifier being checked against the `guid` access point
|
||||
* @param test a test for the discovered object;
|
||||
* expects at least `Type` checking
|
||||
* @param description an explanation of how the object, if not discovered, should be identified
|
||||
* @return `true` if the object was discovered and validates correctly;
|
||||
* `false` if the object failed any tests
|
||||
*/
|
||||
def ValidateObject(
|
||||
guid: Int => Option[PlanetSideGameObject],
|
||||
elog: Logger,
|
||||
errorCounter: AtomicInteger
|
||||
)(object_guid: Int, test: PlanetSideGameObject => Boolean, description: String): Boolean = {
|
||||
try {
|
||||
if (!test(guid(object_guid).get)) {
|
||||
elog.error(s"expected id $object_guid to be a $description, but it was not")
|
||||
errorCounter.incrementAndGet()
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
elog.error(s"expected a $description at id $object_guid but no object is initialized - $e")
|
||||
errorCounter.incrementAndGet()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
def LockCheck(obj: PlanetSideGameObject): Boolean = {
|
||||
import net.psforever.objects.serverobject.locks.IFFLock
|
||||
obj.isInstanceOf[IFFLock]
|
||||
}
|
||||
|
||||
def DoorCheck(obj: PlanetSideGameObject): Boolean = {
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
obj.isInstanceOf[Door]
|
||||
}
|
||||
|
||||
def TerminalCheck(obj: PlanetSideGameObject): Boolean = {
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
obj.isInstanceOf[Terminal]
|
||||
}
|
||||
|
||||
def ImplantMechCheck(obj: PlanetSideGameObject): Boolean = {
|
||||
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
||||
obj.isInstanceOf[ImplantTerminalMech]
|
||||
}
|
||||
|
||||
def VehicleSpawnPadCheck(obj: PlanetSideGameObject): Boolean = {
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
obj.isInstanceOf[VehicleSpawnPad]
|
||||
}
|
||||
|
||||
def FacilityTurretCheck(obj: PlanetSideGameObject): Boolean = {
|
||||
import net.psforever.objects.serverobject.turret.FacilityTurret
|
||||
obj.isInstanceOf[FacilityTurret]
|
||||
}
|
||||
|
||||
def WeaponCheck(obj: PlanetSideGameObject): Boolean = {
|
||||
import net.psforever.objects.Tool
|
||||
obj.isInstanceOf[Tool]
|
||||
}
|
||||
}
|
||||
|
|
@ -86,127 +86,4 @@ object ZoneDeployableActor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Add an `avatar` as the key of an `Avatar` to `Player` object pair in the given collection.
|
||||
// * @param avatar an `Avatar` object
|
||||
// * @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||
// * @return true, if the mapping is for a new key;
|
||||
// * false, if the key already exists
|
||||
// */
|
||||
// def PopulationJoin(avatar : Avatar, playerMap : TrieMap[Avatar, Option[Player]]) : Boolean = {
|
||||
// playerMap.get(avatar) match {
|
||||
// case Some(_) =>
|
||||
// false
|
||||
// case None =>
|
||||
// playerMap += avatar -> None
|
||||
// true
|
||||
// }
|
||||
// }
|
||||
// /**
|
||||
// * Remove an `avatar` from the key of an `Avatar` to `Player` object pair in the given collection.
|
||||
// * If a `Player` object is associated at the time, return it safely.
|
||||
// * @param avatar an `Avatar` object
|
||||
// * @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||
// * @return any `Player` object that was associated at the time the `avatar` was removed
|
||||
// */
|
||||
// def PopulationLeave(avatar : Avatar, playerMap : TrieMap[Avatar, Option[Player]]) : Option[Player] = {
|
||||
// playerMap.remove(avatar) match {
|
||||
// case None =>
|
||||
// None
|
||||
// case Some(tplayer) =>
|
||||
// tplayer
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Associate a `Player` object as a value to an existing `Avatar` object that will be its key.
|
||||
// * Do not overwrite players that are already associated.
|
||||
// * @param avatar an `Avatar` object
|
||||
// * @param player a `Player` object
|
||||
// * @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||
// * @return the `Player` object that is associated with the `Avatar` key
|
||||
// */
|
||||
// def PopulationSpawn(avatar : Avatar, player : Player, playerMap : TrieMap[Avatar, Option[Player]]) : Option[Player] = {
|
||||
// playerMap.get(avatar) match {
|
||||
// case None =>
|
||||
// None
|
||||
// case Some(tplayer) =>
|
||||
// tplayer match {
|
||||
// case Some(aplayer) =>
|
||||
// Some(aplayer)
|
||||
// case None =>
|
||||
// playerMap(avatar) = Some(player)
|
||||
// Some(player)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Disassociate a `Player` object from an existing `Avatar` object that was be its key.
|
||||
// * @param avatar an `Avatar` object
|
||||
// * @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||
// * @return any `Player` object that is associated at the time
|
||||
// */
|
||||
// def PopulationRelease(avatar : Avatar, playerMap : TrieMap[Avatar, Option[Player]]) : Option[Player] = {
|
||||
// playerMap.get(avatar) match {
|
||||
// case None =>
|
||||
// None
|
||||
// case Some(tplayer) =>
|
||||
// playerMap(avatar) = None
|
||||
// tplayer
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * If the given `player` passes a condition check, add it to the list.
|
||||
// * @param player a `Player` object
|
||||
// * @param corpseList a list of `Player` objects
|
||||
// * @return true, if the `player` was added to the list;
|
||||
// * false, otherwise
|
||||
// */
|
||||
// def CorpseAdd(player : Player, corpseList : ListBuffer[Player]) : Boolean = {
|
||||
// if(player.isBackpack) {
|
||||
// corpseList += player
|
||||
// true
|
||||
// }
|
||||
// else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Remove the given `player` from the list.
|
||||
// * @param player a `Player` object
|
||||
// * @param corpseList a list of `Player` objects
|
||||
// */
|
||||
// def CorpseRemove(player : Player, corpseList : ListBuffer[Player]) : Unit = {
|
||||
// recursiveFindCorpse(corpseList.iterator, player) match {
|
||||
// case None => ;
|
||||
// case Some(index) =>
|
||||
// corpseList.remove(index)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * A recursive function that finds and removes a specific player from a list of players.
|
||||
// * @param iter an `Iterator` of `Player` objects
|
||||
// * @param player the target `Player`
|
||||
// * @param index the index of the discovered `Player` object
|
||||
// * @return the index of the `Player` object in the list to be removed;
|
||||
// * `None`, otherwise
|
||||
// */
|
||||
// @tailrec final def recursiveFindCorpse(iter : Iterator[Player], player : Player, index : Int = 0) : Option[Int] = {
|
||||
// if(!iter.hasNext) {
|
||||
// None
|
||||
// }
|
||||
// else {
|
||||
// if(iter.next == player) {
|
||||
// Some(index)
|
||||
// }
|
||||
// else {
|
||||
// recursiveFindCorpse(iter, player, index + 1)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,8 +127,8 @@ object PacketHelpers {
|
|||
createEnumerationCodec(enum, storageCodec.xmap[Int](_.toInt, _.toLong))
|
||||
}
|
||||
|
||||
/** Create a Codec for enumeratum's Enum type */
|
||||
def createEnumCodec[E <: IntEnumEntry](enum: IntEnum[E], storageCodec: Codec[Int]): Codec[E] = {
|
||||
/** Create a Codec for enumeratum's IntEnum type */
|
||||
def createIntEnumCodec[E <: IntEnumEntry](enum: IntEnum[E], storageCodec: Codec[Int]): Codec[E] = {
|
||||
type Struct = Int :: HNil
|
||||
val struct: Codec[Struct] = storageCodec.hlist
|
||||
|
||||
|
|
@ -149,6 +149,10 @@ object PacketHelpers {
|
|||
struct.narrow[E](from, to)
|
||||
}
|
||||
|
||||
def createLongIntEnumCodec[E <: IntEnumEntry](enum: IntEnum[E], storageCodec: Codec[Long]): Codec[E] = {
|
||||
createIntEnumCodec(enum, storageCodec.xmap[Int](_.toInt, _.toLong))
|
||||
}
|
||||
|
||||
/** Common codec for how PlanetSide stores string sizes
|
||||
*
|
||||
* When the first bit of the byte is set, the size can be between [0, 127].
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ final case class BindPlayerMessage(
|
|||
bind_desc: String,
|
||||
display_icon: Boolean,
|
||||
logging: Boolean,
|
||||
spawn_group: SpawnGroup.Value,
|
||||
spawn_group: SpawnGroup,
|
||||
zone_number: Long,
|
||||
unk4: Long,
|
||||
pos: Vector3
|
||||
|
|
@ -84,7 +84,7 @@ object BindPlayerMessage extends Marshallable[BindPlayerMessage] {
|
|||
*/
|
||||
val Standard = BindPlayerMessage(BindStatus.Unbind, "", false, false, SpawnGroup.BoundAMS, 0, 0, Vector3.Zero)
|
||||
|
||||
private val spawnGroupCodec = PacketHelpers.createEnumerationCodec(SpawnGroup, uint4)
|
||||
private val spawnGroupCodec = PacketHelpers.createIntEnumCodec(SpawnGroup, uint4)
|
||||
|
||||
implicit val codec: Codec[BindPlayerMessage] = (
|
||||
("action" | BindStatus.codec) ::
|
||||
|
|
|
|||
|
|
@ -8,22 +8,25 @@ import scodec.codecs._
|
|||
|
||||
/**
|
||||
* na
|
||||
* @param unk1 when defined, na;
|
||||
* non-zero when selecting the sanctuary option from a non-sanctuary continent deployment map
|
||||
* @param spawn_type the type of spawn point destination
|
||||
* @param unk3 na
|
||||
* @param unk4 na
|
||||
* @param zone_number when defined, the continent number
|
||||
*
|
||||
* @param unk1 when defined, na;
|
||||
* non-zero when selecting the sanctuary option from a non-sanctuary continent deployment map
|
||||
* @param spawn_type the type of spawn point destination
|
||||
* @param unk3 na
|
||||
* @param unk4 na
|
||||
* @param zone_number when defined, the zone number
|
||||
*/
|
||||
final case class SpawnRequestMessage(unk1: Int, spawn_type: SpawnGroup.Value, unk3: Int, unk4: Int, zone_number: Int)
|
||||
final case class SpawnRequestMessage(unk1: Int, spawn_type: SpawnGroup, unk3: Int, unk4: Int, zone_number: Int)
|
||||
extends PlanetSideGamePacket {
|
||||
type Packet = SpawnRequestMessage
|
||||
|
||||
def opcode = GamePacketOpcode.SpawnRequestMessage
|
||||
|
||||
def encode = SpawnRequestMessage.encode(this)
|
||||
}
|
||||
|
||||
object SpawnRequestMessage extends Marshallable[SpawnRequestMessage] {
|
||||
private val spawnGroupCodec = PacketHelpers.createLongEnumerationCodec(SpawnGroup, uint32L)
|
||||
private val spawnGroupCodec = PacketHelpers.createLongIntEnumCodec(SpawnGroup, uint32L)
|
||||
|
||||
implicit val codec: Codec[SpawnRequestMessage] = (
|
||||
("unk1" | uint16L) ::
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ object ServerType extends IntEnum[ServerType] {
|
|||
case object ReleasedGemini extends ServerType(4, "released_gemini")
|
||||
|
||||
val values = findValues
|
||||
implicit val codec = PacketHelpers.createEnumCodec(this, uint8L)
|
||||
implicit val codec = PacketHelpers.createIntEnumCodec(this, uint8L)
|
||||
}
|
||||
|
||||
// This MUST be an IP address. The client DOES NOT do name resolution properly
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package net.psforever.persistence
|
||||
|
||||
case class Building(
|
||||
localId: Int, // aka map id
|
||||
zoneId: Int, // aka zone number
|
||||
factionId: Int
|
||||
)
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.types
|
||||
|
||||
import enumeratum.values.{IntEnum, IntEnumEntry}
|
||||
|
||||
/**
|
||||
* The spawn group.<br>
|
||||
* <br>
|
||||
|
|
@ -17,11 +19,37 @@ package net.psforever.types
|
|||
* The icons produced by the normal and the bound tower and facility groups are not detailed.
|
||||
* The ones that are not designated as "bound" also do not display icons when manually set.
|
||||
* The AMS spawn group icons have an overhead AMS glyph and are smaller in radius, identical otherwise.
|
||||
*
|
||||
* @see `BindPlayerMessage`
|
||||
*/
|
||||
object SpawnGroup extends Enumeration {
|
||||
type Type = Value
|
||||
sealed abstract class SpawnGroup(val value: Int) extends IntEnumEntry
|
||||
|
||||
object SpawnGroup extends IntEnum[SpawnGroup] {
|
||||
val values = findValues
|
||||
|
||||
case object Sanctuary extends SpawnGroup(0)
|
||||
|
||||
case object BoundAMS extends SpawnGroup(1)
|
||||
|
||||
case object AMS extends SpawnGroup(2)
|
||||
|
||||
case object Unknown3 extends SpawnGroup(3)
|
||||
|
||||
case object BoundTower extends SpawnGroup(4) // unused?
|
||||
case object BoundFacility extends SpawnGroup(5)
|
||||
|
||||
case object Tower extends SpawnGroup(6)
|
||||
|
||||
case object Facility extends SpawnGroup(7)
|
||||
|
||||
case object Unknown8 extends SpawnGroup(8)
|
||||
|
||||
case object Unknown9 extends SpawnGroup(9)
|
||||
|
||||
case object Unknown10 extends SpawnGroup(10)
|
||||
|
||||
case object Unknown11 extends SpawnGroup(11)
|
||||
|
||||
case object WarpGate extends SpawnGroup(12)
|
||||
|
||||
val Sanctuary, BoundAMS, AMS, Unknown3, BoundTower, //unused?
|
||||
BoundFacility, Tower, Facility, Unknown8, Unknown9, Unknown10, Unknown11, Unknown12 = Value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ case class AppConfig(
|
|||
world: WorldConfig,
|
||||
admin: AdminConfig,
|
||||
database: DatabaseConfig,
|
||||
game: GameConfig,
|
||||
antiCheat: AntiCheatConfig,
|
||||
network: NetworkConfig,
|
||||
developer: DeveloperConfig,
|
||||
|
|
@ -103,6 +104,10 @@ case class SessionConfig(
|
|||
outboundGraceTime: Duration
|
||||
)
|
||||
|
||||
case class GameConfig(
|
||||
instantActionAms: Boolean
|
||||
)
|
||||
|
||||
case class DeveloperConfig(
|
||||
netSim: NetSimConfig
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
package net.psforever.util
|
||||
|
||||
import io.getquill.{PostgresJAsyncContext, SnakeCase}
|
||||
import net.psforever.persistence
|
||||
import net.psforever.persistence.{Account, Building, Loadout, Locker, Login, Character}
|
||||
|
||||
object Database {
|
||||
implicit val accountSchemaMeta = ctx.schemaMeta[persistence.Account]("accounts", _.id -> "id")
|
||||
implicit val characterSchemaMeta = ctx.schemaMeta[persistence.Character]("characters", _.id -> "id")
|
||||
implicit val loadoutSchemaMeta = ctx.schemaMeta[persistence.Loadout]("loadouts", _.id -> "id")
|
||||
implicit val lockerSchemaMeta = ctx.schemaMeta[persistence.Locker]("lockers", _.id -> "id")
|
||||
implicit val loginSchemaMeta = ctx.schemaMeta[persistence.Login]("logins", _.id -> "id")
|
||||
val ctx = new PostgresJAsyncContext(SnakeCase, Config.config.getConfig("database"))
|
||||
|
||||
implicit val accountSchemaMeta: ctx.SchemaMeta[Account] = ctx.schemaMeta[Account]("accounts")
|
||||
implicit val characterSchemaMeta: ctx.SchemaMeta[Character] = ctx.schemaMeta[Character]("characters")
|
||||
implicit val loadoutSchemaMeta: ctx.SchemaMeta[Loadout] = ctx.schemaMeta[Loadout]("loadouts")
|
||||
implicit val lockerSchemaMeta: ctx.SchemaMeta[Locker] = ctx.schemaMeta[Locker]("lockers")
|
||||
implicit val loginSchemaMeta: ctx.SchemaMeta[Login] = ctx.schemaMeta[Login]("logins")
|
||||
implicit val buildingSchemaMeta: ctx.SchemaMeta[Building] = ctx.schemaMeta[Building]("buildings")
|
||||
|
||||
// TODO remove if this gets merged https://github.com/getquill/quill/pull/1765
|
||||
implicit class ILike(s1: String) {
|
||||
|
||||
import ctx._
|
||||
|
||||
def ilike(s2: String) = quote(infix"$s1 ilike $s2".as[Boolean])
|
||||
}
|
||||
|
||||
val ctx = new PostgresJAsyncContext(SnakeCase, Config.config.getConfig("database"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ object Zones {
|
|||
val zones: HashMap[String, Zone] = HashMap(
|
||||
(
|
||||
"z1",
|
||||
new Zone("z1", Await.result(Maps.map01, 30 seconds), 1) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z1", Await.result(Maps.map01, 60 seconds), 1) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -26,10 +26,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"z2",
|
||||
new Zone("z2", Await.result(Maps.map02, 30 seconds), 2) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z2", Await.result(Maps.map02, 60 seconds), 2) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -38,10 +38,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"z3",
|
||||
new Zone("z3", Await.result(Maps.map03, 30 seconds), 3) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z3", Await.result(Maps.map03, 60 seconds), 3) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -50,84 +50,22 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"z4",
|
||||
new Zone("z4", Await.result(Maps.map04, 30 seconds), 4) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z4", Await.result(Maps.map04, 60 seconds), 4) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
||||
BuildingByMapId(5).get.Faction = PlanetSideEmpire.TR //Akkan
|
||||
BuildingByMapId(6).get.Faction = PlanetSideEmpire.TR //Baal
|
||||
BuildingByMapId(7).get.Faction = PlanetSideEmpire.TR //Dagon
|
||||
BuildingByMapId(8).get.Faction = PlanetSideEmpire.NC //Enkidu
|
||||
BuildingByMapId(9).get.Faction = PlanetSideEmpire.VS //Girru
|
||||
BuildingByMapId(10).get.Faction = PlanetSideEmpire.VS //Hanish
|
||||
BuildingByMapId(11).get.Faction = PlanetSideEmpire.VS //Irkalla
|
||||
BuildingByMapId(12).get.Faction = PlanetSideEmpire.VS //Kusag
|
||||
BuildingByMapId(13).get.Faction = PlanetSideEmpire.VS //Lahar
|
||||
BuildingByMapId(14).get.Faction = PlanetSideEmpire.NC //Marduk
|
||||
BuildingByMapId(15).get.Faction = PlanetSideEmpire.NC //Neti
|
||||
BuildingByMapId(16).get.Faction = PlanetSideEmpire.NC //Zaqar
|
||||
BuildingByMapId(17).get.Faction = PlanetSideEmpire.NC //S_Marduk_Tower
|
||||
BuildingByMapId(18).get.Faction = PlanetSideEmpire.NC //W_Neti_Tower
|
||||
BuildingByMapId(19).get.Faction = PlanetSideEmpire.NC //W_Zaqar_Tower
|
||||
BuildingByMapId(20).get.Faction = PlanetSideEmpire.NC //E_Zaqar_Tower
|
||||
BuildingByMapId(21).get.Faction = PlanetSideEmpire.NC //NE_Neti_Tower
|
||||
BuildingByMapId(22).get.Faction = PlanetSideEmpire.NC //SE_Ceryshen_Warpgate_Tower
|
||||
BuildingByMapId(23).get.Faction = PlanetSideEmpire.VS //S_Kusag_Tower
|
||||
BuildingByMapId(24).get.Faction = PlanetSideEmpire.VS //NW_Kusag_Tower
|
||||
BuildingByMapId(25).get.Faction = PlanetSideEmpire.VS //N_Ceryshen_Warpgate_Tower
|
||||
BuildingByMapId(26).get.Faction = PlanetSideEmpire.VS //SE_Irkalla_Tower
|
||||
BuildingByMapId(27).get.Faction = PlanetSideEmpire.VS //S_Irkalla_Tower
|
||||
BuildingByMapId(28).get.Faction = PlanetSideEmpire.TR //NE_Enkidu_Tower
|
||||
BuildingByMapId(29).get.Faction = PlanetSideEmpire.NC //SE_Akkan_Tower
|
||||
BuildingByMapId(30).get.Faction = PlanetSideEmpire.NC //SW_Enkidu_Tower
|
||||
BuildingByMapId(31).get.Faction = PlanetSideEmpire.TR //E_Searhus_Warpgate_Tower
|
||||
BuildingByMapId(32).get.Faction = PlanetSideEmpire.TR //N_Searhus_Warpgate_Tower
|
||||
BuildingByMapId(33).get.Faction = PlanetSideEmpire.VS //E_Girru_Tower
|
||||
BuildingByMapId(34).get.Faction = PlanetSideEmpire.VS //SE_Hanish_Tower
|
||||
BuildingByMapId(35).get.Faction = PlanetSideEmpire.TR //SW_Hanish_Tower
|
||||
BuildingByMapId(36).get.Faction = PlanetSideEmpire.VS //W_Girru_Tower
|
||||
BuildingByMapId(37).get.Faction = PlanetSideEmpire.TR //E_Dagon_Tower
|
||||
BuildingByMapId(38).get.Faction = PlanetSideEmpire.TR //NE_Baal_Tower
|
||||
BuildingByMapId(39).get.Faction = PlanetSideEmpire.TR //SE_Baal_Tower
|
||||
BuildingByMapId(40).get.Faction = PlanetSideEmpire.TR //S_Dagon_Tower
|
||||
BuildingByMapId(41).get.Faction = PlanetSideEmpire.NC //W_Ceryshen_Warpgate_Tower
|
||||
BuildingByMapId(42).get.Faction = PlanetSideEmpire.NEUTRAL //dagon bunker
|
||||
BuildingByMapId(43).get.Faction = PlanetSideEmpire.NEUTRAL //Akkan North Bunker
|
||||
BuildingByMapId(44).get.Faction = PlanetSideEmpire.NEUTRAL //Enkidu East Bunker
|
||||
BuildingByMapId(45).get.Faction = PlanetSideEmpire.NEUTRAL //Neti bunker
|
||||
BuildingByMapId(46).get.Faction = PlanetSideEmpire.NEUTRAL //Hanish West Bunker
|
||||
BuildingByMapId(47).get.Faction = PlanetSideEmpire.NEUTRAL //Irkalla East Bunker
|
||||
BuildingByMapId(48).get.Faction = PlanetSideEmpire.NEUTRAL //Zaqar bunker
|
||||
BuildingByMapId(49).get.Faction = PlanetSideEmpire.NEUTRAL //Kusag West Bunker
|
||||
BuildingByMapId(50).get.Faction = PlanetSideEmpire.NEUTRAL //marduk bunker
|
||||
BuildingByMapId(51).get.Faction = PlanetSideEmpire.TR //baal bunker
|
||||
BuildingByMapId(52).get.Faction = PlanetSideEmpire.NEUTRAL //girru bunker
|
||||
BuildingByMapId(53).get.Faction = PlanetSideEmpire.NEUTRAL //lahar bunker
|
||||
BuildingByMapId(54).get.Faction = PlanetSideEmpire.NEUTRAL //akkan bunker
|
||||
BuildingByMapId(55).get.Faction = PlanetSideEmpire.VS //Irkalla_Tower
|
||||
BuildingByMapId(56).get.Faction = PlanetSideEmpire.VS //Hanish_Tower
|
||||
BuildingByMapId(57).get.Faction = PlanetSideEmpire.VS //E_Ceryshen_Warpgate_Tower
|
||||
BuildingByMapId(58).get.Faction = PlanetSideEmpire.VS //Lahar_Tower
|
||||
BuildingByMapId(59).get.Faction = PlanetSideEmpire.VS //VSSanc_Warpgate_Tower
|
||||
BuildingByMapId(60).get.Faction = PlanetSideEmpire.TR //Akkan_Tower
|
||||
BuildingByMapId(61).get.Faction = PlanetSideEmpire.NC //TRSanc_Warpgate_Tower
|
||||
BuildingByMapId(62).get.Faction = PlanetSideEmpire.NC //Marduk_Tower
|
||||
BuildingByMapId(63).get.Faction = PlanetSideEmpire.TR //NW_Dagon_Tower
|
||||
BuildingByMapId(64).get.Faction = PlanetSideEmpire.NEUTRAL //E7 East Bunker (at north from bridge)
|
||||
BuildingByMapId(65).get.Faction = PlanetSideEmpire.VS //W_Hanish_Tower
|
||||
}
|
||||
}
|
||||
),
|
||||
(
|
||||
"z5",
|
||||
new Zone("z5", Await.result(Maps.map05, 30 seconds), 5) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z5", Await.result(Maps.map05, 60 seconds), 5) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -136,27 +74,22 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"z6",
|
||||
new Zone("z6", Await.result(Maps.map06, 30 seconds), 6) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z6", Await.result(Maps.map06, 60 seconds), 6) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
BuildingByMapId(2).get.Faction = PlanetSideEmpire.VS
|
||||
BuildingByMapId(48).get.Faction = PlanetSideEmpire.VS
|
||||
BuildingByMapId(49).get.Faction = PlanetSideEmpire.VS
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
}
|
||||
}
|
||||
),
|
||||
(
|
||||
"z7",
|
||||
new Zone("z7", Await.result(Maps.map07, 30 seconds), 7) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z7", Await.result(Maps.map07, 60 seconds), 7) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -165,10 +98,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"z8",
|
||||
new Zone("z8", Await.result(Maps.map08, 30 seconds), 8) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z8", Await.result(Maps.map08, 60 seconds), 8) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -177,10 +110,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"z9",
|
||||
new Zone("z9", Await.result(Maps.map09, 30 seconds), 9) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z9", Await.result(Maps.map09, 60 seconds), 9) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -189,10 +122,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"z10",
|
||||
new Zone("z10", Await.result(Maps.map10, 30 seconds), 10) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("z10", Await.result(Maps.map10, 60 seconds), 10) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -201,12 +134,14 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"home1",
|
||||
new Zone("home1", Await.result(Maps.map11, 30 seconds), 11) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
new Zone("home1", Await.result(Maps.map11, 60 seconds), 11) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
Buildings.values.foreach { _.Faction = PlanetSideEmpire.NC }
|
||||
Buildings.values.foreach {
|
||||
_.Faction = PlanetSideEmpire.NC
|
||||
}
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
}
|
||||
|
|
@ -214,12 +149,14 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"home2",
|
||||
new Zone("home2", Await.result(Maps.map12, 30 seconds), 12) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
new Zone("home2", Await.result(Maps.map12, 60 seconds), 12) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
Buildings.values.foreach { _.Faction = PlanetSideEmpire.TR }
|
||||
Buildings.values.foreach {
|
||||
_.Faction = PlanetSideEmpire.TR
|
||||
}
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
}
|
||||
|
|
@ -227,12 +164,14 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"home3",
|
||||
new Zone("home3", Await.result(Maps.map13, 30 seconds), 13) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
new Zone("home3", Await.result(Maps.map13, 60 seconds), 13) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
Buildings.values.foreach { _.Faction = PlanetSideEmpire.VS }
|
||||
Buildings.values.foreach {
|
||||
_.Faction = PlanetSideEmpire.VS
|
||||
}
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
}
|
||||
|
|
@ -276,10 +215,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"c1",
|
||||
new Zone("c1", Await.result(Maps.ugd01, 30 seconds), 23) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("c1", Await.result(Maps.ugd01, 60 seconds), 23) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -288,10 +227,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"c2",
|
||||
new Zone("c2", Await.result(Maps.ugd02, 30 seconds), 24) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("c2", Await.result(Maps.ugd02, 60 seconds), 24) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -300,10 +239,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"c3",
|
||||
new Zone("c3", Await.result(Maps.ugd03, 30 seconds), 25) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("c3", Await.result(Maps.ugd03, 60 seconds), 25) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -312,10 +251,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"c4",
|
||||
new Zone("c4", Await.result(Maps.ugd04, 30 seconds), 26) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("c4", Await.result(Maps.ugd04, 60 seconds), 26) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -324,10 +263,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"c5",
|
||||
new Zone("c5", Await.result(Maps.ugd05, 30 seconds), 27) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("c5", Await.result(Maps.ugd05, 60 seconds), 27) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -336,10 +275,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"c6",
|
||||
new Zone("c6", Await.result(Maps.ugd06, 30 seconds), 28) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("c6", Await.result(Maps.ugd06, 60 seconds), 28) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -348,10 +287,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"i1",
|
||||
new Zone("i1", Await.result(Maps.map99, 30 seconds), 29) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("i1", Await.result(Maps.map99, 60 seconds), 29) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -360,10 +299,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"i2",
|
||||
new Zone("i2", Await.result(Maps.map98, 30 seconds), 30) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("i2", Await.result(Maps.map98, 60 seconds), 30) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -372,10 +311,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"i3",
|
||||
new Zone("i3", Await.result(Maps.map97, 30 seconds), 31) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("i3", Await.result(Maps.map97, 60 seconds), 31) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -384,10 +323,10 @@ object Zones {
|
|||
),
|
||||
(
|
||||
"i4",
|
||||
new Zone("i4", Await.result(Maps.map96, 30 seconds), 32) {
|
||||
override def Init(implicit context: ActorContext): Unit = {
|
||||
super.Init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
||||
new Zone("i4", Await.result(Maps.map96, 60 seconds), 32) {
|
||||
override def init(implicit context: ActorContext): Unit = {
|
||||
super.init(context)
|
||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||
|
||||
InitZoneAmenities(zone = this)
|
||||
|
|
@ -560,9 +499,9 @@ object Zones {
|
|||
case t: ObjectSource if t.Definition == GlobalDefinitions.manned_turret =>
|
||||
60 seconds
|
||||
case _: DeployableSource =>
|
||||
30 seconds
|
||||
60 seconds
|
||||
case _: ComplexDeployableSource =>
|
||||
30 seconds
|
||||
60 seconds
|
||||
case _ =>
|
||||
0 seconds
|
||||
}
|
||||
|
|
|
|||
218
common/src/main/scala/services/InterstellarClusterService.scala
Normal file
218
common/src/main/scala/services/InterstellarClusterService.scala
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
package services
|
||||
|
||||
import akka.actor.typed.receptionist.{Receptionist, ServiceKey}
|
||||
import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors}
|
||||
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.objects.{Avatar, Player, SpawnPoint, Vehicle}
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, SpawnGroup, Vector3}
|
||||
import net.psforever.util.Config
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.util.Random
|
||||
|
||||
object InterstellarClusterService {
|
||||
val InterstellarClusterServiceKey: ServiceKey[Command] =
|
||||
ServiceKey[InterstellarClusterService.Command]("interstellarCluster")
|
||||
|
||||
def apply(zones: Iterable[Zone]): Behavior[Command] =
|
||||
Behaviors
|
||||
.supervise[Command] {
|
||||
Behaviors.setup { context =>
|
||||
context.system.receptionist ! Receptionist.Register(InterstellarClusterServiceKey, context.self)
|
||||
new InterstellarClusterService(context, zones)
|
||||
}
|
||||
}
|
||||
.onFailure[Exception](SupervisorStrategy.restart)
|
||||
|
||||
sealed trait Command
|
||||
|
||||
final case class FindZoneActor(predicate: Zone => Boolean, replyTo: ActorRef[ZoneActorResponse]) extends Command
|
||||
|
||||
final case class ZoneActorResponse(zoneActor: Option[ActorRef[ZoneActor.Command]])
|
||||
|
||||
final case class FindZone(predicate: Zone => Boolean, replyTo: ActorRef[ZoneResponse]) extends Command
|
||||
|
||||
final case class ZoneResponse(zoneActor: Option[Zone])
|
||||
|
||||
final case class FilterZones(predicate: Zone => Boolean, replyTo: ActorRef[ZonesResponse]) extends Command
|
||||
|
||||
final case class ZonesResponse(zoneActor: Iterable[Zone])
|
||||
|
||||
final case class GetInstantActionSpawnPoint(faction: PlanetSideEmpire.Value, replyTo: ActorRef[SpawnPointResponse])
|
||||
extends Command
|
||||
|
||||
final case class GetSpawnPoint(
|
||||
zoneNumber: Int,
|
||||
player: Player,
|
||||
target: PlanetSideGUID,
|
||||
replyTo: ActorRef[SpawnPointResponse]
|
||||
) extends Command
|
||||
|
||||
final case class GetNearbySpawnPoint(
|
||||
zoneNumber: Int,
|
||||
player: Player,
|
||||
spawnGroups: Seq[SpawnGroup],
|
||||
replyTo: ActorRef[SpawnPointResponse]
|
||||
) extends Command
|
||||
|
||||
final case class GetRandomSpawnPoint(
|
||||
zoneNumber: Int,
|
||||
faction: PlanetSideEmpire.Value,
|
||||
spawnGroups: Seq[SpawnGroup],
|
||||
replyTo: ActorRef[SpawnPointResponse]
|
||||
) extends Command
|
||||
|
||||
final case class SpawnPointResponse(response: Option[(Zone, SpawnPoint)])
|
||||
|
||||
final case class GetPlayers(replyTo: ActorRef[PlayersResponse]) extends Command
|
||||
|
||||
final case class PlayersResponse(players: Seq[Avatar])
|
||||
}
|
||||
|
||||
class InterstellarClusterService(context: ActorContext[InterstellarClusterService.Command], _zones: Iterable[Zone])
|
||||
extends AbstractBehavior[InterstellarClusterService.Command](context) {
|
||||
|
||||
import InterstellarClusterService._
|
||||
|
||||
private[this] val log = org.log4s.getLogger
|
||||
|
||||
val zoneActors: mutable.Map[String, (ActorRef[ZoneActor.Command], Zone)] = mutable.Map(
|
||||
_zones.map {
|
||||
case zone =>
|
||||
val zoneActor = context.spawn(ZoneActor(zone), s"zone-${zone.Id}")
|
||||
(zone.Id, (zoneActor, zone))
|
||||
}.toSeq: _*
|
||||
)
|
||||
|
||||
val zones = zoneActors.map {
|
||||
case (id, (_, zone)) => zone
|
||||
}
|
||||
|
||||
override def onMessage(msg: Command): Behavior[Command] = {
|
||||
log.info(s"$msg")
|
||||
msg match {
|
||||
case GetPlayers(replyTo) =>
|
||||
replyTo ! PlayersResponse(zones.map(_.Players).flatten.toSeq)
|
||||
case FindZoneActor(predicate, replyTo) =>
|
||||
replyTo ! ZoneActorResponse(
|
||||
zoneActors.collectFirst {
|
||||
case (_, (actor, zone)) if predicate(zone) => actor
|
||||
}
|
||||
)
|
||||
|
||||
case FindZone(predicate, replyTo) =>
|
||||
replyTo ! ZoneResponse(zones.find(predicate))
|
||||
|
||||
case FilterZones(predicate, replyTo) =>
|
||||
replyTo ! ZonesResponse(zones.filter(predicate))
|
||||
|
||||
case GetInstantActionSpawnPoint(faction, replyTo) =>
|
||||
val res = zones
|
||||
.filter(_.Players.nonEmpty)
|
||||
.flatMap { zone =>
|
||||
zone.HotSpotData.collect {
|
||||
case spot => (zone, spot)
|
||||
}
|
||||
}
|
||||
.map {
|
||||
case (zone, spot) =>
|
||||
(
|
||||
zone,
|
||||
spot,
|
||||
zone.findNearestSpawnPoints(
|
||||
faction,
|
||||
spot.DisplayLocation,
|
||||
if (Config.app.game.instantActionAms) Seq(SpawnGroup.Tower, SpawnGroup.Facility, SpawnGroup.AMS)
|
||||
else Seq(SpawnGroup.Tower, SpawnGroup.Facility)
|
||||
)
|
||||
)
|
||||
}
|
||||
.collect {
|
||||
case (zone, info, Some(spawns)) => (zone, info, spawns)
|
||||
}
|
||||
.toList
|
||||
.sortBy { case (_, spot, _) => spot.Activity.values.foldLeft(0)(_ + _.Heat) }(
|
||||
Ordering[Int].reverse
|
||||
) // greatest > least
|
||||
.sortWith {
|
||||
case ((_, spot1, _), (_, spot2, _)) =>
|
||||
spot1.ActivityBy().contains(faction) // prefer own faction activity
|
||||
}
|
||||
.headOption
|
||||
.flatMap {
|
||||
case (zone, info, spawns) =>
|
||||
val pos = info.DisplayLocation
|
||||
val spawnPoint = spawns.minBy(point => Vector3.DistanceSquared(point.Position, pos))
|
||||
//Some(zone, pos, spawnPoint)
|
||||
Some(zone, spawnPoint)
|
||||
case _ => None
|
||||
}
|
||||
replyTo ! SpawnPointResponse(res)
|
||||
|
||||
case GetRandomSpawnPoint(zoneNumber, faction, spawnGroups, replyTo) =>
|
||||
val response = zones.find(_.Number == zoneNumber) match {
|
||||
case Some(zone) =>
|
||||
/*
|
||||
val location = math.abs(Random.nextInt() % 4) match {
|
||||
case 0 => Vector3(sanctuary.map.Scale.width, sanctuary.map.Scale.height, 0) //NE
|
||||
case 1 => Vector3(sanctuary.map.Scale.width, 0, 0) //SE
|
||||
case 2 => Vector3.Zero //SW
|
||||
case 3 => Vector3(0, sanctuary.map.Scale.height, 0) //NW
|
||||
}
|
||||
sanctuary.findNearestSpawnPoints(
|
||||
faction,
|
||||
location,
|
||||
structures
|
||||
) */
|
||||
Random.shuffle(zone.findSpawns(faction, spawnGroups)).headOption match {
|
||||
case Some((_, spawnPoints)) if spawnPoints.nonEmpty =>
|
||||
Some((zone, Random.shuffle(spawnPoints.toList).head))
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
case None =>
|
||||
log.error(s"no zone $zoneNumber")
|
||||
None
|
||||
}
|
||||
replyTo ! SpawnPointResponse(response)
|
||||
|
||||
case GetSpawnPoint(zoneNumber, player, target, replyTo) =>
|
||||
zones.find(_.Number == zoneNumber) match {
|
||||
case Some(zone) =>
|
||||
zone.findSpawns(player.Faction, SpawnGroup.values).find {
|
||||
case (spawn: Building, spawnPoints) =>
|
||||
spawn.MapId == target.guid || spawnPoints.exists(_.GUID == target)
|
||||
case (spawn: Vehicle, spawnPoints) =>
|
||||
spawn.GUID == target || spawnPoints.exists(_.GUID.guid == target.guid)
|
||||
case _ => false
|
||||
} match {
|
||||
case Some((_, spawnPoints)) =>
|
||||
replyTo ! SpawnPointResponse(Some(zone, Random.shuffle(spawnPoints.toList).head))
|
||||
case _ =>
|
||||
replyTo ! SpawnPointResponse(None)
|
||||
}
|
||||
case None =>
|
||||
replyTo ! SpawnPointResponse(None)
|
||||
}
|
||||
|
||||
case GetNearbySpawnPoint(zoneNumber, player, spawnGroups, replyTo) =>
|
||||
zones.find(_.Number == zoneNumber) match {
|
||||
case Some(zone) =>
|
||||
zone.findNearestSpawnPoints(player.Faction, player.Position, spawnGroups) match {
|
||||
case None | Some(Nil) =>
|
||||
replyTo ! SpawnPointResponse(None)
|
||||
case Some(spawnPoints) =>
|
||||
replyTo ! SpawnPointResponse(Some(zone, scala.util.Random.shuffle(spawnPoints).head))
|
||||
}
|
||||
case None =>
|
||||
replyTo ! SpawnPointResponse(None)
|
||||
}
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,20 +2,31 @@
|
|||
package services
|
||||
|
||||
import akka.actor.{Actor, ActorIdentity, ActorRef, ActorSystem, Identify, Props}
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import akka.actor.typed
|
||||
import akka.actor.typed.receptionist.Receptionist
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
object ServiceManager {
|
||||
var serviceManager = ActorRef.noSender
|
||||
|
||||
var receptionist: typed.ActorRef[Receptionist.Command] = null
|
||||
|
||||
def boot(implicit system: ActorSystem) = {
|
||||
serviceManager = system.actorOf(Props[ServiceManager], "service")
|
||||
receptionist = system.toTyped.receptionist
|
||||
serviceManager
|
||||
}
|
||||
|
||||
case class Register(props: Props, name: String)
|
||||
|
||||
case class Lookup(name: String)
|
||||
|
||||
case class LookupFromTyped(name: String, replyTo: typed.ActorRef[LookupResult])
|
||||
|
||||
case class LookupResult(request: String, endpoint: ActorRef)
|
||||
|
||||
}
|
||||
|
||||
class ServiceManager extends Actor {
|
||||
|
|
@ -38,6 +49,11 @@ class ServiceManager extends Actor {
|
|||
lookups += nextLookupId -> RequestEntry(name, sender())
|
||||
nextLookupId += 1
|
||||
|
||||
case LookupFromTyped(name, replyTo) =>
|
||||
context.actorSelection(name) ! Identify(nextLookupId)
|
||||
lookups += nextLookupId -> RequestEntry(name, replyTo.toClassic)
|
||||
nextLookupId += 1
|
||||
|
||||
case ActorIdentity(id, Some(ref)) =>
|
||||
val idNumber = id.asInstanceOf[Long]
|
||||
lookups.get(idNumber) match {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package services.local
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||
import net.psforever.objects.ce.Deployable
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
||||
import net.psforever.objects.serverobject.terminals.{CaptureTerminal, Terminal}
|
||||
|
|
@ -131,7 +132,7 @@ class LocalService(zone: Zone) extends Actor {
|
|||
|
||||
// If the owner of this capture terminal is on the lattice trigger a zone wide map update to update lattice benefits
|
||||
zone.Lattice find building match {
|
||||
case Some(_) => building.TriggerZoneMapUpdate()
|
||||
case Some(_) => building.Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
case None => ;
|
||||
}
|
||||
case LocalAction.RouterTelepadTransport(player_guid, passenger_guid, src_guid, dest_guid) =>
|
||||
|
|
@ -247,9 +248,7 @@ class LocalService(zone: Zone) extends Actor {
|
|||
|
||||
if (building.NtuLevel > 0) {
|
||||
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
|
||||
|
||||
building.Faction = hackedByFaction
|
||||
self ! LocalServiceMessage(zone.Id, LocalAction.SetEmpire(building.GUID, hackedByFaction))
|
||||
building.Actor ! BuildingActor.SetFaction(hackedByFaction)
|
||||
} else {
|
||||
log.info("Base hack completed, but base was out of NTU.")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package services.local.support
|
||||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.objects.Default
|
||||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
|
|
@ -44,7 +45,9 @@ class HackCaptureActor extends Actor {
|
|||
// Restart the timer, in case this is the first object in the hacked objects list or the object was removed and re-added
|
||||
RestartTimer()
|
||||
|
||||
if (target.isInstanceOf[CaptureTerminal]) { target.Owner.asInstanceOf[Building].TriggerZoneMapUpdate() }
|
||||
if (target.isInstanceOf[CaptureTerminal]) {
|
||||
target.Owner.asInstanceOf[Building].Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
}
|
||||
|
||||
case HackCaptureActor.ProcessCompleteHacks() =>
|
||||
log.trace("Processing complete hacks")
|
||||
|
|
@ -74,7 +77,9 @@ class HackCaptureActor extends Actor {
|
|||
case HackCaptureActor.ClearHack(target, _) =>
|
||||
hackedObjects = hackedObjects.filterNot(x => x.target == target)
|
||||
|
||||
if (target.isInstanceOf[CaptureTerminal]) { target.Owner.asInstanceOf[Building].TriggerZoneMapUpdate() }
|
||||
if (target.isInstanceOf[CaptureTerminal]) {
|
||||
target.Owner.asInstanceOf[Building].Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
}
|
||||
|
||||
// Restart the timer in case the object we just removed was the next one scheduled
|
||||
RestartTimer()
|
||||
|
|
|
|||
|
|
@ -1,55 +1,29 @@
|
|||
package services.properties
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Stash}
|
||||
import net.psforever.objects.zones.InterstellarCluster
|
||||
import akka.actor.Actor
|
||||
import net.psforever.packet.game.{GamePropertyTarget, PropertyOverrideMessage}
|
||||
import net.psforever.packet.game.PropertyOverrideMessage.GamePropertyScope
|
||||
import net.psforever.packet.game.objectcreate.ObjectClass
|
||||
import services.ServiceManager
|
||||
import services.ServiceManager.Lookup
|
||||
|
||||
import net.psforever.zones.Zones
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
class PropertyOverrideManager extends Actor with Stash {
|
||||
class PropertyOverrideManager extends Actor {
|
||||
private[this] val log = org.log4s.getLogger("PropertyOverrideManager")
|
||||
|
||||
private var overrides: Map[Int, Map[String, List[(String, String)]]] = Map()
|
||||
private var gamePropertyScopes: List[PropertyOverrideMessage.GamePropertyScope] = List()
|
||||
private var interstellarCluster: ActorRef = Actor.noSender
|
||||
private var zoneIds: List[Int] = List()
|
||||
lazy private val zoneIds: Iterable[Int] = Zones.zones.values.map(_.Number)
|
||||
|
||||
override def preStart = {
|
||||
log.info(s"Starting PropertyOverrideManager")
|
||||
ServiceManager.serviceManager ! Lookup("cluster")
|
||||
LoadOverridesFromFile(zoneId = 0) // Global overrides
|
||||
for (zoneId <- zoneIds) {
|
||||
LoadOverridesFromFile(zoneId)
|
||||
}
|
||||
|
||||
ProcessGamePropertyScopes()
|
||||
}
|
||||
|
||||
override def receive = ServiceLookup
|
||||
|
||||
def ServiceLookup: Receive = {
|
||||
case ServiceManager.LookupResult("cluster", endpoint) =>
|
||||
interstellarCluster = endpoint
|
||||
|
||||
if (interstellarCluster != ActorRef.noSender) {
|
||||
interstellarCluster ! InterstellarCluster.GetZoneIds()
|
||||
}
|
||||
|
||||
case InterstellarCluster.ZoneIds(zoneIds) =>
|
||||
this.zoneIds = zoneIds
|
||||
|
||||
unstashAll()
|
||||
LoadOverridesFromFile(zoneId = 0) // Global overrides
|
||||
for (zoneId <- zoneIds) {
|
||||
LoadOverridesFromFile(zoneId)
|
||||
}
|
||||
|
||||
ProcessGamePropertyScopes()
|
||||
|
||||
context.become(ReceiveCommand)
|
||||
|
||||
case _ => stash()
|
||||
}
|
||||
|
||||
def ReceiveCommand: Receive = {
|
||||
override def receive: Receive = {
|
||||
case PropertyOverrideManager.GetOverridesMessage => {
|
||||
sender ! gamePropertyScopes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.Props
|
||||
import base.ActorTest
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
import net.psforever.objects.{Default, GlobalDefinitions}
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.serverobject.structures._
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
import org.specs2.mutable.Specification
|
||||
import services.ServiceManager
|
||||
import services.galaxy.GalaxyService
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
|
||||
class AmenityTest extends Specification {
|
||||
val definition = new AmenityDefinition(0) {
|
||||
|
|
@ -115,82 +111,12 @@ class WarpGateTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
class BuildingControl1Test extends ActorTest {
|
||||
class BuildingActor1Test extends ActorTest {
|
||||
"Building Control" should {
|
||||
"construct" in {
|
||||
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||
bldg.Actor = system.spawn(BuildingActor(Zone.Nowhere, bldg), "test").toClassic
|
||||
assert(bldg.Actor != Default.Actor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BuildingControl2Test extends ActorTest {
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService], "galaxy")
|
||||
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Faction = PlanetSideEmpire.TR
|
||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||
bldg.Actor ! "startup"
|
||||
|
||||
"Building Control" should {
|
||||
"convert and assert faction affinity on convert request" in {
|
||||
expectNoMessage(500 milliseconds)
|
||||
|
||||
assert(bldg.Faction == PlanetSideEmpire.TR)
|
||||
bldg.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.VS)
|
||||
val reply = receiveOne(500 milliseconds)
|
||||
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
|
||||
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == bldg)
|
||||
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.VS)
|
||||
assert(bldg.Faction == PlanetSideEmpire.VS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BuildingControl3Test extends ActorTest {
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService], "galaxy")
|
||||
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Faction = PlanetSideEmpire.TR
|
||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||
val door1 = Door(GlobalDefinitions.door)
|
||||
door1.GUID = PlanetSideGUID(1)
|
||||
door1.Actor = system.actorOf(Props(classOf[DoorControl], door1), "door1-test")
|
||||
val door2 = Door(GlobalDefinitions.door)
|
||||
door2.GUID = PlanetSideGUID(2)
|
||||
door2.Actor = system.actorOf(Props(classOf[DoorControl], door2), "door2-test")
|
||||
bldg.Amenities = door2
|
||||
bldg.Amenities = door1
|
||||
bldg.Actor ! "startup"
|
||||
|
||||
"Building Control" should {
|
||||
"convert and assert faction affinity on convert request, and for each of its amenities" in {
|
||||
expectNoMessage(500 milliseconds)
|
||||
|
||||
assert(bldg.Faction == PlanetSideEmpire.TR)
|
||||
assert(bldg.Amenities.length == 2)
|
||||
assert(bldg.Amenities.head == door2)
|
||||
assert(bldg.Amenities(1) == door1)
|
||||
|
||||
bldg.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.VS)
|
||||
val reply = ActorTest.receiveMultiple(3, 500 milliseconds, this)
|
||||
//val reply = receiveN(3, Duration.create(5000, "ms"))
|
||||
assert(reply.length == 3)
|
||||
var building_count = 0
|
||||
var door_count = 0
|
||||
reply.foreach(item => {
|
||||
assert(item.isInstanceOf[FactionAffinity.AssertFactionAffinity])
|
||||
val item2 = item.asInstanceOf[FactionAffinity.AssertFactionAffinity]
|
||||
item2.obj match {
|
||||
case _: Building =>
|
||||
building_count += 1
|
||||
case _: Door =>
|
||||
door_count += 1
|
||||
case _ =>
|
||||
assert(false)
|
||||
}
|
||||
assert(item2.faction == PlanetSideEmpire.VS)
|
||||
})
|
||||
assert(building_count == 1 && door_count == 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import akka.actor.{Actor, Props}
|
|||
import akka.routing.RandomPool
|
||||
import akka.testkit.TestProbe
|
||||
import base.ActorTest
|
||||
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||
import net.psforever.objects.guid.{NumberPoolHub, TaskResolver}
|
||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
|
|
@ -12,12 +13,13 @@ import net.psforever.objects.{Avatar, GlobalDefinitions, Ntu, Player, Vehicle}
|
|||
import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl, ResourceSiloDefinition}
|
||||
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||
import net.psforever.objects.serverobject.transfer.TransferBehavior
|
||||
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
import net.psforever.packet.game.UseItemMessage
|
||||
import net.psforever.types._
|
||||
import org.specs2.mutable.Specification
|
||||
import services.ServiceManager
|
||||
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
|
|
@ -97,8 +99,7 @@ class ResourceSiloControlUseTest extends ActorTest {
|
|||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-zone-actor")
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawnAnonymous(ZoneActor(zone))
|
||||
val building = new Building(
|
||||
"Building",
|
||||
building_guid = 0,
|
||||
|
|
@ -117,7 +118,7 @@ class ResourceSiloControlUseTest extends ActorTest {
|
|||
new Avatar(0L, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)
|
||||
) //guid=3
|
||||
val vehicle = Vehicle(GlobalDefinitions.ant) //guid=4
|
||||
val probe = new TestProbe(system)
|
||||
val probe = new TestProbe(system)
|
||||
|
||||
guid.register(building, 1)
|
||||
guid.register(obj, 2)
|
||||
|
|
@ -139,7 +140,7 @@ class ResourceSiloControlUseTest extends ActorTest {
|
|||
val reply = probe.receiveOne(2000 milliseconds)
|
||||
assert(reply match {
|
||||
case TransferBehavior.Discharging(Ntu.Nanites) => true
|
||||
case _ => false
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -221,21 +222,21 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
|||
assert(obj.CapacitorDisplay == 4)
|
||||
assert(reply1 match {
|
||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 4)) => true
|
||||
case _ => false
|
||||
case _ => false
|
||||
})
|
||||
assert(reply2.isInstanceOf[Building.SendMapUpdate])
|
||||
assert(reply2.isInstanceOf[BuildingActor.MapUpdate])
|
||||
|
||||
val reply3 = zoneEvents.receiveOne(500 milliseconds)
|
||||
assert(!obj.LowNtuWarningOn)
|
||||
assert(reply3 match {
|
||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => true
|
||||
case _ => false
|
||||
case _ => false
|
||||
})
|
||||
|
||||
val reply4 = zoneEvents.receiveOne(500 milliseconds)
|
||||
assert(reply4 match {
|
||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 48, 0)) => true
|
||||
case _ => false
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -295,7 +296,7 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
|
|||
.attribute_value == 3
|
||||
)
|
||||
|
||||
assert(reply2.isInstanceOf[Building.SendMapUpdate])
|
||||
assert(reply2.isInstanceOf[BuildingActor.MapUpdate])
|
||||
|
||||
val reply3 = zoneEvents.receiveOne(500 milliseconds)
|
||||
assert(!obj.LowNtuWarningOn)
|
||||
|
|
@ -355,7 +356,9 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
|
|||
expectNoMessage(500 milliseconds)
|
||||
zoneEvents.expectNoMessage(500 milliseconds)
|
||||
buildingEvents.expectNoMessage(500 milliseconds)
|
||||
assert(obj.NtuCapacitor == 299 || obj.NtuCapacitor == 300) // Just in case the capacitor level drops while waiting for the message check 299 & 300
|
||||
assert(
|
||||
obj.NtuCapacitor == 299 || obj.NtuCapacitor == 300
|
||||
) // Just in case the capacitor level drops while waiting for the message check 299 & 300
|
||||
assert(obj.CapacitorDisplay == 3)
|
||||
assert(!obj.LowNtuWarningOn)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import net.psforever.objects.guid.source.LimitedNumberSource
|
|||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.objects.vital.VehicleShieldCharge
|
||||
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
import net.psforever.packet.game.{CargoMountPointStatusMessage, ObjectDetachMessage, PlanetsideAttributeMessage}
|
||||
import net.psforever.types.{PlanetSideGUID, _}
|
||||
import org.specs2.mutable._
|
||||
|
|
@ -19,8 +19,11 @@ import services.{RemoverActor, ServiceManager}
|
|||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
|
||||
class VehicleTest extends Specification {
|
||||
|
||||
import VehicleTest._
|
||||
|
||||
"SeatDefinition" should {
|
||||
|
|
@ -408,10 +411,12 @@ class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTes
|
|||
val guid = new NumberPoolHub(new LimitedNumberSource(10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
GUID(guid)
|
||||
|
||||
override def SetupNumberPools(): Unit = {}
|
||||
}
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-zone-actor")
|
||||
zone.Init(context)
|
||||
zone.actor = system.spawn(ZoneActor(zone), "test-zone-actor")
|
||||
// crappy workaround but without it the zone doesn't get initialized in time
|
||||
expectNoMessage(400 milliseconds)
|
||||
|
||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||
vehicle.Faction = PlanetSideEmpire.TR
|
||||
|
|
@ -533,10 +538,12 @@ class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActor
|
|||
ServiceManager.boot
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
GUID(guid)
|
||||
|
||||
override def SetupNumberPools(): Unit = {}
|
||||
}
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-zone-actor")
|
||||
zone.Init(context)
|
||||
zone.actor = system.spawn(ZoneActor(zone), "test-zone-actor")
|
||||
// crappy workaround but without it the zone doesn't get initialized in time
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||
vehicle.Faction = PlanetSideEmpire.TR
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package objects
|
|||
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import akka.actor.{ActorContext, ActorRef, Props}
|
||||
import akka.actor.ActorContext
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
|
|
@ -14,14 +14,18 @@ import net.psforever.objects.serverobject.tube.SpawnTube
|
|||
import net.psforever.objects._
|
||||
import net.psforever.types._
|
||||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType}
|
||||
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
import net.psforever.objects.Vehicle
|
||||
import org.specs2.mutable.Specification
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class ZoneTest extends Specification {
|
||||
def test(a: String, b: Int, c: Int, d: Zone, e: ActorContext): Building = { Building.NoBuilding }
|
||||
def test(a: String, b: Int, c: Int, d: Zone, e: ActorContext): Building = {
|
||||
Building.NoBuilding
|
||||
}
|
||||
|
||||
"ZoneMap" should {
|
||||
"construct" in {
|
||||
|
|
@ -116,29 +120,26 @@ class ZoneTest extends Specification {
|
|||
|
||||
class ZoneActorTest extends ActorTest {
|
||||
"Zone" should {
|
||||
"have an Actor" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} }
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-actor")
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
assert(zone.Actor != ActorRef.noSender)
|
||||
}
|
||||
|
||||
"create new number pools before the Actor is started" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} }
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) {
|
||||
override def SetupNumberPools() = {}
|
||||
}
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||
assert(zone.AddPool("test1", 1 to 2))
|
||||
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-add-pool-actor") //note: not Init'd yet
|
||||
zone.actor = system.spawn(ZoneActor(zone), "test-add-pool-actor") //note: not Init'd yet
|
||||
assert(zone.AddPool("test2", 3 to 4))
|
||||
}
|
||||
|
||||
"remove existing number pools before the Actor is started" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} }
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) {
|
||||
override def SetupNumberPools() = {}
|
||||
}
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||
assert(zone.AddPool("test1", 1 to 2))
|
||||
assert(zone.RemovePool("test1"))
|
||||
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-remove-pool-actor") //note: not Init'd yet
|
||||
zone.actor = system.spawn(ZoneActor(zone), "test-remove-pool-actor") //note: not Init'd yet
|
||||
assert(zone.AddPool("test2", 3 to 4))
|
||||
assert(zone.RemovePool("test2"))
|
||||
}
|
||||
|
|
@ -146,8 +147,7 @@ class ZoneActorTest extends ActorTest {
|
|||
"refuse new number pools after the Actor is started" in {
|
||||
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} }
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(40150)))
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-add-pool-actor-init")
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), "test-add-pool-actor-init")
|
||||
expectNoMessage(Duration.create(500, "ms"))
|
||||
|
||||
assert(!zone.AddPool("test1", 1 to 2))
|
||||
|
|
@ -158,8 +158,7 @@ class ZoneActorTest extends ActorTest {
|
|||
|
||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||
zone.AddPool("test", 1 to 2)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-remove-pool-actor-init")
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), "test-remove-pool-actor-init")
|
||||
expectNoMessage(Duration.create(300, "ms"))
|
||||
|
||||
assert(!zone.RemovePool("test"))
|
||||
|
|
@ -203,8 +202,7 @@ class ZoneActorTest extends ActorTest {
|
|||
ObjectToBuilding(10, 7)
|
||||
}
|
||||
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = {} }
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-init")
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), "test-init")
|
||||
expectNoMessage(Duration.create(1, "seconds"))
|
||||
|
||||
val groups = zone.SpawnGroups()
|
||||
|
|
@ -230,80 +228,6 @@ class ZoneActorTest extends ActorTest {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
"select spawn points based on the position of the player in reference to buildings" in {
|
||||
val map6 = new ZoneMap("map6") {
|
||||
LocalBuilding(
|
||||
"Building",
|
||||
building_guid = 1,
|
||||
map_id = 1,
|
||||
FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1, 1, 1)))
|
||||
)
|
||||
LocalObject(2, SpawnTube.Constructor(Vector3(1, 0, 0), Vector3.Zero))
|
||||
ObjectToBuilding(2, 1)
|
||||
|
||||
LocalBuilding(
|
||||
"Building",
|
||||
building_guid = 3,
|
||||
map_id = 3,
|
||||
FoundationBuilder(Building.Structure(StructureType.Building, Vector3(4, 4, 4)))
|
||||
)
|
||||
LocalObject(4, SpawnTube.Constructor(Vector3(1, 0, 0), Vector3.Zero))
|
||||
ObjectToBuilding(4, 3)
|
||||
}
|
||||
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = {} }
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-spawn")
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMessage(Duration.create(1, "seconds"))
|
||||
val player = Player(Avatar("Chord", PlanetSideEmpire.NEUTRAL, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
|
||||
val bldg1 = zone.Building(1).get
|
||||
val bldg3 = zone.Building(3).get
|
||||
player.Position = Vector3(1, 1, 1) //closer to bldg1
|
||||
zone.Actor ! Zone.Lattice.RequestSpawnPoint(1, player, 7)
|
||||
val reply1 = receiveOne(Duration.create(200, "ms"))
|
||||
assert(reply1.isInstanceOf[Zone.Lattice.SpawnPoint])
|
||||
assert(reply1.asInstanceOf[Zone.Lattice.SpawnPoint].zone_id == "test")
|
||||
assert(reply1.asInstanceOf[Zone.Lattice.SpawnPoint].spawn_point.Owner == bldg1)
|
||||
|
||||
player.Position = Vector3(3, 3, 3) //closer to bldg3
|
||||
zone.Actor ! Zone.Lattice.RequestSpawnPoint(1, player, 7)
|
||||
val reply3 = receiveOne(Duration.create(200, "ms"))
|
||||
assert(reply3.isInstanceOf[Zone.Lattice.SpawnPoint])
|
||||
assert(reply3.asInstanceOf[Zone.Lattice.SpawnPoint].zone_id == "test")
|
||||
assert(reply3.asInstanceOf[Zone.Lattice.SpawnPoint].spawn_point.Owner == bldg3)
|
||||
}
|
||||
|
||||
"will report if no spawn points have been found in a zone" in {
|
||||
val map6 = new ZoneMap("map6") {
|
||||
LocalBuilding(
|
||||
"Building",
|
||||
building_guid = 1,
|
||||
map_id = 1,
|
||||
FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1, 1, 1)))
|
||||
)
|
||||
|
||||
LocalBuilding(
|
||||
"Building",
|
||||
building_guid = 3,
|
||||
map_id = 3,
|
||||
FoundationBuilder(Building.Structure(StructureType.Tower, Vector3(4, 4, 4)))
|
||||
)
|
||||
LocalObject(5, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||
ObjectToBuilding(5, 3)
|
||||
}
|
||||
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = {} }
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-no-spawn")
|
||||
zone.Actor ! Zone.Init()
|
||||
expectNoMessage(Duration.create(300, "ms"))
|
||||
val player = Player(Avatar("Chord", PlanetSideEmpire.NEUTRAL, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
|
||||
zone.Actor ! Zone.Lattice.RequestSpawnPoint(1, player, 7)
|
||||
val reply = receiveOne(Duration.create(200, "ms"))
|
||||
assert(reply.isInstanceOf[Zone.Lattice.NoValidSpawnPoint])
|
||||
assert(reply.asInstanceOf[Zone.Lattice.NoValidSpawnPoint].zone_number == 1)
|
||||
assert(reply.asInstanceOf[Zone.Lattice.NoValidSpawnPoint].spawn_group.contains(7))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -312,8 +236,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
"add new user to zones" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
assert(zone.Players.isEmpty)
|
||||
|
|
@ -328,8 +251,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
"remove user from zones" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
receiveOne(Duration.create(200, "ms")) //consume
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
|
|
@ -345,8 +267,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player = Player(avatar)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
|
|
@ -366,8 +287,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player = Player(avatar)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
|
|
@ -390,8 +310,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player = Player(avatar)
|
||||
player.GUID = PlanetSideGUID(1)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
|
|
@ -416,8 +335,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player1 = Player(avatar)
|
||||
val player2 = Player(avatar)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
|
|
@ -442,8 +360,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
val player = Player(avatar)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
assert(zone.Players.isEmpty)
|
||||
|
|
@ -460,8 +377,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
"user tries to Release a character, but did not Spawn a character first" in {
|
||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
zone.Population ! Zone.Population.Join(avatar)
|
||||
expectNoMessage(Duration.create(100, "ms"))
|
||||
|
|
@ -483,8 +399,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
player.Release
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
assert(zone.Corpses.isEmpty)
|
||||
|
|
@ -498,8 +413,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
player.Release
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
zone.Population ! Zone.Corpse.Add(player)
|
||||
expectNoMessage(Duration.create(500, "ms"))
|
||||
|
|
@ -519,8 +433,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
player2.Release
|
||||
val player3 = Player(Avatar("Chord3", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
player3.Release
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
zone.Population ! Zone.Corpse.Add(player1)
|
||||
zone.Population ! Zone.Corpse.Add(player2)
|
||||
|
|
@ -542,8 +455,7 @@ class ZonePopulationTest extends ActorTest {
|
|||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||
//player.Release !!important
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
assert(zone.Corpses.isEmpty)
|
||||
|
|
@ -560,8 +472,7 @@ class ZoneGroundDropItemTest extends ActorTest {
|
|||
hub.register(item, 10)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||
zone.GUID(hub)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
"DropItem" should {
|
||||
|
|
@ -586,8 +497,7 @@ class ZoneGroundCanNotDropItem1Test extends ActorTest {
|
|||
//hub.register(item, 10) //!important
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||
zone.GUID(hub)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
"DropItem" should {
|
||||
|
|
@ -612,8 +522,7 @@ class ZoneGroundCanNotDropItem2Test extends ActorTest {
|
|||
hub.register(item, 10) //!important
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||
//zone.GUID(hub) //!important
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
"DropItem" should {
|
||||
|
|
@ -638,8 +547,7 @@ class ZoneGroundCanNotDropItem3Test extends ActorTest {
|
|||
hub.register(item, 10) //!important
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||
zone.GUID(hub) //!important
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
"DropItem" should {
|
||||
|
|
@ -672,8 +580,7 @@ class ZoneGroundPickupItemTest extends ActorTest {
|
|||
hub.register(item, 10)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||
zone.GUID(hub)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
"PickupItem" should {
|
||||
|
|
@ -701,8 +608,7 @@ class ZoneGroundCanNotPickupItemTest extends ActorTest {
|
|||
hub.register(item, 10)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||
zone.GUID(hub) //still registered to this zone
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
"PickupItem" should {
|
||||
|
|
@ -726,8 +632,7 @@ class ZoneGroundRemoveItemTest extends ActorTest {
|
|||
hub.register(item, 10)
|
||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||
zone.GUID(hub) //still registered to this zone
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
"RemoveItem" should {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package objects.terminal
|
|||
import akka.actor.Props
|
||||
import akka.testkit.TestProbe
|
||||
import base.ActorTest
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||
import net.psforever.objects.serverobject.terminals.{
|
||||
|
|
@ -12,14 +13,14 @@ import net.psforever.objects.serverobject.terminals.{
|
|||
ProximityUnit,
|
||||
Terminal
|
||||
}
|
||||
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, PlanetSideGUID}
|
||||
import org.specs2.mutable.Specification
|
||||
import services.Service
|
||||
import services.local.LocalService
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
|
||||
class ProximityTest extends Specification {
|
||||
"ProximityUnit" should {
|
||||
|
|
@ -106,7 +107,7 @@ class ProximityTerminalControlStartTest extends ActorTest {
|
|||
"ProximityTerminalControl" should {
|
||||
//setup
|
||||
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
||||
Actor = system.actorOf(Props(classOf[ZoneActor], this), "test-zone")
|
||||
actor = system.spawn(ZoneActor(this), "test-zone")
|
||||
override def SetupNumberPools() = {
|
||||
AddPool("dynamic", 1 to 10)
|
||||
}
|
||||
|
|
@ -146,7 +147,7 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest {
|
|||
"ProximityTerminalControl" should {
|
||||
//setup
|
||||
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
||||
Actor = system.actorOf(Props(classOf[ZoneActor], this), "test-zone")
|
||||
actor = system.spawn(ZoneActor(this), "test-zone")
|
||||
override def SetupNumberPools() = {
|
||||
AddPool("dynamic", 1 to 10)
|
||||
}
|
||||
|
|
@ -199,7 +200,7 @@ class ProximityTerminalControlStopTest extends ActorTest {
|
|||
"ProximityTerminalControl" should {
|
||||
//setup
|
||||
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
||||
Actor = system.actorOf(Props(classOf[ZoneActor], this), "test-zone")
|
||||
actor = system.spawn(ZoneActor(this), "test-zone")
|
||||
override def SetupNumberPools() = {
|
||||
AddPool("dynamic", 1 to 10)
|
||||
}
|
||||
|
|
@ -242,7 +243,7 @@ class ProximityTerminalControlNotStopTest extends ActorTest {
|
|||
"ProximityTerminalControl" should {
|
||||
//setup
|
||||
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
||||
Actor = system.actorOf(Props(classOf[ZoneActor], this), "test-zone")
|
||||
actor = system.spawn(ZoneActor(this), "test-zone")
|
||||
override def SetupNumberPools() = {
|
||||
AddPool("dynamic", 1 to 10)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
<pattern>%date{ISO8601} [%thread] %5level "%X" %logger{35} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>OFF</level>
|
||||
<!--<level>TRACE</level>-->
|
||||
<!--<level>OFF</level>-->
|
||||
<level>TRACE</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
CREATE TABLE IF NOT EXISTS "buildings" (
|
||||
local_id INT NOT NULL,
|
||||
zone_id INT NOT NULL,
|
||||
faction_id INT NOT NULL,
|
||||
PRIMARY KEY (local_id, zone_id)
|
||||
);
|
||||
|
|
@ -4,7 +4,7 @@ import java.net.InetAddress
|
|||
import java.util.Locale
|
||||
|
||||
import akka.{actor => classic}
|
||||
import akka.actor.typed.ActorSystem
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import akka.routing.RandomPool
|
||||
import ch.qos.logback.classic.LoggerContext
|
||||
import ch.qos.logback.classic.joran.JoranConfigurator
|
||||
|
|
@ -15,7 +15,7 @@ import net.psforever.objects.guid.TaskResolver
|
|||
import org.slf4j
|
||||
import org.fusesource.jansi.Ansi._
|
||||
import org.fusesource.jansi.Ansi.Color._
|
||||
import services.ServiceManager
|
||||
import services.{InterstellarClusterService, ServiceManager}
|
||||
import services.account.{AccountIntermediaryService, AccountPersistenceService}
|
||||
import services.chat.ChatService
|
||||
import services.galaxy.GalaxyService
|
||||
|
|
@ -27,7 +27,6 @@ import org.flywaydb.core.Flyway
|
|||
import java.nio.file.Paths
|
||||
import scopt.OParser
|
||||
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import net.psforever.actors.session.SessionActor
|
||||
import net.psforever.login.psadmin.PsAdminActor
|
||||
import net.psforever.login.{
|
||||
|
|
@ -94,8 +93,6 @@ object PsLogin {
|
|||
implicit val system = classic.ActorSystem("PsLogin")
|
||||
Default(system)
|
||||
|
||||
val typedSystem: ActorSystem[Nothing] = system.toTyped
|
||||
|
||||
/** Create pipelines for the login and world servers
|
||||
*
|
||||
* The first node in the pipe is an Actor that handles the crypto for protecting packets.
|
||||
|
|
@ -130,16 +127,16 @@ object PsLogin {
|
|||
None
|
||||
}
|
||||
|
||||
val continents = Zones.zones.values ++ Seq(Zone.Nowhere)
|
||||
val zones = Zones.zones.values ++ Seq(Zone.Nowhere)
|
||||
|
||||
system.spawnAnonymous(ChatService())
|
||||
system.spawn(ChatService(), ChatService.ChatServiceKey.id)
|
||||
system.spawn(InterstellarClusterService(zones), InterstellarClusterService.InterstellarClusterServiceKey.id)
|
||||
|
||||
val serviceManager = ServiceManager.boot
|
||||
serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService], "accountIntermediary")
|
||||
serviceManager ! ServiceManager.Register(RandomPool(150).props(classic.Props[TaskResolver]), "taskResolver")
|
||||
serviceManager ! ServiceManager.Register(classic.Props[GalaxyService], "galaxy")
|
||||
serviceManager ! ServiceManager.Register(classic.Props[SquadService], "squad")
|
||||
serviceManager ! ServiceManager.Register(classic.Props(classOf[InterstellarCluster], continents), "cluster")
|
||||
serviceManager ! ServiceManager.Register(classic.Props[AccountPersistenceService], "accountPersistence")
|
||||
serviceManager ! ServiceManager.Register(classic.Props[PropertyOverrideManager], "propertyOverrideManager")
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import net.psforever.objects.zones.Zone
|
|||
import net.psforever.types.{PlanetSideGUID, _}
|
||||
import services.RemoverActor
|
||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
|
|
@ -213,7 +215,6 @@ object VehicleSpawnPadControlTest {
|
|||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
import net.psforever.objects.vehicles.VehicleControl
|
||||
import net.psforever.objects.zones.ZoneActor
|
||||
import net.psforever.objects.Tool
|
||||
import net.psforever.types.CharacterGender
|
||||
|
||||
|
|
@ -228,8 +229,7 @@ object VehicleSpawnPadControlTest {
|
|||
override def SetupNumberPools(): Unit = {}
|
||||
}
|
||||
zone.GUID(guid)
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), s"test-zone-${System.nanoTime()}")
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), s"test-zone-${System.nanoTime()}")
|
||||
|
||||
// Hack: Wait for the Zone to finish booting, otherwise later tests will fail randomly due to race conditions
|
||||
// with actor probe setting
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import akka.routing.RandomPool
|
|||
import actor.base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectClass, ObjectCreateMessageParent, PlacementData}
|
||||
import net.psforever.packet.game.{ObjectCreateMessage, PlayerStateMessageUpstream}
|
||||
import net.psforever.types._
|
||||
|
|
@ -14,6 +14,8 @@ import services.{RemoverActor, Service, ServiceManager}
|
|||
import services.avatar._
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
|
||||
class AvatarService1Test extends ActorTest {
|
||||
"AvatarService" should {
|
||||
|
|
@ -510,8 +512,7 @@ class AvatarReleaseTest extends ActorTest {
|
|||
}
|
||||
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
|
||||
val obj = Player(Avatar("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
|
||||
obj.Continent = "test"
|
||||
obj.Release
|
||||
|
|
@ -561,8 +562,7 @@ class AvatarReleaseEarly1Test extends ActorTest {
|
|||
}
|
||||
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
|
||||
val obj = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
|
||||
obj.Continent = "test"
|
||||
obj.Release
|
||||
|
|
@ -613,8 +613,7 @@ class AvatarReleaseEarly2Test extends ActorTest {
|
|||
}
|
||||
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||
zone.Actor ! Zone.Init()
|
||||
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
|
||||
val objAlt =
|
||||
Player(
|
||||
Avatar("TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 1, CharacterVoice.Voice1)
|
||||
|
|
|
|||
|
|
@ -1,51 +0,0 @@
|
|||
import re
|
||||
|
||||
def getmap():
|
||||
data = open("tmp").read()
|
||||
lines = data.split("\n")
|
||||
lines_stripped = [l.strip().rstrip() for l in lines]
|
||||
|
||||
datalines = []
|
||||
for i in lines_stripped:
|
||||
m = re.findall(r'^[A-Z0-9a-z_]+', i)
|
||||
if len(m):
|
||||
datalines.append(m[0])
|
||||
|
||||
return datalines
|
||||
|
||||
def top():
|
||||
datalines = getmap()
|
||||
|
||||
for i in range(0, len(datalines), 16):
|
||||
print("// OPCODES 0x%02x-%02x" % (i, i+15))
|
||||
print("\n".join([d+"," for d in datalines[i:min(i+8, len(datalines))]]))
|
||||
print("// 0x%02x" % (i+8))
|
||||
print("\n".join([d+"," for d in datalines[min(i+8,len(datalines)):min(i+16, len(datalines))]]))
|
||||
print("")
|
||||
|
||||
def bot():
|
||||
data = open("tmp2").read()
|
||||
lines = data.split("\n")
|
||||
lines_stripped = [l.strip().rstrip() for l in lines]
|
||||
|
||||
datalinesMap = getmap()
|
||||
datalines = []
|
||||
for i in lines_stripped:
|
||||
m = re.findall(r'^case ([0-9]+)', i)
|
||||
if len(m):
|
||||
num = int(m[0])
|
||||
m = re.findall(r'=> (.*)', i)[0]
|
||||
|
||||
if m.startswith("noDecoder"):
|
||||
datalines.append((num, "noDecoder(%s)" % datalinesMap[num]))
|
||||
else:
|
||||
datalines.append((num, m))
|
||||
|
||||
for i in range(0, len(datalines), 16):
|
||||
print("// OPCODES 0x%02x-%02x" % (i, i+15))
|
||||
print("\n".join(["case 0x%02x => %s" % (n,d) for n,d in datalines[i:min(i+8, len(datalines))]]))
|
||||
print("// 0x%02x" % (i+8))
|
||||
print("\n".join(["case 0x%02x => %s" % (n,d) for n,d in datalines[i+8:min(i+16, len(datalines))]]))
|
||||
print("")
|
||||
|
||||
top()
|
||||
Loading…
Reference in a new issue