mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +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
|
The default database is named `psforever` and the credentials are
|
||||||
`psforever:psforever`. To change these, create a configuration file at
|
`psforever:psforever`. To change these, create a configuration file at
|
||||||
`config/psforever.conf`. For configuration options and their defaults, see
|
`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.
|
ALL access to tables, sequences, and functions.
|
||||||
The permissions required can be summarized by the SQL below.
|
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.
|
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"),
|
packMain := Map("ps-login" -> "net.psforever.pslogin.PsLogin"),
|
||||||
packArchivePrefix := "pslogin",
|
packArchivePrefix := "pslogin",
|
||||||
packExtraClasspath := Map("ps-login" -> Seq("${PROG_HOME}/pscrypto-lib", "${PROG_HOME}/config")),
|
packExtraClasspath := Map("ps-login" -> Seq("${PROG_HOME}/pscrypto-lib", "${PROG_HOME}/config")),
|
||||||
packResourceDir += (baseDirectory.value / "pscrypto-lib" -> "pscrypto-lib"),
|
packResourceDir += (baseDirectory.value / "pscrypto-lib" -> "pscrypto-lib"),
|
||||||
packResourceDir += (baseDirectory.value / "config" -> "config"),
|
packResourceDir += (baseDirectory.value / "config" -> "config")
|
||||||
packResourceDir += (baseDirectory.value / "pslogin/src/main/resources" -> "config")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
lazy val root = (project in file("."))
|
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"))
|
lazy val decodePacketsPackSettings = Seq(packMain := Map("psf-decode-packets" -> "DecodePackets"))
|
||||||
|
|
||||||
// Special test configuration for really quiet tests (used in CI)
|
// 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.
|
# The SSL configuration of the database connection.
|
||||||
# One of: disable prefer require verify-full
|
# One of: disable prefer require verify-full
|
||||||
sslmode = prefer
|
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 {
|
anti-cheat {
|
||||||
|
|
@ -110,5 +119,13 @@ kamon {
|
||||||
apm.api-key = ""
|
apm.api-key = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
include "akka"
|
sentry {
|
||||||
include "dispatchers"
|
# 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 = {
|
def accountLogin(username: String, password: String): Unit = {
|
||||||
import ctx._
|
import ctx._
|
||||||
val newToken = this.generateToken()
|
val newToken = this.generateToken()
|
||||||
|
log.info("accountLogin")
|
||||||
val result = for {
|
val result = for {
|
||||||
// backwards compatibility: prefer exact match first, then try lowercase
|
// backwards compatibility: prefer exact match first, then try lowercase
|
||||||
accountsExact <- ctx.run(query[persistence.Account].filter(_.username == lift(username)))
|
accountsExact <- ctx.run(query[persistence.Account].filter(_.username == lift(username)))
|
||||||
|
|
@ -171,6 +171,7 @@ class LoginSessionActor extends Actor with MDCContextAware {
|
||||||
}
|
}
|
||||||
login <- accountOption match {
|
login <- accountOption match {
|
||||||
case Some(account) =>
|
case Some(account) =>
|
||||||
|
log.info(s"$account")
|
||||||
(account.inactive, password.isBcrypted(account.passhash)) match {
|
(account.inactive, password.isBcrypted(account.passhash)) match {
|
||||||
case (false, true) =>
|
case (false, true) =>
|
||||||
accountIntermediary ! StoreAccountData(newToken, new Account(account.id, account.username, account.gm))
|
accountIntermediary ! StoreAccountData(newToken, new Account(account.id, account.username, account.gm))
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,40 @@
|
||||||
package net.psforever.login.psadmin
|
package net.psforever.login.psadmin
|
||||||
|
|
||||||
|
import akka.actor.typed.receptionist.Receptionist
|
||||||
import akka.actor.{Actor, ActorRef}
|
import akka.actor.{Actor, ActorRef}
|
||||||
import net.psforever.objects.zones.InterstellarCluster
|
import services.{InterstellarClusterService, ServiceManager}
|
||||||
|
|
||||||
import scala.collection.mutable.Map
|
import scala.collection.mutable.Map
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
||||||
class CmdListPlayers(args: Array[String], services: Map[String, ActorRef]) extends Actor {
|
class CmdListPlayers(args: Array[String], services: Map[String, ActorRef]) extends Actor {
|
||||||
private[this] val log = org.log4s.getLogger(self.path.name)
|
private[this] val log = org.log4s.getLogger(self.path.name)
|
||||||
|
|
||||||
override def preStart = {
|
override def preStart = {
|
||||||
services { "cluster" } ! InterstellarCluster.ListPlayers()
|
ServiceManager.receptionist ! Receptionist.Find(
|
||||||
|
InterstellarClusterService.InterstellarClusterServiceKey,
|
||||||
|
context.self
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def receive = {
|
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]()
|
val data = Map[String, Any]()
|
||||||
data { "player_count" } = players.size
|
data {
|
||||||
data { "player_list" } = Array[String]()
|
"player_count"
|
||||||
|
} = players.size
|
||||||
|
data {
|
||||||
|
"player_list"
|
||||||
|
} = Array[String]()
|
||||||
|
|
||||||
if (players.isEmpty) {
|
if (players.isEmpty) {
|
||||||
context.parent ! CommandGoodResponse("No players currently online!", data)
|
context.parent ! CommandGoodResponse("No players currently online!", data)
|
||||||
} else {
|
} else {
|
||||||
data { "player_list" } = players
|
data {
|
||||||
|
"player_list"
|
||||||
|
} = players
|
||||||
context.parent ! CommandGoodResponse(s"${players.length} players online\n", data)
|
context.parent ! CommandGoodResponse(s"${players.length} players online\n", data)
|
||||||
}
|
}
|
||||||
case default => log.error(s"Unexpected message $default")
|
case default => log.error(s"Unexpected message $default")
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef}
|
import akka.actor.{Actor, ActorRef}
|
||||||
|
import net.psforever.actors.commands.NtuCommand
|
||||||
import net.psforever.objects.serverobject.transfer.{TransferBehavior, TransferContainer}
|
import net.psforever.objects.serverobject.transfer.{TransferBehavior, TransferContainer}
|
||||||
|
|
||||||
object Ntu {
|
object Ntu {
|
||||||
|
|
@ -9,77 +10,81 @@ object Ntu {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message for a `sender` announcing it has nanites it can offer the recipient.
|
* Message for a `sender` announcing it has nanites it can offer the recipient.
|
||||||
|
*
|
||||||
* @param src the nanite container recognized as the sender
|
* @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.
|
* Message for a `sender` asking for nanites from the recipient.
|
||||||
|
*
|
||||||
* @param min a minimum amount of nanites requested;
|
* @param min a minimum amount of nanites requested;
|
||||||
* if 0, the `sender` has no expectations
|
* if 0, the `sender` has no expectations
|
||||||
* @param max the amount of nanites required to not make further requests;
|
* @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
|
* 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.
|
* 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
|
* @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 {
|
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 {
|
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 = scala.math.max(0, scala.math.min(value, Definition.MaxNtuCapacitor))
|
||||||
NtuCapacitor
|
NtuCapacitor
|
||||||
}
|
}
|
||||||
|
|
||||||
def Definition : NtuContainerDefinition
|
def Definition: NtuContainerDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
trait 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 = max
|
||||||
MaxNtuCapacitor
|
MaxNtuCapacitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait NtuStorageBehavior extends Actor {
|
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.Offer(src) => HandleNtuOffer(sender, src)
|
||||||
|
|
||||||
case Ntu.Grant(_, 0) | Ntu.Request(0, 0) | TransferBehavior.Stopping() => StopNtuBehavior(sender)
|
case Ntu.Grant(_, 0) | Ntu.Request(0, 0) | TransferBehavior.Stopping() => StopNtuBehavior(sender)
|
||||||
|
|
||||||
case Ntu.Request(min, max) => HandleNtuRequest(sender, min, max)
|
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 {
|
val (interface, slotNumber) = player.VehicleSeated match {
|
||||||
case Some(mech_guid) =>
|
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 })) {
|
if (!player.Implants.exists({ case (implantType, _, _) => implantType == implant_type })) {
|
||||||
//no duplicates
|
//no duplicates
|
||||||
player.InstallImplant(implant)
|
player.InstallImplant(implant)
|
||||||
|
|
@ -547,7 +547,7 @@ class PlayerControl(player: Player) extends Actor with JammableBehavior with Dam
|
||||||
val (interface, slotNumber) = player.VehicleSeated match {
|
val (interface, slotNumber) = player.VehicleSeated match {
|
||||||
case Some(mech_guid) =>
|
case Some(mech_guid) =>
|
||||||
(
|
(
|
||||||
zone.Map.TerminalToInterface.get(mech_guid.guid),
|
zone.map.TerminalToInterface.get(mech_guid.guid),
|
||||||
player.UninstallImplant(implant_type)
|
player.UninstallImplant(implant_type)
|
||||||
)
|
)
|
||||||
case None =>
|
case None =>
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
||||||
player: Player
|
player: Player
|
||||||
): Boolean = {
|
): Boolean = {
|
||||||
val zone = obj.Zone
|
val zone = obj.Zone
|
||||||
zone.Map.TerminalToInterface.get(obj.GUID.guid) match {
|
zone.map.TerminalToInterface.get(obj.GUID.guid) match {
|
||||||
case Some(interface_guid) =>
|
case Some(interface_guid) =>
|
||||||
(zone.GUID(interface_guid) match {
|
(zone.GUID(interface_guid) match {
|
||||||
case Some(interface) => !interface.Destroyed
|
case Some(interface) => !interface.Destroyed
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.objects.serverobject.resourcesilo
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef}
|
import akka.actor.{Actor, ActorRef}
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
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.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||||
import net.psforever.objects.serverobject.transfer.TransferBehavior
|
import net.psforever.objects.serverobject.transfer.TransferBehavior
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.Building
|
||||||
|
|
@ -10,7 +11,6 @@ import net.psforever.objects.{Ntu, NtuContainer, NtuStorageBehavior}
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
import services.Service
|
import services.Service
|
||||||
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
import services.local.{LocalAction, LocalServiceMessage}
|
|
||||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
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`.
|
* An `Actor` that handles messages being dispatched to a specific `Resource Silo`.
|
||||||
|
*
|
||||||
* @param resourceSilo the `Resource Silo` object being governed
|
* @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
|
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 = {
|
def receive: Receive = {
|
||||||
case "startup" =>
|
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
|
// 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)
|
context.become(Processing)
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
def Processing : Receive = checkBehavior
|
def Processing: Receive =
|
||||||
.orElse(storageBehavior)
|
checkBehavior
|
||||||
.orElse {
|
.orElse(storageBehavior)
|
||||||
case CommonMessages.Use(player, _) =>
|
.orElse {
|
||||||
if(resourceSilo.Faction == PlanetSideEmpire.NEUTRAL || player.Faction == resourceSilo.Faction) {
|
case CommonMessages.Use(player, _) =>
|
||||||
resourceSilo.Zone.Vehicles.find(v => v.PassengerInSeat(player).contains(0)) match {
|
if (resourceSilo.Faction == PlanetSideEmpire.NEUTRAL || player.Faction == resourceSilo.Faction) {
|
||||||
case Some(vehicle) =>
|
resourceSilo.Zone.Vehicles.find(v => v.PassengerInSeat(player).contains(0)) match {
|
||||||
context.system.scheduler.scheduleOnce(delay = 1000 milliseconds, vehicle.Actor, TransferBehavior.Discharging(Ntu.Nanites))
|
case Some(vehicle) =>
|
||||||
case _ =>
|
context.system.scheduler.scheduleOnce(
|
||||||
|
delay = 1000 milliseconds,
|
||||||
|
vehicle.Actor,
|
||||||
|
TransferBehavior.Discharging(Ntu.Nanites)
|
||||||
|
)
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
||||||
LowNtuWarning(enabled)
|
LowNtuWarning(enabled)
|
||||||
|
|
||||||
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
||||||
UpdateChargeLevel(amount)
|
UpdateChargeLevel(amount)
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
def LowNtuWarning(enabled : Boolean) : Unit = {
|
def LowNtuWarning(enabled: Boolean): Unit = {
|
||||||
resourceSilo.LowNtuWarningOn = enabled
|
resourceSilo.LowNtuWarningOn = enabled
|
||||||
log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to $enabled")
|
log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to $enabled")
|
||||||
val building = resourceSilo.Owner
|
val building = resourceSilo.Owner
|
||||||
val zone = building.Zone
|
val zone = building.Zone
|
||||||
building.Zone.AvatarEvents ! AvatarServiceMessage(
|
building.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
zone.Id,
|
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 = {
|
def UpdateChargeLevel(amount: Int): Unit = {
|
||||||
val siloChargeBeforeChange = resourceSilo.NtuCapacitor
|
val siloChargeBeforeChange = resourceSilo.NtuCapacitor
|
||||||
val siloDisplayBeforeChange = resourceSilo.CapacitorDisplay
|
val siloDisplayBeforeChange = resourceSilo.CapacitorDisplay
|
||||||
val building = resourceSilo.Owner.asInstanceOf[Building]
|
val building = resourceSilo.Owner.asInstanceOf[Building]
|
||||||
val zone = building.Zone
|
val zone = building.Zone
|
||||||
|
|
||||||
// Increase if positive passed in or decrease charge level if negative number is passed in
|
// Increase if positive passed in or decrease charge level if negative number is passed in
|
||||||
resourceSilo.NtuCapacitor += amount
|
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
|
// Only send updated capacitor display value to all clients if it has actually changed
|
||||||
if (resourceSilo.CapacitorDisplay != siloDisplayBeforeChange) {
|
if (resourceSilo.CapacitorDisplay != siloDisplayBeforeChange) {
|
||||||
log.trace(s"Silo ${resourceSilo.GUID} NTU bar level has changed from $siloDisplayBeforeChange to ${resourceSilo.CapacitorDisplay}")
|
log.trace(
|
||||||
resourceSilo.Owner.Actor ! Building.SendMapUpdate(all_clients = true)
|
s"Silo ${resourceSilo.GUID} NTU bar level has changed from $siloDisplayBeforeChange to ${resourceSilo.CapacitorDisplay}"
|
||||||
|
)
|
||||||
|
resourceSilo.Owner.Actor ! BuildingActor.MapUpdate()
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
zone.Id,
|
zone.Id,
|
||||||
AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)
|
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
|
val ntuIsLow = resourceSilo.NtuCapacitor.toFloat / resourceSilo.Definition.MaxNtuCapacitor.toFloat < 0.2f
|
||||||
if (resourceSilo.LowNtuWarningOn && !ntuIsLow) {
|
if (resourceSilo.LowNtuWarningOn && !ntuIsLow) {
|
||||||
LowNtuWarning(enabled = false)
|
LowNtuWarning(enabled = false)
|
||||||
}
|
} else if (!resourceSilo.LowNtuWarningOn && ntuIsLow) {
|
||||||
else if (!resourceSilo.LowNtuWarningOn && ntuIsLow) {
|
|
||||||
LowNtuWarning(enabled = true)
|
LowNtuWarning(enabled = true)
|
||||||
}
|
}
|
||||||
if (resourceSilo.NtuCapacitor == 0 && siloChargeBeforeChange > 0) {
|
if (resourceSilo.NtuCapacitor == 0 && siloChargeBeforeChange > 0) {
|
||||||
// Oops, someone let the base run out of power. Shut it all down.
|
// Oops, someone let the base run out of power. Shut it all down.
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttribute(building.GUID, 48, 1))
|
zone.AvatarEvents ! AvatarServiceMessage(zone.Id, AvatarAction.PlanetsideAttribute(building.GUID, 48, 1))
|
||||||
building.Faction = PlanetSideEmpire.NEUTRAL
|
building.Actor ! BuildingActor.SetFaction(PlanetSideEmpire.NEUTRAL)
|
||||||
zone.LocalEvents ! LocalServiceMessage(zone.Id, LocalAction.SetEmpire(building.GUID, PlanetSideEmpire.NEUTRAL))
|
} else if (siloChargeBeforeChange == 0 && resourceSilo.NtuCapacitor > 0) {
|
||||||
building.TriggerZoneMapUpdate()
|
|
||||||
}
|
|
||||||
else if (siloChargeBeforeChange == 0 && resourceSilo.NtuCapacitor > 0) {
|
|
||||||
// Power restored. Reactor Online. Sensors Online. Weapons Online. All systems nominal.
|
// Power restored. Reactor Online. Sensors Online. Weapons Online. All systems nominal.
|
||||||
//todo: Check generator is online before starting up
|
//todo: Check generator is online before starting up
|
||||||
zone.AvatarEvents ! AvatarServiceMessage(
|
zone.AvatarEvents ! AvatarServiceMessage(
|
||||||
zone.Id,
|
zone.Id,
|
||||||
AvatarAction.PlanetsideAttribute(building.GUID, 48, 0)
|
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.
|
* The silo will agree to offers until its nanite capacitor is completely full.
|
||||||
*/
|
*/
|
||||||
def HandleNtuOffer(sender : ActorRef, src : NtuContainer) : Unit = {
|
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = {
|
||||||
sender ! (if(resourceSilo.NtuCapacitor < resourceSilo.MaxNtuCapacitor) {
|
sender ! (if (resourceSilo.NtuCapacitor < resourceSilo.MaxNtuCapacitor) {
|
||||||
Ntu.Request(0, resourceSilo.MaxNtuCapacitor - resourceSilo.NtuCapacitor)
|
Ntu.Request(0, resourceSilo.MaxNtuCapacitor - resourceSilo.NtuCapacitor)
|
||||||
}
|
} else {
|
||||||
else {
|
StopNtuBehavior(sender)
|
||||||
StopNtuBehavior(sender)
|
Ntu.Request(0, 0)
|
||||||
Ntu.Request(0, 0)
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the animation trigger and attempt the stop animation.
|
* Reset the animation trigger and attempt the stop animation.
|
||||||
*/
|
*/
|
||||||
def StopNtuBehavior(sender : ActorRef) : Unit = {
|
def StopNtuBehavior(sender: ActorRef): Unit = {
|
||||||
panelAnimationFunc = PanelAnimation
|
panelAnimationFunc = PanelAnimation
|
||||||
panelAnimationFunc(0)
|
panelAnimationFunc(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
|
*
|
||||||
* @param sender na
|
* @param sender na
|
||||||
* @param min a minimum amount of nanites requested;
|
* @param min a minimum amount of nanites requested;
|
||||||
* @param max the amount of nanites required to not make further requests;
|
* @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
|
val originalAmount = resourceSilo.NtuCapacitor
|
||||||
UpdateChargeLevel(-min)
|
UpdateChargeLevel(-min)
|
||||||
sender ! Ntu.Grant(resourceSilo, originalAmount - resourceSilo.NtuCapacitor)
|
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.
|
* Accept nanites into the silo capacitor and set the animation state.
|
||||||
*/
|
*/
|
||||||
def HandleNtuGrant(sender : ActorRef, src : NtuContainer, amount : Int) : Unit = {
|
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit = {
|
||||||
if(amount != 0) {
|
if (amount != 0) {
|
||||||
val originalAmount = resourceSilo.NtuCapacitor
|
val originalAmount = resourceSilo.NtuCapacitor
|
||||||
UpdateChargeLevel(amount)
|
UpdateChargeLevel(amount)
|
||||||
panelAnimationFunc(resourceSilo.NtuCapacitor - originalAmount)
|
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
|
* 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.
|
* 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.
|
* These effects are both controlled by thee same packet.
|
||||||
|
*
|
||||||
* @param trigger if positive, activate the animation;
|
* @param trigger if positive, activate the animation;
|
||||||
* if negative or zero, disable the animation
|
* if negative or zero, disable the animation
|
||||||
*/
|
*/
|
||||||
def PanelAnimation(trigger : Int) : Unit = {
|
def PanelAnimation(trigger: Int): Unit = {
|
||||||
val zone = resourceSilo.Zone
|
val zone = resourceSilo.Zone
|
||||||
zone.VehicleEvents ! VehicleServiceMessage(
|
zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
zone.Id,
|
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
|
) // panel glow on & orb particles on
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do nothing this turn.
|
* 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 java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
import akka.actor.ActorContext
|
import akka.actor.ActorContext
|
||||||
|
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||||
import net.psforever.objects.{Default, GlobalDefinitions, Player}
|
import net.psforever.objects.{Default, GlobalDefinitions, Player}
|
||||||
import net.psforever.objects.definition.ObjectDefinition
|
import net.psforever.objects.definition.ObjectDefinition
|
||||||
import net.psforever.objects.serverobject.generator.Generator
|
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.terminals.CaptureTerminal
|
||||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects.zones.Zone
|
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 net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState, Vector3}
|
||||||
import scalax.collection.{Graph, GraphEdge}
|
import scalax.collection.{Graph, GraphEdge}
|
||||||
import services.Service
|
import services.Service
|
||||||
import services.local.{LocalAction, LocalServiceMessage}
|
import services.local.{LocalAction, LocalServiceMessage}
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
||||||
class Building(
|
class Building(
|
||||||
private val name: String,
|
private val name: String,
|
||||||
private val building_guid: Int,
|
private val building_guid: Int,
|
||||||
private val map_id: Int,
|
private val map_id: Int,
|
||||||
private val zone: Zone,
|
private val zone: Zone,
|
||||||
private val buildingType: StructureType.Value,
|
private val buildingType: StructureType,
|
||||||
private val buildingDefinition: BuildingDefinition
|
private val buildingDefinition: BuildingDefinition
|
||||||
) extends AmenityOwner {
|
) extends AmenityOwner {
|
||||||
|
|
||||||
|
|
@ -71,7 +73,8 @@ class Building(
|
||||||
} else if (IsCapitol) {
|
} else if (IsCapitol) {
|
||||||
UpdateForceDomeStatus()
|
UpdateForceDomeStatus()
|
||||||
}
|
}
|
||||||
TriggerZoneMapUpdate()
|
// FIXME null check is a bad idea but tests rely on it
|
||||||
|
if (Zone.actor != null) Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||||
Faction
|
Faction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,10 +129,6 @@ class Building(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def TriggerZoneMapUpdate(): Unit = {
|
|
||||||
if (Actor != Default.Actor) Actor ! Building.TriggerZoneMapUpdate(Zone.Number)
|
|
||||||
}
|
|
||||||
|
|
||||||
def UpdateForceDomeStatus(): Unit = {
|
def UpdateForceDomeStatus(): Unit = {
|
||||||
if (IsCapitol) {
|
if (IsCapitol) {
|
||||||
val originalStatus = ForceDomeActive
|
val originalStatus = ForceDomeActive
|
||||||
|
|
@ -155,7 +154,7 @@ class Building(
|
||||||
Zone.Id,
|
Zone.Id,
|
||||||
LocalAction.UpdateForceDomeStatus(Service.defaultPlayerGUID, GUID, ForceDomeActive)
|
LocalAction.UpdateForceDomeStatus(Service.defaultPlayerGUID, GUID, ForceDomeActive)
|
||||||
)
|
)
|
||||||
Actor ! Building.SendMapUpdate(all_clients = true)
|
Actor ! BuildingActor.MapUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,27 +170,7 @@ class Building(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def Info: (
|
def infoUpdateMessage(): BuildingInfoUpdateMessage = {
|
||||||
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
|
|
||||||
) = {
|
|
||||||
val ntuLevel: Int = NtuLevel
|
val ntuLevel: Int = NtuLevel
|
||||||
//if we have a capture terminal, get the hack status & time (in milliseconds) from control console if it exists
|
//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 {
|
val (hacking, hackingFaction, hackTime): (Boolean, PlanetSideEmpire.Value, Long) = CaptureTerminal match {
|
||||||
|
|
@ -264,31 +243,33 @@ class Building(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//out
|
|
||||||
(
|
BuildingInfoUpdateMessage(
|
||||||
|
Zone.Number,
|
||||||
|
MapId,
|
||||||
ntuLevel,
|
ntuLevel,
|
||||||
hacking,
|
hacking,
|
||||||
hackingFaction,
|
hackingFaction,
|
||||||
hackTime,
|
hackTime,
|
||||||
if (ntuLevel > 0) Faction else PlanetSideEmpire.NEUTRAL,
|
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,
|
None,
|
||||||
generatorState,
|
generatorState,
|
||||||
spawnTubesNormal,
|
spawnTubesNormal,
|
||||||
ForceDomeActive,
|
forceDomeActive,
|
||||||
latticeBenefit,
|
latticeBenefit,
|
||||||
48, //cavern_benefit; !! Field > 0 will cause malformed packet. See class def.
|
48, // cavern benefit
|
||||||
Nil, //unk4
|
Nil, // unk4,
|
||||||
0, //unk5
|
0, // unk5
|
||||||
false, //unk6
|
false, // unk6
|
||||||
8, //!! unk7 Field != 8 will cause malformed packet. See class def.
|
8, // unk7 Field != 8 will cause malformed packet
|
||||||
None, //unk7x
|
None, // unk7x
|
||||||
boostSpawnPain, //boost_spawn_pain
|
boostSpawnPain,
|
||||||
boostGeneratorPain //boost_generator_pain
|
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
|
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)
|
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)
|
new Building(name, guid, map_id, zone, buildingType, GlobalDefinitions.building)
|
||||||
}
|
}
|
||||||
|
|
||||||
def Structure(
|
def Structure(
|
||||||
buildingType: StructureType.Value,
|
buildingType: StructureType,
|
||||||
location: Vector3,
|
location: Vector3,
|
||||||
rotation: Vector3,
|
rotation: Vector3,
|
||||||
definition: BuildingDefinition
|
definition: BuildingDefinition
|
||||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): Building = {
|
)(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)
|
val obj = new Building(name, guid, map_id, zone, buildingType, definition)
|
||||||
obj.Position = location
|
obj.Position = location
|
||||||
obj.Orientation = rotation
|
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
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
def Structure(
|
def Structure(
|
||||||
buildingType: StructureType.Value,
|
buildingType: StructureType,
|
||||||
location: Vector3
|
location: Vector3
|
||||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): Building = {
|
)(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)
|
val obj = new Building(name, guid, map_id, zone, buildingType, GlobalDefinitions.building)
|
||||||
obj.Position = location
|
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
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
def Structure(
|
def Structure(
|
||||||
buildingType: StructureType.Value
|
buildingType: StructureType
|
||||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): Building = {
|
)(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)
|
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
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
def Structure(
|
def Structure(
|
||||||
buildingType: StructureType.Value,
|
buildingType: StructureType,
|
||||||
buildingDefinition: BuildingDefinition,
|
buildingDefinition: BuildingDefinition,
|
||||||
location: Vector3
|
location: Vector3
|
||||||
)(name: String, guid: Int, id: Int, zone: Zone, context: ActorContext): Building = {
|
)(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)
|
val obj = new Building(name, guid, id, zone, buildingType, buildingDefinition)
|
||||||
obj.Position = location
|
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
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class AmenityStateChange(obj: Amenity)
|
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
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.structures
|
package net.psforever.objects.serverobject.structures
|
||||||
|
|
||||||
/**
|
import enumeratum.{EnumEntry, Enum}
|
||||||
* 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
|
|
||||||
|
|
||||||
val Bridge, // technically, a "bridge section"
|
sealed trait StructureType extends EnumEntry
|
||||||
Building, // generic
|
|
||||||
Bunker, // low accessible ground cover
|
object StructureType extends Enum[StructureType] {
|
||||||
Facility, // large base
|
val values = findValues
|
||||||
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
|
case object Bridge extends StructureType // technically, a "bridge section"
|
||||||
WarpGate // transport point between zones
|
case object Building extends StructureType // generic
|
||||||
= Value
|
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.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.{GlobalDefinitions, NtuContainer, SpawnPoint}
|
import net.psforever.objects.{GlobalDefinitions, NtuContainer, SpawnPoint}
|
||||||
import net.psforever.objects.zones.Zone
|
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 net.psforever.types.{PlanetSideEmpire, PlanetSideGeneratorState, Vector3}
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
|
|
||||||
import scala.collection.mutable
|
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 */
|
/** what faction views this warp gate as a broadcast gate */
|
||||||
private var broadcast: mutable.Set[PlanetSideEmpire.Value] = mutable.Set.empty[PlanetSideEmpire.Value]
|
private var broadcast: mutable.Set[PlanetSideEmpire.Value] = mutable.Set.empty[PlanetSideEmpire.Value]
|
||||||
|
|
||||||
override def Info: (
|
override def infoUpdateMessage(): BuildingInfoUpdateMessage = {
|
||||||
Int,
|
BuildingInfoUpdateMessage(
|
||||||
Boolean,
|
Zone.Number,
|
||||||
PlanetSideEmpire.Value,
|
MapId,
|
||||||
Long,
|
|
||||||
PlanetSideEmpire.Value,
|
|
||||||
Long,
|
|
||||||
Option[Additional1],
|
|
||||||
PlanetSideGeneratorState.Value,
|
|
||||||
Boolean,
|
|
||||||
Boolean,
|
|
||||||
Int,
|
|
||||||
Int,
|
|
||||||
List[Additional2],
|
|
||||||
Long,
|
|
||||||
Boolean,
|
|
||||||
Int,
|
|
||||||
Option[Additional3],
|
|
||||||
Boolean,
|
|
||||||
Boolean
|
|
||||||
) = {
|
|
||||||
(
|
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
PlanetSideEmpire.NEUTRAL,
|
PlanetSideEmpire.NEUTRAL,
|
||||||
|
|
@ -179,19 +163,17 @@ object WarpGate {
|
||||||
}
|
}
|
||||||
|
|
||||||
def Structure(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): 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)
|
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
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
def Structure(
|
def Structure(
|
||||||
location: Vector3
|
location: Vector3
|
||||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): WarpGate = {
|
)(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)
|
val obj = new WarpGate(name, guid, map_id, zone, GlobalDefinitions.warpgate)
|
||||||
obj.Position = location
|
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
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,10 +181,9 @@ object WarpGate {
|
||||||
location: Vector3,
|
location: Vector3,
|
||||||
buildingDefinition: WarpGateDefinition
|
buildingDefinition: WarpGateDefinition
|
||||||
)(name: String, guid: Int, map_id: Int, zone: Zone, context: ActorContext): WarpGate = {
|
)(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)
|
val obj = new WarpGate(name, guid, map_id, zone, buildingDefinition)
|
||||||
obj.Position = location
|
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
|
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
|
package net.psforever.objects.vehicles
|
||||||
|
|
||||||
import akka.actor.{ActorRef, Cancellable}
|
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.deploy.Deployment
|
||||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||||
import net.psforever.objects.serverobject.structures.WarpGate
|
import net.psforever.objects.serverobject.structures.WarpGate
|
||||||
|
|
@ -10,21 +12,22 @@ import net.psforever.objects.{NtuContainer, _}
|
||||||
import net.psforever.types.DriveState
|
import net.psforever.types.DriveState
|
||||||
import services.Service
|
import services.Service
|
||||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
||||||
import scala.concurrent.ExecutionContext.Implicits.global
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
trait AntTransferBehavior extends TransferBehavior
|
trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
||||||
with NtuStorageBehavior {
|
var ntuChargingTick: Cancellable = Default.Cancellable
|
||||||
var ntuChargingTick : Cancellable = Default.Cancellable
|
var panelAnimationFunc: () => Unit = NoCharge
|
||||||
var panelAnimationFunc : ()=>Unit = NoCharge
|
|
||||||
|
|
||||||
def TransferMaterial = Ntu.Nanites
|
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
|
val zone = vehicle.Zone
|
||||||
zone.VehicleEvents ! VehicleServiceMessage(
|
zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
zone.Id,
|
zone.Id,
|
||||||
|
|
@ -33,7 +36,7 @@ trait AntTransferBehavior extends TransferBehavior
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Charging */
|
/** Charging */
|
||||||
def StartNtuChargingEvent(vehicle : NtuContainer) : Unit = {
|
def StartNtuChargingEvent(vehicle: NtuContainer): Unit = {
|
||||||
val zone = vehicle.Zone
|
val zone = vehicle.Zone
|
||||||
zone.VehicleEvents ! VehicleServiceMessage(
|
zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
zone.Id,
|
zone.Id,
|
||||||
|
|
@ -41,8 +44,8 @@ trait AntTransferBehavior extends TransferBehavior
|
||||||
) // orb particle effect on
|
) // orb particle effect on
|
||||||
}
|
}
|
||||||
|
|
||||||
def UpdateNtuUI(vehicle : Vehicle with NtuContainer) : Unit = {
|
def UpdateNtuUI(vehicle: Vehicle with NtuContainer): Unit = {
|
||||||
if(vehicle.Seats.values.exists(_.isOccupied)) {
|
if (vehicle.Seats.values.exists(_.isOccupied)) {
|
||||||
val display = scala.math.ceil(vehicle.NtuCapacitorScaled).toLong
|
val display = scala.math.ceil(vehicle.NtuCapacitorScaled).toLong
|
||||||
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
|
vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
|
||||||
vehicle.Actor.toString,
|
vehicle.Actor.toString,
|
||||||
|
|
@ -51,76 +54,82 @@ trait AntTransferBehavior extends TransferBehavior
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def HandleChargingEvent(target : TransferContainer) : Boolean = {
|
def HandleChargingEvent(target: TransferContainer): Boolean = {
|
||||||
ntuChargingTick.cancel
|
ntuChargingTick.cancel
|
||||||
val obj = ChargeTransferObject
|
val obj = ChargeTransferObject
|
||||||
//log.trace(s"NtuCharging: Vehicle $guid is charging NTU capacitor.")
|
//log.trace(s"NtuCharging: Vehicle $guid is charging NTU capacitor.")
|
||||||
if(obj.NtuCapacitor < obj.Definition.MaxNtuCapacitor) {
|
if (obj.NtuCapacitor < obj.Definition.MaxNtuCapacitor) {
|
||||||
//charging
|
//charging
|
||||||
panelAnimationFunc = InitialCharge
|
panelAnimationFunc = InitialCharge
|
||||||
transferTarget = Some(target)
|
transferTarget = Some(target)
|
||||||
transferEvent = TransferBehavior.Event.Charging
|
transferEvent = TransferBehavior.Event.Charging
|
||||||
val (min, max) = target match {
|
target match {
|
||||||
case _ : WarpGate =>
|
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)
|
//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 max = obj.Definition.MaxNtuCapacitor - obj.NtuCapacitor
|
||||||
val ntuMin = scala.math.min(obj.Definition.MaxNtuCapacitor/75, ntuMax)
|
target.Actor ! BuildingActor.Ntu(
|
||||||
(ntuMin, ntuMax)
|
NtuCommand.Request(scala.math.min(obj.Definition.MaxNtuCapacitor / 75, max), context.self)
|
||||||
|
)
|
||||||
case _ =>
|
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
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Fully charged
|
// Fully charged
|
||||||
TryStopChargingEvent(obj)
|
TryStopChargingEvent(obj)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def ReceiveAndDepositUntilFull(vehicle : Vehicle, amount : Int) : Boolean = {
|
def ReceiveAndDepositUntilFull(vehicle: Vehicle, amount: Int): Boolean = {
|
||||||
val isNotFull = (vehicle.NtuCapacitor += amount) < vehicle.Definition.MaxNtuCapacitor
|
val isNotFull = (vehicle.NtuCapacitor += amount) < vehicle.Definition.MaxNtuCapacitor
|
||||||
UpdateNtuUI(vehicle)
|
UpdateNtuUI(vehicle)
|
||||||
isNotFull
|
isNotFull
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Discharging */
|
/** Discharging */
|
||||||
def HandleDischargingEvent(target : TransferContainer) : Boolean = {
|
def HandleDischargingEvent(target: TransferContainer): Boolean = {
|
||||||
//log.trace(s"NtuDischarging: Vehicle $guid is discharging NTU into silo $silo_guid")
|
//log.trace(s"NtuDischarging: Vehicle $guid is discharging NTU into silo $silo_guid")
|
||||||
val obj = ChargeTransferObject
|
val obj = ChargeTransferObject
|
||||||
if(obj.NtuCapacitor > 0) {
|
if (obj.NtuCapacitor > 0) {
|
||||||
panelAnimationFunc = InitialDischarge
|
panelAnimationFunc = InitialDischarge
|
||||||
transferTarget = Some(target)
|
transferTarget = Some(target)
|
||||||
transferEvent = TransferBehavior.Event.Discharging
|
transferEvent = TransferBehavior.Event.Discharging
|
||||||
target.Actor ! Ntu.Offer(obj)
|
target.Actor ! Ntu.Offer(obj)
|
||||||
ntuChargingTick.cancel
|
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
|
true
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
TryStopChargingEvent(obj)
|
TryStopChargingEvent(obj)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def NoCharge() : Unit = {}
|
def NoCharge(): Unit = {}
|
||||||
|
|
||||||
def InitialCharge() : Unit = {
|
def InitialCharge(): Unit = {
|
||||||
panelAnimationFunc = NoCharge
|
panelAnimationFunc = NoCharge
|
||||||
val obj = ChargeTransferObject
|
val obj = ChargeTransferObject
|
||||||
ActivatePanelsForChargingEvent(obj)
|
ActivatePanelsForChargingEvent(obj)
|
||||||
StartNtuChargingEvent(obj)
|
StartNtuChargingEvent(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
def InitialDischarge() : Unit = {
|
def InitialDischarge(): Unit = {
|
||||||
panelAnimationFunc = NoCharge
|
panelAnimationFunc = NoCharge
|
||||||
ActivatePanelsForChargingEvent(ChargeTransferObject)
|
ActivatePanelsForChargingEvent(ChargeTransferObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
def WithdrawAndTransmit(vehicle : Vehicle, maxRequested : Int) : Any = {
|
def WithdrawAndTransmit(vehicle: Vehicle, maxRequested: Int): Any = {
|
||||||
val chargeable = ChargeTransferObject
|
val chargeable = ChargeTransferObject
|
||||||
var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), maxRequested)
|
var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), maxRequested)
|
||||||
chargeable.NtuCapacitor -= chargeToDeposit
|
chargeable.NtuCapacitor -= chargeToDeposit
|
||||||
UpdateNtuUI(chargeable)
|
UpdateNtuUI(chargeable)
|
||||||
|
|
@ -128,27 +137,34 @@ trait AntTransferBehavior extends TransferBehavior
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Stopping */
|
/** Stopping */
|
||||||
override def TryStopChargingEvent(container : TransferContainer) : Unit = {
|
override def TryStopChargingEvent(container: TransferContainer): Unit = {
|
||||||
val vehicle = ChargeTransferObject
|
val vehicle = ChargeTransferObject
|
||||||
ntuChargingTick.cancel
|
ntuChargingTick.cancel
|
||||||
if(transferEvent != TransferBehavior.Event.None) {
|
if (transferEvent != TransferBehavior.Event.None) {
|
||||||
if(vehicle.DeploymentState == DriveState.Deployed) {
|
if (vehicle.DeploymentState == DriveState.Deployed) {
|
||||||
//turning off glow/orb effects on ANT doesn't seem to work when deployed. Try to undeploy ANT first
|
//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)
|
vehicle.Actor ! Deployment.TryUndeploy(DriveState.Undeploying)
|
||||||
ntuChargingTick = context.system.scheduler.scheduleOnce(250 milliseconds, self, TransferBehavior.Stopping())
|
ntuChargingTick = context.system.scheduler.scheduleOnce(250 milliseconds, self, TransferBehavior.Stopping())
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
//vehicle is not deployed; just do cleanup
|
//vehicle is not deployed; just do cleanup
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
val zone = vehicle.Zone
|
val zone = vehicle.Zone
|
||||||
val zoneId = zone.Id
|
val zoneId = zone.Id
|
||||||
val events = zone.VehicleEvents
|
val events = zone.VehicleEvents
|
||||||
if(transferEvent == TransferBehavior.Event.Charging) {
|
if (transferEvent == TransferBehavior.Event.Charging) {
|
||||||
events ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 52, 0L)) // panel glow off
|
events ! VehicleServiceMessage(
|
||||||
events ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 49, 0L)) // orb particle effect off
|
zoneId,
|
||||||
}
|
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 52, 0L)
|
||||||
else if(transferEvent == TransferBehavior.Event.Discharging) {
|
) // panel glow off
|
||||||
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
|
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 = {
|
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit = {
|
||||||
if(transferEvent == TransferBehavior.Event.Discharging) {
|
if (transferEvent == TransferBehavior.Event.Discharging) {
|
||||||
val chargeable = ChargeTransferObject
|
val chargeable = ChargeTransferObject
|
||||||
val chargeToDeposit = if(min == 0) {
|
val chargeToDeposit = if (min == 0) {
|
||||||
transferTarget match {
|
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)
|
// 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)
|
scala.math.min(scala.math.min(silo.MaxNtuCapacitor / 105, chargeable.NtuCapacitor), max)
|
||||||
case _ =>
|
case _ =>
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
scala.math.min(min, chargeable.NtuCapacitor)
|
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
|
chargeable.NtuCapacitor -= chargeToDeposit
|
||||||
UpdateNtuUI(chargeable)
|
UpdateNtuUI(chargeable)
|
||||||
sender ! Ntu.Grant(chargeable, chargeToDeposit)
|
sender ! Ntu.Grant(chargeable, chargeToDeposit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def HandleNtuGrant(sender : ActorRef, src : NtuContainer, amount : Int) : Unit = {
|
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit = {
|
||||||
if(transferEvent == TransferBehavior.Event.Charging) {
|
if (transferEvent == TransferBehavior.Event.Charging) {
|
||||||
val obj = ChargeTransferObject
|
val obj = ChargeTransferObject
|
||||||
if(ReceiveAndDepositUntilFull(obj, amount)) {
|
if (ReceiveAndDepositUntilFull(obj, amount)) {
|
||||||
panelAnimationFunc()
|
panelAnimationFunc()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
TryStopChargingEvent(obj)
|
TryStopChargingEvent(obj)
|
||||||
sender ! Ntu.Request(0, 0)
|
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.inventory.Container
|
||||||
import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition}
|
import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition}
|
||||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
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.turret.FacilityTurret
|
||||||
import net.psforever.objects.serverobject.zipline.ZipLinePath
|
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.avatar.AvatarService
|
||||||
import services.local.LocalService
|
import services.local.LocalService
|
||||||
import services.vehicle.VehicleService
|
import services.vehicle.VehicleService
|
||||||
|
|
@ -33,6 +34,10 @@ import scalax.collection.GraphPredef._
|
||||||
import scalax.collection.GraphEdge._
|
import scalax.collection.GraphEdge._
|
||||||
|
|
||||||
import scala.util.Try
|
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>
|
* 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`.
|
* Static server objects originate from the `ZoneMap`.
|
||||||
* Dynamic game objects originate from player characters.
|
* Dynamic game objects originate from player characters.
|
||||||
* (Write more later.)
|
* (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;
|
* @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`
|
* also used by `LivePlayerList` to indicate a specific `Zone`
|
||||||
* @see `ZoneMap`<br>
|
* @see `ZoneMap`<br>
|
||||||
* `LoadMapMessage`<br>
|
* `LoadMapMessage`<br>
|
||||||
* `LivePlayerList`
|
* `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. */
|
/** 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
|
private var soi = Default.Actor
|
||||||
|
|
||||||
/** Used by the globally unique identifier system to coordinate requests. */
|
/** 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] =
|
private val constructions: ListBuffer[PlanetSideGameObject with Deployable] = ListBuffer()
|
||||||
ListBuffer[PlanetSideGameObject with Deployable]()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
|
@ -106,8 +111,6 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
||||||
|
|
||||||
private var lattice: Graph[Building, UnDiEdge] = Graph()
|
private var lattice: Graph[Building, UnDiEdge] = Graph()
|
||||||
|
|
||||||
private var zipLinePaths: List[ZipLinePath] = List()
|
|
||||||
|
|
||||||
/** key - spawn zone id, value - buildings belonging to spawn zone */
|
/** key - spawn zone id, value - buildings belonging to spawn zone */
|
||||||
private var spawnGroups: Map[Building, List[SpawnPoint]] = PairMap[Building, List[SpawnPoint]]()
|
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.
|
* Execution of this operation should be fail-safe.
|
||||||
* The chances of failure should be mitigated or skipped.
|
* The chances of failure should be mitigated or skipped.
|
||||||
* A testing routine should be run after the fact on the results of the process.
|
* A testing routine should be run after the fact on the results of the process.
|
||||||
|
*
|
||||||
* @see `ZoneActor.ZoneSetupCheck`
|
* @see `ZoneActor.ZoneSetupCheck`
|
||||||
* @param context a reference to an `ActorContext` necessary for `Props`
|
* @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) {
|
if (accessor == Default.Actor) {
|
||||||
SetupNumberPools()
|
SetupNumberPools()
|
||||||
accessor = context.actorOf(
|
accessor = context.actorOf(
|
||||||
RandomPool(25).props(
|
RandomPool(25).props(
|
||||||
Props(classOf[UniqueNumberSystem], this.guid, UniqueNumberSystem.AllocateNumberPoolActors(this.guid))
|
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")
|
ground = context.actorOf(Props(classOf[ZoneGroundActor], this, equipmentOnGround), s"zone-$Id-ground")
|
||||||
deployables = context.actorOf(Props(classOf[ZoneDeployableActor], this, constructions), s"$Id-deployables")
|
deployables = context.actorOf(Props(classOf[ZoneDeployableActor], this, constructions), s"zone-$Id-deployables")
|
||||||
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this, vehicles), s"$Id-vehicles")
|
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this, vehicles), s"zone-$Id-vehicles")
|
||||||
population = context.actorOf(Props(classOf[ZonePopulationActor], this, players, corpses), s"$Id-players")
|
population = context.actorOf(Props(classOf[ZonePopulationActor], this, players, corpses), s"zone-$Id-players")
|
||||||
projector = context.actorOf(
|
projector = context.actorOf(
|
||||||
Props(classOf[ZoneHotSpotDisplay], this, hotspots, 15 seconds, hotspotHistory, 60 seconds),
|
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")
|
avatarEvents = context.actorOf(Props(classOf[AvatarService], this), s"zone-$Id-avatar-events")
|
||||||
localEvents = context.actorOf(Props(classOf[LocalService], this), s"$Id-local-events")
|
localEvents = context.actorOf(Props(classOf[LocalService], this), s"zone-$Id-local-events")
|
||||||
vehicleEvents = context.actorOf(Props(classOf[VehicleService], this), s"$Id-vehicle-events")
|
vehicleEvents = context.actorOf(Props(classOf[VehicleService], this), s"zone-$Id-vehicle-events")
|
||||||
|
|
||||||
implicit val guid: NumberPoolHub = this.guid //passed into builderObject.Build implicitly
|
implicit val guid: NumberPoolHub = this.guid //passed into builderObject.Build implicitly
|
||||||
BuildLocalObjects(context, guid)
|
BuildLocalObjects(context, guid)
|
||||||
|
|
@ -189,7 +193,118 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
||||||
AssignAmenities()
|
AssignAmenities()
|
||||||
CreateSpawnGroups()
|
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
|
//guid.AddPool("l", (60001 to 65535).toList).Selector = new RandomSelector
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
def findSpawns(
|
||||||
* A reference to the primary `Actor` that governs this `Zone`.
|
faction: PlanetSideEmpire.Value,
|
||||||
* @return an `ActorRef`
|
spawnGroups: Seq[SpawnGroup]
|
||||||
* @see `ZoneActor`<br>
|
): List[(AmenityOwner, Iterable[SpawnPoint])] = {
|
||||||
* `Zone.Init`
|
val ams = spawnGroups.contains(SpawnGroup.AMS)
|
||||||
*/
|
val structures = spawnGroups.collect {
|
||||||
def Actor: ActorRef = actor
|
case SpawnGroup.Facility =>
|
||||||
|
StructureType.Facility
|
||||||
/**
|
case SpawnGroup.Tower =>
|
||||||
* Give this `Zone` an `Actor` that will govern its interactions sequentially.
|
StructureType.Tower
|
||||||
* @param zoneActor an `ActorRef` for this `Zone`;
|
case SpawnGroup.WarpGate =>
|
||||||
* will not overwrite any existing governance unless `noSender`
|
StructureType.WarpGate
|
||||||
* @return an `ActorRef`
|
case SpawnGroup.Sanctuary =>
|
||||||
* @see `ZoneActor`
|
StructureType.Building
|
||||||
*/
|
|
||||||
def Actor_=(zoneActor: ActorRef): ActorRef = {
|
|
||||||
if (actor == Default.Actor) {
|
|
||||||
actor = zoneActor
|
|
||||||
}
|
}
|
||||||
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`.
|
* The privileged name that can be used as the second parameter in the packet `LoadMapMessage`.
|
||||||
|
*
|
||||||
* @return the name
|
* @return the name
|
||||||
*/
|
*/
|
||||||
def Id: String = zoneId
|
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.
|
* The numerical index of the `Zone` as it is recognized in a variety of packets.
|
||||||
|
*
|
||||||
* @return the abstract index position of this `Zone`
|
* @return the abstract index position of this `Zone`
|
||||||
*/
|
*/
|
||||||
def Number: Int = zoneNumber
|
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
|
* @return synchronized reference to the globally unique identifier system
|
||||||
*/
|
*/
|
||||||
def GUID(hub: NumberPoolHub): Boolean = {
|
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.Color.RED
|
||||||
import org.fusesource.jansi.Ansi.ansi
|
import org.fusesource.jansi.Ansi.ansi
|
||||||
println(
|
println(
|
||||||
|
|
@ -407,12 +569,12 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
||||||
lattice
|
lattice
|
||||||
}
|
}
|
||||||
|
|
||||||
def ZipLinePaths: List[ZipLinePath] = {
|
def zipLinePaths: List[ZipLinePath] = {
|
||||||
zipLinePaths
|
map.ZipLinePaths
|
||||||
}
|
}
|
||||||
|
|
||||||
private def BuildLocalObjects(implicit context: ActorContext, guid: NumberPoolHub): Unit = {
|
private def BuildLocalObjects(implicit context: ActorContext, guid: NumberPoolHub): Unit = {
|
||||||
Map.LocalObjects.foreach({ builderObject =>
|
map.LocalObjects.foreach({ builderObject =>
|
||||||
builderObject.Build
|
builderObject.Build
|
||||||
|
|
||||||
val obj = guid(builderObject.Id)
|
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
|
//guard against errors here, but don't worry about specifics; let ZoneActor.ZoneSetupCheck complain about problems
|
||||||
val other: ListBuffer[IdentifiableEntity] = new ListBuffer[IdentifiableEntity]()
|
val other: ListBuffer[IdentifiableEntity] = new ListBuffer[IdentifiableEntity]()
|
||||||
//turret to weapon
|
//turret to weapon
|
||||||
Map.TurretToWeapon.foreach({
|
map.TurretToWeapon.foreach({
|
||||||
case (turret_guid, weapon_guid) =>
|
case (turret_guid, weapon_guid) =>
|
||||||
((GUID(turret_guid) match {
|
((GUID(turret_guid) match {
|
||||||
case Some(obj: FacilityTurret) =>
|
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] = {
|
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 {
|
val registrationKeys: Map[Int, Try[LoanedKey]] = buildingList.map {
|
||||||
case ((_, building_guid: Int, _), _) =>
|
case ((_, building_guid: Int, _), _) =>
|
||||||
(building_guid, guid.register(building_guid))
|
(building_guid, guid.register(building_guid))
|
||||||
|
|
@ -471,7 +633,7 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def AssignAmenities(): Unit = {
|
private def AssignAmenities(): Unit = {
|
||||||
Map.ObjectToBuilding.foreach({
|
map.ObjectToBuilding.foreach({
|
||||||
case (object_guid, building_id) =>
|
case (object_guid, building_id) =>
|
||||||
(buildings.get(building_id), guid(object_guid)) match {
|
(buildings.get(building_id), guid(object_guid)) match {
|
||||||
case (Some(building), Some(amenity)) =>
|
case (Some(building), Some(amenity)) =>
|
||||||
|
|
@ -498,7 +660,7 @@ class Zone(private val zoneId: String, zoneMap: ZoneMap, zoneNumber: Int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private def MakeLattice(): Unit = {
|
private def MakeLattice(): Unit = {
|
||||||
lattice ++= Map.LatticeLink.map {
|
lattice ++= map.LatticeLink.map {
|
||||||
case (source, target) =>
|
case (source, target) =>
|
||||||
val (sourceBuilding, targetBuilding) = (Building(source), Building(target)) match {
|
val (sourceBuilding, targetBuilding) = (Building(source), Building(target)) match {
|
||||||
case (Some(sBuilding), Some(tBuilding)) => (sBuilding, tBuilding)
|
case (Some(sBuilding), Some(tBuilding)) => (sBuilding, tBuilding)
|
||||||
|
|
@ -650,12 +812,6 @@ object Zone {
|
||||||
new Zone(id, map, number)
|
new Zone(id, map, number)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Message to initialize the `Zone`.
|
|
||||||
* @see `Zone.Init(implicit ActorContext)`
|
|
||||||
*/
|
|
||||||
final case class Init()
|
|
||||||
|
|
||||||
object Population {
|
object Population {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -730,79 +886,6 @@ object Zone {
|
||||||
final case class Remove(player: Player)
|
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 {
|
object Ground {
|
||||||
final case class DropItem(item: Equipment, pos: Vector3, orient: Vector3)
|
final case class DropItem(item: Equipment, pos: Vector3, orient: Vector3)
|
||||||
final case class ItemOnGround(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))
|
createEnumerationCodec(enum, storageCodec.xmap[Int](_.toInt, _.toLong))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a Codec for enumeratum's Enum type */
|
/** Create a Codec for enumeratum's IntEnum type */
|
||||||
def createEnumCodec[E <: IntEnumEntry](enum: IntEnum[E], storageCodec: Codec[Int]): Codec[E] = {
|
def createIntEnumCodec[E <: IntEnumEntry](enum: IntEnum[E], storageCodec: Codec[Int]): Codec[E] = {
|
||||||
type Struct = Int :: HNil
|
type Struct = Int :: HNil
|
||||||
val struct: Codec[Struct] = storageCodec.hlist
|
val struct: Codec[Struct] = storageCodec.hlist
|
||||||
|
|
||||||
|
|
@ -149,6 +149,10 @@ object PacketHelpers {
|
||||||
struct.narrow[E](from, to)
|
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
|
/** Common codec for how PlanetSide stores string sizes
|
||||||
*
|
*
|
||||||
* When the first bit of the byte is set, the size can be between [0, 127].
|
* 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,
|
bind_desc: String,
|
||||||
display_icon: Boolean,
|
display_icon: Boolean,
|
||||||
logging: Boolean,
|
logging: Boolean,
|
||||||
spawn_group: SpawnGroup.Value,
|
spawn_group: SpawnGroup,
|
||||||
zone_number: Long,
|
zone_number: Long,
|
||||||
unk4: Long,
|
unk4: Long,
|
||||||
pos: Vector3
|
pos: Vector3
|
||||||
|
|
@ -84,7 +84,7 @@ object BindPlayerMessage extends Marshallable[BindPlayerMessage] {
|
||||||
*/
|
*/
|
||||||
val Standard = BindPlayerMessage(BindStatus.Unbind, "", false, false, SpawnGroup.BoundAMS, 0, 0, Vector3.Zero)
|
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] = (
|
implicit val codec: Codec[BindPlayerMessage] = (
|
||||||
("action" | BindStatus.codec) ::
|
("action" | BindStatus.codec) ::
|
||||||
|
|
|
||||||
|
|
@ -8,22 +8,25 @@ import scodec.codecs._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* na
|
||||||
* @param unk1 when defined, na;
|
*
|
||||||
* non-zero when selecting the sanctuary option from a non-sanctuary continent deployment map
|
* @param unk1 when defined, na;
|
||||||
* @param spawn_type the type of spawn point destination
|
* non-zero when selecting the sanctuary option from a non-sanctuary continent deployment map
|
||||||
* @param unk3 na
|
* @param spawn_type the type of spawn point destination
|
||||||
* @param unk4 na
|
* @param unk3 na
|
||||||
* @param zone_number when defined, the continent number
|
* @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 {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = SpawnRequestMessage
|
type Packet = SpawnRequestMessage
|
||||||
|
|
||||||
def opcode = GamePacketOpcode.SpawnRequestMessage
|
def opcode = GamePacketOpcode.SpawnRequestMessage
|
||||||
|
|
||||||
def encode = SpawnRequestMessage.encode(this)
|
def encode = SpawnRequestMessage.encode(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
object SpawnRequestMessage extends Marshallable[SpawnRequestMessage] {
|
object SpawnRequestMessage extends Marshallable[SpawnRequestMessage] {
|
||||||
private val spawnGroupCodec = PacketHelpers.createLongEnumerationCodec(SpawnGroup, uint32L)
|
private val spawnGroupCodec = PacketHelpers.createLongIntEnumCodec(SpawnGroup, uint32L)
|
||||||
|
|
||||||
implicit val codec: Codec[SpawnRequestMessage] = (
|
implicit val codec: Codec[SpawnRequestMessage] = (
|
||||||
("unk1" | uint16L) ::
|
("unk1" | uint16L) ::
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ object ServerType extends IntEnum[ServerType] {
|
||||||
case object ReleasedGemini extends ServerType(4, "released_gemini")
|
case object ReleasedGemini extends ServerType(4, "released_gemini")
|
||||||
|
|
||||||
val values = findValues
|
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
|
// 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
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.types
|
package net.psforever.types
|
||||||
|
|
||||||
|
import enumeratum.values.{IntEnum, IntEnumEntry}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The spawn group.<br>
|
* The spawn group.<br>
|
||||||
* <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 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 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.
|
* The AMS spawn group icons have an overhead AMS glyph and are smaller in radius, identical otherwise.
|
||||||
|
*
|
||||||
* @see `BindPlayerMessage`
|
* @see `BindPlayerMessage`
|
||||||
*/
|
*/
|
||||||
object SpawnGroup extends Enumeration {
|
sealed abstract class SpawnGroup(val value: Int) extends IntEnumEntry
|
||||||
type Type = Value
|
|
||||||
|
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,
|
world: WorldConfig,
|
||||||
admin: AdminConfig,
|
admin: AdminConfig,
|
||||||
database: DatabaseConfig,
|
database: DatabaseConfig,
|
||||||
|
game: GameConfig,
|
||||||
antiCheat: AntiCheatConfig,
|
antiCheat: AntiCheatConfig,
|
||||||
network: NetworkConfig,
|
network: NetworkConfig,
|
||||||
developer: DeveloperConfig,
|
developer: DeveloperConfig,
|
||||||
|
|
@ -103,6 +104,10 @@ case class SessionConfig(
|
||||||
outboundGraceTime: Duration
|
outboundGraceTime: Duration
|
||||||
)
|
)
|
||||||
|
|
||||||
|
case class GameConfig(
|
||||||
|
instantActionAms: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
case class DeveloperConfig(
|
case class DeveloperConfig(
|
||||||
netSim: NetSimConfig
|
netSim: NetSimConfig
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,24 @@
|
||||||
package net.psforever.util
|
package net.psforever.util
|
||||||
|
|
||||||
import io.getquill.{PostgresJAsyncContext, SnakeCase}
|
import io.getquill.{PostgresJAsyncContext, SnakeCase}
|
||||||
import net.psforever.persistence
|
import net.psforever.persistence.{Account, Building, Loadout, Locker, Login, Character}
|
||||||
|
|
||||||
object Database {
|
object Database {
|
||||||
implicit val accountSchemaMeta = ctx.schemaMeta[persistence.Account]("accounts", _.id -> "id")
|
val ctx = new PostgresJAsyncContext(SnakeCase, Config.config.getConfig("database"))
|
||||||
implicit val characterSchemaMeta = ctx.schemaMeta[persistence.Character]("characters", _.id -> "id")
|
|
||||||
implicit val loadoutSchemaMeta = ctx.schemaMeta[persistence.Loadout]("loadouts", _.id -> "id")
|
implicit val accountSchemaMeta: ctx.SchemaMeta[Account] = ctx.schemaMeta[Account]("accounts")
|
||||||
implicit val lockerSchemaMeta = ctx.schemaMeta[persistence.Locker]("lockers", _.id -> "id")
|
implicit val characterSchemaMeta: ctx.SchemaMeta[Character] = ctx.schemaMeta[Character]("characters")
|
||||||
implicit val loginSchemaMeta = ctx.schemaMeta[persistence.Login]("logins", _.id -> "id")
|
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
|
// TODO remove if this gets merged https://github.com/getquill/quill/pull/1765
|
||||||
implicit class ILike(s1: String) {
|
implicit class ILike(s1: String) {
|
||||||
|
|
||||||
import ctx._
|
import ctx._
|
||||||
|
|
||||||
def ilike(s2: String) = quote(infix"$s1 ilike $s2".as[Boolean])
|
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(
|
val zones: HashMap[String, Zone] = HashMap(
|
||||||
(
|
(
|
||||||
"z1",
|
"z1",
|
||||||
new Zone("z1", Await.result(Maps.map01, 30 seconds), 1) {
|
new Zone("z1", Await.result(Maps.map01, 60 seconds), 1) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -26,10 +26,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"z2",
|
"z2",
|
||||||
new Zone("z2", Await.result(Maps.map02, 30 seconds), 2) {
|
new Zone("z2", Await.result(Maps.map02, 60 seconds), 2) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -38,10 +38,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"z3",
|
"z3",
|
||||||
new Zone("z3", Await.result(Maps.map03, 30 seconds), 3) {
|
new Zone("z3", Await.result(Maps.map03, 60 seconds), 3) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -50,84 +50,22 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"z4",
|
"z4",
|
||||||
new Zone("z4", Await.result(Maps.map04, 30 seconds), 4) {
|
new Zone("z4", Await.result(Maps.map04, 60 seconds), 4) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
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",
|
"z5",
|
||||||
new Zone("z5", Await.result(Maps.map05, 30 seconds), 5) {
|
new Zone("z5", Await.result(Maps.map05, 60 seconds), 5) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -136,27 +74,22 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"z6",
|
"z6",
|
||||||
new Zone("z6", Await.result(Maps.map06, 30 seconds), 6) {
|
new Zone("z6", Await.result(Maps.map06, 60 seconds), 6) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
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)
|
InitZoneAmenities(zone = this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"z7",
|
"z7",
|
||||||
new Zone("z7", Await.result(Maps.map07, 30 seconds), 7) {
|
new Zone("z7", Await.result(Maps.map07, 60 seconds), 7) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -165,10 +98,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"z8",
|
"z8",
|
||||||
new Zone("z8", Await.result(Maps.map08, 30 seconds), 8) {
|
new Zone("z8", Await.result(Maps.map08, 60 seconds), 8) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -177,10 +110,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"z9",
|
"z9",
|
||||||
new Zone("z9", Await.result(Maps.map09, 30 seconds), 9) {
|
new Zone("z9", Await.result(Maps.map09, 60 seconds), 9) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -189,10 +122,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"z10",
|
"z10",
|
||||||
new Zone("z10", Await.result(Maps.map10, 30 seconds), 10) {
|
new Zone("z10", Await.result(Maps.map10, 60 seconds), 10) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -201,12 +134,14 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"home1",
|
"home1",
|
||||||
new Zone("home1", Await.result(Maps.map11, 30 seconds), 11) {
|
new Zone("home1", Await.result(Maps.map11, 60 seconds), 11) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
|
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
Buildings.values.foreach { _.Faction = PlanetSideEmpire.NC }
|
Buildings.values.foreach {
|
||||||
|
_.Faction = PlanetSideEmpire.NC
|
||||||
|
}
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
}
|
}
|
||||||
|
|
@ -214,12 +149,14 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"home2",
|
"home2",
|
||||||
new Zone("home2", Await.result(Maps.map12, 30 seconds), 12) {
|
new Zone("home2", Await.result(Maps.map12, 60 seconds), 12) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
|
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
Buildings.values.foreach { _.Faction = PlanetSideEmpire.TR }
|
Buildings.values.foreach {
|
||||||
|
_.Faction = PlanetSideEmpire.TR
|
||||||
|
}
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
}
|
}
|
||||||
|
|
@ -227,12 +164,14 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"home3",
|
"home3",
|
||||||
new Zone("home3", Await.result(Maps.map13, 30 seconds), 13) {
|
new Zone("home3", Await.result(Maps.map13, 60 seconds), 13) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
|
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
Buildings.values.foreach { _.Faction = PlanetSideEmpire.VS }
|
Buildings.values.foreach {
|
||||||
|
_.Faction = PlanetSideEmpire.VS
|
||||||
|
}
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
}
|
}
|
||||||
|
|
@ -276,10 +215,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"c1",
|
"c1",
|
||||||
new Zone("c1", Await.result(Maps.ugd01, 30 seconds), 23) {
|
new Zone("c1", Await.result(Maps.ugd01, 60 seconds), 23) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -288,10 +227,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"c2",
|
"c2",
|
||||||
new Zone("c2", Await.result(Maps.ugd02, 30 seconds), 24) {
|
new Zone("c2", Await.result(Maps.ugd02, 60 seconds), 24) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -300,10 +239,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"c3",
|
"c3",
|
||||||
new Zone("c3", Await.result(Maps.ugd03, 30 seconds), 25) {
|
new Zone("c3", Await.result(Maps.ugd03, 60 seconds), 25) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -312,10 +251,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"c4",
|
"c4",
|
||||||
new Zone("c4", Await.result(Maps.ugd04, 30 seconds), 26) {
|
new Zone("c4", Await.result(Maps.ugd04, 60 seconds), 26) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -324,10 +263,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"c5",
|
"c5",
|
||||||
new Zone("c5", Await.result(Maps.ugd05, 30 seconds), 27) {
|
new Zone("c5", Await.result(Maps.ugd05, 60 seconds), 27) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -336,10 +275,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"c6",
|
"c6",
|
||||||
new Zone("c6", Await.result(Maps.ugd06, 30 seconds), 28) {
|
new Zone("c6", Await.result(Maps.ugd06, 60 seconds), 28) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -348,10 +287,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"i1",
|
"i1",
|
||||||
new Zone("i1", Await.result(Maps.map99, 30 seconds), 29) {
|
new Zone("i1", Await.result(Maps.map99, 60 seconds), 29) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -360,10 +299,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"i2",
|
"i2",
|
||||||
new Zone("i2", Await.result(Maps.map98, 30 seconds), 30) {
|
new Zone("i2", Await.result(Maps.map98, 60 seconds), 30) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -372,10 +311,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"i3",
|
"i3",
|
||||||
new Zone("i3", Await.result(Maps.map97, 30 seconds), 31) {
|
new Zone("i3", Await.result(Maps.map97, 60 seconds), 31) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -384,10 +323,10 @@ object Zones {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"i4",
|
"i4",
|
||||||
new Zone("i4", Await.result(Maps.map96, 30 seconds), 32) {
|
new Zone("i4", Await.result(Maps.map96, 60 seconds), 32) {
|
||||||
override def Init(implicit context: ActorContext): Unit = {
|
override def init(implicit context: ActorContext): Unit = {
|
||||||
super.Init(context)
|
super.init(context)
|
||||||
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(Map.Scale, 80, 80)
|
HotSpotCoordinateFunction = Zones.HotSpots.StandardRemapping(map.Scale, 80, 80)
|
||||||
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
HotSpotTimeFunction = Zones.HotSpots.StandardTimeRules
|
||||||
|
|
||||||
InitZoneAmenities(zone = this)
|
InitZoneAmenities(zone = this)
|
||||||
|
|
@ -560,9 +499,9 @@ object Zones {
|
||||||
case t: ObjectSource if t.Definition == GlobalDefinitions.manned_turret =>
|
case t: ObjectSource if t.Definition == GlobalDefinitions.manned_turret =>
|
||||||
60 seconds
|
60 seconds
|
||||||
case _: DeployableSource =>
|
case _: DeployableSource =>
|
||||||
30 seconds
|
60 seconds
|
||||||
case _: ComplexDeployableSource =>
|
case _: ComplexDeployableSource =>
|
||||||
30 seconds
|
60 seconds
|
||||||
case _ =>
|
case _ =>
|
||||||
0 seconds
|
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
|
package services
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorIdentity, ActorRef, ActorSystem, Identify, Props}
|
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
|
import scala.collection.mutable
|
||||||
|
|
||||||
object ServiceManager {
|
object ServiceManager {
|
||||||
var serviceManager = ActorRef.noSender
|
var serviceManager = ActorRef.noSender
|
||||||
|
|
||||||
|
var receptionist: typed.ActorRef[Receptionist.Command] = null
|
||||||
|
|
||||||
def boot(implicit system: ActorSystem) = {
|
def boot(implicit system: ActorSystem) = {
|
||||||
serviceManager = system.actorOf(Props[ServiceManager], "service")
|
serviceManager = system.actorOf(Props[ServiceManager], "service")
|
||||||
|
receptionist = system.toTyped.receptionist
|
||||||
serviceManager
|
serviceManager
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Register(props: Props, name: String)
|
case class Register(props: Props, name: String)
|
||||||
|
|
||||||
case class Lookup(name: String)
|
case class Lookup(name: String)
|
||||||
|
|
||||||
|
case class LookupFromTyped(name: String, replyTo: typed.ActorRef[LookupResult])
|
||||||
|
|
||||||
case class LookupResult(request: String, endpoint: ActorRef)
|
case class LookupResult(request: String, endpoint: ActorRef)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServiceManager extends Actor {
|
class ServiceManager extends Actor {
|
||||||
|
|
@ -38,6 +49,11 @@ class ServiceManager extends Actor {
|
||||||
lookups += nextLookupId -> RequestEntry(name, sender())
|
lookups += nextLookupId -> RequestEntry(name, sender())
|
||||||
nextLookupId += 1
|
nextLookupId += 1
|
||||||
|
|
||||||
|
case LookupFromTyped(name, replyTo) =>
|
||||||
|
context.actorSelection(name) ! Identify(nextLookupId)
|
||||||
|
lookups += nextLookupId -> RequestEntry(name, replyTo.toClassic)
|
||||||
|
nextLookupId += 1
|
||||||
|
|
||||||
case ActorIdentity(id, Some(ref)) =>
|
case ActorIdentity(id, Some(ref)) =>
|
||||||
val idNumber = id.asInstanceOf[Long]
|
val idNumber = id.asInstanceOf[Long]
|
||||||
lookups.get(idNumber) match {
|
lookups.get(idNumber) match {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package services.local
|
package services.local
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef, Props}
|
import akka.actor.{Actor, ActorRef, Props}
|
||||||
|
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
||||||
import net.psforever.objects.serverobject.terminals.{CaptureTerminal, Terminal}
|
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
|
// 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 {
|
zone.Lattice find building match {
|
||||||
case Some(_) => building.TriggerZoneMapUpdate()
|
case Some(_) => building.Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||||
case None => ;
|
case None => ;
|
||||||
}
|
}
|
||||||
case LocalAction.RouterTelepadTransport(player_guid, passenger_guid, src_guid, dest_guid) =>
|
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) {
|
if (building.NtuLevel > 0) {
|
||||||
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
|
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
|
||||||
|
building.Actor ! BuildingActor.SetFaction(hackedByFaction)
|
||||||
building.Faction = hackedByFaction
|
|
||||||
self ! LocalServiceMessage(zone.Id, LocalAction.SetEmpire(building.GUID, hackedByFaction))
|
|
||||||
} else {
|
} else {
|
||||||
log.info("Base hack completed, but base was out of NTU.")
|
log.info("Base hack completed, but base was out of NTU.")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package services.local.support
|
package services.local.support
|
||||||
|
|
||||||
import akka.actor.{Actor, Cancellable}
|
import akka.actor.{Actor, Cancellable}
|
||||||
|
import net.psforever.actors.zone.ZoneActor
|
||||||
import net.psforever.objects.Default
|
import net.psforever.objects.Default
|
||||||
import net.psforever.objects.serverobject.hackable.Hackable
|
import net.psforever.objects.serverobject.hackable.Hackable
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
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
|
// Restart the timer, in case this is the first object in the hacked objects list or the object was removed and re-added
|
||||||
RestartTimer()
|
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() =>
|
case HackCaptureActor.ProcessCompleteHacks() =>
|
||||||
log.trace("Processing complete hacks")
|
log.trace("Processing complete hacks")
|
||||||
|
|
@ -74,7 +77,9 @@ class HackCaptureActor extends Actor {
|
||||||
case HackCaptureActor.ClearHack(target, _) =>
|
case HackCaptureActor.ClearHack(target, _) =>
|
||||||
hackedObjects = hackedObjects.filterNot(x => x.target == 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
|
// Restart the timer in case the object we just removed was the next one scheduled
|
||||||
RestartTimer()
|
RestartTimer()
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,29 @@
|
||||||
package services.properties
|
package services.properties
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef, Stash}
|
import akka.actor.Actor
|
||||||
import net.psforever.objects.zones.InterstellarCluster
|
|
||||||
import net.psforever.packet.game.{GamePropertyTarget, PropertyOverrideMessage}
|
import net.psforever.packet.game.{GamePropertyTarget, PropertyOverrideMessage}
|
||||||
import net.psforever.packet.game.PropertyOverrideMessage.GamePropertyScope
|
import net.psforever.packet.game.PropertyOverrideMessage.GamePropertyScope
|
||||||
import net.psforever.packet.game.objectcreate.ObjectClass
|
import net.psforever.packet.game.objectcreate.ObjectClass
|
||||||
import services.ServiceManager
|
import net.psforever.zones.Zones
|
||||||
import services.ServiceManager.Lookup
|
|
||||||
|
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
class PropertyOverrideManager extends Actor with Stash {
|
class PropertyOverrideManager extends Actor {
|
||||||
private[this] val log = org.log4s.getLogger("PropertyOverrideManager")
|
private[this] val log = org.log4s.getLogger("PropertyOverrideManager")
|
||||||
|
|
||||||
private var overrides: Map[Int, Map[String, List[(String, String)]]] = Map()
|
private var overrides: Map[Int, Map[String, List[(String, String)]]] = Map()
|
||||||
private var gamePropertyScopes: List[PropertyOverrideMessage.GamePropertyScope] = List()
|
private var gamePropertyScopes: List[PropertyOverrideMessage.GamePropertyScope] = List()
|
||||||
private var interstellarCluster: ActorRef = Actor.noSender
|
lazy private val zoneIds: Iterable[Int] = Zones.zones.values.map(_.Number)
|
||||||
private var zoneIds: List[Int] = List()
|
|
||||||
|
|
||||||
override def preStart = {
|
override def preStart = {
|
||||||
log.info(s"Starting PropertyOverrideManager")
|
LoadOverridesFromFile(zoneId = 0) // Global overrides
|
||||||
ServiceManager.serviceManager ! Lookup("cluster")
|
for (zoneId <- zoneIds) {
|
||||||
|
LoadOverridesFromFile(zoneId)
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessGamePropertyScopes()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def receive = ServiceLookup
|
override def receive: Receive = {
|
||||||
|
|
||||||
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 = {
|
|
||||||
case PropertyOverrideManager.GetOverridesMessage => {
|
case PropertyOverrideManager.GetOverridesMessage => {
|
||||||
sender ! gamePropertyScopes
|
sender ! gamePropertyScopes
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,15 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import akka.actor.Props
|
|
||||||
import base.ActorTest
|
import base.ActorTest
|
||||||
|
import net.psforever.actors.zone.BuildingActor
|
||||||
import net.psforever.objects.{Default, GlobalDefinitions}
|
import net.psforever.objects.{Default, GlobalDefinitions}
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.doors.Door
|
||||||
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
|
|
||||||
import net.psforever.objects.serverobject.structures._
|
import net.psforever.objects.serverobject.structures._
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
|
import net.psforever.types.PlanetSideEmpire
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
import services.ServiceManager
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
import services.galaxy.GalaxyService
|
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
|
||||||
|
|
||||||
class AmenityTest extends Specification {
|
class AmenityTest extends Specification {
|
||||||
val definition = new AmenityDefinition(0) {
|
val definition = new AmenityDefinition(0) {
|
||||||
|
|
@ -115,82 +111,12 @@ class WarpGateTest extends Specification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BuildingControl1Test extends ActorTest {
|
class BuildingActor1Test extends ActorTest {
|
||||||
"Building Control" should {
|
"Building Control" should {
|
||||||
"construct" in {
|
"construct" in {
|
||||||
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
|
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)
|
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.routing.RandomPool
|
||||||
import akka.testkit.TestProbe
|
import akka.testkit.TestProbe
|
||||||
import base.ActorTest
|
import base.ActorTest
|
||||||
|
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||||
import net.psforever.objects.guid.{NumberPoolHub, TaskResolver}
|
import net.psforever.objects.guid.{NumberPoolHub, TaskResolver}
|
||||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
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.resourcesilo.{ResourceSilo, ResourceSiloControl, ResourceSiloDefinition}
|
||||||
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.serverobject.transfer.TransferBehavior
|
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.packet.game.UseItemMessage
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
import services.ServiceManager
|
import services.ServiceManager
|
||||||
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
|
@ -97,8 +99,7 @@ class ResourceSiloControlUseTest extends ActorTest {
|
||||||
override def SetupNumberPools() = {}
|
override def SetupNumberPools() = {}
|
||||||
GUID(guid)
|
GUID(guid)
|
||||||
}
|
}
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-zone-actor")
|
zone.actor = system.spawnAnonymous(ZoneActor(zone))
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
val building = new Building(
|
val building = new Building(
|
||||||
"Building",
|
"Building",
|
||||||
building_guid = 0,
|
building_guid = 0,
|
||||||
|
|
@ -117,7 +118,7 @@ class ResourceSiloControlUseTest extends ActorTest {
|
||||||
new Avatar(0L, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)
|
new Avatar(0L, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)
|
||||||
) //guid=3
|
) //guid=3
|
||||||
val vehicle = Vehicle(GlobalDefinitions.ant) //guid=4
|
val vehicle = Vehicle(GlobalDefinitions.ant) //guid=4
|
||||||
val probe = new TestProbe(system)
|
val probe = new TestProbe(system)
|
||||||
|
|
||||||
guid.register(building, 1)
|
guid.register(building, 1)
|
||||||
guid.register(obj, 2)
|
guid.register(obj, 2)
|
||||||
|
|
@ -139,7 +140,7 @@ class ResourceSiloControlUseTest extends ActorTest {
|
||||||
val reply = probe.receiveOne(2000 milliseconds)
|
val reply = probe.receiveOne(2000 milliseconds)
|
||||||
assert(reply match {
|
assert(reply match {
|
||||||
case TransferBehavior.Discharging(Ntu.Nanites) => true
|
case TransferBehavior.Discharging(Ntu.Nanites) => true
|
||||||
case _ => false
|
case _ => false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -221,21 +222,21 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
||||||
assert(obj.CapacitorDisplay == 4)
|
assert(obj.CapacitorDisplay == 4)
|
||||||
assert(reply1 match {
|
assert(reply1 match {
|
||||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 4)) => true
|
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)
|
val reply3 = zoneEvents.receiveOne(500 milliseconds)
|
||||||
assert(!obj.LowNtuWarningOn)
|
assert(!obj.LowNtuWarningOn)
|
||||||
assert(reply3 match {
|
assert(reply3 match {
|
||||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => true
|
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => true
|
||||||
case _ => false
|
case _ => false
|
||||||
})
|
})
|
||||||
|
|
||||||
val reply4 = zoneEvents.receiveOne(500 milliseconds)
|
val reply4 = zoneEvents.receiveOne(500 milliseconds)
|
||||||
assert(reply4 match {
|
assert(reply4 match {
|
||||||
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 48, 0)) => true
|
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
|
.attribute_value == 3
|
||||||
)
|
)
|
||||||
|
|
||||||
assert(reply2.isInstanceOf[Building.SendMapUpdate])
|
assert(reply2.isInstanceOf[BuildingActor.MapUpdate])
|
||||||
|
|
||||||
val reply3 = zoneEvents.receiveOne(500 milliseconds)
|
val reply3 = zoneEvents.receiveOne(500 milliseconds)
|
||||||
assert(!obj.LowNtuWarningOn)
|
assert(!obj.LowNtuWarningOn)
|
||||||
|
|
@ -355,7 +356,9 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
|
||||||
expectNoMessage(500 milliseconds)
|
expectNoMessage(500 milliseconds)
|
||||||
zoneEvents.expectNoMessage(500 milliseconds)
|
zoneEvents.expectNoMessage(500 milliseconds)
|
||||||
buildingEvents.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.CapacitorDisplay == 3)
|
||||||
assert(!obj.LowNtuWarningOn)
|
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.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.vehicles._
|
import net.psforever.objects.vehicles._
|
||||||
import net.psforever.objects.vital.VehicleShieldCharge
|
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.packet.game.{CargoMountPointStatusMessage, ObjectDetachMessage, PlanetsideAttributeMessage}
|
||||||
import net.psforever.types.{PlanetSideGUID, _}
|
import net.psforever.types.{PlanetSideGUID, _}
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
|
|
@ -19,8 +19,11 @@ import services.{RemoverActor, ServiceManager}
|
||||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
import net.psforever.actors.zone.ZoneActor
|
||||||
|
|
||||||
class VehicleTest extends Specification {
|
class VehicleTest extends Specification {
|
||||||
|
|
||||||
import VehicleTest._
|
import VehicleTest._
|
||||||
|
|
||||||
"SeatDefinition" should {
|
"SeatDefinition" should {
|
||||||
|
|
@ -408,10 +411,12 @@ class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTes
|
||||||
val guid = new NumberPoolHub(new LimitedNumberSource(10))
|
val guid = new NumberPoolHub(new LimitedNumberSource(10))
|
||||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
GUID(guid)
|
GUID(guid)
|
||||||
|
|
||||||
override def SetupNumberPools(): Unit = {}
|
override def SetupNumberPools(): Unit = {}
|
||||||
}
|
}
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-zone-actor")
|
zone.actor = system.spawn(ZoneActor(zone), "test-zone-actor")
|
||||||
zone.Init(context)
|
// crappy workaround but without it the zone doesn't get initialized in time
|
||||||
|
expectNoMessage(400 milliseconds)
|
||||||
|
|
||||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
vehicle.Faction = PlanetSideEmpire.TR
|
vehicle.Faction = PlanetSideEmpire.TR
|
||||||
|
|
@ -533,10 +538,12 @@ class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActor
|
||||||
ServiceManager.boot
|
ServiceManager.boot
|
||||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||||
GUID(guid)
|
GUID(guid)
|
||||||
|
|
||||||
override def SetupNumberPools(): Unit = {}
|
override def SetupNumberPools(): Unit = {}
|
||||||
}
|
}
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-zone-actor")
|
zone.actor = system.spawn(ZoneActor(zone), "test-zone-actor")
|
||||||
zone.Init(context)
|
// crappy workaround but without it the zone doesn't get initialized in time
|
||||||
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
vehicle.Faction = PlanetSideEmpire.TR
|
vehicle.Faction = PlanetSideEmpire.TR
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package objects
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
import akka.actor.{ActorContext, ActorRef, Props}
|
import akka.actor.ActorContext
|
||||||
import base.ActorTest
|
import base.ActorTest
|
||||||
import net.psforever.objects.entity.IdentifiableEntity
|
import net.psforever.objects.entity.IdentifiableEntity
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
|
|
@ -14,14 +14,18 @@ import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType}
|
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 net.psforever.objects.Vehicle
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
import net.psforever.actors.zone.ZoneActor
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
class ZoneTest extends Specification {
|
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 {
|
"ZoneMap" should {
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
@ -116,29 +120,26 @@ class ZoneTest extends Specification {
|
||||||
|
|
||||||
class ZoneActorTest extends ActorTest {
|
class ZoneActorTest extends ActorTest {
|
||||||
"Zone" should {
|
"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 {
|
"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)))
|
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||||
assert(zone.AddPool("test1", 1 to 2))
|
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))
|
assert(zone.AddPool("test2", 3 to 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
"remove existing number pools before the Actor is started" in {
|
"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)))
|
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||||
assert(zone.AddPool("test1", 1 to 2))
|
assert(zone.AddPool("test1", 1 to 2))
|
||||||
assert(zone.RemovePool("test1"))
|
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.AddPool("test2", 3 to 4))
|
||||||
assert(zone.RemovePool("test2"))
|
assert(zone.RemovePool("test2"))
|
||||||
}
|
}
|
||||||
|
|
@ -146,8 +147,7 @@ class ZoneActorTest extends ActorTest {
|
||||||
"refuse new number pools after the Actor is started" in {
|
"refuse new number pools after 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(40150)))
|
zone.GUID(new NumberPoolHub(new LimitedNumberSource(40150)))
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-add-pool-actor-init")
|
zone.actor = system.spawn(ZoneActor(zone), "test-add-pool-actor-init")
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(Duration.create(500, "ms"))
|
expectNoMessage(Duration.create(500, "ms"))
|
||||||
|
|
||||||
assert(!zone.AddPool("test1", 1 to 2))
|
assert(!zone.AddPool("test1", 1 to 2))
|
||||||
|
|
@ -158,8 +158,7 @@ class ZoneActorTest extends ActorTest {
|
||||||
|
|
||||||
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
|
||||||
zone.AddPool("test", 1 to 2)
|
zone.AddPool("test", 1 to 2)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-remove-pool-actor-init")
|
zone.actor = system.spawn(ZoneActor(zone), "test-remove-pool-actor-init")
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(Duration.create(300, "ms"))
|
expectNoMessage(Duration.create(300, "ms"))
|
||||||
|
|
||||||
assert(!zone.RemovePool("test"))
|
assert(!zone.RemovePool("test"))
|
||||||
|
|
@ -203,8 +202,7 @@ class ZoneActorTest extends ActorTest {
|
||||||
ObjectToBuilding(10, 7)
|
ObjectToBuilding(10, 7)
|
||||||
}
|
}
|
||||||
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = {} }
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-init")
|
zone.actor = system.spawn(ZoneActor(zone), "test-init")
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(Duration.create(1, "seconds"))
|
expectNoMessage(Duration.create(1, "seconds"))
|
||||||
|
|
||||||
val groups = zone.SpawnGroups()
|
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 {
|
"add new user to zones" in {
|
||||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
assert(zone.Players.isEmpty)
|
assert(zone.Players.isEmpty)
|
||||||
|
|
@ -328,8 +251,7 @@ class ZonePopulationTest extends ActorTest {
|
||||||
"remove user from zones" in {
|
"remove user from zones" in {
|
||||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
receiveOne(Duration.create(200, "ms")) //consume
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
zone.Population ! Zone.Population.Join(avatar)
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
expectNoMessage(Duration.create(100, "ms"))
|
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 zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||||
val player = Player(avatar)
|
val player = Player(avatar)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
zone.Population ! Zone.Population.Join(avatar)
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
expectNoMessage(Duration.create(100, "ms"))
|
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 zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||||
val player = Player(avatar)
|
val player = Player(avatar)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
zone.Population ! Zone.Population.Join(avatar)
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
expectNoMessage(Duration.create(100, "ms"))
|
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 avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||||
val player = Player(avatar)
|
val player = Player(avatar)
|
||||||
player.GUID = PlanetSideGUID(1)
|
player.GUID = PlanetSideGUID(1)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
zone.Population ! Zone.Population.Join(avatar)
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
expectNoMessage(Duration.create(100, "ms"))
|
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 avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||||
val player1 = Player(avatar)
|
val player1 = Player(avatar)
|
||||||
val player2 = Player(avatar)
|
val player2 = Player(avatar)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
zone.Population ! Zone.Population.Join(avatar)
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
expectNoMessage(Duration.create(100, "ms"))
|
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 zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||||
val player = Player(avatar)
|
val player = Player(avatar)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
assert(zone.Players.isEmpty)
|
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 {
|
"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 zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
zone.Population ! Zone.Population.Join(avatar)
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
expectNoMessage(Duration.create(100, "ms"))
|
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 zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||||
player.Release
|
player.Release
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
assert(zone.Corpses.isEmpty)
|
assert(zone.Corpses.isEmpty)
|
||||||
|
|
@ -498,8 +413,7 @@ class ZonePopulationTest extends ActorTest {
|
||||||
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||||
player.Release
|
player.Release
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
zone.Population ! Zone.Corpse.Add(player)
|
zone.Population ! Zone.Corpse.Add(player)
|
||||||
expectNoMessage(Duration.create(500, "ms"))
|
expectNoMessage(Duration.create(500, "ms"))
|
||||||
|
|
@ -519,8 +433,7 @@ class ZonePopulationTest extends ActorTest {
|
||||||
player2.Release
|
player2.Release
|
||||||
val player3 = Player(Avatar("Chord3", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
val player3 = Player(Avatar("Chord3", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||||
player3.Release
|
player3.Release
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
zone.Population ! Zone.Corpse.Add(player1)
|
zone.Population ! Zone.Corpse.Add(player1)
|
||||||
zone.Population ! Zone.Corpse.Add(player2)
|
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 zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
|
||||||
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
|
||||||
//player.Release !!important
|
//player.Release !!important
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
assert(zone.Corpses.isEmpty)
|
assert(zone.Corpses.isEmpty)
|
||||||
|
|
@ -560,8 +472,7 @@ class ZoneGroundDropItemTest extends ActorTest {
|
||||||
hub.register(item, 10)
|
hub.register(item, 10)
|
||||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||||
zone.GUID(hub)
|
zone.GUID(hub)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
"DropItem" should {
|
"DropItem" should {
|
||||||
|
|
@ -586,8 +497,7 @@ class ZoneGroundCanNotDropItem1Test extends ActorTest {
|
||||||
//hub.register(item, 10) //!important
|
//hub.register(item, 10) //!important
|
||||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||||
zone.GUID(hub)
|
zone.GUID(hub)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
"DropItem" should {
|
"DropItem" should {
|
||||||
|
|
@ -612,8 +522,7 @@ class ZoneGroundCanNotDropItem2Test extends ActorTest {
|
||||||
hub.register(item, 10) //!important
|
hub.register(item, 10) //!important
|
||||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||||
//zone.GUID(hub) //!important
|
//zone.GUID(hub) //!important
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
"DropItem" should {
|
"DropItem" should {
|
||||||
|
|
@ -638,8 +547,7 @@ class ZoneGroundCanNotDropItem3Test extends ActorTest {
|
||||||
hub.register(item, 10) //!important
|
hub.register(item, 10) //!important
|
||||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||||
zone.GUID(hub) //!important
|
zone.GUID(hub) //!important
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
"DropItem" should {
|
"DropItem" should {
|
||||||
|
|
@ -672,8 +580,7 @@ class ZoneGroundPickupItemTest extends ActorTest {
|
||||||
hub.register(item, 10)
|
hub.register(item, 10)
|
||||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||||
zone.GUID(hub)
|
zone.GUID(hub)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
"PickupItem" should {
|
"PickupItem" should {
|
||||||
|
|
@ -701,8 +608,7 @@ class ZoneGroundCanNotPickupItemTest extends ActorTest {
|
||||||
hub.register(item, 10)
|
hub.register(item, 10)
|
||||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||||
zone.GUID(hub) //still registered to this zone
|
zone.GUID(hub) //still registered to this zone
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
"PickupItem" should {
|
"PickupItem" should {
|
||||||
|
|
@ -726,8 +632,7 @@ class ZoneGroundRemoveItemTest extends ActorTest {
|
||||||
hub.register(item, 10)
|
hub.register(item, 10)
|
||||||
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
|
||||||
zone.GUID(hub) //still registered to this zone
|
zone.GUID(hub) //still registered to this zone
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), ZoneTest.TestName)
|
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
expectNoMessage(200 milliseconds)
|
expectNoMessage(200 milliseconds)
|
||||||
|
|
||||||
"RemoveItem" should {
|
"RemoveItem" should {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package objects.terminal
|
||||||
import akka.actor.Props
|
import akka.actor.Props
|
||||||
import akka.testkit.TestProbe
|
import akka.testkit.TestProbe
|
||||||
import base.ActorTest
|
import base.ActorTest
|
||||||
|
import net.psforever.actors.zone.ZoneActor
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.serverobject.terminals.{
|
import net.psforever.objects.serverobject.terminals.{
|
||||||
|
|
@ -12,14 +13,14 @@ import net.psforever.objects.serverobject.terminals.{
|
||||||
ProximityUnit,
|
ProximityUnit,
|
||||||
Terminal
|
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.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, PlanetSideGUID}
|
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, PlanetSideGUID}
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
import services.Service
|
import services.Service
|
||||||
import services.local.LocalService
|
import services.local.LocalService
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
|
||||||
class ProximityTest extends Specification {
|
class ProximityTest extends Specification {
|
||||||
"ProximityUnit" should {
|
"ProximityUnit" should {
|
||||||
|
|
@ -106,7 +107,7 @@ class ProximityTerminalControlStartTest extends ActorTest {
|
||||||
"ProximityTerminalControl" should {
|
"ProximityTerminalControl" should {
|
||||||
//setup
|
//setup
|
||||||
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
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() = {
|
override def SetupNumberPools() = {
|
||||||
AddPool("dynamic", 1 to 10)
|
AddPool("dynamic", 1 to 10)
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +147,7 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest {
|
||||||
"ProximityTerminalControl" should {
|
"ProximityTerminalControl" should {
|
||||||
//setup
|
//setup
|
||||||
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
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() = {
|
override def SetupNumberPools() = {
|
||||||
AddPool("dynamic", 1 to 10)
|
AddPool("dynamic", 1 to 10)
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +200,7 @@ class ProximityTerminalControlStopTest extends ActorTest {
|
||||||
"ProximityTerminalControl" should {
|
"ProximityTerminalControl" should {
|
||||||
//setup
|
//setup
|
||||||
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
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() = {
|
override def SetupNumberPools() = {
|
||||||
AddPool("dynamic", 1 to 10)
|
AddPool("dynamic", 1 to 10)
|
||||||
}
|
}
|
||||||
|
|
@ -242,7 +243,7 @@ class ProximityTerminalControlNotStopTest extends ActorTest {
|
||||||
"ProximityTerminalControl" should {
|
"ProximityTerminalControl" should {
|
||||||
//setup
|
//setup
|
||||||
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
|
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() = {
|
override def SetupNumberPools() = {
|
||||||
AddPool("dynamic", 1 to 10)
|
AddPool("dynamic", 1 to 10)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@
|
||||||
<pattern>%date{ISO8601} [%thread] %5level "%X" %logger{35} - %msg%n</pattern>
|
<pattern>%date{ISO8601} [%thread] %5level "%X" %logger{35} - %msg%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
<level>OFF</level>
|
<!--<level>OFF</level>-->
|
||||||
<!--<level>TRACE</level>-->
|
<level>TRACE</level>
|
||||||
</filter>
|
</filter>
|
||||||
</appender>
|
</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 java.util.Locale
|
||||||
|
|
||||||
import akka.{actor => classic}
|
import akka.{actor => classic}
|
||||||
import akka.actor.typed.ActorSystem
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
import akka.routing.RandomPool
|
import akka.routing.RandomPool
|
||||||
import ch.qos.logback.classic.LoggerContext
|
import ch.qos.logback.classic.LoggerContext
|
||||||
import ch.qos.logback.classic.joran.JoranConfigurator
|
import ch.qos.logback.classic.joran.JoranConfigurator
|
||||||
|
|
@ -15,7 +15,7 @@ import net.psforever.objects.guid.TaskResolver
|
||||||
import org.slf4j
|
import org.slf4j
|
||||||
import org.fusesource.jansi.Ansi._
|
import org.fusesource.jansi.Ansi._
|
||||||
import org.fusesource.jansi.Ansi.Color._
|
import org.fusesource.jansi.Ansi.Color._
|
||||||
import services.ServiceManager
|
import services.{InterstellarClusterService, ServiceManager}
|
||||||
import services.account.{AccountIntermediaryService, AccountPersistenceService}
|
import services.account.{AccountIntermediaryService, AccountPersistenceService}
|
||||||
import services.chat.ChatService
|
import services.chat.ChatService
|
||||||
import services.galaxy.GalaxyService
|
import services.galaxy.GalaxyService
|
||||||
|
|
@ -27,7 +27,6 @@ import org.flywaydb.core.Flyway
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import scopt.OParser
|
import scopt.OParser
|
||||||
|
|
||||||
import akka.actor.typed.scaladsl.adapter._
|
|
||||||
import net.psforever.actors.session.SessionActor
|
import net.psforever.actors.session.SessionActor
|
||||||
import net.psforever.login.psadmin.PsAdminActor
|
import net.psforever.login.psadmin.PsAdminActor
|
||||||
import net.psforever.login.{
|
import net.psforever.login.{
|
||||||
|
|
@ -94,8 +93,6 @@ object PsLogin {
|
||||||
implicit val system = classic.ActorSystem("PsLogin")
|
implicit val system = classic.ActorSystem("PsLogin")
|
||||||
Default(system)
|
Default(system)
|
||||||
|
|
||||||
val typedSystem: ActorSystem[Nothing] = system.toTyped
|
|
||||||
|
|
||||||
/** Create pipelines for the login and world servers
|
/** Create pipelines for the login and world servers
|
||||||
*
|
*
|
||||||
* The first node in the pipe is an Actor that handles the crypto for protecting packets.
|
* The first node in the pipe is an Actor that handles the crypto for protecting packets.
|
||||||
|
|
@ -130,16 +127,16 @@ object PsLogin {
|
||||||
None
|
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
|
val serviceManager = ServiceManager.boot
|
||||||
serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService], "accountIntermediary")
|
serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService], "accountIntermediary")
|
||||||
serviceManager ! ServiceManager.Register(RandomPool(150).props(classic.Props[TaskResolver]), "taskResolver")
|
serviceManager ! ServiceManager.Register(RandomPool(150).props(classic.Props[TaskResolver]), "taskResolver")
|
||||||
serviceManager ! ServiceManager.Register(classic.Props[GalaxyService], "galaxy")
|
serviceManager ! ServiceManager.Register(classic.Props[GalaxyService], "galaxy")
|
||||||
serviceManager ! ServiceManager.Register(classic.Props[SquadService], "squad")
|
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[AccountPersistenceService], "accountPersistence")
|
||||||
serviceManager ! ServiceManager.Register(classic.Props[PropertyOverrideManager], "propertyOverrideManager")
|
serviceManager ! ServiceManager.Register(classic.Props[PropertyOverrideManager], "propertyOverrideManager")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.types.{PlanetSideGUID, _}
|
import net.psforever.types.{PlanetSideGUID, _}
|
||||||
import services.RemoverActor
|
import services.RemoverActor
|
||||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
import net.psforever.actors.zone.ZoneActor
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
|
@ -213,7 +215,6 @@ object VehicleSpawnPadControlTest {
|
||||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.Building
|
||||||
import net.psforever.objects.vehicles.VehicleControl
|
import net.psforever.objects.vehicles.VehicleControl
|
||||||
import net.psforever.objects.zones.ZoneActor
|
|
||||||
import net.psforever.objects.Tool
|
import net.psforever.objects.Tool
|
||||||
import net.psforever.types.CharacterGender
|
import net.psforever.types.CharacterGender
|
||||||
|
|
||||||
|
|
@ -228,8 +229,7 @@ object VehicleSpawnPadControlTest {
|
||||||
override def SetupNumberPools(): Unit = {}
|
override def SetupNumberPools(): Unit = {}
|
||||||
}
|
}
|
||||||
zone.GUID(guid)
|
zone.GUID(guid)
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), s"test-zone-${System.nanoTime()}")
|
zone.actor = system.spawn(ZoneActor(zone), s"test-zone-${System.nanoTime()}")
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
|
|
||||||
// Hack: Wait for the Zone to finish booting, otherwise later tests will fail randomly due to race conditions
|
// Hack: Wait for the Zone to finish booting, otherwise later tests will fail randomly due to race conditions
|
||||||
// with actor probe setting
|
// with actor probe setting
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import akka.routing.RandomPool
|
||||||
import actor.base.ActorTest
|
import actor.base.ActorTest
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
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.objectcreate.{DroppedItemData, ObjectClass, ObjectCreateMessageParent, PlacementData}
|
||||||
import net.psforever.packet.game.{ObjectCreateMessage, PlayerStateMessageUpstream}
|
import net.psforever.packet.game.{ObjectCreateMessage, PlayerStateMessageUpstream}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
|
|
@ -14,6 +14,8 @@ import services.{RemoverActor, Service, ServiceManager}
|
||||||
import services.avatar._
|
import services.avatar._
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
import net.psforever.actors.zone.ZoneActor
|
||||||
|
|
||||||
class AvatarService1Test extends ActorTest {
|
class AvatarService1Test extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
|
|
@ -510,8 +512,7 @@ class AvatarReleaseTest extends ActorTest {
|
||||||
}
|
}
|
||||||
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
||||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
val obj = Player(Avatar("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
|
val obj = Player(Avatar("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
|
||||||
obj.Continent = "test"
|
obj.Continent = "test"
|
||||||
obj.Release
|
obj.Release
|
||||||
|
|
@ -561,8 +562,7 @@ class AvatarReleaseEarly1Test extends ActorTest {
|
||||||
}
|
}
|
||||||
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
||||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
val obj = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
|
val obj = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1))
|
||||||
obj.Continent = "test"
|
obj.Continent = "test"
|
||||||
obj.Release
|
obj.Release
|
||||||
|
|
@ -613,8 +613,7 @@ class AvatarReleaseEarly2Test extends ActorTest {
|
||||||
}
|
}
|
||||||
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service")
|
||||||
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||||
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
zone.actor = system.spawn(ZoneActor(zone), "release-test-zone")
|
||||||
zone.Actor ! Zone.Init()
|
|
||||||
val objAlt =
|
val objAlt =
|
||||||
Player(
|
Player(
|
||||||
Avatar("TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 1, CharacterVoice.Voice1)
|
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