diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala index 2b566812..9a60f87a 100644 --- a/common/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala @@ -9,9 +9,10 @@ import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.serverobject.deploy.Deployment +import net.psforever.objects.serverobject.structures.AmenityOwner import net.psforever.objects.vehicles._ import net.psforever.objects.vital.{DamageResistanceModel, StandardResistanceProfile, Vitality} -import net.psforever.objects.zones.ZoneAware +import net.psforever.objects.zones.{Zone, ZoneAware} import net.psforever.packet.game.PlanetSideGUID import net.psforever.types.PlanetSideEmpire @@ -73,6 +74,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ with Deployment with Vitality with OwnableByPlayer + with AmenityOwner with StandardResistanceProfile with Container { private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR @@ -84,8 +86,12 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ private var cloaked : Boolean = false private var flying : Boolean = false private var capacitor : Int = 0 - private var continent : String = "home2" //the zone id - +/** + * Normally, the vehicle is the resident of a `Zone` object and that is what it considers its "continent." + * Since the `Vehicle` object can switch between `Zone` objects, however, + * it may become useful to allow the vehicle to identify as belonging to its future zone earlier than reference assignment. + */ + private var continent : Option[String] = None //the zone id /** * Permissions control who gets to access different parts of the vehicle; * the groups are Driver (seat), Gunner (seats), Passenger (seats), and the Trunk @@ -508,10 +514,25 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ */ def Definition : VehicleDefinition = vehicleDef - override def Continent : String = continent + /** + * When assigning a new `Zone` object for the `Vehicle` object, eliminate + * @param zone a reference to the `Zone` object + * @return a reference to the `Zone` object + */ + override def Zone_=(zone : Zone) : Zone = { + continent = None + super.Zone_=(zone) + } + override def Continent : String = continent.getOrElse(Zone.Id) + + /** + * Give the `Vehicle` object a custom `Zone` identifier. + * @param zoneId the custom identifier of the `Zone` object + * @return the identifier of the `Zone` object + */ override def Continent_=(zoneId : String) : String = { - continent = zoneId + continent = Some(zoneId) Continent } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala index 52b1cad2..2918b7de 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala @@ -1,7 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.pad -import akka.actor.{ActorContext, ActorRef, Cancellable, Props} +import akka.actor.{ActorContext, Cancellable, Props} import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.pad.process.{VehicleSpawnControlBase, VehicleSpawnControlConcealPlayer} import net.psforever.objects.zones.Zone @@ -12,28 +12,32 @@ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ /** - * An `Actor` that handles vehicle spawning orders for a `VehicleSpawnPad`. - * The basic `VehicleSpawnControl` is the root of a simple tree of "spawn control" objects that chain to each other. - * Each object performs on (or more than one related) actions upon the vehicle order that was submitted.
+ * An `Actor` that handles vehicle spawning orders for a `VehicleSpawnPad` entity. + * The basic `VehicleSpawnControl` is the root of a sequence of "spawn control" objects that chain to each other. + * Each object performs one (or more related) actions upon the vehicle order that was submitted.
*
- * The purpose of the base actor is to serve as the entry point for the spawning process. - * A spawn pad receives vehicle orders from an attached `Terminal` object. + * The purpose of the base actor is to serve as the entry point for the spawning process + * and to manage the order queue. + * A spawn pad receives vehicle orders from a related `Terminal` object. * The control object accepts orders, enqueues them, and, * whenever prompted by a previous complete order or by an absence of active orders, * will select the first available order to be completed. * This order will be "tracked" and will be given to the first functional "spawn control" object of the process. * If the process is completed, or is ever aborted by any of the subsequent tasks, * control will propagate down back to this control object. + * At this time, (or) once again, a new order can be submitted or will be selected. * @param pad the `VehicleSpawnPad` object being governed */ class VehicleSpawnControl(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) with FactionAffinityBehavior.Check { /** a reminder sent to future customers */ var periodicReminder : Cancellable = DefaultCancellable.obj /** a list of vehicle orders that have been submitted for this spawn pad */ - private var orders : List[VehicleSpawnControl.Order] = List.empty[VehicleSpawnControl.Order] + var orders : List[VehicleSpawnControl.Order] = List.empty[VehicleSpawnControl.Order] /** the current vehicle order being acted upon; * used as a guard condition to control order processing rate */ - private var trackedOrder : Option[VehicleSpawnControl.Order] = None + var trackedOrder : Option[VehicleSpawnControl.Order] = None + /** how to process either the first order or every subsequent order */ + var handleOrderFunc : VehicleSpawnControl.Order => Unit = NewTasking def LogId = "" @@ -55,13 +59,16 @@ class VehicleSpawnControl(pad : VehicleSpawnPad) extends VehicleSpawnControlBase def receive : Receive = checkBehavior.orElse { case VehicleSpawnPad.VehicleOrder(player, vehicle) => - trace(s"order from $player for $vehicle received") - orders = orders :+ VehicleSpawnControl.Order(player, vehicle, sender) - if(trackedOrder.isEmpty && orders.length == 1) { - SelectOrder() + trace(s"order from ${player.Name} for a ${vehicle.Definition.Name} received") + try { + handleOrderFunc(VehicleSpawnControl.Order(player, vehicle)) } - else { - sender ! VehicleSpawnControl.RenderOrderRemainderMsg(orders.length + 1) + catch { + case _ : AssertionError if vehicle.HasGUID => //same as order being dropped + VehicleSpawnControl.DisposeSpawnedVehicle(vehicle, pad.Owner.Zone) + case _ : AssertionError => ; //shrug + case e : Exception => //something unexpected + e.printStackTrace() } case VehicleSpawnControl.ProcessControl.GetNewOrder => @@ -89,7 +96,7 @@ class VehicleSpawnControl(pad : VehicleSpawnPad) extends VehicleSpawnControlBase ) } else { - VehicleSpawnControl.BlockedReminder(entry, entry +: orders) + BlockedReminder(entry, orders) } case None => ; periodicReminder.cancel @@ -97,43 +104,143 @@ class VehicleSpawnControl(pad : VehicleSpawnPad) extends VehicleSpawnControlBase case VehicleSpawnControl.ProcessControl.Flush => periodicReminder.cancel - orders.foreach { VehicleSpawnControl.CancelOrder(_, Continent) } + orders.foreach { CancelOrder } orders = Nil trackedOrder match { case Some(entry) => - VehicleSpawnControl.CancelOrder(entry, Continent) + CancelOrder(entry) case None => ; } trackedOrder = None - concealPlayer ! akka.actor.Kill //will cause the actor to restart, which will abort any trapped messages + concealPlayer ! akka.actor.Kill //should cause the actor to restart, which will abort any trapped messages case _ => ; } - def SelectOrder() : Unit = { + /** + * Take this order - the "first order" - and immediately begin processing it. + * All orders accepted in the meantime will be queued and a note about priority will be issued. + * @param order the order being accepted + */ + def NewTasking(order : VehicleSpawnControl.Order) : Unit = { + handleOrderFunc = QueuedTasking + ProcessOrder(Some(order)) + } + + /** + * While an order is being processed, + * all orders accepted in the meantime will be queued and a note about priority will be issued. + * @param order the order being accepted + */ + def QueuedTasking(order : VehicleSpawnControl.Order) : Unit = { + val name = order.driver.Name + if((trackedOrder match { + case Some(tracked) => !tracked.driver.Name.equals(name) + case None => true + }) && orders.forall { !_.driver.Name.equals(name) }) { + //not a second order from an existing order's player + orders = orders :+ order + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(name, VehicleSpawnPad.Reminders.Queue, Some(orders.length + 1)) + } + else { + VehicleSpawnControl.DisposeSpawnedVehicle(order, pad.Owner.Zone) + } + } + + /** + * Select the next available queued order and begin processing it. + */ + def SelectOrder() : Unit = ProcessOrder(SelectFirstOrder()) + + /** + * Select the next-available queued order if there is no current order being fulfilled. + * If the queue has been exhausted, set functionality to prepare to accept the next order as a "first order." + * @return the next-available order + */ + def SelectFirstOrder() : Option[VehicleSpawnControl.Order] = { trackedOrder match { case None => - periodicReminder.cancel val (completeOrder, remainingOrders) : (Option[VehicleSpawnControl.Order], List[VehicleSpawnControl.Order]) = orders match { case x :: Nil => (Some(x), Nil) case x :: b => - trace(s"order backlog size: ${b.size}") - VehicleSpawnControl.recursiveOrderReminder(b.iterator) (Some(x), b) case Nil => + handleOrderFunc = NewTasking (None, Nil) } orders = remainingOrders - completeOrder match { - case Some(entry) => - trace(s"processing next order - a ${entry.vehicle.Definition.Name} for ${entry.driver.Name}") - trackedOrder = completeOrder //guard on - context.system.scheduler.scheduleOnce(2000 milliseconds, concealPlayer, VehicleSpawnControl.Process.ConcealPlayer(entry)) - case None => - trackedOrder = None - } - case Some(_) => ; //do not work on new orders + completeOrder + case Some(_) => + None + } + } + + /** + * If a new order is accepted, begin processing it. + * Inform all customers whose orders are still queued of their priority number + * and activate the guard to ensure multiple orders don't get processed at the same time. + * @param order the order being accepted; + * `None`, if no order found or submitted + */ + def ProcessOrder(order : Option[VehicleSpawnControl.Order]) : Unit = { + periodicReminder.cancel + order match { + case Some(_order) => + recursiveOrderReminder(orders.iterator) + trace(s"processing next order - a ${_order.vehicle.Definition.Name} for ${_order.driver.Name}") + trackedOrder = order //guard on + context.system.scheduler.scheduleOnce(2000 milliseconds, concealPlayer, _order) + case None => ; + } + } + + /** + * na + * @param blockedOrder the previous order whose vehicle is blocking the spawn pad from operating + * @param recipients all of the other customers who will be receiving the message + */ + def BlockedReminder(blockedOrder : VehicleSpawnControl.Order, recipients : Seq[VehicleSpawnControl.Order]) : Unit = { + val relevantRecipients = blockedOrder.vehicle.Seats(0).Occupant.orElse(pad.Owner.Zone.GUID(blockedOrder.vehicle.Owner)) match { + case Some(p : Player) => + (VehicleSpawnControl.Order(p, blockedOrder.vehicle) +: recipients).iterator //who took possession of the vehicle + case _ => + (blockedOrder +: recipients).iterator //who ordered the vehicle + } + recursiveBlockedReminder(relevantRecipients, + if(blockedOrder.vehicle.Health == 0) + Option("Clear the wreckage.") + else + None + ) + } + + /** + * Cancel this vehicle order and inform the person who made it, if possible. + * @param entry the order being cancelled + * @param context an `ActorContext` object for which to create the `TaskResolver` object + */ + def CancelOrder(entry : VehicleSpawnControl.Order)(implicit context : ActorContext) : Unit = { + val vehicle = entry.vehicle + if(vehicle.Seats.values.count(_.isOccupied) == 0) { + VehicleSpawnControl.DisposeSpawnedVehicle(entry, pad.Owner.Zone) + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(entry.driver.Name, VehicleSpawnPad.Reminders.Cancelled) + } + } + + @tailrec private final def recursiveBlockedReminder(iter : Iterator[VehicleSpawnControl.Order], cause : Option[Any]) : Unit = { + if(iter.hasNext) { + val recipient = iter.next + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(recipient.driver.Name, VehicleSpawnPad.Reminders.Blocked, cause) + recursiveBlockedReminder(iter, cause) + } + } + + @tailrec private final def recursiveOrderReminder(iter : Iterator[VehicleSpawnControl.Order], position : Int = 2) : Unit = { + if(iter.hasNext) { + val recipient = iter.next + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(recipient.driver.Name, VehicleSpawnPad.Reminders.Queue, Some(position)) + recursiveOrderReminder(iter, position + 1) } } } @@ -152,159 +259,35 @@ object VehicleSpawnControl { Flush = Value } - /** - * An `Enumeration` of the stages of a full vehicle spawning process, passing the current order being processed. - * Messages in this group are used by the `receive` entry points of the multiple child objects - * that perform the vehicle spawning operation. - */ - object Process { - sealed class Order(entry : VehicleSpawnControl.Order) - - final case class ConcealPlayer(entry : VehicleSpawnControl.Order) extends Order(entry) - final case class LoadVehicle(entry : VehicleSpawnControl.Order) extends Order(entry) - final case class SeatDriver(entry : VehicleSpawnControl.Order) extends Order(entry) - final case class RailJackAction(entry : VehicleSpawnControl.Order) extends Order(entry) - final case class ServerVehicleOverride(entry : VehicleSpawnControl.Order) extends Order(entry) - final case class StartGuided(entry : VehicleSpawnControl.Order) extends Order(entry) - final case class DriverVehicleControl(entry : VehicleSpawnControl.Order) extends Order(entry) - final case class FinalClearance(entry : VehicleSpawnControl.Order) extends Order(entry) - } /** - * An entry that stores vehicle spawn pad spawning tasks (called "orders"). + * An entry that stores a vehicle spawn pad spawning task (called an "order"). * @param driver the player who wants the vehicle * @param vehicle the vehicle - * @param sendTo a callback `Actor` associated with the player (in other words, `WorldSessionActor`) */ - final case class Order(driver : Player, vehicle : Vehicle, sendTo : ActorRef) - - /** - * Properly clean up a vehicle that has been registered, but not yet been spawned into the game world.
- *
- * Constructs a temporary `TaskResolver` to deal with the vehicle's registration status. - * This "temporary" router will persist as if it were a `static` variable in some other language - * due to the fact that the `ActorSystem` object will remember it existing. - * After the primary task is complete, the router that was created is stopped so that it can be garbage collected. - * We could re-use it theoretically, but the `context` might be untrustworthy. - * @param entry the order being cancelled - * @param zone the continent on which the vehicle was registered - * @param context an `ActorContext` object for which to create the `TaskResolver` object - */ - def DisposeVehicle(entry : VehicleSpawnControl.Order, zone: Zone)(implicit context : ActorContext) : Unit = { - import akka.actor.{ActorRef, PoisonPill} - import akka.routing.SmallestMailboxPool - import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver} - import net.psforever.types.Vector3 - val vehicle = entry.vehicle - vehicle.Position = Vector3.Zero - zone.VehicleEvents ! VehicleSpawnPad.RevealPlayer(entry.driver.GUID, zone.Id) - - val router = context.actorOf( - SmallestMailboxPool(10).props(Props[TaskResolver]), - s"vehicle-spawn-control-emergency-decon-resolver-${System.nanoTime}" - ) - router ! - TaskResolver.GiveTask( - new Task() { - private val localRouter = router - - override def isComplete = Task.Resolution.Success - - def Execute(resolver : ActorRef) : Unit = { - resolver ! scala.util.Success(this) - } - - override def Cleanup() : Unit = { localRouter ! PoisonPill } //where the router is stopped - }, List(GUIDTask.UnregisterVehicle(vehicle)(zone.GUID)) - ) + final case class Order(driver : Player, vehicle : Vehicle) { + assert(driver.HasGUID, s"when ordering a vehicle, the prospective driver ${driver.Name} does not have a GUID") + assert(vehicle.HasGUID, s"when ordering a vehicle, the ${vehicle.Definition.Name} does not have a GUID") + val DriverGUID = driver.GUID } /** * Properly clean up a vehicle that has been registered and spawned into the game world. + * Call this downstream of "`ConcealPlayer`". * @param entry the order being cancelled * @param zone the continent on which the vehicle was registered */ def DisposeSpawnedVehicle(entry : VehicleSpawnControl.Order, zone: Zone) : Unit = { - //TODO this cleanup will handle the vehicle; but, the former driver may be thrown into the void - zone.VehicleEvents ! VehicleSpawnPad.DisposeVehicle(entry.vehicle, zone) - zone.VehicleEvents ! VehicleSpawnPad.RevealPlayer(entry.driver.GUID, zone.Id) + DisposeSpawnedVehicle(entry.vehicle, zone) + zone.VehicleEvents ! VehicleSpawnPad.RevealPlayer(entry.DriverGUID) } /** - * Remind a customer how long it will take for their vehicle order to be processed. - * @param position position in the queue - * @return an index-appropriate `VehicleSpawnPad.PeriodicReminder` object - */ - def RenderOrderRemainderMsg(position : Int) : VehicleSpawnPad.PeriodicReminder = { - VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"$position")) - } - - /** - * - * @param blockedOrder the previous order whose vehicle is blocking the spawn pad from operating - * @param recipients all of the customers who will be receiving the message - */ - def BlockedReminder(blockedOrder : VehicleSpawnControl.Order, recipients : Seq[VehicleSpawnControl.Order]) : Unit = { - val wrecked : Option[Any] = if(blockedOrder.vehicle.Health == 0) { - Option("Clear the wreckage.") - } - else { - None - } - VehicleSpawnControl.recursiveBlockedReminder(recipients.iterator, wrecked) - } - - /** - * Cancel this vehicle order and inform the person who made it, if possible. - * @param entry the order being cancelled + * Properly clean up a vehicle that has been registered and spawned into the game world. + * @param vehicle the vehicle being cancelled * @param zone the continent on which the vehicle was registered - * @param context an `ActorContext` object for which to create the `TaskResolver` object */ - def CancelOrder(entry : VehicleSpawnControl.Order, zone : Zone)(implicit context : ActorContext) : Unit = { - val vehicle = entry.vehicle - if(vehicle.Seats.values.count(_.isOccupied) == 0) { - if(vehicle.Actor != ActorRef.noSender) { - VehicleSpawnControl.DisposeSpawnedVehicle(entry, zone) - } - else { - VehicleSpawnControl.DisposeVehicle(entry, zone) - } - if(entry.sendTo != ActorRef.noSender) { - entry.sendTo ! VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Cancelled) - } - } - } - -// @tailrec private final def recursiveFindOrder(iter : Iterator[VehicleSpawnControl.Order], target : ActorRef, index : Int = 0) : Option[Int] = { -// if(!iter.hasNext) { -// None -// } -// else { -// val recipient = iter.next -// if(recipient.sendTo == target) { -// Some(index) -// } -// else { -// recursiveFindOrder(iter, target, index + 1) -// } -// } -// } - - @tailrec private final def recursiveBlockedReminder(iter : Iterator[VehicleSpawnControl.Order], cause : Option[Any]) : Unit = { - if(iter.hasNext) { - val recipient = iter.next - recipient.sendTo ! VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, cause) - recursiveBlockedReminder(iter, cause) - } - } - - @tailrec private final def recursiveOrderReminder(iter : Iterator[VehicleSpawnControl.Order], position : Int = 2) : Unit = { - if(iter.hasNext) { - val recipient = iter.next - if(recipient.sendTo != ActorRef.noSender) { - recipient.sendTo ! RenderOrderRemainderMsg(position) - } - recursiveOrderReminder(iter, position + 1) - } + def DisposeSpawnedVehicle(vehicle : Vehicle, zone: Zone) : Unit = { + zone.VehicleEvents ! VehicleSpawnPad.DisposeVehicle(vehicle) } } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala index db274cfd..1b7251a3 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala @@ -1,54 +1,26 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.pad -import net.psforever.objects.serverobject.pad.process.AutoDriveControls import net.psforever.objects.{Player, Vehicle} import net.psforever.objects.serverobject.structures.Amenity -import net.psforever.objects.zones.Zone import net.psforever.packet.game.PlanetSideGUID /** * A structure-owned server object that is a "spawn pad" for vehicles.
*
- * Spawn pads have no purpose on their own but - * maintain the operative queue that introduces the vehicle into the game world and applies initial activity to it and - * maintain a position and a direction where the vehicle will be made to appear (as a `PlanetSideServerObject`). - * The actual functionality managed by this object is wholly found on its accompanying `Actor`. + * Spawn pads have no purpose on their own, save to represent the position and orientation of the game object. + * Their control `Actor` object maintains the operative queue by which a vehicle is introduced into the game world. + * The common features of spawn pads are its horizontal doors. + * Most spawn pads also contain a lifting platform that hoists the vehicles out a concealed trench. + * The Battleframe Robotics spawn sheds do not have lifting platforms as they are vertical structures. * @see `VehicleSpawnControl` * @param spDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields */ class VehicleSpawnPad(spDef : VehicleSpawnPadDefinition) extends Amenity { - /** - * Use the in-game railed platform to lift the spawned vehicle out of the trench. - * When set, the client performs the standard vehicle entry procedure, including lifting platform animations. - * When unset, the client depicts the player manually boarding the new vehicle within the trench area. - * Eventually, the vehicle is then hoisted out into the open; without this set, that hoisting is abrupt. - * The main reason to disable this feature is to avoid an `ObjectAttachMessage` for an incorrect object designation. - * Unset if not guaranteed to have the correct globally unique id of the spawn pad. - */ - private var onRails : Boolean = true - - private var guidedPath : List[AutoDriveControls.Configuration] = Nil - - def Railed : Boolean = onRails - - def Railed_=(useRails : Boolean) : Boolean = { - onRails = useRails - Railed - } - - def Guide : List[AutoDriveControls.Configuration] = guidedPath - - def Guide_=(path : List[AutoDriveControls.Configuration]) : List[AutoDriveControls.Configuration] = { - guidedPath = path - Guide - } - def Definition : VehicleSpawnPadDefinition = spDef } object VehicleSpawnPad { - /** * Message to the spawn pad to enqueue the following vehicle order. * This is the entry point to vehicle spawn pad functionality. @@ -61,24 +33,21 @@ object VehicleSpawnPad { * Message to indicate that a certain player should be made transparent. * @see `GenericObjectActionMessage` * @param player_guid the player - * @param zone_id the zone in which the spawn pad is located */ - final case class ConcealPlayer(player_guid : PlanetSideGUID, zone_id : String) + final case class ConcealPlayer(player_guid: PlanetSideGUID) /** * Message is intended to undo the effects of the above message, `ConcealPlayer`. * @see `ConcealPlayer` * @param player_guid the player - * @param zone_id the zone in which the spawn pad is located */ - final case class RevealPlayer(player_guid : PlanetSideGUID, zone_id : String) + final case class RevealPlayer(player_guid: PlanetSideGUID) /** * Message to properly introduce the vehicle into the zone. * @param vehicle the vehicle being spawned - * @param zone the zone in which the spawn pad is located */ - final case class LoadVehicle(vehicle : Vehicle, zone : Zone) + final case class LoadVehicle(vehicle: Vehicle) /** * Message to attach the vehicle to the spawn pad's lifting platform ("put on rails"). @@ -86,76 +55,77 @@ object VehicleSpawnPad { * @see `ObjectAttachMessage` * @param vehicle the vehicle being spawned * @param pad the spawn pad - * @param zone_id the zone in which the spawn pad is located */ - final case class AttachToRails(vehicle : Vehicle, pad : VehicleSpawnPad, zone_id : String) + final case class AttachToRails(vehicle: Vehicle, pad: VehicleSpawnPad) /** * Message to detach the vehicle from the spawn pad's lifting platform ("put on rails"). * @see `ObjectDetachMessage` * @param vehicle the vehicle being spawned * @param pad the spawn pad - * @param zone_id the zone in which the spawn pad is located */ - final case class DetachFromRails(vehicle : Vehicle, pad : VehicleSpawnPad, zone_id : String) + final case class DetachFromRails(vehicle: Vehicle, pad: VehicleSpawnPad) /** * Message that resets the spawn pad for its next order fulfillment operation by lowering the lifting platform. * @see `GenericObjectActionMessage` * @param pad the spawn pad - * @param zone_id the zone in which the spawn pad is located */ - final case class ResetSpawnPad(pad : VehicleSpawnPad, zone_id : String) + final case class ResetSpawnPad(pad: VehicleSpawnPad) /** * Message that acts as callback to the driver that the process of sitting in the driver seat will be initiated soon. * This information should only be communicated to the driver's client only. + * @param driver_name the person who will drive the vehicle * @param vehicle the vehicle being spawned * @param pad the spawn pad */ - final case class StartPlayerSeatedInVehicle(vehicle : Vehicle, pad : VehicleSpawnPad) + final case class StartPlayerSeatedInVehicle(driver_name : String, vehicle : Vehicle, pad : VehicleSpawnPad) /** * Message that acts as callback to the driver that the process of sitting in the driver seat should be finished. * This information should only be communicated to the driver's client only. + * @param driver_name the person who will drive the vehicle * @param vehicle the vehicle being spawned * @param pad the spawn pad */ - final case class PlayerSeatedInVehicle(vehicle : Vehicle, pad : VehicleSpawnPad) //TODO while using fake rails + final case class PlayerSeatedInVehicle(driver_name : String, vehicle : Vehicle, pad : VehicleSpawnPad) //TODO while using fake rails /** * Message that starts the newly-spawned vehicle to begin driving away from the spawn pad. * Information about the driving process is available on the vehicle itself. * This information should only be communicated to the driver's client only. * @see `VehicleDefinition` + * @param driver_name the person who will drive the vehicle * @param vehicle the vehicle * @param pad the spawn pad */ - final case class ServerVehicleOverrideStart(vehicle : Vehicle, pad : VehicleSpawnPad) + final case class ServerVehicleOverrideStart(driver_name : String, vehicle : Vehicle, pad : VehicleSpawnPad) /** * Message that transitions the newly-spawned vehicle into a cancellable auto-drive state. * Information about the driving process is available on the vehicle itself. * This information should only be communicated to the driver's client only. * @see `VehicleDefinition` + * @param driver_name the person who will drive the vehicle * @param vehicle the vehicle * @param pad the spawn pad */ - final case class ServerVehicleOverrideEnd(vehicle : Vehicle, pad : VehicleSpawnPad) + final case class ServerVehicleOverrideEnd(driver_name : String, vehicle : Vehicle, pad : VehicleSpawnPad) /** * Message to initiate the process of properly disposing of the vehicle that may have been or was spawned into the game world. * @param vehicle the vehicle - * @param zone the zone in which the spawn pad is located */ - final case class DisposeVehicle(vehicle : Vehicle, zone : Zone) + final case class DisposeVehicle(vehicle: Vehicle) /** * Message to send targeted messages to the clients of specific users. + * @param driver_name the person who will drive the vehicle * @param reason the nature of the message * @param data optional information for rendering the message to the client */ - final case class PeriodicReminder(reason : Reminders.Value, data : Option[Any] = None) + final case class PeriodicReminder(driver_name : String, reason : Reminders.Value, data : Option[Any] = None) /** * An `Enumeration` of reasons for sending a periodic reminder to the user. @@ -179,7 +149,6 @@ object VehicleSpawnPad { import akka.actor.ActorContext import net.psforever.types.Vector3 - /** * Instantiate and configure a `VehicleSpawnPad` object * @param pdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields @@ -191,7 +160,6 @@ object VehicleSpawnPad { */ def Constructor(pos : Vector3, pdef: VehicleSpawnPadDefinition, orient : Vector3)(id : Int, context : ActorContext) : VehicleSpawnPad = { import akka.actor.Props - import net.psforever.objects.GlobalDefinitions val obj = VehicleSpawnPad(pdef) obj.Position = pos diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/AutoDriveControls.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/AutoDriveControls.scala deleted file mode 100644 index 4a67fe04..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/AutoDriveControls.scala +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.pad.process - -import net.psforever.objects.{GlobalDefinitions, Vehicle} -import net.psforever.types.Vector3 - -/** - * Instructions to be processed by `VehicleSpawnControlGuided`. - * These instructions coordinate basic vehicle manipulations such as driving, turning, and stopping. - * If defined, they will operate on a newly formed vehicle after it is released from its spawn pad lifting platform - * and after it has been issued at least one `ServerVehicleOverrideMsg` packet. - */ -object AutoDriveControls { - - /** - * A container that translates to a new `Setting` instruction. - * Instructions are maintained in this form until they will be used due to the nature of the `Setting` object. - * The least that this object needs to do is accept parameters that matches the specific `Setting` that it outputs. - */ - sealed trait Configuration { - def Create : Setting - } - - /** - * An instruction to be consumed by the cyclic operation of `VehicleSpawnControlGuided` - * and are created by a `Configuration` object. - * They are considered semi-immutable `case class` objects. - * Externally, they are immutable by proper Scala standards. - * Internally, they will be permitted `private` fields that can be modified the first time the object is used. - */ - sealed trait Setting { - /** - * The nature of the action being performed. - * @return an enumerated value that explains the purpose of the action - */ - def Type : State.Value - /** - * The delay in between checks to determine if this setting has accomplished its goal or has entered an invalid state. - * @return the length of the delay - */ - def Delay : Long = 200L - /** - * Data that is important for fulfilling the instruction on a user's client. - * Highly specific to the implementation. - * @return any data deemed important; `None`, if unnecessary - */ - def Data : Option[Any] = None - /** - * Perform a test to determine if the vehicle is capable of performing the action this instruction requires. - * The test is typically simplistic in nature and often boils down to whether o not the vehicle is mobile. - * @param vehicle the vehicle being controlled - * @return `true`, if the action can (probably) be accomplished under the current conditions; `false`, otherwise - */ - def Validate(vehicle : Vehicle) : Boolean = vehicle.isMoving - /** - * Perform a test to determine if the vehicle has reached a set of conditions - * where the action performed by the instruction has been fulfilled. - * This should count as the "end of this step" and the "beginning of the next step." - * @param vehicle the vehicle being controlled - * @return `true`, if the action has run to completion; `false`, otherwise - */ - def CompletionTest(vehicle : Vehicle) : Boolean - } - - /** - * The nature of the action being performed. - * Different actions can be divided into types. - */ - object State extends Enumeration { - val - Cancel, - Climb, - Drive, - Stop, - Turn, - Wait - = Value - } - - protected final case class AutoDrive(speed : Int) extends Setting { - def Type = State.Drive - - override def Data = Some(speed) - - override def Validate(vehicle : Vehicle) : Boolean = true - - def CompletionTest(vehicle : Vehicle) = vehicle.isMoving - } - - protected final case class AutoDriveDistance(start : Vector3, sqDistance : Float) extends Setting { - def Type = State.Wait - - def CompletionTest(vehicle : Vehicle) : Boolean = { - Vector3.DistanceSquared(vehicle.Position.xy, start) > sqDistance - } - } - - protected final case class AutoDriveDistanceFromHere(sqDistance : Float) extends Setting { - private var start : Option[Vector3] = None - - def Type = State.Wait - - def CompletionTest(vehicle : Vehicle) : Boolean = { - val startLoc = start.getOrElse({ - start = Some(vehicle.Position.xy) - start.get - }) - Vector3.DistanceSquared(vehicle.Position.xy, startLoc) > sqDistance - } - } - - protected final case class AutoDriveForTime(length : Long) extends Setting { - private var start : Option[Long] = None - - def Type = State.Wait - - def CompletionTest(vehicle : Vehicle) : Boolean = { - val time : Long = System.currentTimeMillis - val startTime = start.getOrElse({ - start = Some(time) - time - }) - time - startTime >= length - } - - override def Validate(vehicle : Vehicle) : Boolean = true - } - - protected final case class AutoDriveTurnBy(angle : Float, direction : Int) extends Setting { - private var end : Option[Float] = None - private var currAng : Float = 0f - - def Type = State.Turn - - override def Delay : Long = 100L //increased frequency - - override def Data = Some(direction) - - def CompletionTest(vehicle : Vehicle) : Boolean = { - val endAng = end.getOrElse { - currAng = vehicle.Orientation.z - var ang = (currAng + angle) % 360f - if(ang < 0f) { - ang += 360f - } - end = Some(ang) - ang - } - val lastAng = currAng - currAng = vehicle.Orientation.z - //check that the expected angle is sandwiched between the previous angle and the current angle - currAng == endAng || (lastAng < endAng && endAng <= currAng) || (lastAng > endAng && endAng >= currAng) - } - - override def Validate(vehicle : Vehicle) : Boolean = direction != 15 && super.Validate(vehicle) - } - - protected final case class AutoDriveFirstGear() extends Setting { - private var speed : Int = 0 - - def Type = State.Drive - - override def Data = Some(speed) - - def CompletionTest(vehicle : Vehicle) = vehicle.isMoving - - override def Validate(vehicle : Vehicle) : Boolean = { - speed = vehicle.Definition.AutoPilotSpeed1 - true - } - } - - protected final case class AutoDriveSecondGear() extends Setting { - private var speed : Int = 0 - - def Type = State.Drive - - override def Data = Some(speed) - - def CompletionTest(vehicle : Vehicle) = vehicle.isMoving - - override def Validate(vehicle : Vehicle) : Boolean = { - speed = vehicle.Definition.AutoPilotSpeed2 - true - } - } - - protected final case class AutoDriveClimb(altitude : Float) extends Setting { - def Type = State.Climb - - override def Data = Some(altitude) - - def CompletionTest(vehicle : Vehicle) = { - vehicle.Position.z >= altitude - } - - override def Validate(vehicle : Vehicle) : Boolean = GlobalDefinitions.isFlightVehicle(vehicle.Definition) - } - - protected final case class AutoDriveCancelEarly(test : (Vehicle) => Boolean) extends Setting { - def Type = State.Cancel - - def CompletionTest(vehicle : Vehicle) = true - - override def Validate(vehicle : Vehicle) : Boolean = test(vehicle) - } - - protected final case class AutoDriveStop() extends Setting { - def Type = State.Stop - - override def Validate(vehicle : Vehicle) : Boolean = true - - def CompletionTest(vehicle : Vehicle) = Validate(vehicle) - } - - /** - * Use a validation test to determine if the remainder of the instructions should be processed. - * @param test the custom valid conditions of the vehicle for continuing - */ - final case class CancelEarly(test : (Vehicle)=>Boolean) extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveCancelEarly(test) - } - - /** - * Gain altitude with a flying vehicle. - * The climb speed is fixed. - * @param altitude the vertical distance to ascend - */ - final case class Climb(altitude : Float) extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveClimb(altitude) - } - - /** - * Drive a certain distance from somewhere. - * @param start the fixed coordinates of the origin point - * @param distance how far from the origin point the vehicle should travel - */ - final case class Distance(start : Vector3, distance : Float) extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveDistance(start, distance * distance) - } - - /** - * Drive a certain distance from where the vehicle is at the time that the instruction is called. - * The starting position is the current position of the vehicle. - * @param distance how far from the origin point the vehicle should travel - */ - final case class DistanceFromHere(distance : Float) extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveDistanceFromHere(distance * distance) - } - - /** - * Basic drive forward instruction. - * @see `ServerVehicleOverrideMsg.forward_speed` - * @param speed the speed that the vehicle accelerates to; - * scaled in a curious way - */ - final case class Drive(speed : Int) extends Configuration { - def Create : Setting = AutoDriveControls.AutoDrive(speed) - } - - /** - * Special drive forward instruction. - * @see `ServerVehicleOverrideMsg.forward_speed` - * @see `VehicleDefinition.AutoPilotSpeed1` - */ - final case class FirstGear() extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveFirstGear() - } - - /** - * Drive or idle for a certain duration. - * The starting position is the current position of the vehicle. - * @param time how long to contiue driving under the current conditions - */ - final case class ForTime(time : Long) extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveForTime(time) - } - - /** - * Special drive forward instruction. - * @see `ServerVehicleOverrideMsg.forward_speed` - * @see `VehicleDefinition.AutoPilotSpeed2` - */ - final case class SecondGear() extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveSecondGear() - } - - /** - * Stop driving (but do not cancel the server override state). - */ - final case class Stop() extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveStop() - } - - /** - * Cause the vehicle to turn a certain amount. - * @see `VehicleMessage.wheel_direction` - * @param angle the angle by which to turn the vehicle - * @param direction the wheel direction of the vehicle - */ - final case class TurnBy(angle : Float, direction : Int) extends Configuration { - def Create : Setting = AutoDriveControls.AutoDriveTurnBy(angle, direction) - } -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlBase.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlBase.scala index 284d0999..5494f6ae 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlBase.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlBase.scala @@ -3,7 +3,6 @@ package net.psforever.objects.serverobject.pad.process import akka.actor.Actor import net.psforever.objects.serverobject.pad.VehicleSpawnPad -import net.psforever.objects.serverobject.structures.Building import net.psforever.objects.zones.Zone import org.log4s.Logger @@ -26,11 +25,11 @@ abstract class VehicleSpawnControlBase(pad : VehicleSpawnPad) extends Actor { */ private def GetLogger(logid : String) : Logger = baseLogger match { case None => - if(!pad.HasGUID || Continent == Zone.Nowhere) { + if(!pad.HasGUID || pad.Owner.Zone == Zone.Nowhere) { org.log4s.getLogger(s"uninitialized_${pad.Definition.Name}$logid") } else { - baseLogger = Some(org.log4s.getLogger(s"${Continent.Id}-${pad.Definition.Name}-${pad.GUID.guid}$logid")) + baseLogger = Some(org.log4s.getLogger(s"${pad.Continent}-${pad.Definition.Name}-${pad.GUID.guid}$logid")) baseLogger.get } case Some(logger) => @@ -56,14 +55,4 @@ abstract class VehicleSpawnControlBase(pad : VehicleSpawnPad) extends Actor { * @param msg the message */ def trace(msg : String) : Unit = log.trace(msg) - - /** - * The continent the pad recognizes as a place of installation will change as its `Owner` changes. - * Originally, it belongs to a default non-`Building` object that is owned by a default non-`Zone` object. - * Eventually, it will belong to an active `Building` object that will belong to an active `Zone` object. - * With respect to `GetLogger(String)`, the active `Zone` object will be valid shortly after the object is registered, - * but will still be separated from being owned by a valid `Building` object by a few validation checks. - * @return the (current) `Zone` object - */ - def Continent : Zone = pad.Owner.asInstanceOf[Building].Zone } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlConcealPlayer.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlConcealPlayer.scala index 21baed97..3e7188b8 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlConcealPlayer.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlConcealPlayer.scala @@ -1,7 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.pad.process -import akka.actor.{ActorRef, Props} +import akka.actor.Props import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import scala.concurrent.ExecutionContext.Implicits.global @@ -24,17 +24,16 @@ class VehicleSpawnControlConcealPlayer(pad : VehicleSpawnPad) extends VehicleSpa val loadVehicle = context.actorOf(Props(classOf[VehicleSpawnControlLoadVehicle], pad), s"${context.parent.path.name}-load") def receive : Receive = { - case VehicleSpawnControl.Process.ConcealPlayer(entry) => - val driver = entry.driver - //TODO how far can the driver get stray from the Terminal before his order is cancelled? - if(entry.sendTo != ActorRef.noSender && driver.Continent == Continent.Id && driver.VehicleSeated.isEmpty) { + case order @ VehicleSpawnControl.Order(driver, _) => + //TODO how far can the driver stray from the Terminal before his order is cancelled? + if(driver.Continent == pad.Continent && driver.VehicleSeated.isEmpty) { trace(s"hiding ${driver.Name}") - Continent.VehicleEvents ! VehicleSpawnPad.ConcealPlayer(driver.GUID, Continent.Id) - context.system.scheduler.scheduleOnce(2000 milliseconds, loadVehicle, VehicleSpawnControl.Process.LoadVehicle(entry)) + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.ConcealPlayer(driver.GUID) + context.system.scheduler.scheduleOnce(2000 milliseconds, loadVehicle, order) } else { trace(s"integral component lost; abort order fulfillment") - VehicleSpawnControl.DisposeVehicle(entry, Continent) + VehicleSpawnControl.DisposeSpawnedVehicle(order.vehicle, pad.Owner.Zone) context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlDriverControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlDriverControl.scala index 98db2d77..8bf2cc75 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlDriverControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlDriverControl.scala @@ -1,7 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.pad.process -import akka.actor.{ActorRef, Props} +import akka.actor.Props import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} /** @@ -20,35 +20,22 @@ class VehicleSpawnControlDriverControl(pad : VehicleSpawnPad) extends VehicleSpa val finalClear = context.actorOf(Props(classOf[VehicleSpawnControlFinalClearance], pad), s"${context.parent.path.name}-final") def receive : Receive = { - case VehicleSpawnControl.Process.DriverVehicleControl(entry) => - val vehicle = entry.vehicle - if(pad.Railed) { - Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id) - } + case order @ VehicleSpawnControl.Order(driver, vehicle) => if(vehicle.Health == 0) { trace(s"vehicle was already destroyed; but, everything is fine") } - if(entry.sendTo != ActorRef.noSender) { - val driver = entry.driver - entry.sendTo ! VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, pad) - if(driver.VehicleSeated.contains(vehicle.GUID)) { - trace(s"returning control of ${vehicle.Definition.Name} to ${driver.Name}") - } - else { - trace(s"${driver.Name} is not seated in ${vehicle.Definition.Name}; vehicle controls have been locked") - } + if(vehicle.PassengerInSeat(driver).contains(0)) { + trace(s"returning control of ${vehicle.Definition.Name} to ${driver.Name}") + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.ServerVehicleOverrideEnd(driver.Name, vehicle, pad) } else { - trace("can not properly return control to driver") + trace(s"${driver.Name} is not seated in ${vehicle.Definition.Name}; vehicle controls have been locked") } - finalClear ! VehicleSpawnControl.Process.FinalClearance(entry) + finalClear ! order case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) => context.parent ! msg - case msg @ VehicleSpawnControl.Process.FinalClearance(_) => - finalClear ! msg - case _ => ; } } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlFinalClearance.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlFinalClearance.scala index c5f32288..68f9ef89 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlFinalClearance.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlFinalClearance.scala @@ -2,7 +2,9 @@ package net.psforever.objects.serverobject.pad.process import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} +import net.psforever.packet.game.PlanetSideGUID import net.psforever.types.Vector3 +import services.vehicle.{VehicleAction, VehicleServiceMessage} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ @@ -22,17 +24,24 @@ class VehicleSpawnControlFinalClearance(pad : VehicleSpawnPad) extends VehicleSp def LogId = "-clearer" def receive : Receive = { - case VehicleSpawnControl.Process.FinalClearance(entry) => + case order @ VehicleSpawnControl.Order(driver, vehicle) => + if(vehicle.PassengerInSeat(driver).isEmpty) { + //ensure the vacant vehicle is above the trench and doors + vehicle.Position = pad.Position + Vector3.z(pad.Definition.VehicleCreationZOffset) + val definition = vehicle.Definition + pad.Owner.Zone.VehicleEvents ! VehicleServiceMessage(s"${pad.Continent}", VehicleAction.LoadVehicle(PlanetSideGUID(0), vehicle, definition.ObjectId, vehicle.GUID, definition.Packet.ConstructorData(vehicle).get)) + } context.parent ! VehicleSpawnControl.ProcessControl.Reminder - self ! VehicleSpawnControlFinalClearance.Test(entry) + self ! VehicleSpawnControlFinalClearance.Test(order) - case VehicleSpawnControlFinalClearance.Test(entry) => + case test @ VehicleSpawnControlFinalClearance.Test(entry) => if(Vector3.DistanceSquared(entry.vehicle.Position, pad.Position) > 100.0f) { //10m away from pad trace("pad cleared") + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad) context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder } else { - context.system.scheduler.scheduleOnce(2000 milliseconds, self, VehicleSpawnControlFinalClearance.Test(entry)) + context.system.scheduler.scheduleOnce(2000 milliseconds, self, test) } case _ => ; diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlGuided.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlGuided.scala deleted file mode 100644 index 9011082d..00000000 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlGuided.scala +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2017 PSForever -package net.psforever.objects.serverobject.pad.process - -import akka.actor.{ActorRef, Props} -import net.psforever.objects.Vehicle -import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration._ - -/** - * An `Actor` that handles vehicle spawning orders for a `VehicleSpawnPad`. - * The basic `VehicleSpawnControl` is the root of a simple tree of "spawn control" objects that chain to each other. - * Each object performs on (or more than one related) actions upon the vehicle order that was submitted.
- *
- * After the vehicle has been released from the spawn pad lifting platform, - * it enters into an auto-drive mode that has at least two stages. - * An undefined number of stages cane be included, however. - * This can lead the newly-spawned vehicle through a rough pre-defined path.
- *
- * Throughout this process, the conditions of `ServerVehicleOverrideMsg` are still in effect. - * @param pad the `VehicleSpawnPad` object being governed - */ -class VehicleSpawnControlGuided(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) { - def LogId = "-guide" - - val driverControl = context.actorOf(Props(classOf[VehicleSpawnControlDriverControl], pad), s"${context.parent.path.name}-driver") - - def receive : Receive = { - case VehicleSpawnControl.Process.StartGuided(entry) => - pad.Guide match { - case Nil => - trace("no guided path for this pad") - driverControl ! VehicleSpawnControl.Process.DriverVehicleControl(entry) - case path => - self ! VehicleSpawnControlGuided.InitialGuided(entry, path.map { _.Create }) - } - - case VehicleSpawnControlGuided.SelectNextGuided(entry, actions) => - actions match { - case Nil | _ :: Nil => - trace("custom vehicle path completed") - driverControl ! VehicleSpawnControl.Process.DriverVehicleControl(entry) - case _ :: xs => - self ! VehicleSpawnControlGuided.InitialGuided(entry, xs) - } - - case VehicleSpawnControlGuided.InitialGuided(entry, actions) => - val vehicle = entry.vehicle - if(entry.sendTo != ActorRef.noSender && vehicle.Health != 0 && entry.driver.VehicleSeated.contains(vehicle.GUID) && actions.head.Validate(vehicle)) { - trace(s"custom vehicle path plotted - ${actions.head.Type}") - entry.sendTo ! VehicleSpawnControlGuided.GuidedControl(actions.head.Type, vehicle, actions.head.Data) - self ! VehicleSpawnControlGuided.ContinueGuided(entry, actions) - } - else { - trace(s"projected ${vehicle.Definition.Name} path interruption; exit guided mode") - driverControl ! VehicleSpawnControl.Process.DriverVehicleControl(entry) - } - - case VehicleSpawnControlGuided.ValidateGuided(entry, actions) => - val vehicle = entry.vehicle - if(entry.sendTo != ActorRef.noSender && vehicle.Health != 0 && entry.driver.VehicleSeated.contains(vehicle.GUID) && actions.head.Validate(vehicle)) { - self ! VehicleSpawnControlGuided.ContinueGuided(entry, actions) - } - else { - trace(s"plotted ${vehicle.Definition.Name} path interruption; exit guided mode") - driverControl ! VehicleSpawnControl.Process.DriverVehicleControl(entry) - } - - case VehicleSpawnControlGuided.ContinueGuided(entry, actions) => - if(actions.head.CompletionTest(entry.vehicle)) { - trace("step completed") - self ! VehicleSpawnControlGuided.SelectNextGuided(entry, actions) - } - else { - context.system.scheduler.scheduleOnce(actions.head.Delay milliseconds, self, VehicleSpawnControlGuided.ValidateGuided(entry, actions)) - } - - case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) => - context.parent ! msg - - case msg @ VehicleSpawnControl.Process.FinalClearance(_) => - driverControl ! msg - - case _ => ; - } -} - -object VehicleSpawnControlGuided { - /** - * Select the first instruction from the list. - * @param entry the vehicle order - * @param actions the list of instructions related to this spawn pad - */ - private final case class InitialGuided(entry : VehicleSpawnControl.Order, actions : List[AutoDriveControls.Setting]) - /** - * Swap to the next instruction, if it exists. - * @param entry the vehicle order - * @param actions the list of instructions related to this spawn pad - */ - private final case class SelectNextGuided(entry : VehicleSpawnControl.Order, actions : List[AutoDriveControls.Setting]) - /** - * The validation test determines whether the vehicle, the driver, and any other important elements - * are still in a state where the current instruction can be accomplished. - * If the validation test passes, the current instruction can continue to run to completion. - * If the validation test fails, the remainder of the instructions are aborted. - * @param entry the vehicle order - * @param actions the list of instructions related to this spawn pad - */ - private final case class ValidateGuided(entry : VehicleSpawnControl.Order, actions : List[AutoDriveControls.Setting]) - /** - * If the previous validation test passes, the current instruction can continue to run to completion. - * Once completed, the next instruction can be selected. - * @param entry the vehicle order - * @param actions the list of instructions related to this spawn pad - */ - private final case class ContinueGuided(entry : VehicleSpawnControl.Order, actions : List[AutoDriveControls.Setting]) - - /** - * A message that explains the current instruction in the guided mode to another agency. - * @param command the nature of the action being performed - * @param vehicle the vehicle being controlled - * @param data optional data used to process the instruction - */ - final case class GuidedControl(command : AutoDriveControls.State.Value, vehicle : Vehicle, data : Option[Any]) -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala index c84462ab..b548bd71 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala @@ -15,8 +15,8 @@ import scala.concurrent.duration._ * Each object performs on (or more than one related) actions upon the vehicle order that was submitted.
*
* This object introduces the vehicle into the game environment. - * The vehicle must be added to the `Continent`, loaded onto other players' clients, and given an initial timed deconstruction event. - * For actual details on this process, please refer to the external source represented by `Continent.VehicleEvents`. + * The vehicle must be added to the `Zone` object, loaded onto other players' clients, and given an initial timed deconstruction event. + * For actual details on this process, please refer to the external source represented by `pad.Owner.Zone.VehicleEvents`. * It has failure cases should the driver be in an incorrect state. * @param pad the `VehicleSpawnPad` object being governed */ @@ -26,21 +26,17 @@ class VehicleSpawnControlLoadVehicle(pad : VehicleSpawnPad) extends VehicleSpawn val railJack = context.actorOf(Props(classOf[VehicleSpawnControlRailJack], pad), s"${context.parent.path.name}-rails") def receive : Receive = { - case VehicleSpawnControl.Process.LoadVehicle(entry) => - val vehicle = entry.vehicle - if(entry.driver.Continent == Continent.Id) { + case order @ VehicleSpawnControl.Order(driver, vehicle) => + if(driver.Continent == pad.Continent && vehicle.Health > 0) { trace(s"loading the ${vehicle.Definition.Name}") - if(pad.Railed) { - //load the vehicle in the spawn pad trench, underground, initially - vehicle.Position = vehicle.Position - Vector3(0, 0, if(GlobalDefinitions.isFlightVehicle(vehicle.Definition)) 9 else 5) - } - vehicle.Cloaked = vehicle.Definition.CanCloak && entry.driver.Cloaked - Continent.VehicleEvents ! VehicleSpawnPad.LoadVehicle(vehicle, Continent) - context.system.scheduler.scheduleOnce(100 milliseconds, railJack, VehicleSpawnControl.Process.RailJackAction(entry)) + vehicle.Position = vehicle.Position - Vector3.z(if(GlobalDefinitions.isFlightVehicle(vehicle.Definition)) 9 else 5) //appear below the trench and doors + vehicle.Cloaked = vehicle.Definition.CanCloak && driver.Cloaked + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.LoadVehicle(vehicle) + context.system.scheduler.scheduleOnce(100 milliseconds, railJack, order) } else { - trace("owner lost; abort order fulfillment") - VehicleSpawnControl.DisposeVehicle(entry, Continent) + trace("owner lost or vehicle in poor condition; abort order fulfillment") + VehicleSpawnControl.DisposeSpawnedVehicle(order, pad.Owner.Zone) context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala index bb3bf5bd..e5789fd5 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala @@ -25,15 +25,9 @@ class VehicleSpawnControlRailJack(pad : VehicleSpawnPad) extends VehicleSpawnCon val seatDriver = context.actorOf(Props(classOf[VehicleSpawnControlSeatDriver], pad), s"${context.parent.path.name}-seat") def receive : Receive = { - case VehicleSpawnControl.Process.RailJackAction(entry) => - if(pad.Railed) { - trace(s"attaching vehicle to railed platform") - Continent.VehicleEvents ! VehicleSpawnPad.AttachToRails(entry.vehicle, pad, Continent.Id) - } - else { - trace(s"railed platform skipped; vehicle positioned in pad trench temporarily") - } - context.system.scheduler.scheduleOnce(10 milliseconds, seatDriver, VehicleSpawnControl.Process.SeatDriver(entry)) + case order @ VehicleSpawnControl.Order(_, vehicle) => + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.AttachToRails(vehicle, pad) + context.system.scheduler.scheduleOnce(10 milliseconds, seatDriver, order) case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) => context.parent ! msg diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala index 2fb0f248..8253dd92 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala @@ -2,9 +2,7 @@ package net.psforever.objects.serverobject.pad.process import akka.actor.{ActorRef, Props} -import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} -import net.psforever.types.Vector3 import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ @@ -29,62 +27,35 @@ class VehicleSpawnControlSeatDriver(pad : VehicleSpawnPad) extends VehicleSpawnC val vehicleOverride = context.actorOf(Props(classOf[VehicleSpawnControlServerVehicleOverride], pad), s"${context.parent.path.name}-override") def receive : Receive = { - case VehicleSpawnControl.Process.SeatDriver(entry) => - self ! VehicleSpawnControlSeatDriver.AwaitVehicleReadiness(entry) - - case VehicleSpawnControlSeatDriver.AwaitVehicleReadiness(entry) => - if(entry.vehicle.Actor == ActorRef.noSender) { //wait for a necessary vehicle component to be loaded - context.system.scheduler.scheduleOnce(50 milliseconds, self, VehicleSpawnControlSeatDriver.AwaitVehicleReadiness(entry)) + case order @ VehicleSpawnControl.Order(_, vehicle) => + if(vehicle.Actor == ActorRef.noSender) { //wait for a necessary vehicle component to be loaded + context.system.scheduler.scheduleOnce(50 milliseconds, self, order) } else { trace("vehicle ready") - self ! VehicleSpawnControlSeatDriver.BeginDriverInSeat(entry) + self ! VehicleSpawnControlSeatDriver.BeginDriverInSeat(order) } case VehicleSpawnControlSeatDriver.BeginDriverInSeat(entry) => val driver = entry.driver - if(entry.sendTo != ActorRef.noSender && entry.vehicle.Health > 0 && driver.isAlive && driver.Continent == Continent.Id && driver.VehicleSeated.isEmpty) { + if(entry.vehicle.Health > 0 && driver.isAlive && driver.Continent == pad.Continent && driver.VehicleSeated.isEmpty) { trace("driver to be made seated in vehicle") - entry.sendTo ! VehicleSpawnPad.StartPlayerSeatedInVehicle(entry.vehicle, pad) - entry.vehicle.Actor.tell(Mountable.TryMount(driver, 0), entry.sendTo) //entry.sendTo should handle replies to TryMount - context.system.scheduler.scheduleOnce(1500 milliseconds, self, VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry)) + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.StartPlayerSeatedInVehicle(entry.driver.Name, entry.vehicle, pad) } - else { + else{ trace("driver lost; vehicle stranded on pad") - context.system.scheduler.scheduleOnce(1000 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry)) - } - - case VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry) => - val driver = entry.driver - if(entry.sendTo == ActorRef.noSender || !driver.isAlive || driver.Continent != Continent.Id) { - trace("driver lost, but operations can continue") - vehicleOverride ! VehicleSpawnControl.Process.ServerVehicleOverride(entry) - } - else if(entry.vehicle.Health == 0 || entry.vehicle.Position == Vector3.Zero) { - //skip ahead for cleanup - vehicleOverride ! VehicleSpawnControl.Process.ServerVehicleOverride(entry) - } - else if(driver.isAlive && driver.VehicleSeated.isEmpty) { - if(pad.Railed) { - Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(entry.vehicle, pad, Continent.Id) - } - context.system.scheduler.scheduleOnce(100 milliseconds, self, VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry)) - } - else { - trace(s"driver is sitting down") - val time = if(pad.Railed) 1000 else VehicleSpawnControlSeatDriver.RaillessSeatAnimationTimes(entry.vehicle.Definition.Name) - context.system.scheduler.scheduleOnce(time milliseconds, self, VehicleSpawnControlSeatDriver.DriverInSeat(entry)) } + context.system.scheduler.scheduleOnce(2500 milliseconds, self, VehicleSpawnControlSeatDriver.DriverInSeat(entry)) case VehicleSpawnControlSeatDriver.DriverInSeat(entry) => - if(entry.sendTo != ActorRef.noSender || entry.driver.Continent != Continent.Id) { + if(entry.driver.isAlive && entry.vehicle.PassengerInSeat(entry.driver).contains(0)) { trace(s"driver ${entry.driver.Name} has taken the wheel") - entry.sendTo ! VehicleSpawnPad.PlayerSeatedInVehicle(entry.vehicle, pad) + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.PlayerSeatedInVehicle(entry.driver.Name, entry.vehicle, pad) } else { trace("driver lost, but operations can continue") } - context.system.scheduler.scheduleOnce(250 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry)) + context.system.scheduler.scheduleOnce(250 milliseconds, vehicleOverride, entry) case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) => context.parent ! msg @@ -94,51 +65,7 @@ class VehicleSpawnControlSeatDriver(pad : VehicleSpawnPad) extends VehicleSpawnC } object VehicleSpawnControlSeatDriver { - final case class AwaitVehicleReadiness(entry : VehicleSpawnControl.Order) - final case class BeginDriverInSeat(entry : VehicleSpawnControl.Order) - final case class AwaitDriverInSeat(entry : VehicleSpawnControl.Order) - final case class DriverInSeat(entry : VehicleSpawnControl.Order) - - /** - * If the spawn pad associated with this `Actor` chain is not `Railed` - - * not guaranteed to have the correct ingame globally unique id of the spawn pad - - * then the animation of the driver boarding their vehicle will be displayed. - * Although the network is finicky, these times should compensate a beneficial visual delay. - * The BFRs, the Switchblade, and the Flail are all untested. - */ - private val RaillessSeatAnimationTimes : Map[String, Int] = Map( - "fury" -> 600, - "quadassault" -> 600, - "quadstealth" -> 600, - "two_man_assault_buggy" -> 1000, - "skyguard" -> 1300, - "threemanheavybuggy" -> 1000, - "twomanheavybuggy" -> 1800, - "twomanhoverbuggy" -> 1800, - "mediumtransport" -> 1300, - "battlewagon" -> 1300, - "thunderer" -> 1300, - "aurora" -> 1300, - "apc_tr" -> 2300, - "apc_nc" -> 2300, - "apc_vs" -> 2300, - "prowler" -> 1000, - "vanguard" -> 2000, - "magrider" -> 1800, - "ant" -> 2500, - "ams" -> 1000, - "router" -> 2500, - "mosquito" -> 2000, - "lightgunship" -> 2000, - "wasp" -> 2000, - "liberator" -> 1800, - "vulture" -> 1800, - "dropship" -> 2000, - "galaxy_gunship" -> 2000, - "lodestar" -> 2000, - "phantasm" -> 1800 - ).withDefaultValue(1000) } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala index d7331618..f77cb4ce 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala @@ -1,7 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.pad.process -import akka.actor.{ActorRef, Props} +import akka.actor.Props import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import net.psforever.types.Vector3 @@ -22,46 +22,32 @@ import scala.concurrent.duration._ class VehicleSpawnControlServerVehicleOverride(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) { def LogId = "-overrider" - val vehicleGuide = context.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), s"${context.parent.path.name}-guide") + val driverControl = context.actorOf(Props(classOf[VehicleSpawnControlDriverControl], pad), s"${context.parent.path.name}-driver") def receive : Receive = { - case VehicleSpawnControl.Process.ServerVehicleOverride(entry) => - val vehicle = entry.vehicle + case order @ VehicleSpawnControl.Order(driver, vehicle) => val vehicleFailState = vehicle.Health == 0 || vehicle.Position == Vector3.Zero - val driverFailState = !entry.driver.isAlive || entry.driver.Continent != Continent.Id || (if(vehicle.HasGUID) { !entry.driver.VehicleSeated.contains(vehicle.GUID) } else { true }) + val driverFailState = !driver.isAlive || driver.Continent != pad.Continent || !vehicle.PassengerInSeat(driver).contains(0) + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad) if(vehicleFailState || driverFailState) { if(vehicleFailState) { trace(s"vehicle was already destroyed") - if(pad.Railed) { - Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id) - } } else { trace(s"driver is not ready") - if(pad.Railed) { - Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad, Continent.Id) - } } - Continent.VehicleEvents ! VehicleSpawnPad.RevealPlayer(entry.driver.GUID, Continent.Id) - vehicleGuide ! VehicleSpawnControl.Process.FinalClearance(entry) + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.RevealPlayer(order.DriverGUID) + driverControl ! order } else { - if(pad.Railed) { - Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad, Continent.Id) - } - if(entry.sendTo != ActorRef.noSender) { - trace(s"telling ${entry.driver.Name} that the server is assuming control of the ${vehicle.Definition.Name}") - entry.sendTo ! VehicleSpawnPad.ServerVehicleOverrideStart(vehicle, pad) - context.system.scheduler.scheduleOnce(3000 milliseconds, vehicleGuide, VehicleSpawnControl.Process.StartGuided(entry)) - } + trace(s"telling ${driver.Name} that the server is assuming control of the ${vehicle.Definition.Name}") + pad.Owner.Zone.VehicleEvents ! VehicleSpawnPad.ServerVehicleOverrideStart(driver.Name, vehicle, pad) + context.system.scheduler.scheduleOnce(4000 milliseconds, driverControl, order) } case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) => context.parent ! msg - case msg @ VehicleSpawnControl.Process.FinalClearance(_) => - vehicleGuide ! msg - case _ => ; } } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/painbox/PainboxControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/painbox/PainboxControl.scala index abf7f67b..68cc9518 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/painbox/PainboxControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/painbox/PainboxControl.scala @@ -1,37 +1,31 @@ package net.psforever.objects.serverobject.painbox -import akka.actor.{Actor, ActorRef, Cancellable} -import net.psforever.objects.{DefaultCancellable, GlobalDefinitions} +import akka.actor.{Actor, Cancellable} +import net.psforever.objects.DefaultCancellable import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.serverobject.structures.Building import net.psforever.types.{PlanetSideEmpire, Vector3} -import services.ServiceManager -import services.ServiceManager.Lookup import services.avatar.{AvatarAction, AvatarServiceMessage} import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global class PainboxControl(painbox: Painbox) extends Actor { - var avatarService : ActorRef = Actor.noSender - private[this] val log = org.log4s.getLogger(s"Painbox") + //private[this] val log = org.log4s.getLogger(s"Painbox") private var painboxTick: Cancellable = DefaultCancellable.obj private var nearestDoor : Door = null def receive : Receive = { case "startup" => - ServiceManager.serviceManager ! Lookup("avatar") - nearestDoor = painbox.Owner.asInstanceOf[Building].Amenities.filter(x => x.isInstanceOf[Door]) - .map(x => x.asInstanceOf[Door]) - .sortBy(door => Vector3.DistanceSquared(painbox.Position, door.Position)) - .head - - case ServiceManager.LookupResult("avatar", endpoint) => - avatarService = endpoint - log.trace("PainboxControl: " + painbox.GUID + " Got avatar service " + endpoint) - - context.become(Processing) - painboxTick = context.system.scheduler.schedule(0 seconds,1 second, self, Painbox.Tick()) + painbox.Owner match { + case obj : Building => + nearestDoor = obj.Amenities + .collect { case door : Door => door } + .minBy(door => Vector3.DistanceSquared(painbox.Position, door.Position)) + painboxTick = context.system.scheduler.schedule(0 seconds,1 second, self, Painbox.Tick()) + context.become(Processing) + case _ => ; + } case _ => ; } @@ -39,24 +33,21 @@ class PainboxControl(painbox: Painbox) extends Actor { def Processing : Receive = { case Painbox.Tick() => //todo: Account for overlapping pain fields - if(painbox.Owner.Faction == PlanetSideEmpire.NEUTRAL) return null - if(painbox.Definition.HasNearestDoorDependency && nearestDoor.Open.isEmpty) return null - - val playersToCheck = painbox.Owner.asInstanceOf[Building].PlayersInSOI - if(playersToCheck.length == 0) return null - // todo: Disable if no base power - - val playersInRange = playersToCheck.filter(p => - p.Faction != painbox.Owner.Faction - && p.Health > 0 - && Math.pow(p.Position.x - painbox.Position.x, 2) + Math.pow(p.Position.y - painbox.Position.y, 2) + Math.pow(p.Position.z - painbox.Position.z, 2) < Math.pow(painbox.Definition.Radius, 2) - ) - - // Make 'em hurt. - playersInRange.foreach({ p => - avatarService ! AvatarServiceMessage(p.Name, AvatarAction.EnvironmentalDamage(p.GUID, painbox.Definition.Damage)) - // todo: Pain module - // todo: REK boosting - }) + //todo: Pain module + //todo: REK boosting + val owner = painbox.Owner.asInstanceOf[Building] + val faction = owner.Faction + if(faction != PlanetSideEmpire.NEUTRAL && nearestDoor.Open.nonEmpty) { + val events = owner.Zone.AvatarEvents + val damage = painbox.Definition.Damage + val radius = painbox.Definition.Radius * painbox.Definition.Radius + val position = painbox.Position + owner.PlayersInSOI + .collect { case p if p.Faction != faction + && p.Health > 0 + && Vector3.DistanceSquared(p.Position, position) < radius => + events ! AvatarServiceMessage(p.Name, AvatarAction.EnvironmentalDamage(p.GUID, damage)) + } + } } } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala index 17d255e5..fce74ece 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala @@ -1,35 +1,24 @@ -// Copyright (c) 2017 PSForever +// Copyright (c) 2019 PSForever package net.psforever.objects.serverobject.resourcesilo -import akka.actor.{Actor, ActorRef} +import akka.actor.Actor import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.structures.Building -import net.psforever.packet.game.PlanetSideGUID -import services.ServiceManager.Lookup -import services._ import services.avatar.{AvatarAction, AvatarServiceMessage} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ - /** * An `Actor` that handles messages being dispatched to a specific `Resource Silo`. * @param resourceSilo the `Resource Silo` object being governed */ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with FactionAffinityBehavior.Check { def FactionObject : FactionAffinity = resourceSilo - var avatarService : ActorRef = Actor.noSender private[this] val log = org.log4s.getLogger def receive : Receive = { case "startup" => - ServiceManager.serviceManager ! Lookup("avatar") - - case ServiceManager.LookupResult("avatar", endpoint) => - avatarService = endpoint - log.trace("ResourceSiloControl: Silo " + resourceSilo.GUID + " Got avatar service " + endpoint) - // 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.become(Processing) @@ -43,7 +32,12 @@ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with Factio case ResourceSilo.LowNtuWarning(enabled: Boolean) => resourceSilo.LowNtuWarningOn = enabled log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to $enabled") - avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(resourceSilo.Owner.asInstanceOf[Building].GUID, 47, if(resourceSilo.LowNtuWarningOn) 1 else 0)) + val building = resourceSilo.Owner + val zone = building.Zone + building.Zone.AvatarEvents ! AvatarServiceMessage( + zone.Id, + AvatarAction.PlanetsideAttribute(building.GUID, 47, if(resourceSilo.LowNtuWarningOn) 1 else 0) + ) case ResourceSilo.UpdateChargeLevel(amount: Int) => val siloChargeBeforeChange = resourceSilo.ChargeLevel @@ -54,14 +48,18 @@ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with Factio log.trace(s"UpdateChargeLevel: Silo ${resourceSilo.GUID} set to ${resourceSilo.ChargeLevel}") } - val ntuBarLevel = scala.math.ceil((resourceSilo.ChargeLevel.toFloat / resourceSilo.MaximumCharge.toFloat) * 10).toInt // Only send updated capacitor display value to all clients if it has actually changed if(resourceSilo.CapacitorDisplay != ntuBarLevel) { log.trace(s"Silo ${resourceSilo.GUID} NTU bar level has changed from ${resourceSilo.CapacitorDisplay} to $ntuBarLevel") resourceSilo.CapacitorDisplay = ntuBarLevel resourceSilo.Owner.Actor ! Building.SendMapUpdate(all_clients = true) - avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)) + val building = resourceSilo.Owner + val zone = building.Zone + zone.AvatarEvents ! AvatarServiceMessage( + zone.Id, + AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay) + ) } val ntuIsLow = resourceSilo.ChargeLevel.toFloat / resourceSilo.MaximumCharge.toFloat < 0.2f @@ -71,20 +69,25 @@ class ResourceSiloControl(resourceSilo : ResourceSilo) extends Actor with Factio self ! ResourceSilo.LowNtuWarning(enabled = true) } - + val building = resourceSilo.Owner + val zone = building.Zone if(resourceSilo.ChargeLevel == 0 && siloChargeBeforeChange > 0) { // Oops, someone let the base run out of power. Shut it all down. //todo: Make base neutral if silo hits zero NTU //todo: temporarily disabled until warpgates can bring ANTs from sanctuary, otherwise we'd be stuck in a situation with an unpowered base and no way to get an ANT to refill it. -// avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(PlanetSideGUID(resourceSilo.Owner.asInstanceOf[Building].ModelId), 48, 1)) +// zone.AvatarEvents ! AvatarServiceMessage( +// zone.Id, +// AvatarAction.PlanetsideAttribute(PlanetSideGUID(building.MapId), 48, 1) +// ) } else if (siloChargeBeforeChange == 0 && resourceSilo.ChargeLevel > 0) { // Power restored. Reactor Online. Sensors Online. Weapons Online. All systems nominal. //todo: Check generator is online before starting up - avatarService ! AvatarServiceMessage(resourceSilo.Owner.asInstanceOf[Building].Zone.Id, AvatarAction.PlanetsideAttribute(resourceSilo.Owner.asInstanceOf[Building].GUID, 48, 0)) + zone.AvatarEvents ! AvatarServiceMessage( + zone.Id, + AvatarAction.PlanetsideAttribute(building.GUID, 48, 0) + ) } case _ => ; } - - } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala index 1887c7a8..9a3ea7f8 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/Amenity.scala @@ -3,8 +3,27 @@ package net.psforever.objects.serverobject.structures import net.psforever.objects.Vehicle import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.objects.zones.{Zone => World } import net.psforever.types.{PlanetSideEmpire, Vector3} +/** + * Amenities are elements of the game that belong to other elements of the game. + * Their owners are also elements of the game, ones that understand that they belong to a specific `Zone` object. + * @see `PlanetSideServerObject` + * @see `Zone` + * @see `ZoneAware` + */ +trait AmenityOwner extends PlanetSideServerObject { + private var zoneRef : World = World.Nowhere + + def Zone_=(zone : World) : World = { + zoneRef = zone + Zone + } + + def Zone : World = zoneRef +} + /** * Amenities are elements of the game that belong to other elements of the game.
*
@@ -17,7 +36,7 @@ import net.psforever.types.{PlanetSideEmpire, Vector3} */ abstract class Amenity extends PlanetSideServerObject { /** what other entity has authority over this amenity; usually either a building or a vehicle */ - private var owner : PlanetSideServerObject = Building.NoBuilding + private var owner : AmenityOwner = Building.NoBuilding /** if the entity exists at a specific position relative to the owner's position */ private var offset : Option[Vector3] = None @@ -27,17 +46,16 @@ abstract class Amenity extends PlanetSideServerObject { * Reference the object that is in direct association with (is superior to) this one. * @return the object associated as this object's "owner" */ - def Owner : PlanetSideServerObject = owner + def Owner : AmenityOwner = owner /** * Set an object to have a direct association with (be superior to) this one. * @see `Amenity.AmenityTarget` * @param obj the object trying to become associated as this object's "owner" - * @tparam T a validation of the type of object that can be an owner * @return the object associated as this object's "owner" */ - def Owner_=[T : Amenity.AmenityTarget](obj : T) : PlanetSideServerObject = { - owner = obj.asInstanceOf[PlanetSideServerObject] + def Owner_=(obj : AmenityOwner) : AmenityOwner = { + owner = obj Owner } @@ -61,24 +79,3 @@ abstract class Amenity extends PlanetSideServerObject { case _ => super.Continent } } - -object Amenity { - /** - * A `trait` for validating the type of object that can be allowed to become an `Amenity` object's `Owner`.
- *
- * The `Owner` defaults to a type of `PlanetSideServerObject` in reference type; - * but, that distinction is mainly to allow for a common ancestor with appropriate methods. - * Only certain types of `PlanetSideServerObject` are formally allowed to be owners. - * In execution, the `T` is the type of object that implicitly converts into an acceptable type of sub-object. - * The companion object maintains the hardcoded conversions. - * If such an implicit conversion does not exist, the assignment is unacceptable at compile time. - * @tparam T the permitted type of object - */ - sealed trait AmenityTarget[T] - - object AmenityTarget { - import net.psforever.objects.Vehicle - implicit object BuildingTarget extends AmenityTarget[Building] { } - implicit object VehicleTarget extends AmenityTarget[Vehicle] { } - } -} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala index 5b7bd202..d4d7f712 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala @@ -15,7 +15,8 @@ import net.psforever.objects.zones.Zone import net.psforever.packet.game._ import net.psforever.types.{PlanetSideEmpire, Vector3} -class Building(private val building_guid : Int, private val map_id : Int, private val zone : Zone, private val buildingType : StructureType.Value, private val buildingDefinition : ObjectDefinition) extends PlanetSideServerObject { +class Building(private val building_guid : Int, private val map_id : Int, val zone : Zone, private val buildingType : StructureType.Value, private val buildingDefinition : ObjectDefinition) extends PlanetSideServerObject + with AmenityOwner { /** * The map_id is the identifier number used in BuildingInfoUpdateMessage. This is the index that the building appears in the MPO file starting from index 1 * The GUID is the identifier number used in SetEmpireMessage / Facility hacking / PlanetSideAttributeMessage. @@ -23,6 +24,7 @@ class Building(private val building_guid : Int, private val map_id : Int, privat private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL private var amenities : List[Amenity] = List.empty private var playersInSOI : List[Player] = List.empty + super.Zone_=(zone) GUID = PlanetSideGUID(building_guid) @@ -44,7 +46,7 @@ class Building(private val building_guid : Int, private val map_id : Int, privat } def CaptureConsoleIsHacked : Boolean = { - Amenities.filter(x => x.Definition == GlobalDefinitions.capture_terminal).headOption.asInstanceOf[Option[CaptureTerminal]] match { + Amenities.find(x => x.Definition == GlobalDefinitions.capture_terminal).asInstanceOf[Option[CaptureTerminal]] match { case Some(obj: CaptureTerminal) => obj.HackedBy.isDefined case None => false @@ -58,8 +60,6 @@ class Building(private val building_guid : Int, private val map_id : Int, privat playersInSOI } - def Zone : Zone = zone - def Info : ( Int, Boolean, PlanetSideEmpire.Value, Long, PlanetSideEmpire.Value, @@ -128,9 +128,11 @@ class Building(private val building_guid : Int, private val map_id : Int, privat def BuildingType : StructureType.Value = buildingType - override def Continent : String = zone.Id + override def Zone_=(zone : Zone) : Zone = Zone //building never leaves zone after being set in constructor - override def Continent_=(zone : String) : String = Continent + override def Continent : String = Zone.Id + + override def Continent_=(zone : String) : String = Continent //building never leaves zone after being set in constructor def Definition: ObjectDefinition = buildingDefinition } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala index 3fd1a7cd..19e1a26b 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/BuildingControl.scala @@ -11,22 +11,17 @@ import services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage, Gala class BuildingControl(building : Building) extends Actor with FactionAffinityBehavior.Check { def FactionObject : FactionAffinity = building var galaxyService : ActorRef = Actor.noSender - var localService : ActorRef = Actor.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("local") } 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("local", endpoint) => - localService = endpoint - log.trace("BuildingControl: Building " + building.GUID + " Got local service " + endpoint) case FactionAffinity.ConvertFactionAffinity(faction) => val originalAffinity = building.Faction if(originalAffinity != (building.Faction = faction)) { diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala index f6abadaa..8fd7cc53 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala @@ -6,7 +6,7 @@ import net.psforever.objects._ import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.hackable.HackableBehavior -import services.{Service, ServiceManager} +import services.Service import scala.collection.mutable import scala.concurrent.duration._ @@ -18,7 +18,6 @@ import scala.concurrent.duration._ * @param term the proximity unit (terminal) */ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor with FactionAffinityBehavior.Check with HackableBehavior.GenericHackable { - var service : ActorRef = ActorRef.noSender var terminalAction : Cancellable = DefaultCancellable.obj val callbacks : mutable.ListBuffer[ActorRef] = new mutable.ListBuffer[ActorRef]() val log = org.log4s.getLogger @@ -33,10 +32,6 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor def Start : Receive = checkBehavior .orElse { case Service.Startup() => - ServiceManager.serviceManager ! ServiceManager.Lookup("local") - - case ServiceManager.LookupResult("local", ref) => - service = ref context.become(Run) case _ => ; @@ -45,15 +40,14 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor def Run : Receive = checkBehavior .orElse(hackableBehavior) .orElse { - case CommonMessages.Use(_, Some(target : PlanetSideGameObject)) => - if(term.Definition.asInstanceOf[ProximityDefinition].Validations.exists(p => p(target))) { - Use(target, term.Continent, sender) - } - - case CommonMessages.Use(_, Some((target : PlanetSideGameObject, callback : ActorRef))) => - if(term.Definition.asInstanceOf[ProximityDefinition].Validations.exists(p => p(target))) { - Use(target, term.Continent, callback) - } + case CommonMessages.Use(_, Some(target : PlanetSideGameObject)) => + if(term.Definition.asInstanceOf[ProximityDefinition].Validations.exists(p => p(target))) { + Use(target, term.Continent, sender) + } + case CommonMessages.Use(_, Some((target : PlanetSideGameObject, callback : ActorRef))) => + if(term.Definition.asInstanceOf[ProximityDefinition].Validations.exists(p => p(target))) { + Use(target, term.Continent, callback) + } case CommonMessages.Use(_, _) => log.warn(s"unexpected format for CommonMessages.Use in this context") @@ -68,7 +62,7 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor val proxDef = term.Definition.asInstanceOf[ProximityDefinition] val validateFunc : PlanetSideGameObject=>Boolean = term.Validate(proxDef.UseRadius * proxDef.UseRadius, proxDef.Validations) val callbackList = callbacks.toList - term.Targets.zipWithIndex.foreach({ case((target, index)) => + term.Targets.zipWithIndex.foreach({ case(target, index) => if(validateFunc(target)) { callbackList.lift(index) match { case Some(cback) => @@ -92,7 +86,7 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor def Use(target : PlanetSideGameObject, zone : String, callback : ActorRef) : Unit = { val hadNoUsers = term.NumberUsers == 0 if(term.AddUser(target)) { - log.info(s"ProximityTerminal.Use: unit ${term.Definition.Name}@${term.GUID.guid} will act on $target") + log.trace(s"ProximityTerminal.Use: unit ${term.Definition.Name}@${term.GUID.guid} will act on $target") //add callback callbacks += callback //activation @@ -101,7 +95,7 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor import scala.concurrent.ExecutionContext.Implicits.global terminalAction.cancel terminalAction = context.system.scheduler.schedule(500 milliseconds, medDef.Interval, self, ProximityTerminalControl.TerminalAction()) - service ! Terminal.StartProximityEffect(term) + TerminalObject.Owner.Zone.LocalEvents ! Terminal.StartProximityEffect(term) } } else { @@ -114,13 +108,13 @@ class ProximityTerminalControl(term : Terminal with ProximityUnit) extends Actor val previousUsers = term.NumberUsers val hadUsers = previousUsers > 0 if(whereTarget > -1 && term.RemoveUser(target)) { - log.info(s"ProximityTerminal.Unuse: unit ${term.Definition.Name}@${term.GUID.guid} will cease operation on $target") + log.trace(s"ProximityTerminal.Unuse: unit ${term.Definition.Name}@${term.GUID.guid} will cease operation on $target") //remove callback callbacks.remove(whereTarget) //de-activation (global / local) if(term.NumberUsers == 0 && hadUsers) { terminalAction.cancel - service ! Terminal.StopProximityEffect(term) + TerminalObject.Owner.Zone.LocalEvents ! Terminal.StopProximityEffect(term) } } else { diff --git a/common/src/main/scala/net/psforever/objects/zones/Zone.scala b/common/src/main/scala/net/psforever/objects/zones/Zone.scala index 37d2fb10..ccf2866b 100644 --- a/common/src/main/scala/net/psforever/objects/zones/Zone.scala +++ b/common/src/main/scala/net/psforever/objects/zones/Zone.scala @@ -22,6 +22,9 @@ import net.psforever.objects.serverobject.turret.FacilityTurret import net.psforever.packet.game.PlanetSideGUID import net.psforever.types.{PlanetSideEmpire, Vector3} import services.Service +import services.avatar.AvatarService +import services.local.LocalService +import services.vehicle.VehicleService import scala.collection.concurrent.TrieMap import scala.collection.mutable.ListBuffer @@ -89,6 +92,10 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) { /** calculate a duration from a given interaction's participants */ private var hotspotTimeFunc : (SourceEntry, SourceEntry)=>FiniteDuration = Zone.HotSpot.Rules.NoTime /** */ + private var avatarEvents : ActorRef = ActorRef.noSender + /** */ + private var localEvents : ActorRef = ActorRef.noSender + /** */ private var vehicleEvents : ActorRef = ActorRef.noSender /** @@ -110,9 +117,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) { */ def Init(implicit context : ActorContext) : Unit = { if(accessor == ActorRef.noSender) { - implicit val guid : NumberPoolHub = this.guid //passed into builderObject.Build implicitly SetupNumberPools() - accessor = context.actorOf(RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystem.AllocateNumberPoolActors(guid))), s"$Id-uns") + accessor = context.actorOf(RandomPool(25).props(Props(classOf[UniqueNumberSystem], this.guid, UniqueNumberSystem.AllocateNumberPoolActors(this.guid))), s"$Id-uns") ground = context.actorOf(Props(classOf[ZoneGroundActor], this, equipmentOnGround), s"$Id-ground") deployables = context.actorOf(Props(classOf[ZoneDeployableActor], this, constructions), s"$Id-deployables") transport = context.actorOf(Props(classOf[ZoneVehicleActor], this, vehicles), s"$Id-vehicles") @@ -120,6 +126,11 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) { projector = context.actorOf(Props(classOf[ZoneHotSpotProjector], this), s"$Id-hotpots") soi = context.actorOf(Props(classOf[SphereOfInfluenceActor], this), s"$Id-soi") + avatarEvents = context.actorOf(Props(classOf[AvatarService], this), s"$Id-avatar-events") + localEvents = context.actorOf(Props(classOf[LocalService], this), s"$Id-local-events") + vehicleEvents = context.actorOf(Props(classOf[VehicleService], this), s"$Id-vehicle-events") + + implicit val guid : NumberPoolHub = this.guid //passed into builderObject.Build implicitly BuildLocalObjects(context, guid) BuildSupportObjects() MakeBuildings(context) @@ -492,12 +503,24 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) { */ def ClientInitialization() : Zone = this + def AvatarEvents : ActorRef = avatarEvents + + def AvatarEvents_=(bus : ActorRef) : ActorRef = { + avatarEvents = bus + AvatarEvents + } + + def LocalEvents : ActorRef = localEvents + + def LocalEvents_=(bus : ActorRef) : ActorRef = { + localEvents = bus + LocalEvents + } + def VehicleEvents : ActorRef = vehicleEvents def VehicleEvents_=(bus : ActorRef) : ActorRef = { - if(vehicleEvents == ActorRef.noSender) { - vehicleEvents = bus - } + vehicleEvents = bus VehicleEvents } } diff --git a/common/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala b/common/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala index f5052bd7..ca328fd8 100644 --- a/common/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala +++ b/common/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala @@ -211,7 +211,7 @@ class ZoneHotSpotProjector(zone : Zone) extends Actor { } newSpot } - log.info(s"new coordinate remapping function provided; updating ${redoneSpots.size} hotspots") + log.trace(s"new coordinate remapping function provided; updating ${redoneSpots.size} hotspots") zone.HotSpots = redoneSpots } diff --git a/common/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala b/common/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala index 98764820..265de52b 100644 --- a/common/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala +++ b/common/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala @@ -42,7 +42,7 @@ class ZoneVehicleActor(zone : Zone, vehicleList : ListBuffer[Vehicle]) extends A } else { vehicleList += vehicle - vehicle.Continent = zone.Id + vehicle.Zone = zone vehicle.Actor = context.actorOf(Props(classOf[VehicleControl], vehicle), s"${vehicle.Definition.Name}_${vehicle.GUID.guid}") } diff --git a/common/src/main/scala/services/avatar/AvatarService.scala b/common/src/main/scala/services/avatar/AvatarService.scala index f2c45843..e7b724a7 100644 --- a/common/src/main/scala/services/avatar/AvatarService.scala +++ b/common/src/main/scala/services/avatar/AvatarService.scala @@ -2,19 +2,20 @@ package services.avatar import akka.actor.{Actor, ActorRef, Props} +import net.psforever.objects.zones.Zone import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectCreateMessageParent, PlacementData} import services.avatar.support.{CorpseRemovalActor, DroppedItemRemover} import services.{GenericEventBus, RemoverActor, Service} -class AvatarService extends Actor { - private val undertaker : ActorRef = context.actorOf(Props[CorpseRemovalActor], "corpse-removal-agent") - private val janitor = context.actorOf(Props[DroppedItemRemover], "item-remover-agent") +class AvatarService(zone : Zone) extends Actor { + private val undertaker : ActorRef = context.actorOf(Props[CorpseRemovalActor], s"${zone.Id}-corpse-removal-agent") + private val janitor = context.actorOf(Props[DroppedItemRemover], s"${zone.Id}-item-remover-agent") private [this] val log = org.log4s.getLogger override def preStart = { - log.info("Starting...") + log.trace(s"Awaiting ${zone.Id} avatar events ...") } val AvatarEvents = new GenericEventBus[AvatarServiceResponse] //AvatarEventBus @@ -88,7 +89,7 @@ class AvatarService extends Actor { AvatarEvents.publish( AvatarServiceResponse(s"/$forChannel/Avatar", Service.defaultPlayerGUID, AvatarResponse.DestroyDisplay(killer, victim, method, unk)) ) - case AvatarAction.DropItem(player_guid, item, zone) => + case AvatarAction.DropItem(player_guid, item, _) => val definition = item.Definition val objectData = DroppedItemData( PlacementData(item.Position, item.Orientation), @@ -173,7 +174,7 @@ class AvatarService extends Actor { AvatarEvents.publish( AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, sequence, end, target)) ) - case AvatarAction.PickupItem(player_guid, zone, target, slot, item, unk) => + case AvatarAction.PickupItem(player_guid, _, target, slot, item, unk) => janitor forward RemoverActor.ClearSpecific(List(item), zone) AvatarEvents.publish( AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, { @@ -193,7 +194,7 @@ class AvatarService extends Actor { AvatarEvents.publish( AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.PutDownFDU(player_guid)) ) - case AvatarAction.Release(player, zone, time) => + case AvatarAction.Release(player, _, time) => undertaker forward RemoverActor.AddTask(player, zone, time) AvatarEvents.publish( AvatarServiceResponse(s"/$forChannel/Avatar", player.GUID, AvatarResponse.Release(player)) diff --git a/common/src/main/scala/services/galaxy/GalaxyAction.scala b/common/src/main/scala/services/galaxy/GalaxyAction.scala deleted file mode 100644 index 34c0b4de..00000000 --- a/common/src/main/scala/services/galaxy/GalaxyAction.scala +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2017 PSForever -package services.galaxy - -import net.psforever.packet.game.BuildingInfoUpdateMessage - -object GalaxyAction { - trait Action - - final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends Action -} diff --git a/common/src/main/scala/services/galaxy/GalaxyResponse.scala b/common/src/main/scala/services/galaxy/GalaxyResponse.scala deleted file mode 100644 index 980399ce..00000000 --- a/common/src/main/scala/services/galaxy/GalaxyResponse.scala +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2017 PSForever -package services.galaxy - -import net.psforever.objects.zones.HotSpotInfo -import net.psforever.packet.game.BuildingInfoUpdateMessage - -object GalaxyResponse { - trait Response - - final case class HotSpotUpdate(zone_id : Int, priority : Int, host_spot_info : List[HotSpotInfo]) extends Response - final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends Response -} diff --git a/common/src/main/scala/services/galaxy/GalaxyService.scala b/common/src/main/scala/services/galaxy/GalaxyService.scala index 796aee91..8b1501bb 100644 --- a/common/src/main/scala/services/galaxy/GalaxyService.scala +++ b/common/src/main/scala/services/galaxy/GalaxyService.scala @@ -19,33 +19,44 @@ class GalaxyService extends Actor { case Service.Join(faction) if "TRNCVS".containsSlice(faction) => val path = s"/$faction/Galaxy" val who = sender() - log.info(s"$who has joined $path") + log.trace(s"$who has joined $path") GalaxyEvents.subscribe(who, path) - case Service.Join(_) => + case Service.Join("galaxy") => val path = s"/Galaxy" val who = sender() - log.info(s"$who has joined $path") + log.trace(s"$who has joined $path") + GalaxyEvents.subscribe(who, path) + + case Service.Join(channel) => + val path = s"/$channel/Galaxy" + val who = sender() + log.trace(s"$who has joined $path") GalaxyEvents.subscribe(who, path) case Service.Leave(None) => GalaxyEvents.unsubscribe(sender()) - case Service.Leave(_) => - val path = s"/Galaxy" + case Service.Leave(Some(channel)) => + val path = s"/$channel/Galaxy" val who = sender() - log.info(s"$who has left $path") - GalaxyEvents.unsubscribe(who, path) + log.trace(s"$who has left $path") + GalaxyEvents.unsubscribe(sender(), path) case Service.LeaveAll() => GalaxyEvents.unsubscribe(sender()) - case GalaxyServiceMessage(action) => + case GalaxyServiceMessage(forChannel, action) => action match { case GalaxyAction.MapUpdate(msg: BuildingInfoUpdateMessage) => GalaxyEvents.publish( GalaxyServiceResponse(s"/Galaxy", GalaxyResponse.MapUpdate(msg)) ) + + case GalaxyAction.TransferPassenger(player_guid, temp_channel, vehicle, vehicle_to_delete) => + GalaxyEvents.publish( + GalaxyServiceResponse(s"/$forChannel/Galaxy", GalaxyResponse.TransferPassenger(temp_channel, vehicle, vehicle_to_delete)) + ) case _ => ; } diff --git a/common/src/main/scala/services/galaxy/GalaxyServiceMessage.scala b/common/src/main/scala/services/galaxy/GalaxyServiceMessage.scala index a013af5e..ec85a2a0 100644 --- a/common/src/main/scala/services/galaxy/GalaxyServiceMessage.scala +++ b/common/src/main/scala/services/galaxy/GalaxyServiceMessage.scala @@ -1,4 +1,19 @@ // Copyright (c) 2017 PSForever package services.galaxy -final case class GalaxyServiceMessage(actionMessage : GalaxyAction.Action) +import net.psforever.objects.Vehicle +import net.psforever.packet.game.{BuildingInfoUpdateMessage, PlanetSideGUID} + +final case class GalaxyServiceMessage(forChannel : String, actionMessage : GalaxyAction.Action) + +object GalaxyServiceMessage { + def apply(actionMessage : GalaxyAction.Action) : GalaxyServiceMessage = GalaxyServiceMessage("", actionMessage) +} + +object GalaxyAction { + trait Action + + final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends Action + + final case class TransferPassenger(player_guid : PlanetSideGUID, temp_channel : String, vehicle : Vehicle, vehicle_to_delete : PlanetSideGUID) extends Action +} diff --git a/common/src/main/scala/services/galaxy/GalaxyServiceResponse.scala b/common/src/main/scala/services/galaxy/GalaxyServiceResponse.scala index 28125a89..4d81254c 100644 --- a/common/src/main/scala/services/galaxy/GalaxyServiceResponse.scala +++ b/common/src/main/scala/services/galaxy/GalaxyServiceResponse.scala @@ -1,9 +1,20 @@ // Copyright (c) 2017 PSForever package services.galaxy -import net.psforever.packet.game.PlanetSideGUID +import net.psforever.objects.Vehicle +import net.psforever.objects.zones.HotSpotInfo +import net.psforever.packet.game.{BuildingInfoUpdateMessage, PlanetSideGUID} import services.GenericEventBusMsg final case class GalaxyServiceResponse(toChannel : String, replyMessage : GalaxyResponse.Response ) extends GenericEventBusMsg + +object GalaxyResponse { + trait Response + + final case class HotSpotUpdate(zone_id : Int, priority : Int, host_spot_info : List[HotSpotInfo]) extends Response + final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends Response + + final case class TransferPassenger(temp_channel : String, vehicle : Vehicle, vehicle_to_delete : PlanetSideGUID) extends Response +} diff --git a/common/src/main/scala/services/local/LocalAction.scala b/common/src/main/scala/services/local/LocalAction.scala deleted file mode 100644 index 2b3b22c5..00000000 --- a/common/src/main/scala/services/local/LocalAction.scala +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2017 PSForever -package services.local - -import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle} -import net.psforever.objects.ce.Deployable -import net.psforever.objects.serverobject.PlanetSideServerObject -import net.psforever.objects.serverobject.doors.Door -import net.psforever.objects.serverobject.hackable.Hackable -import net.psforever.objects.serverobject.terminals.CaptureTerminal -import net.psforever.objects.vehicles.Utility -import net.psforever.objects.zones.Zone -import net.psforever.packet.game._ -import net.psforever.types.{PlanetSideEmpire, Vector3} - -object LocalAction { - trait Action - - final case class AlertDestroyDeployable(player_guid : PlanetSideGUID, obj : PlanetSideGameObject with Deployable) extends Action - final case class DeployableMapIcon(player_guid : PlanetSideGUID, behavior : DeploymentAction.Value, deployInfo : DeployableInfo) extends Action - final case class DoorOpens(player_guid : PlanetSideGUID, continent : Zone, door : Door) extends Action - final case class DoorCloses(player_guid : PlanetSideGUID, door_guid : PlanetSideGUID) extends Action - final case class HackClear(player_guid : PlanetSideGUID, target : PlanetSideServerObject, unk1 : Long, unk2 : Long = 8L) extends Action - final case class HackTemporarily(player_guid : PlanetSideGUID, continent : Zone, target : PlanetSideServerObject, unk1 : Long, duration: Int, unk2 : Long = 8L) extends Action - final case class ClearTemporaryHack(player_guid: PlanetSideGUID, target: PlanetSideServerObject with Hackable) extends Action - final case class HackCaptureTerminal(player_guid : PlanetSideGUID, continent : Zone, target : CaptureTerminal, unk1 : Long, unk2 : Long = 8L, isResecured : Boolean) extends Action - final case class RouterTelepadTransport(player_guid : PlanetSideGUID, passenger_guid : PlanetSideGUID, src_guid : PlanetSideGUID, dest_guid : PlanetSideGUID) extends Action - final case class SetEmpire(object_guid: PlanetSideGUID, empire: PlanetSideEmpire.Value) extends Action - final case class ToggleTeleportSystem(player_guid : PlanetSideGUID, router : Vehicle, systemPlan : Option[(Utility.InternalTelepad, TelepadDeployable)]) extends Action - final case class TriggerEffect(player_guid : PlanetSideGUID, effect : String, target : PlanetSideGUID) extends Action - final case class TriggerEffectInfo(player_guid : PlanetSideGUID, effect : String, target : PlanetSideGUID, unk1 : Boolean, unk2 : Long) extends Action - final case class TriggerEffectLocation(player_guid : PlanetSideGUID, effect : String, pos : Vector3, orient : Vector3) extends Action - final case class TriggerSound(player_guid : PlanetSideGUID, sound : TriggeredSound.Value, pos : Vector3, unk : Int, volume : Float) extends Action -} diff --git a/common/src/main/scala/services/local/LocalResponse.scala b/common/src/main/scala/services/local/LocalResponse.scala deleted file mode 100644 index f2cae70c..00000000 --- a/common/src/main/scala/services/local/LocalResponse.scala +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2017 PSForever -package services.local - -import net.psforever.objects.ce.Deployable -import net.psforever.objects.vehicles.Utility -import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle} -import net.psforever.packet.game._ -import net.psforever.types.{PlanetSideEmpire, Vector3} - -object LocalResponse { - trait Response - - final case class AlertDestroyDeployable(obj : PlanetSideGameObject with Deployable) extends Response - final case class DeployableMapIcon(action : DeploymentAction.Value, deployInfo : DeployableInfo) extends Response - final case class DoorOpens(door_guid : PlanetSideGUID) extends Response - final case class DoorCloses(door_guid : PlanetSideGUID) extends Response - final case class EliminateDeployable(obj : PlanetSideGameObject with Deployable, object_guid : PlanetSideGUID, pos : Vector3) extends Response - final case class HackClear(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long) extends Response - final case class HackObject(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long) extends Response - final case class HackCaptureTerminal(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long, isResecured: Boolean) extends Response - final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response - final case class ProximityTerminalEffect(object_guid : PlanetSideGUID, effectState : Boolean) extends Response - final case class RouterTelepadMessage(msg : String) extends Response - final case class RouterTelepadTransport(passenger_guid : PlanetSideGUID, src_guid : PlanetSideGUID, dest_guid : PlanetSideGUID) extends Response - final case class SetEmpire(object_guid: PlanetSideGUID, empire: PlanetSideEmpire.Value) extends Response - final case class ToggleTeleportSystem(router : Vehicle, systemPlan : Option[(Utility.InternalTelepad, TelepadDeployable)]) extends Response - final case class TriggerEffect(target: PlanetSideGUID, effect: String, effectInfo: Option[TriggeredEffect] = None, triggeredLocation: Option[TriggeredEffectLocation] = None) extends Response - final case class TriggerSound(sound : TriggeredSound.Value, pos : Vector3, unk : Int, volume : Float) extends Response -} diff --git a/common/src/main/scala/services/local/LocalService.scala b/common/src/main/scala/services/local/LocalService.scala index d5907c2c..c46a215d 100644 --- a/common/src/main/scala/services/local/LocalService.scala +++ b/common/src/main/scala/services/local/LocalService.scala @@ -5,47 +5,38 @@ import akka.actor.{Actor, ActorRef, Props} import net.psforever.objects.ce.Deployable import net.psforever.objects.serverobject.resourcesilo.ResourceSilo import net.psforever.objects.serverobject.structures.{Amenity, Building} -import net.psforever.objects.serverobject.terminals.{CaptureTerminal, ProximityUnit, Terminal} -import net.psforever.objects.zones.{InterstellarCluster, Zone} +import net.psforever.objects.serverobject.terminals.{CaptureTerminal, Terminal} +import net.psforever.objects.zones.Zone import net.psforever.objects._ import net.psforever.packet.game.{PlanetSideGUID, TriggeredEffect, TriggeredEffectLocation} import net.psforever.objects.vital.Vitality import net.psforever.types.Vector3 import services.local.support._ import services.vehicle.{VehicleAction, VehicleServiceMessage} -import services.{GenericEventBus, RemoverActor, Service, ServiceManager} +import services.{GenericEventBus, RemoverActor, Service} -import scala.util.Success import scala.concurrent.duration._ -import akka.pattern.ask import net.psforever.objects.serverobject.hackable.Hackable import net.psforever.objects.vehicles.{Utility, UtilityType} -import services.ServiceManager.Lookup import services.support.SupportActor import scala.concurrent.duration.Duration -class LocalService extends Actor { - private val doorCloser = context.actorOf(Props[DoorCloseActor], "local-door-closer") - private val hackClearer = context.actorOf(Props[HackClearActor], "local-hack-clearer") - private val hackCapturer = context.actorOf(Props[HackCaptureActor], "local-hack-capturer") - private val engineer = context.actorOf(Props[DeployableRemover], "deployable-remover-agent") - private val teleportDeployment : ActorRef = context.actorOf(Props[RouterTelepadActivation], "telepad-activate-agent") +class LocalService(zone : Zone) extends Actor { + private val doorCloser = context.actorOf(Props[DoorCloseActor], s"${zone.Id}-local-door-closer") + private val hackClearer = context.actorOf(Props[HackClearActor], s"${zone.Id}-local-hack-clearer") + private val hackCapturer = context.actorOf(Props[HackCaptureActor], s"${zone.Id}-local-hack-capturer") + private val engineer = context.actorOf(Props[DeployableRemover], s"${zone.Id}-deployable-remover-agent") + private val teleportDeployment : ActorRef = context.actorOf(Props[RouterTelepadActivation], s"${zone.Id}-telepad-activate-agent") private [this] val log = org.log4s.getLogger - var cluster : ActorRef = Actor.noSender override def preStart = { - log.info("Starting...") - ServiceManager.serviceManager ! Lookup("cluster") + log.trace(s"Awaiting ${zone.Id} local events ...") } val LocalEvents = new GenericEventBus[LocalServiceResponse] - def receive = { - case ServiceManager.LookupResult("cluster", endpoint) => - cluster = endpoint - log.trace("LocalService got cluster service " + endpoint) - + def receive : Receive = { case Service.Join(channel) => val path = s"/$channel/Local" val who = sender() @@ -74,7 +65,7 @@ class LocalService extends Actor { LocalEvents.publish( LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.DeployableMapIcon(behavior, deployInfo)) ) - case LocalAction.DoorOpens(player_guid, zone, door) => + case LocalAction.DoorOpens(player_guid, _, door) => doorCloser ! DoorCloseActor.DoorIsOpen(door, zone) LocalEvents.publish( LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.DoorOpens(door.GUID)) @@ -87,21 +78,19 @@ class LocalService extends Actor { LocalEvents.publish( LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.HackClear(target.GUID, unk1, unk2)) ) - case LocalAction.HackTemporarily(player_guid, zone, target, unk1, duration, unk2) => + case LocalAction.HackTemporarily(player_guid, _, target, unk1, duration, unk2) => hackClearer ! HackClearActor.ObjectIsHacked(target, zone, unk1, unk2, duration) LocalEvents.publish( LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.HackObject(target.GUID, unk1, unk2)) ) case LocalAction.ClearTemporaryHack(_, target) => hackClearer ! HackClearActor.ObjectIsResecured(target) - case LocalAction.HackCaptureTerminal(player_guid, zone, target, unk1, unk2, isResecured) => - + case LocalAction.HackCaptureTerminal(player_guid, _, target, unk1, unk2, isResecured) => // When a CC is hacked (or resecured) all amenities for the base should be unhacked val hackableAmenities = target.Owner.asInstanceOf[Building].Amenities.filter(x => x.isInstanceOf[Hackable]).map(x => x.asInstanceOf[Amenity with Hackable]) hackableAmenities.foreach(amenity => if(amenity.HackedBy.isDefined) { hackClearer ! HackClearActor.ObjectIsResecured(amenity) } ) - if(isResecured){ hackCapturer ! HackCaptureActor.ClearHack(target, zone) } else { @@ -114,7 +103,6 @@ class LocalService extends Actor { hackCapturer ! HackCaptureActor.ObjectIsHacked(target, zone, unk1, unk2, duration = 1 nanosecond) } } - LocalEvents.publish( LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.HackCaptureTerminal(target.GUID, unk1, unk2, isResecured)) ) @@ -150,70 +138,60 @@ class LocalService extends Actor { } //response from DoorCloseActor - case DoorCloseActor.CloseTheDoor(door_guid, zone_id) => + case DoorCloseActor.CloseTheDoor(door_guid, _) => LocalEvents.publish( - LocalServiceResponse(s"/$zone_id/Local", Service.defaultPlayerGUID, LocalResponse.DoorCloses(door_guid)) + LocalServiceResponse(s"/${zone.Id}/Local", Service.defaultPlayerGUID, LocalResponse.DoorCloses(door_guid)) ) //response from HackClearActor - case HackClearActor.ClearTheHack(target_guid, zone_id, unk1, unk2) => + case HackClearActor.ClearTheHack(target_guid, _, unk1, unk2) => log.warn(s"Clearing hack for $target_guid") LocalEvents.publish( - LocalServiceResponse(s"/$zone_id/Local", Service.defaultPlayerGUID, LocalResponse.HackClear(target_guid, unk1, unk2)) + LocalServiceResponse(s"/${zone.Id}/Local", Service.defaultPlayerGUID, LocalResponse.HackClear(target_guid, unk1, unk2)) ) //message from ProximityTerminalControl case Terminal.StartProximityEffect(terminal) => LocalEvents.publish( - LocalServiceResponse(s"/${terminal.Owner.Continent}/Local", PlanetSideGUID(0), LocalResponse.ProximityTerminalEffect(terminal.GUID, true)) + LocalServiceResponse(s"/${zone.Id}/Local", PlanetSideGUID(0), LocalResponse.ProximityTerminalEffect(terminal.GUID, true)) ) case Terminal.StopProximityEffect(terminal) => LocalEvents.publish( - LocalServiceResponse(s"/${terminal.Owner.Continent}/Local", PlanetSideGUID(0), LocalResponse.ProximityTerminalEffect(terminal.GUID, false)) + LocalServiceResponse(s"/${zone.Id}/Local", PlanetSideGUID(0), LocalResponse.ProximityTerminalEffect(terminal.GUID, false)) ) - case HackCaptureActor.HackTimeoutReached(capture_terminal_guid, zone_id, _, _, hackedByFaction) => - import scala.concurrent.ExecutionContext.Implicits.global - ask(cluster, InterstellarCluster.GetWorld(zone_id))(1 seconds).onComplete { - case Success(InterstellarCluster.GiveWorld(_, zone)) => - val terminal = zone.asInstanceOf[Zone].GUID(capture_terminal_guid).get.asInstanceOf[CaptureTerminal] - val building = terminal.Owner.asInstanceOf[Building] - - // todo: Move this to a function for Building - var ntuLevel = 0 - building.Amenities.find(_.Definition == GlobalDefinitions.resource_silo).asInstanceOf[Option[ResourceSilo]] match { - case Some(obj: ResourceSilo) => - ntuLevel = obj.CapacitorDisplay.toInt - case _ => - // Base has no NTU silo - likely a tower / cavern CC - ntuLevel = 1 - } - - if(ntuLevel > 0) { - log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction") - - building.Faction = hackedByFaction - self ! LocalServiceMessage(zone.Id, LocalAction.SetEmpire(building.GUID, hackedByFaction)) - } else { - log.info("Base hack completed, but base was out of NTU.") - } - - // Reset CC back to normal operation - self ! LocalServiceMessage(zone.Id, LocalAction.HackCaptureTerminal(PlanetSideGUID(-1), zone, terminal, 0, 8L, isResecured = true)) - //todo: this appears to be the way to reset the base warning lights after the hack finishes but it doesn't seem to work. The attribute above is a workaround - self ! HackClearActor.ClearTheHack(building.GUID, zone.Id, 3212836864L, 8L) - case Success(_) => - log.warn("Got success from InterstellarCluster.GetWorld but didn't know how to handle it") - - case scala.util.Failure(_) => log.warn(s"LocalService Failed to get zone when hack timeout was reached") + case HackCaptureActor.HackTimeoutReached(capture_terminal_guid, _, _, _, hackedByFaction) => + val terminal = zone.GUID(capture_terminal_guid).get.asInstanceOf[CaptureTerminal] + val building = terminal.Owner.asInstanceOf[Building] + // todo: Move this to a function for Building + var ntuLevel = building.Amenities.find(_.Definition == GlobalDefinitions.resource_silo) match { + case Some(obj: ResourceSilo) => + obj.CapacitorDisplay.toInt + case _ => + // Base has no NTU silo - likely a tower / cavern CC + 1 } + if(ntuLevel > 0) { + log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction") + + building.Faction = hackedByFaction + self ! LocalServiceMessage(zone.Id, LocalAction.SetEmpire(building.GUID, hackedByFaction)) + } else { + log.info("Base hack completed, but base was out of NTU.") + } + + // Reset CC back to normal operation + self ! LocalServiceMessage(zone.Id, LocalAction.HackCaptureTerminal(PlanetSideGUID(-1), zone, terminal, 0, 8L, isResecured = true)) + //todo: this appears to be the way to reset the base warning lights after the hack finishes but it doesn't seem to work. The attribute above is a workaround + self ! HackClearActor.ClearTheHack(building.GUID, zone.Id, 3212836864L, 8L) + //message to Engineer case LocalServiceMessage.Deployables(msg) => engineer forward msg //message(s) from Engineer - case msg @ DeployableRemover.EliminateDeployable(obj : TurretDeployable, guid, pos, zone) => + case msg @ DeployableRemover.EliminateDeployable(obj : TurretDeployable, guid, pos, _) => val seats = obj.Seats.values if(seats.count(_.isOccupied) > 0) { val wasKickedByDriver = false //TODO yeah, I don't know @@ -230,27 +208,27 @@ class LocalService extends Actor { context.system.scheduler.scheduleOnce(Duration.create(2, "seconds"), self, msg) } else { - EliminateDeployable(obj, guid, pos, zone.Id) + EliminateDeployable(obj, guid, pos) } - case DeployableRemover.EliminateDeployable(obj : BoomerDeployable, guid, pos, zone) => - EliminateDeployable(obj, guid, pos, zone.Id) + case DeployableRemover.EliminateDeployable(obj : BoomerDeployable, guid, pos, _) => + EliminateDeployable(obj, guid, pos) obj.Trigger match { case Some(trigger) => log.warn(s"LocalService: deconstructing boomer in ${zone.Id}, but trigger@${trigger.GUID.guid} still exists") case _ => ; } - case DeployableRemover.EliminateDeployable(obj : TelepadDeployable, guid, pos, zone) => + case DeployableRemover.EliminateDeployable(obj : TelepadDeployable, guid, pos, _) => obj.Active = false //ClearSpecific will also remove objects that do not have GUID's; we may not have a GUID at this time teleportDeployment ! SupportActor.ClearSpecific(List(obj), zone) - EliminateDeployable(obj, guid, pos, zone.Id) + EliminateDeployable(obj, guid, pos) - case DeployableRemover.EliminateDeployable(obj, guid, pos, zone) => - EliminateDeployable(obj, guid, pos, zone.Id) + case DeployableRemover.EliminateDeployable(obj, guid, pos, _) => + EliminateDeployable(obj, guid, pos) - case DeployableRemover.DeleteTrigger(trigger_guid, zone) => + case DeployableRemover.DeleteTrigger(trigger_guid, _) => LocalEvents.publish( LocalServiceResponse(s"/${zone.Id}/Local", Service.defaultPlayerGUID, LocalResponse.ObjectDelete(trigger_guid, 0)) ) @@ -260,7 +238,7 @@ class LocalService extends Actor { teleportDeployment forward msg //from RouterTelepadActivation - case RouterTelepadActivation.ActivateTeleportSystem(telepad, zone) => + case RouterTelepadActivation.ActivateTeleportSystem(telepad, _) => val remoteTelepad = telepad.asInstanceOf[TelepadDeployable] remoteTelepad.Active = true zone.GUID(remoteTelepad.Router) match { @@ -294,13 +272,13 @@ class LocalService extends Actor { } case _ => log.error(s"ActivateTeleportSystem: vehicle@${router.GUID.guid} in ${zone.Id} is not a router?") - RouterTelepadError(remoteTelepad, zone, "@Telepad_NoDeploy_RouterLost") + RouterTelepadError(remoteTelepad, "@Telepad_NoDeploy_RouterLost") } case Some(o) => log.error(s"ActivateTeleportSystem: ${o.Definition.Name}@${o.GUID.guid} in ${zone.Id} is not a router") - RouterTelepadError(remoteTelepad, zone, "@Telepad_NoDeploy_RouterLost") + RouterTelepadError(remoteTelepad, "@Telepad_NoDeploy_RouterLost") case None => - RouterTelepadError(remoteTelepad, zone, "@Telepad_NoDeploy_RouterLost") + RouterTelepadError(remoteTelepad, "@Telepad_NoDeploy_RouterLost") } //synchronized damage calculations @@ -315,10 +293,9 @@ class LocalService extends Actor { /** * na * @param telepad na - * @param zone na * @param msg na */ - def RouterTelepadError(telepad : TelepadDeployable, zone : Zone, msg : String) : Unit = { + def RouterTelepadError(telepad : TelepadDeployable, msg : String) : Unit = { telepad.OwnerName match { case Some(name) => LocalEvents.publish( @@ -344,11 +321,10 @@ class LocalService extends Actor { * @param guid the deployable objects globally unique identifier; * may be a former identifier * @param position the deployable's position - * @param zoneId the zone where the deployable is currently placed */ - def EliminateDeployable(obj : PlanetSideGameObject with Deployable, guid : PlanetSideGUID, position : Vector3, zoneId : String) : Unit = { + def EliminateDeployable(obj : PlanetSideGameObject with Deployable, guid : PlanetSideGUID, position : Vector3) : Unit = { LocalEvents.publish( - LocalServiceResponse(s"/$zoneId/Local", Service.defaultPlayerGUID, LocalResponse.EliminateDeployable(obj, guid, position)) + LocalServiceResponse(s"/${zone.Id}/Local", Service.defaultPlayerGUID, LocalResponse.EliminateDeployable(obj, guid, position)) ) obj.OwnerName match { case Some(name) => diff --git a/common/src/main/scala/services/local/LocalServiceMessage.scala b/common/src/main/scala/services/local/LocalServiceMessage.scala index 07164a26..3e81c479 100644 --- a/common/src/main/scala/services/local/LocalServiceMessage.scala +++ b/common/src/main/scala/services/local/LocalServiceMessage.scala @@ -1,6 +1,17 @@ // Copyright (c) 2017 PSForever package services.local +import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle} +import net.psforever.objects.ce.Deployable +import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.objects.serverobject.doors.Door +import net.psforever.objects.serverobject.hackable.Hackable +import net.psforever.objects.serverobject.terminals.CaptureTerminal +import net.psforever.objects.vehicles.Utility +import net.psforever.objects.zones.Zone +import net.psforever.packet.game.{DeployableInfo, DeploymentAction, PlanetSideGUID, TriggeredSound} +import net.psforever.types.{PlanetSideEmpire, Vector3} + final case class LocalServiceMessage(forChannel : String, actionMessage : LocalAction.Action) object LocalServiceMessage { @@ -8,3 +19,23 @@ object LocalServiceMessage { final case class Telepads(msg : Any) } + +object LocalAction { + trait Action + + final case class AlertDestroyDeployable(player_guid : PlanetSideGUID, obj : PlanetSideGameObject with Deployable) extends Action + final case class DeployableMapIcon(player_guid : PlanetSideGUID, behavior : DeploymentAction.Value, deployInfo : DeployableInfo) extends Action + final case class DoorOpens(player_guid : PlanetSideGUID, continent : Zone, door : Door) extends Action + final case class DoorCloses(player_guid : PlanetSideGUID, door_guid : PlanetSideGUID) extends Action + final case class HackClear(player_guid : PlanetSideGUID, target : PlanetSideServerObject, unk1 : Long, unk2 : Long = 8L) extends Action + final case class HackTemporarily(player_guid : PlanetSideGUID, continent : Zone, target : PlanetSideServerObject, unk1 : Long, duration: Int, unk2 : Long = 8L) extends Action + final case class ClearTemporaryHack(player_guid: PlanetSideGUID, target: PlanetSideServerObject with Hackable) extends Action + final case class HackCaptureTerminal(player_guid : PlanetSideGUID, continent : Zone, target : CaptureTerminal, unk1 : Long, unk2 : Long = 8L, isResecured : Boolean) extends Action + final case class RouterTelepadTransport(player_guid : PlanetSideGUID, passenger_guid : PlanetSideGUID, src_guid : PlanetSideGUID, dest_guid : PlanetSideGUID) extends Action + final case class SetEmpire(object_guid: PlanetSideGUID, empire: PlanetSideEmpire.Value) extends Action + final case class ToggleTeleportSystem(player_guid : PlanetSideGUID, router : Vehicle, systemPlan : Option[(Utility.InternalTelepad, TelepadDeployable)]) extends Action + final case class TriggerEffect(player_guid : PlanetSideGUID, effect : String, target : PlanetSideGUID) extends Action + final case class TriggerEffectInfo(player_guid : PlanetSideGUID, effect : String, target : PlanetSideGUID, unk1 : Boolean, unk2 : Long) extends Action + final case class TriggerEffectLocation(player_guid : PlanetSideGUID, effect : String, pos : Vector3, orient : Vector3) extends Action + final case class TriggerSound(player_guid : PlanetSideGUID, sound : TriggeredSound.Value, pos : Vector3, unk : Int, volume : Float) extends Action +} diff --git a/common/src/main/scala/services/local/LocalServiceResponse.scala b/common/src/main/scala/services/local/LocalServiceResponse.scala index 4708feb5..cd31aa7a 100644 --- a/common/src/main/scala/services/local/LocalServiceResponse.scala +++ b/common/src/main/scala/services/local/LocalServiceResponse.scala @@ -1,10 +1,37 @@ // Copyright (c) 2017 PSForever package services.local -import net.psforever.packet.game.PlanetSideGUID +import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle} +import net.psforever.objects.ce.Deployable +import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal} +import net.psforever.objects.vehicles.Utility +import net.psforever.packet.game._ +import net.psforever.types.{PlanetSideEmpire, Vector3} import services.GenericEventBusMsg final case class LocalServiceResponse(toChannel : String, avatar_guid : PlanetSideGUID, replyMessage : LocalResponse.Response ) extends GenericEventBusMsg + +object LocalResponse { + trait Response + + final case class AlertDestroyDeployable(obj : PlanetSideGameObject with Deployable) extends Response + final case class DeployableMapIcon(action : DeploymentAction.Value, deployInfo : DeployableInfo) extends Response + final case class DoorOpens(door_guid : PlanetSideGUID) extends Response + final case class DoorCloses(door_guid : PlanetSideGUID) extends Response + final case class EliminateDeployable(obj : PlanetSideGameObject with Deployable, object_guid : PlanetSideGUID, pos : Vector3) extends Response + final case class HackClear(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long) extends Response + final case class HackObject(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long) extends Response + final case class HackCaptureTerminal(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long, isResecured: Boolean) extends Response + final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response + final case class ProximityTerminalAction(terminal : Terminal with ProximityUnit, target : PlanetSideGameObject) extends Response + final case class ProximityTerminalEffect(object_guid : PlanetSideGUID, effectState : Boolean) extends Response + final case class RouterTelepadMessage(msg : String) extends Response + final case class RouterTelepadTransport(passenger_guid : PlanetSideGUID, src_guid : PlanetSideGUID, dest_guid : PlanetSideGUID) extends Response + final case class SetEmpire(object_guid: PlanetSideGUID, empire: PlanetSideEmpire.Value) extends Response + final case class ToggleTeleportSystem(router : Vehicle, systemPlan : Option[(Utility.InternalTelepad, TelepadDeployable)]) extends Response + final case class TriggerEffect(target: PlanetSideGUID, effect: String, effectInfo: Option[TriggeredEffect] = None, triggeredLocation: Option[TriggeredEffectLocation] = None) extends Response + final case class TriggerSound(sound : TriggeredSound.Value, pos : Vector3, unk : Int, volume : Float) extends Response +} diff --git a/common/src/main/scala/services/vehicle/VehicleAction.scala b/common/src/main/scala/services/vehicle/VehicleAction.scala deleted file mode 100644 index 982f8977..00000000 --- a/common/src/main/scala/services/vehicle/VehicleAction.scala +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2017 PSForever -package services.vehicle - -import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle} -import net.psforever.objects.equipment.Equipment -import net.psforever.objects.vehicles.Utility -import net.psforever.objects.zones.Zone -import net.psforever.packet.PlanetSideGamePacket -import net.psforever.packet.game.PlanetSideGUID -import net.psforever.packet.game.objectcreate.ConstructorData -import net.psforever.types.{BailType, DriveState, Vector3} - -object VehicleAction { - trait Action - - final case class ChildObjectState(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Action - final case class DeployRequest(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, state : DriveState.Value, unk1 : Int, unk2 : Boolean, pos : Vector3) extends Action - final case class DismountVehicle(player_guid : PlanetSideGUID, bailType : BailType.Value, unk2 : Boolean) extends Action - final case class EquipmentInSlot(player_guid : PlanetSideGUID, target_guid : PlanetSideGUID, slot : Int, equipment : Equipment) extends Action - final case class InventoryState(player_guid : PlanetSideGUID, obj : PlanetSideGameObject, parent_guid : PlanetSideGUID, start : Int, con_data : ConstructorData) extends Action - final case class InventoryState2(player_guid : PlanetSideGUID, obj_guid : PlanetSideGUID, parent_guid : PlanetSideGUID, value : Int) extends Action - final case class KickPassenger(player_guid : PlanetSideGUID, unk1 : Int, unk2 : Boolean, vehicle_guid : PlanetSideGUID) extends Action - final case class LoadVehicle(player_guid : PlanetSideGUID, vehicle : Vehicle, vtype : Int, vguid : PlanetSideGUID, vdata : ConstructorData) extends Action - final case class MountVehicle(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, seat : Int) extends Action - final case class ObjectDelete(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action - final case class Ownership(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID) extends Action - final case class PlanetsideAttribute(player_guid : PlanetSideGUID, target_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action - final case class SeatPermissions(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, seat_group : Int, permission : Long) extends Action - final case class StowEquipment(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action - final case class UnloadVehicle(player_guid : PlanetSideGUID, continent : Zone, vehicle : Vehicle, vehicle_guid : PlanetSideGUID) extends Action - final case class UnstowEquipment(player_guid : PlanetSideGUID, item_guid : PlanetSideGUID) extends Action - final case class VehicleState(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, unk1 : Int, pos : Vector3, ang : Vector3, vel : Option[Vector3], unk2 : Option[Int], unk3 : Int, unk4 : Int, wheel_direction : Int, unk5 : Boolean, unk6 : Boolean) extends Action - final case class SendResponse(player_guid: PlanetSideGUID, msg : PlanetSideGamePacket) extends Action - final case class UpdateAmsSpawnPoint(zone : Zone) extends Action - - final case class TransferPassengerChannel(player_guid : PlanetSideGUID, temp_channel : String, new_channel : String, vehicle : Vehicle) extends Action - final case class TransferPassenger(player_guid : PlanetSideGUID, temp_channel : String, vehicle : Vehicle, vehicle_to_delete : PlanetSideGUID) extends Action - - final case class ForceDismountVehicleCargo(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, bailed : Boolean, requestedByPassenger : Boolean, kicked : Boolean) extends Action - final case class KickCargo(player_guid : PlanetSideGUID, cargo : Vehicle, speed : Int, delay : Long) extends Action -} diff --git a/common/src/main/scala/services/vehicle/VehicleResponse.scala b/common/src/main/scala/services/vehicle/VehicleResponse.scala deleted file mode 100644 index ca312e94..00000000 --- a/common/src/main/scala/services/vehicle/VehicleResponse.scala +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2017 PSForever -package services.vehicle - -import net.psforever.objects.serverobject.tube.SpawnTube -import net.psforever.objects.vehicles.Utility -import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle} -import net.psforever.packet.PlanetSideGamePacket -import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} -import net.psforever.packet.game.objectcreate.ConstructorData -import net.psforever.types.{BailType, DriveState, Vector3} - -object VehicleResponse { - trait Response - - final case class AttachToRails(vehicle_guid : PlanetSideGUID, rails_guid : PlanetSideGUID) extends Response - final case class ChildObjectState(object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Response - final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Response - final case class DeployRequest(object_guid : PlanetSideGUID, state : DriveState.Value, unk1 : Int, unk2 : Boolean, pos : Vector3) extends Response - final case class DetachFromRails(vehicle_guid : PlanetSideGUID, rails_guid : PlanetSideGUID, rails_pos : Vector3, rails_rot : Float) extends Response - final case class DismountVehicle(bailType : BailType.Value , unk2 : Boolean) extends Response - final case class EquipmentInSlot(pkt : ObjectCreateMessage) extends Response - final case class HitHint(source_guid : PlanetSideGUID) extends Response - final case class InventoryState(obj : PlanetSideGameObject, parent_guid : PlanetSideGUID, start : Int, con_data : ConstructorData) extends Response - final case class InventoryState2(obj_guid : PlanetSideGUID, parent_guid : PlanetSideGUID, value : Int) extends Response - final case class KickPassenger(seat_num : Int, kickedByDriver : Boolean, vehicle_guid : PlanetSideGUID) extends Response - final case class LoadVehicle(vehicle : Vehicle, vtype : Int, vguid : PlanetSideGUID, vdata : ConstructorData) extends Response - final case class MountVehicle(object_guid : PlanetSideGUID, seat : Int) extends Response - final case class Ownership(vehicle_guid : PlanetSideGUID) extends Response - final case class PlanetsideAttribute(vehicle_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Response - final case class ResetSpawnPad(pad_guid : PlanetSideGUID) extends Response - final case class RevealPlayer(player_guid : PlanetSideGUID) extends Response - final case class SeatPermissions(vehicle_guid : PlanetSideGUID, seat_group : Int, permission : Long) extends Response - final case class StowEquipment(vehicle_guid : PlanetSideGUID, slot : Int, itype : Int, iguid : PlanetSideGUID, idata : ConstructorData) extends Response - final case class UnloadVehicle(vehicle : Vehicle, vehicle_guid : PlanetSideGUID) extends Response - final case class UnstowEquipment(item_guid : PlanetSideGUID) extends Response - final case class VehicleState(vehicle_guid : PlanetSideGUID, unk1 : Int, pos : Vector3, ang : Vector3, vel : Option[Vector3], unk2 : Option[Int], unk3 : Int, unk4 : Int, wheel_direction : Int, unk5 : Boolean, unk6 : Boolean) extends Response - final case class SendResponse(msg: PlanetSideGamePacket) extends Response - final case class UpdateAmsSpawnPoint(list : List[SpawnTube]) extends Response - - final case class TransferPassengerChannel(old_channel : String, temp_channel : String, vehicle : Vehicle) extends Response - final case class TransferPassenger(temp_channel : String, vehicle : Vehicle, vehicle_to_delete : PlanetSideGUID) extends Response - - final case class ForceDismountVehicleCargo(vehicle_guid : PlanetSideGUID, bailed : Boolean, requestedByPassenger : Boolean, kicked : Boolean) extends Response - final case class KickCargo(cargo : Vehicle, speed : Int, delay : Long) extends Response -} diff --git a/common/src/main/scala/services/vehicle/VehicleService.scala b/common/src/main/scala/services/vehicle/VehicleService.scala index b32c0721..a12ab503 100644 --- a/common/src/main/scala/services/vehicle/VehicleService.scala +++ b/common/src/main/scala/services/vehicle/VehicleService.scala @@ -16,13 +16,13 @@ import services.{GenericEventBus, RemoverActor, Service} import scala.concurrent.duration._ -class VehicleService extends Actor { - private val vehicleDecon : ActorRef = context.actorOf(Props[VehicleRemover], "vehicle-decon-agent") - private val turretUpgrade : ActorRef = context.actorOf(Props[TurretUpgrader], "turret-upgrade-agent") +class VehicleService(zone : Zone) extends Actor { + private val vehicleDecon : ActorRef = context.actorOf(Props[VehicleRemover], s"${zone.Id}-vehicle-decon-agent") + private val turretUpgrade : ActorRef = context.actorOf(Props[TurretUpgrader], s"${zone.Id}-turret-upgrade-agent") private [this] val log = org.log4s.getLogger override def preStart = { - log.info("Starting...") + log.trace(s"Awaiting ${zone.Id} vehicle events ...") } val VehicleEvents = new GenericEventBus[VehicleServiceResponse] @@ -135,10 +135,6 @@ class VehicleService extends Actor { VehicleEvents.publish( VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.TransferPassengerChannel(old_channel, temp_channel, vehicle)) ) - case VehicleAction.TransferPassenger(player_guid, temp_channel, vehicle, vehicle_to_delete) => - VehicleEvents.publish( - VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.TransferPassenger(temp_channel, vehicle, vehicle_to_delete)) - ) case VehicleAction.ForceDismountVehicleCargo(player_guid, vehicle_guid, bailed, requestedByPassenger, kicked) => VehicleEvents.publish( @@ -159,37 +155,57 @@ class VehicleService extends Actor { case VehicleServiceMessage.TurretUpgrade(msg) => turretUpgrade forward msg - //from VehicleSpawnControl - case VehicleSpawnPad.ConcealPlayer(player_guid, zone_id) => + //from VehicleSpawnControl, etc. + case VehicleSpawnPad.ConcealPlayer(player_guid) => VehicleEvents.publish( - VehicleServiceResponse(s"/$zone_id/Vehicle", Service.defaultPlayerGUID, VehicleResponse.ConcealPlayer(player_guid)) + VehicleServiceResponse(s"/${zone.Id}/Vehicle", Service.defaultPlayerGUID, VehicleResponse.ConcealPlayer(player_guid)) ) - //from VehicleSpawnControl - case VehicleSpawnPad.AttachToRails(vehicle, pad, zone_id) => + case VehicleSpawnPad.AttachToRails(vehicle, pad) => VehicleEvents.publish( - VehicleServiceResponse(s"/$zone_id/Vehicle", Service.defaultPlayerGUID, VehicleResponse.AttachToRails(vehicle.GUID, pad.GUID)) + VehicleServiceResponse(s"/${zone.Id}/Vehicle", Service.defaultPlayerGUID, VehicleResponse.AttachToRails(vehicle.GUID, pad.GUID)) ) - //from VehicleSpawnControl - case VehicleSpawnPad.DetachFromRails(vehicle, pad, zone_id) => + case VehicleSpawnPad.StartPlayerSeatedInVehicle(driver_name, vehicle, pad) => VehicleEvents.publish( - VehicleServiceResponse(s"/$zone_id/Vehicle", Service.defaultPlayerGUID, VehicleResponse.DetachFromRails(vehicle.GUID, pad.GUID, pad.Position, pad.Orientation.z)) + VehicleServiceResponse(s"/$driver_name/Vehicle", Service.defaultPlayerGUID, VehicleResponse.StartPlayerSeatedInVehicle(vehicle, pad)) ) - //from VehicleSpawnControl - case VehicleSpawnPad.ResetSpawnPad(pad, zone_id) => + case VehicleSpawnPad.PlayerSeatedInVehicle(driver_name, vehicle, pad) => VehicleEvents.publish( - VehicleServiceResponse(s"/$zone_id/Vehicle", Service.defaultPlayerGUID, VehicleResponse.ResetSpawnPad(pad.GUID)) + VehicleServiceResponse(s"/$driver_name/Vehicle", Service.defaultPlayerGUID, VehicleResponse.PlayerSeatedInVehicle(vehicle, pad)) ) - case VehicleSpawnPad.RevealPlayer(player_guid, zone_id) => + case VehicleSpawnPad.ServerVehicleOverrideStart(driver_name, vehicle, pad) => VehicleEvents.publish( - VehicleServiceResponse(s"/$zone_id/Vehicle", Service.defaultPlayerGUID, VehicleResponse.RevealPlayer(player_guid)) + VehicleServiceResponse(s"/$driver_name/Vehicle", Service.defaultPlayerGUID, VehicleResponse.ServerVehicleOverrideStart(vehicle, pad)) ) - //from VehicleSpawnControl - case VehicleSpawnPad.LoadVehicle(vehicle, zone) => + case VehicleSpawnPad.ServerVehicleOverrideEnd(driver_name, vehicle, pad) => + VehicleEvents.publish( + VehicleServiceResponse(s"/$driver_name/Vehicle", Service.defaultPlayerGUID, VehicleResponse.ServerVehicleOverrideEnd(vehicle, pad)) + ) + + case VehicleSpawnPad.DetachFromRails(vehicle, pad) => + VehicleEvents.publish( + VehicleServiceResponse(s"/${zone.Id}/Vehicle", Service.defaultPlayerGUID, VehicleResponse.DetachFromRails(vehicle.GUID, pad.GUID, pad.Position, pad.Orientation.z)) + ) + case VehicleSpawnPad.ResetSpawnPad(pad) => + VehicleEvents.publish( + VehicleServiceResponse(s"/${zone.Id}/Vehicle", Service.defaultPlayerGUID, VehicleResponse.ResetSpawnPad(pad.GUID)) + ) + + case VehicleSpawnPad.RevealPlayer(player_guid) => + VehicleEvents.publish( + VehicleServiceResponse(s"/${zone.Id}/Vehicle", Service.defaultPlayerGUID, VehicleResponse.RevealPlayer(player_guid)) + ) + + case VehicleSpawnPad.PeriodicReminder(to, reason, data) => + VehicleEvents.publish( + VehicleServiceResponse(s"/$to/Vehicle", Service.defaultPlayerGUID, VehicleResponse.PeriodicReminder(reason, data)) + ) + + case VehicleSpawnPad.LoadVehicle(vehicle) => val definition = vehicle.Definition val vtype = definition.ObjectId val vguid = vehicle.GUID @@ -201,12 +217,12 @@ class VehicleService extends Actor { //avoid unattended vehicle spawning blocking the pad; user should mount (and does so normally) to reset decon timer vehicleDecon forward RemoverActor.AddTask(vehicle, zone, Some(30 seconds)) - //from VehicleSpawnControl - case VehicleSpawnPad.DisposeVehicle(vehicle, zone) => + case VehicleSpawnPad.DisposeVehicle(vehicle) => + vehicleDecon forward RemoverActor.AddTask(vehicle, zone, Some(0 seconds)) vehicleDecon forward RemoverActor.HurrySpecific(List(vehicle), zone) //correspondence from WorldSessionActor - case VehicleServiceMessage.AMSDeploymentChange(zone) => + case VehicleServiceMessage.AMSDeploymentChange(_) => VehicleEvents.publish( VehicleServiceResponse(s"/${zone.Id}/Vehicle", Service.defaultPlayerGUID, VehicleResponse.UpdateAmsSpawnPoint(AmsSpawnPoints(zone))) ) diff --git a/common/src/main/scala/services/vehicle/VehicleServiceMessage.scala b/common/src/main/scala/services/vehicle/VehicleServiceMessage.scala index 9a1d877a..1c13cdea 100644 --- a/common/src/main/scala/services/vehicle/VehicleServiceMessage.scala +++ b/common/src/main/scala/services/vehicle/VehicleServiceMessage.scala @@ -1,8 +1,13 @@ // Copyright (c) 2017 PSForever package services.vehicle -import net.psforever.objects.Vehicle +import net.psforever.objects.{PlanetSideGameObject, Vehicle} +import net.psforever.objects.equipment.Equipment import net.psforever.objects.zones.Zone +import net.psforever.packet.PlanetSideGamePacket +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.packet.game.objectcreate.ConstructorData +import net.psforever.types.{BailType, DriveState, Vector3} final case class VehicleServiceMessage(forChannel : String, actionMessage : VehicleAction.Action) @@ -16,3 +21,32 @@ object VehicleServiceMessage { final case class AMSDeploymentChange(zone : Zone) } + +object VehicleAction { + trait Action + + final case class ChildObjectState(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Action + final case class DeployRequest(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, state : DriveState.Value, unk1 : Int, unk2 : Boolean, pos : Vector3) extends Action + final case class DismountVehicle(player_guid : PlanetSideGUID, bailType : BailType.Value, unk2 : Boolean) extends Action + final case class EquipmentInSlot(player_guid : PlanetSideGUID, target_guid : PlanetSideGUID, slot : Int, equipment : Equipment) extends Action + final case class InventoryState(player_guid : PlanetSideGUID, obj : PlanetSideGameObject, parent_guid : PlanetSideGUID, start : Int, con_data : ConstructorData) extends Action + final case class InventoryState2(player_guid : PlanetSideGUID, obj_guid : PlanetSideGUID, parent_guid : PlanetSideGUID, value : Int) extends Action + final case class KickPassenger(player_guid : PlanetSideGUID, unk1 : Int, unk2 : Boolean, vehicle_guid : PlanetSideGUID) extends Action + final case class LoadVehicle(player_guid : PlanetSideGUID, vehicle : Vehicle, vtype : Int, vguid : PlanetSideGUID, vdata : ConstructorData) extends Action + final case class MountVehicle(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, seat : Int) extends Action + final case class ObjectDelete(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action + final case class Ownership(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID) extends Action + final case class PlanetsideAttribute(player_guid : PlanetSideGUID, target_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action + final case class SeatPermissions(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, seat_group : Int, permission : Long) extends Action + final case class StowEquipment(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action + final case class UnloadVehicle(player_guid : PlanetSideGUID, continent : Zone, vehicle : Vehicle, vehicle_guid : PlanetSideGUID) extends Action + final case class UnstowEquipment(player_guid : PlanetSideGUID, item_guid : PlanetSideGUID) extends Action + final case class VehicleState(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, unk1 : Int, pos : Vector3, ang : Vector3, vel : Option[Vector3], unk2 : Option[Int], unk3 : Int, unk4 : Int, wheel_direction : Int, unk5 : Boolean, unk6 : Boolean) extends Action + final case class SendResponse(player_guid: PlanetSideGUID, msg : PlanetSideGamePacket) extends Action + final case class UpdateAmsSpawnPoint(zone : Zone) extends Action + + final case class TransferPassengerChannel(player_guid : PlanetSideGUID, temp_channel : String, new_channel : String, vehicle : Vehicle) extends Action + + final case class ForceDismountVehicleCargo(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, bailed : Boolean, requestedByPassenger : Boolean, kicked : Boolean) extends Action + final case class KickCargo(player_guid : PlanetSideGUID, cargo : Vehicle, speed : Int, delay : Long) extends Action +} diff --git a/common/src/main/scala/services/vehicle/VehicleServiceResponse.scala b/common/src/main/scala/services/vehicle/VehicleServiceResponse.scala index 6decd460..a87fe68a 100644 --- a/common/src/main/scala/services/vehicle/VehicleServiceResponse.scala +++ b/common/src/main/scala/services/vehicle/VehicleServiceResponse.scala @@ -1,10 +1,57 @@ // Copyright (c) 2017 PSForever package services.vehicle -import net.psforever.packet.game.PlanetSideGUID +import net.psforever.objects.serverobject.pad.VehicleSpawnPad +import net.psforever.objects.serverobject.pad.VehicleSpawnPad.Reminders +import net.psforever.objects.{PlanetSideGameObject, Vehicle} +import net.psforever.objects.serverobject.tube.SpawnTube +import net.psforever.packet.PlanetSideGamePacket +import net.psforever.packet.game.objectcreate.ConstructorData +import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID} +import net.psforever.types.{BailType, DriveState, Vector3} import services.GenericEventBusMsg final case class VehicleServiceResponse(toChannel : String, avatar_guid : PlanetSideGUID, replyMessage : VehicleResponse.Response ) extends GenericEventBusMsg + +object VehicleResponse { + trait Response + + final case class ChildObjectState(object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Response + final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Response + final case class DeployRequest(object_guid : PlanetSideGUID, state : DriveState.Value, unk1 : Int, unk2 : Boolean, pos : Vector3) extends Response + final case class DismountVehicle(bailType : BailType.Value , unk2 : Boolean) extends Response + final case class EquipmentInSlot(pkt : ObjectCreateMessage) extends Response + final case class HitHint(source_guid : PlanetSideGUID) extends Response + final case class InventoryState(obj : PlanetSideGameObject, parent_guid : PlanetSideGUID, start : Int, con_data : ConstructorData) extends Response + final case class InventoryState2(obj_guid : PlanetSideGUID, parent_guid : PlanetSideGUID, value : Int) extends Response + final case class KickPassenger(seat_num : Int, kickedByDriver : Boolean, vehicle_guid : PlanetSideGUID) extends Response + final case class LoadVehicle(vehicle : Vehicle, vtype : Int, vguid : PlanetSideGUID, vdata : ConstructorData) extends Response + final case class MountVehicle(object_guid : PlanetSideGUID, seat : Int) extends Response + final case class Ownership(vehicle_guid : PlanetSideGUID) extends Response + final case class PlanetsideAttribute(vehicle_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Response + final case class RevealPlayer(player_guid : PlanetSideGUID) extends Response + final case class SeatPermissions(vehicle_guid : PlanetSideGUID, seat_group : Int, permission : Long) extends Response + final case class StowEquipment(vehicle_guid : PlanetSideGUID, slot : Int, itype : Int, iguid : PlanetSideGUID, idata : ConstructorData) extends Response + final case class UnloadVehicle(vehicle : Vehicle, vehicle_guid : PlanetSideGUID) extends Response + final case class UnstowEquipment(item_guid : PlanetSideGUID) extends Response + final case class VehicleState(vehicle_guid : PlanetSideGUID, unk1 : Int, pos : Vector3, ang : Vector3, vel : Option[Vector3], unk2 : Option[Int], unk3 : Int, unk4 : Int, wheel_direction : Int, unk5 : Boolean, unk6 : Boolean) extends Response + final case class SendResponse(msg: PlanetSideGamePacket) extends Response + final case class UpdateAmsSpawnPoint(list : List[SpawnTube]) extends Response + + final case class AttachToRails(vehicle_guid : PlanetSideGUID, rails_guid : PlanetSideGUID) extends Response + final case class StartPlayerSeatedInVehicle(vehicle : Vehicle, pad : VehicleSpawnPad) extends Response + final case class PlayerSeatedInVehicle(vehicle : Vehicle, pad : VehicleSpawnPad) extends Response + final case class DetachFromRails(vehicle_guid : PlanetSideGUID, rails_guid : PlanetSideGUID, rails_pos : Vector3, rails_rot : Float) extends Response + final case class ServerVehicleOverrideStart(vehicle : Vehicle, pad : VehicleSpawnPad) extends Response + final case class ServerVehicleOverrideEnd(vehicle : Vehicle, pad : VehicleSpawnPad) extends Response + final case class ResetSpawnPad(pad_guid : PlanetSideGUID) extends Response + final case class PeriodicReminder(reason : Reminders.Value, data : Option[Any] = None) extends Response + + final case class TransferPassengerChannel(old_channel : String, temp_channel : String, vehicle : Vehicle) extends Response + + final case class ForceDismountVehicleCargo(vehicle_guid : PlanetSideGUID, bailed : Boolean, requestedByPassenger : Boolean, kicked : Boolean) extends Response + final case class KickCargo(cargo : Vehicle, speed : Int, delay : Long) extends Response +} diff --git a/common/src/test/scala/objects/AutoDriveControlsTest.scala b/common/src/test/scala/objects/AutoDriveControlsTest.scala deleted file mode 100644 index 38c100b2..00000000 --- a/common/src/test/scala/objects/AutoDriveControlsTest.scala +++ /dev/null @@ -1,499 +0,0 @@ -// Copyright (c) 2017 PSForever -package objects - -import akka.actor.Props -import akka.testkit.TestProbe -import base.ActorTest -import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} -import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Vehicle} -import net.psforever.objects.serverobject.pad.process.{AutoDriveControls, VehicleSpawnControlGuided} -import net.psforever.packet.game.PlanetSideGUID -import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3} -import org.specs2.mutable.Specification - -import scala.concurrent.duration._ - -class AutoDriveControlsTest extends Specification { - "CancelEntry" should { - val vehicle = Vehicle(GlobalDefinitions.fury) - def exampleTest(vehicle : Vehicle) : Boolean = { vehicle.Position == Vector3(1,1,1) } - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.CancelEarly(exampleTest) - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Cancel - setting.Data mustEqual None - setting.Delay mustEqual 200L - } - - "validate" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.CancelEarly(exampleTest) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Position mustEqual Vector3.Zero - setting.Validate(vehicle) mustEqual false - vehicle.Position = Vector3(1,1,1) - setting.Validate(vehicle) mustEqual true - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.CancelEarly(exampleTest) - val setting : AutoDriveControls.Setting = config.Create - setting.CompletionTest(vehicle) mustEqual true //always true - } - } - - "Climb" should { - val vehicle = Vehicle(GlobalDefinitions.mosquito) - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Climb(10.5f) - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Climb - setting.Data mustEqual Some(10.5f) - setting.Delay mustEqual 200L - } - - "validate" in { - val vehicle_fury = Vehicle(GlobalDefinitions.fury) - val config : AutoDriveControls.Configuration = AutoDriveControls.Climb(10.5f) - val setting : AutoDriveControls.Setting = config.Create - - setting.Validate(vehicle) mustEqual true //mosquito is a flying vehicle - setting.Validate(vehicle_fury) mustEqual false - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Climb(10.5f) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Position mustEqual Vector3.Zero - setting.CompletionTest(vehicle) mustEqual false - vehicle.Position = Vector3(0,0,10.5f) - setting.CompletionTest(vehicle) mustEqual true - } - } - - "Distance" should { - val vehicle = Vehicle(GlobalDefinitions.fury) - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Distance(Vector3.Zero, 10.5f) - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Wait - setting.Data mustEqual None - setting.Delay mustEqual 200L - } - "validate" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Distance(Vector3.Zero, 10.5f) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Velocity mustEqual None - setting.Validate(vehicle) mustEqual false - vehicle.Velocity = Vector3.Zero - setting.Validate(vehicle) mustEqual false - vehicle.Velocity = Vector3(1,0,0) - setting.Validate(vehicle) mustEqual true - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Distance(Vector3.Zero, 10.5f) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Position = Vector3(0,0,0) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Position = Vector3(10.5f,0,0) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Position = Vector3(11,0,0) - setting.CompletionTest(vehicle) mustEqual true - vehicle.Position = Vector3(0,11,0) - setting.CompletionTest(vehicle) mustEqual true - vehicle.Position = Vector3(0,0,11) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Position = Vector3(7.5f,7.5f,0) - setting.CompletionTest(vehicle) mustEqual true - } - } - - "DistanceFromHere" should { - val vehicle = Vehicle(GlobalDefinitions.fury) - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.DistanceFromHere(10.5f) - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Wait - setting.Data mustEqual None - setting.Delay mustEqual 200L - } - - "validate" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.DistanceFromHere(10.5f) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Velocity mustEqual None - setting.Validate(vehicle) mustEqual false - vehicle.Velocity = Vector3.Zero - setting.Validate(vehicle) mustEqual false - vehicle.Velocity = Vector3(1,0,0) - setting.Validate(vehicle) mustEqual true - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.DistanceFromHere(10.5f) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Position = Vector3(0,0,0) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Position = Vector3(10.5f,0,0) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Position = Vector3(11,0,0) - setting.CompletionTest(vehicle) mustEqual true - vehicle.Position = Vector3(0,11,0) - setting.CompletionTest(vehicle) mustEqual true - vehicle.Position = Vector3(0,0,11) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Position = Vector3(7.5f,7.5f,0) - setting.CompletionTest(vehicle) mustEqual true - } - } - - "Drive" should { - val vehicle = Vehicle(GlobalDefinitions.fury) - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Drive(3) - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Drive - setting.Data mustEqual Some(3) - setting.Delay mustEqual 200L - } - - "validate" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Drive(3) - val setting : AutoDriveControls.Setting = config.Create - setting.Validate(vehicle) mustEqual true - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Drive(3) - val setting : AutoDriveControls.Setting = config.Create - vehicle.Velocity mustEqual None - setting.CompletionTest(vehicle) mustEqual false - - vehicle.Velocity = Vector3.Zero - vehicle.Velocity mustEqual Some(Vector3.Zero) - setting.CompletionTest(vehicle) mustEqual false - - vehicle.Velocity = Vector3(1,0,0) - vehicle.Velocity mustEqual Some(Vector3(1,0,0)) - setting.CompletionTest(vehicle) mustEqual true - - } - } - - "FirstGear" should { - val veh_def = GlobalDefinitions.mediumtransport - val vehicle = Vehicle(veh_def) - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.FirstGear() - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Drive - setting.Data mustEqual Some(0) - setting.Delay mustEqual 200L - } - - "validate" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.FirstGear() - val setting : AutoDriveControls.Setting = config.Create - setting.Validate(vehicle) mustEqual true //always true - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.FirstGear() - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Velocity mustEqual None - setting.CompletionTest(vehicle) mustEqual false - vehicle.Velocity = Vector3.Zero - setting.CompletionTest(vehicle) mustEqual false - vehicle.Velocity = Vector3(1,0,0) - setting.CompletionTest(vehicle) mustEqual true - } - - "data" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.FirstGear() - val setting : AutoDriveControls.Setting = config.Create - - setting.Data mustEqual Some(0) - setting.Validate(vehicle) - setting.Data mustEqual Some(veh_def.AutoPilotSpeed1) - } - } - - "ForTime" should { - val veh_def = GlobalDefinitions.mediumtransport - val vehicle = Vehicle(veh_def) - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.ForTime(1200L) - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Wait - setting.Data mustEqual None - setting.Delay mustEqual 200L - } - - "validate" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.ForTime(1200L) - val setting : AutoDriveControls.Setting = config.Create - setting.Validate(vehicle) mustEqual true //always true - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.ForTime(1200L) - val setting : AutoDriveControls.Setting = config.Create - setting.CompletionTest(vehicle) mustEqual false - - Thread.sleep(1100) - setting.CompletionTest(vehicle) mustEqual false - - Thread.sleep(200) - setting.CompletionTest(vehicle) mustEqual true - } - } - - "SecondGear" should { - val veh_def = GlobalDefinitions.mediumtransport - val vehicle = Vehicle(veh_def) - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.SecondGear() - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Drive - setting.Data mustEqual Some(0) - setting.Delay mustEqual 200L - } - - "validate" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.SecondGear() - val setting : AutoDriveControls.Setting = config.Create - setting.Validate(vehicle) mustEqual true //always true - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.SecondGear() - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Velocity mustEqual None - setting.CompletionTest(vehicle) mustEqual false - vehicle.Velocity = Vector3.Zero - setting.CompletionTest(vehicle) mustEqual false - vehicle.Velocity = Vector3(1,0,0) - setting.CompletionTest(vehicle) mustEqual true - } - - "data" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.SecondGear() - val setting : AutoDriveControls.Setting = config.Create - - setting.Data mustEqual Some(0) - setting.Validate(vehicle) - setting.Data mustEqual Some(veh_def.AutoPilotSpeed2) - } - } - - "Stop" should { - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Stop() - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Stop - setting.Data mustEqual None - setting.Delay mustEqual 200L - } - - "validate" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Stop() - val setting : AutoDriveControls.Setting = config.Create - setting.Validate(vehicle) mustEqual true //always true - } - - "completion" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.Stop() - val setting : AutoDriveControls.Setting = config.Create - setting.CompletionTest(vehicle) mustEqual true //always true - } - } - - "TurnBy" should { - "create" in { - val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(35.5f, 23) - val setting : AutoDriveControls.Setting = config.Create - setting.Type mustEqual AutoDriveControls.State.Turn - setting.Data mustEqual Some(23) - setting.Delay mustEqual 100L - } - - "validate (velocity)" in { - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(35.5f, 23) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Velocity mustEqual None - setting.Validate(vehicle) mustEqual false - vehicle.Velocity = Vector3(1,1,1) - setting.Validate(vehicle) mustEqual true - } - - "validate (wheel direction = 15)" in { - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(35.5f, 15) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Velocity = Vector3(1,1,1) - setting.Validate(vehicle) mustEqual false - } - - "completion (passing 35.5-up)" in { - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(35.5f, 25) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Orientation mustEqual Vector3.Zero - setting.CompletionTest(vehicle) mustEqual false - vehicle.Orientation = Vector3(0,0,34.5f) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Orientation = Vector3(0,0,35f) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Orientation = Vector3(0,0,36.0f) - setting.CompletionTest(vehicle) mustEqual true - } - - "completion (passing 35.5 down)" in { - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(-35.5f, 25) - val setting : AutoDriveControls.Setting = config.Create - - vehicle.Orientation = Vector3(0,0,40f) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Orientation = Vector3(0,0,5f) - setting.CompletionTest(vehicle) mustEqual false - vehicle.Orientation = Vector3(0,0,4f) - setting.CompletionTest(vehicle) mustEqual true - } - } -} - -class GuidedControlTest1 extends ActorTest { - "VehicleSpawnControlGuided" should { - "unguided" in { - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - vehicle.GUID = PlanetSideGUID(1) - val driver = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - driver.VehicleSeated = vehicle.GUID - val sendTo = TestProbe() - val order = VehicleSpawnControl.Order(driver, vehicle, sendTo.ref) - val pad = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation) - pad.GUID = PlanetSideGUID(1) - pad.Railed = false //suppress certain events - val guided = system.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), "pad") - - guided ! VehicleSpawnControl.Process.StartGuided(order) - val msg = sendTo.receiveOne(100 milliseconds) - assert(msg.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) - } - } -} - -class GuidedControlTest2 extends ActorTest { - "VehicleSpawnControlGuided" should { - "guided (one)" in { - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - vehicle.GUID = PlanetSideGUID(1) - vehicle.Velocity = Vector3(1,1,1) - val driver = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - driver.VehicleSeated = vehicle.GUID - val sendTo = TestProbe() - val order = VehicleSpawnControl.Order(driver, vehicle, sendTo.ref) - val pad = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation) - pad.Railed = false //suppress certain events - val guided = system.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), "pad") - - pad.Guide = List(AutoDriveControls.FirstGear()) - guided ! VehicleSpawnControl.Process.StartGuided(order) - val msg1 = sendTo.receiveOne(100 milliseconds) - assert(msg1.isInstanceOf[VehicleSpawnControlGuided.GuidedControl]) - assert(msg1.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Drive) - val msg2 = sendTo.receiveOne(200 milliseconds) - assert(msg2.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) - } - } -} - -class GuidedControlTest3 extends ActorTest { - "VehicleSpawnControlGuided" should { - "guided (three)" in { - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - vehicle.GUID = PlanetSideGUID(1) - vehicle.Velocity = Vector3(1,1,1) - val driver = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - driver.VehicleSeated = vehicle.GUID - val sendTo = TestProbe() - val order = VehicleSpawnControl.Order(driver, vehicle, sendTo.ref) - val pad = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation) - pad.Railed = false //suppress certain events - val guided = system.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), "pad") - - pad.Guide = List( - AutoDriveControls.FirstGear(), - AutoDriveControls.ForTime(1000L), - AutoDriveControls.SecondGear() - ) - guided ! VehicleSpawnControl.Process.StartGuided(order) - val msg1 = sendTo.receiveOne(100 milliseconds) - assert(msg1.isInstanceOf[VehicleSpawnControlGuided.GuidedControl]) - assert(msg1.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Drive) - val msg2 = sendTo.receiveOne(100 milliseconds) - assert(msg2.isInstanceOf[VehicleSpawnControlGuided.GuidedControl]) - assert(msg2.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Wait) - sendTo.expectNoMsg(1000 milliseconds) - val msg3 = sendTo.receiveOne(300 milliseconds) - assert(msg3.isInstanceOf[VehicleSpawnControlGuided.GuidedControl]) - assert(msg3.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Drive) - val msg4 = sendTo.receiveOne(200 milliseconds) - assert(msg4.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) - } - } -} - -class GuidedControlTest4 extends ActorTest { - "VehicleSpawnControlGuided" should { - "fail validation test" in { - def validationFailure(vehicle : Vehicle) : Boolean = false - - val vehicle = Vehicle(GlobalDefinitions.mediumtransport) - vehicle.GUID = PlanetSideGUID(1) - vehicle.Velocity = Vector3(1,1,1) - val driver = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) - driver.VehicleSeated = vehicle.GUID - val sendTo = TestProbe() - val order = VehicleSpawnControl.Order(driver, vehicle, sendTo.ref) - val pad = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation) - pad.Railed = false //suppress certain events - val guided = system.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), "pad") - - pad.Guide = List( - AutoDriveControls.FirstGear(), - AutoDriveControls.CancelEarly(validationFailure), - AutoDriveControls.SecondGear() - ) - guided ! VehicleSpawnControl.Process.StartGuided(order) - val msg1 = sendTo.receiveOne(100 milliseconds) - assert(msg1.isInstanceOf[VehicleSpawnControlGuided.GuidedControl]) - assert(msg1.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Drive) - val msg2 = sendTo.receiveOne(200 milliseconds) - assert(msg2.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) - } - } -} diff --git a/common/src/test/scala/objects/ResourceSiloTest.scala b/common/src/test/scala/objects/ResourceSiloTest.scala index fc2f8d2b..23661a4f 100644 --- a/common/src/test/scala/objects/ResourceSiloTest.scala +++ b/common/src/test/scala/objects/ResourceSiloTest.scala @@ -9,11 +9,11 @@ import net.psforever.objects.guid.TaskResolver import net.psforever.objects.{Avatar, GlobalDefinitions, Player} import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl, ResourceSiloDefinition} import net.psforever.objects.serverobject.structures.{Building, StructureType} -import net.psforever.objects.zones.Zone +import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.packet.game.{PlanetSideGUID, UseItemMessage} import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3} import org.specs2.mutable.Specification -import services.ServiceManager +import services.{Service, ServiceManager} import services.avatar.{AvatarAction, AvatarServiceMessage} import scala.concurrent.duration._ @@ -103,24 +103,23 @@ class ResourceSiloControlUseTest extends ActorTest { } class ResourceSiloControlNtuWarningTest extends ActorTest { - val serviceManager = ServiceManager.boot(system) - serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val probe = TestProbe() - serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe), "avatar") + val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0) + val bldg = new Building(building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) val obj = ResourceSilo() obj.GUID = PlanetSideGUID(1) obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo") obj.Actor ! "startup" - obj.Owner = new Building(building_guid = 6, map_id = 0, Zone.Nowhere, StructureType.Building, GlobalDefinitions.building) + obj.Owner = bldg + val zoneEvents = TestProbe("zone-events") "Resource silo" should { "announce high ntu" in { - expectNoMsg(1 seconds) - assert(obj.LowNtuWarningOn == true) + zone.AvatarEvents = zoneEvents.ref + assert(obj.LowNtuWarningOn) obj.Actor ! ResourceSilo.LowNtuWarning(false) - val reply = probe.receiveOne(500 milliseconds) - assert(obj.LowNtuWarningOn == false) + val reply = zoneEvents.receiveOne(500 milliseconds) + assert(!obj.LowNtuWarningOn) assert(reply.isInstanceOf[AvatarServiceMessage]) assert(reply.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere") assert(reply.asInstanceOf[AvatarServiceMessage] @@ -136,29 +135,27 @@ class ResourceSiloControlNtuWarningTest extends ActorTest { } class ResourceSiloControlUpdate1Test extends ActorTest { - val serviceManager = ServiceManager.boot(system) - serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val probe1 = TestProbe() - serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe1), "avatar") + val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0) + val bldg = new Building(building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) val obj = ResourceSilo() obj.GUID = PlanetSideGUID(1) obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo") obj.Actor ! "startup" - val bldg = new Building(building_guid = 6, map_id = 0, Zone.Nowhere, StructureType.Building, GlobalDefinitions.building) - val probe2 = TestProbe() - bldg.Actor = system.actorOf(Props(classOf[ResourceSiloTest.ProbedBuildingControl], probe2), "test-bldg") obj.Owner = bldg + val zoneEvents = TestProbe("zone-events") + val buildingEvents = TestProbe("building-events") "Resource silo" should { "update the charge level and capacitor display (report high ntu, power restored)" in { - expectNoMsg(1 seconds) + zone.AvatarEvents = zoneEvents.ref + bldg.Actor = buildingEvents.ref assert(obj.ChargeLevel == 0) assert(obj.CapacitorDisplay == 0) obj.Actor ! ResourceSilo.UpdateChargeLevel(305) - val reply1 = probe1.receiveOne(500 milliseconds) - val reply2 = probe2.receiveOne(500 milliseconds) + val reply1 = zoneEvents.receiveOne(500 milliseconds) + val reply2 = buildingEvents.receiveOne(500 milliseconds) assert(obj.ChargeLevel == 305) assert(obj.CapacitorDisplay == 4) assert(reply1.isInstanceOf[AvatarServiceMessage]) @@ -174,7 +171,7 @@ class ResourceSiloControlUpdate1Test extends ActorTest { assert(reply2.isInstanceOf[Building.SendMapUpdate]) - val reply3 = probe1.receiveOne(500 milliseconds) + val reply3 = zoneEvents.receiveOne(500 milliseconds) assert(reply3.isInstanceOf[AvatarServiceMessage]) assert(reply3.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere") assert(reply3.asInstanceOf[AvatarServiceMessage] @@ -186,7 +183,7 @@ class ResourceSiloControlUpdate1Test extends ActorTest { assert(reply3.asInstanceOf[AvatarServiceMessage] .actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_value == 0) - val reply4 = probe1.receiveOne(500 milliseconds) + val reply4 = zoneEvents.receiveOne(500 milliseconds) assert(!obj.LowNtuWarningOn) assert(reply4.isInstanceOf[AvatarServiceMessage]) assert(reply4.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere") @@ -203,33 +200,31 @@ class ResourceSiloControlUpdate1Test extends ActorTest { } class ResourceSiloControlUpdate2Test extends ActorTest { - val serviceManager = ServiceManager.boot(system) - serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val probe1 = TestProbe() - serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe1), "avatar") + val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0) + val bldg = new Building(building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) val obj = ResourceSilo() obj.GUID = PlanetSideGUID(1) obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo") obj.Actor ! "startup" - val bldg = new Building(building_guid = 6, map_id = 0, Zone.Nowhere, StructureType.Building, GlobalDefinitions.building) - val probe2 = TestProbe() - bldg.Actor = system.actorOf(Props(classOf[ResourceSiloTest.ProbedBuildingControl], probe2), "test-bldg") obj.Owner = bldg + val zoneEvents = TestProbe("zone-events") + val buildingEvents = TestProbe("building-events") "Resource silo" should { "update the charge level and capacitor display (report good ntu)" in { - expectNoMsg(1 seconds) + zone.AvatarEvents = zoneEvents.ref + bldg.Actor = buildingEvents.ref obj.ChargeLevel = 100 obj.CapacitorDisplay = 1 obj.LowNtuWarningOn = true assert(obj.ChargeLevel == 100) assert(obj.CapacitorDisplay == 1) - assert(obj.LowNtuWarningOn == true) + assert(obj.LowNtuWarningOn) obj.Actor ! ResourceSilo.UpdateChargeLevel(105) - val reply1 = probe1.receiveOne(500 milliseconds) - val reply2 = probe2.receiveOne(500 milliseconds) + val reply1 = zoneEvents.receiveOne(500 milliseconds) + val reply2 = buildingEvents.receiveOne(500 milliseconds) assert(obj.ChargeLevel == 205) assert(obj.CapacitorDisplay == 3) assert(reply1.isInstanceOf[AvatarServiceMessage]) @@ -245,8 +240,8 @@ class ResourceSiloControlUpdate2Test extends ActorTest { assert(reply2.isInstanceOf[Building.SendMapUpdate]) - val reply3 = probe1.receiveOne(500 milliseconds) - assert(obj.LowNtuWarningOn == false) + val reply3 = zoneEvents.receiveOne(500 milliseconds) + assert(!obj.LowNtuWarningOn) assert(reply3.isInstanceOf[AvatarServiceMessage]) assert(reply3.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere") assert(reply3.asInstanceOf[AvatarServiceMessage] @@ -262,43 +257,41 @@ class ResourceSiloControlUpdate2Test extends ActorTest { } class ResourceSiloControlNoUpdateTest extends ActorTest { - val serviceManager = ServiceManager.boot(system) - serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val probe1 = TestProbe() - serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe1), "avatar") + val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0) + val bldg = new Building(building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) val obj = ResourceSilo() obj.GUID = PlanetSideGUID(1) obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo") obj.Actor ! "startup" - val bldg = new Building(building_guid = 6, map_id = 6, Zone.Nowhere, StructureType.Building, GlobalDefinitions.building) - val probe2 = TestProbe() - bldg.Actor = system.actorOf(Props(classOf[ResourceSiloTest.ProbedBuildingControl], probe2), "test-bldg") obj.Owner = bldg + val zoneEvents = TestProbe("zone-events") + val buildingEvents = TestProbe("building-events") "Resource silo" should { "update, but not sufficiently to change the capacitor display" in { - expectNoMsg(1 seconds) + zone.AvatarEvents = zoneEvents.ref + bldg.Actor = buildingEvents.ref obj.ChargeLevel = 250 obj.CapacitorDisplay = 3 obj.LowNtuWarningOn = false assert(obj.ChargeLevel == 250) assert(obj.CapacitorDisplay == 3) - assert(obj.LowNtuWarningOn == false) + assert(!obj.LowNtuWarningOn) obj.Actor ! ResourceSilo.UpdateChargeLevel(50) expectNoMsg(500 milliseconds) - probe1.expectNoMsg(500 milliseconds) - probe2.expectNoMsg(500 milliseconds) + zoneEvents.expectNoMsg(500 milliseconds) + buildingEvents.expectNoMsg(500 milliseconds) assert(obj.ChargeLevel == 299 || obj.ChargeLevel == 300) // Just in case the capacitor level drops while waiting for the message check 299 & 300 assert(obj.CapacitorDisplay == 3) - assert(obj.LowNtuWarningOn == false) + assert(!obj.LowNtuWarningOn) } } } object ResourceSiloTest { - val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) + val player = Player(new Avatar(0L, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) class ProbedAvatarService(probe : TestProbe) extends Actor { override def receive : Receive = { diff --git a/common/src/test/scala/objects/VehicleSpawnPadTest.scala b/common/src/test/scala/objects/VehicleSpawnPadTest.scala index 8ca3daa1..55601244 100644 --- a/common/src/test/scala/objects/VehicleSpawnPadTest.scala +++ b/common/src/test/scala/objects/VehicleSpawnPadTest.scala @@ -4,14 +4,14 @@ package objects import akka.actor.{ActorRef, ActorSystem, Props} import akka.testkit.TestProbe import base.ActorTest -import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import net.psforever.objects.serverobject.structures.StructureType import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Vehicle} import net.psforever.objects.zones.Zone import net.psforever.packet.game.PlanetSideGUID -import net.psforever.types.{CharacterVoice, PlanetSideEmpire, Vector3} +import net.psforever.types._ import org.specs2.mutable.Specification +import services.vehicle.{VehicleAction, VehicleServiceMessage} import scala.concurrent.duration._ @@ -27,14 +27,6 @@ class VehicleSpawnPadTest extends Specification { val obj = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation) obj.Actor mustEqual ActorRef.noSender obj.Definition mustEqual GlobalDefinitions.mb_pad_creation - obj.Railed mustEqual true - } - - "un-railed" in { - val obj = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation) - obj.Railed mustEqual true - obj.Railed = false - obj.Railed mustEqual false } } } @@ -49,264 +41,174 @@ class VehicleSpawnControl1Test extends ActorTest { } } -class VehicleSpawnControl2aTest extends ActorTest { - // This runs for a long time. +class VehicleSpawnControl2Test extends ActorTest { "VehicleSpawnControl" should { - "complete on a vehicle order (block a second one until the first is done and the spawn pad is cleared)" in { + "complete a vehicle order" in { val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) - //we can recycle the vehicle and the player for each order - val probe1 = new TestProbe(system, "first-order") - val probe2 = new TestProbe(system, "second-order") - val probe3 = new TestProbe(system, "zone-events") - zone.VehicleEvents = probe3.ref + val probe = new TestProbe(system, "zone-events") - pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref) //first order - pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe2.ref) //second order + zone.VehicleEvents = probe.ref //zone events + pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order - val probe2Msg1 = probe2.receiveOne(100 milliseconds) - assert(probe2Msg1.isInstanceOf[VehicleSpawnPad.PeriodicReminder]) - assert(probe2Msg1.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Queue) - assert(probe2Msg1.asInstanceOf[VehicleSpawnPad.PeriodicReminder].data.contains("2")) - - val probe3Msg1 = probe3.receiveOne(3 seconds) - assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer]) - - val probe3Msg2 = probe3.receiveOne(3 seconds) - assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle]) - - val probe3Msg3 = probe3.receiveOne(200 milliseconds) - assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.AttachToRails]) - - val probe1Msg1 = probe1.receiveOne(200 milliseconds) - assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) - val probe1Msg2 = probe1.receiveOne(200 milliseconds) - assert(probe1Msg2.isInstanceOf[Mountable.MountMessages]) - val probe1Msg2Contents = probe1Msg2.asInstanceOf[Mountable.MountMessages] - assert(probe1Msg2Contents.response.isInstanceOf[Mountable.CanMount]) - val probe1Msg3 = probe1.receiveOne(3 seconds) - assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle]) - - val probe3Msg4 = probe3.receiveOne(1 seconds) - assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails]) - - val probe1Msg4 = probe1.receiveOne(1 seconds) - assert(probe1Msg4.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideStart]) - val probe1Msg5 = probe1.receiveOne(4 seconds) - assert(probe1Msg5.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) - - val probe1Msg6 = probe1.receiveOne(11 seconds) - assert(probe1Msg6.isInstanceOf[VehicleSpawnPad.PeriodicReminder]) - assert(probe1Msg6.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked) - val probe2Msg2 = probe2.receiveOne(100 milliseconds) - assert(probe2Msg2.isInstanceOf[VehicleSpawnPad.PeriodicReminder]) - assert(probe2Msg2.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked) - - //if we move the vehicle more than 25m away from the pad, we should receive a ResetSpawnPad, and a second ConcealPlayer message - //that means that the first order has cleared and the spawn pad is now working on the second order successfully - player.VehicleSeated = None //since shared between orders, is necessary + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) + vehicle.Seats(0).Occupant = player + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.PlayerSeatedInVehicle]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideStart]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) + //if we move the vehicle away from the pad, we should receive a ResetSpawnPad message + //that means that the first order has cleared and the spawn pad is now waiting for additional orders vehicle.Position = Vector3(12,0,0) - val probe3Msg5 = probe3.receiveOne(4 seconds) - assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad]) - val probe3Msg6 = probe3.receiveOne(4 seconds) - assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.ConcealPlayer]) - } - } -} - -class VehicleSpawnControl2bTest extends ActorTest { - // This runs for a long time. - "VehicleSpawnControl" should { - "complete on a vehicle order (railless)" in { - val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) - //we can recycle the vehicle and the player for each order - val probe1 = new TestProbe(system, "first-order") - val probe2 = new TestProbe(system, "second-order") - val probe3 = new TestProbe(system, "zone-events") - zone.VehicleEvents = probe3.ref - pad.Railed = false - - pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref) //first order - pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe2.ref) //second order - - val probe2Msg1 = probe2.receiveOne(100 milliseconds) - assert(probe2Msg1.isInstanceOf[VehicleSpawnPad.PeriodicReminder]) - assert(probe2Msg1.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Queue) - assert(probe2Msg1.asInstanceOf[VehicleSpawnPad.PeriodicReminder].data.contains("2")) - - val probe3Msg1 = probe3.receiveOne(3 seconds) - assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer]) - - val probe3Msg2 = probe3.receiveOne(3 seconds) - assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle]) - - val probe1Msg1 = probe1.receiveOne(200 milliseconds) - assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) - val probe1Msg2 = probe1.receiveOne(200 milliseconds) - assert(probe1Msg2.isInstanceOf[Mountable.MountMessages]) - val probe1Msg2Contents = probe1Msg2.asInstanceOf[Mountable.MountMessages] - assert(probe1Msg2Contents.response.isInstanceOf[Mountable.CanMount]) - val probe1Msg3 = probe1.receiveOne(4 seconds) - assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle]) - - val probe1Msg4 = probe1.receiveOne(1 seconds) - assert(probe1Msg4.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideStart]) - val probe1Msg5 = probe1.receiveOne(4 seconds) - assert(probe1Msg5.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) - - val probe1Msg6 = probe1.receiveOne(11 seconds) - assert(probe1Msg6.isInstanceOf[VehicleSpawnPad.PeriodicReminder]) - assert(probe1Msg6.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked) - val probe2Msg2 = probe2.receiveOne(100 milliseconds) - assert(probe2Msg2.isInstanceOf[VehicleSpawnPad.PeriodicReminder]) - assert(probe2Msg2.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked) - - //if we move the vehicle more than 10m away from the pad, we should receive a second ConcealPlayer message - //that means that the first order has cleared and the spawn pad is now working on the second order successfully - player.VehicleSeated = None //since shared between orders, is necessary - vehicle.Position = Vector3(12,0,0) - val probe3Msg6 = probe3.receiveOne(10 seconds) - assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.ConcealPlayer]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ResetSpawnPad]) } } } class VehicleSpawnControl3Test extends ActorTest { "VehicleSpawnControl" should { - "player is on wrong continent before vehicle can partially load; vehicle is cleaned up" in { - val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) - val probe1 = new TestProbe(system, "first-order") - val probe3 = new TestProbe(system, "zone-events") - zone.VehicleEvents = probe3.ref - player.Continent = "problem" //problem - - assert(vehicle.HasGUID) - pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref) - - val probe3Msg1 = probe3.receiveOne(3 seconds) - assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.RevealPlayer]) - probe3.expectNoMsg(5 seconds) - assert(!vehicle.HasGUID) //vehicle has been unregistered - } - } -} - -class VehicleSpawnControl4Test extends ActorTest() { - "VehicleSpawnControl" should { - "the player is on wrong continent when the vehicle tries to load; vehicle is cleaned up" in { - val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) - val probe1 = new TestProbe(system, "first-order") - val probe3 = new TestProbe(system, "zone-events") - zone.VehicleEvents = probe3.ref - - pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref) - - val probe3Msg1 = probe3.receiveOne(3 seconds) - assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer]) - player.Continent = "problem" //problem - assert(vehicle.HasGUID) - - val probe3Msg2 = probe3.receiveOne(3 seconds) - assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.RevealPlayer]) - probe3.expectNoMsg(5 seconds) - assert(!vehicle.HasGUID) //vehicle has been unregistered - } - } -} - -//class VehicleSpawnControl5aTest extends ActorTest() { -// "VehicleSpawnControl" should { -// "the vehicle is destroyed before being fully loaded; the vehicle is cleaned up" in { -// val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) -// //we can recycle the vehicle and the player for each order -// val probe1 = new TestProbe(system, "first-order") -// val probe3 = new TestProbe(system, "zone-events") -// zone.VehicleEvents = probe3.ref -// -// pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref) -// -// val probe3Msg1 = probe3.receiveOne(3 seconds) -// assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer]) -// -// val probe3Msg2 = probe3.receiveOne(3 seconds) -// assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle]) -// vehicle.Health = 0 //problem -// -// val probe3Msg3 = probe3.receiveOne(3 seconds) -// assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.DisposeVehicle]) -// val probe3Msg4 = probe3.receiveOne(100 milliseconds) -// assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.RevealPlayer]) -// //note: the vehicle will not be unregistered by this logic alone -// //since LoadVehicle should introduce it into the game world properly, it has to be handled properly -// } -// } -//} - -class VehicleSpawnControl5Test extends ActorTest { - "VehicleSpawnControl" should { - "player dies right after vehicle partially loads; the vehicle spawns and blocks the pad" in { + "block the second vehicle order until the first is completed" in { val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) //we can recycle the vehicle and the player for each order - val probe1 = new TestProbe(system, "first-order") - val probe3 = new TestProbe(system, "zone-events") - zone.VehicleEvents = probe3.ref + val probe = new TestProbe(system, "zone-events") + val player2 = Player(Avatar("test2", player.Faction, CharacterGender.Male, 0, CharacterVoice.Mute)) + player2.GUID = PlanetSideGUID(11) + player2.Continent = zone.Id + player2.Spawn - pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref) + zone.VehicleEvents = probe.ref //zone events + pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //first order + pad.Actor ! VehicleSpawnPad.VehicleOrder(player2, vehicle) //second order (vehicle shared) - val probe3Msg1 = probe3.receiveOne(3 seconds) - assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer]) + assert(probe.receiveOne(1 seconds) match { + case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Queue, _) => true + case _ => false + }) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) + vehicle.Seats(0).Occupant = player + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.PlayerSeatedInVehicle]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideStart]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) + assert(probe.receiveOne(1 minute) match { + case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true + case _ => false + }) + assert(probe.receiveOne(1 minute) match { + case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true + case _ => false + }) - val probe3Msg2 = probe3.receiveOne(3 seconds) - assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle]) - player.Die //problem - - val probe3Msg3 = probe3.receiveOne(3 seconds) - assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.AttachToRails]) - val probe3Msg4 = probe3.receiveOne(3 seconds) - assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails]) - - val probe3Msg5 = probe3.receiveOne(1 seconds) - assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.RevealPlayer]) - - val probe1Msg = probe1.receiveOne(12 seconds) - assert(probe1Msg.isInstanceOf[VehicleSpawnPad.PeriodicReminder]) - assert(probe1Msg.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked) + //if we move the vehicle away from the pad, we should receive a second ConcealPlayer message + //that means that the first order has cleared and the spawn pad is now working on the second order successfully + player.VehicleSeated = None //since shared between orders, as necessary + vehicle.Seats(0).Occupant = None + vehicle.Position = Vector3(12,0,0) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ResetSpawnPad]) + probe.expectMsgClass(3 seconds, classOf[VehicleSpawnPad.ConcealPlayer]) } } } -class VehicleSpawnControl6Test extends ActorTest { +class VehicleSpawnControl4Test extends ActorTest { "VehicleSpawnControl" should { - "the player can not sit in vehicle; vehicle spawns and blocks the pad" in { + "clean up the vehicle if the driver-to-be is on the wrong continent" in { val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) - //we can recycle the vehicle and the player for each order - val probe1 = new TestProbe(system, "first-order") - val probe3 = new TestProbe(system, "zone-events") - zone.VehicleEvents = probe3.ref - - pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref) - - val probe3Msg1 = probe3.receiveOne(3 seconds) - assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer]) - - val probe3Msg2 = probe3.receiveOne(3 seconds) - assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle]) - - val probe3Msg3 = probe3.receiveOne(3 seconds) - assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.AttachToRails]) - - val probe1Msg1 = probe1.receiveOne(200 milliseconds) - assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) + val probe = new TestProbe(system, "zone-events") + zone.VehicleEvents = probe.ref player.Continent = "problem" //problem - probe1.receiveOne(200 milliseconds) //Mountable.MountMessage - val probe3Msg4 = probe3.receiveOne(3 seconds) - assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails]) - val probe3Msg5 = probe3.receiveOne(3 seconds) - assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.RevealPlayer]) + pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order - val probe1Msg3 = probe1.receiveOne(12 seconds) - assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PeriodicReminder]) - assert(probe1Msg3.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DisposeVehicle]) + probe.expectNoMsg(5 seconds) + } + } +} + +class VehicleSpawnControl5Test extends ActorTest() { + "VehicleSpawnControl" should { + "abandon a destroyed vehicle on the spawn pad (blocking)" in { + val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) + + val probe = new TestProbe(system, "zone-events") + zone.VehicleEvents = probe.ref + pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order + + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) + vehicle.Health = 0 //problem + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer]) + assert(probe.receiveOne(1 minute) match { + case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_,_,_,_,_)) => true + case _ => false + }) + assert(probe.receiveOne(1 minute) match { + case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true + case _ => false + }) + } + } +} + +class VehicleSpawnControl6Test extends ActorTest() { + "VehicleSpawnControl" should { + "abandon a vehicle on the spawn pad if driver is unfit to drive (blocking)" in { + val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) + + val probe = new TestProbe(system, "zone-events") + zone.VehicleEvents = probe.ref + pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order + + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) + player.Die + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer]) + assert(probe.receiveOne(1 minute) match { + case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_,_,_,_,_)) => true + case _ => false + }) + assert(probe.receiveOne(1 minute) match { + case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true + case _ => false + }) + } + } +} + +class VehicleSpawnControl7Test extends ActorTest { + "VehicleSpawnControl" should { + "abandon a vehicle on the spawn pad if driver is unfit to drive (blocking)" in { + val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR) + val probe = new TestProbe(system, "zone-events") + player.ExoSuit = ExoSuitType.MAX + + zone.VehicleEvents = probe.ref //zone events + pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order + + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) + probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer]) + assert(probe.receiveOne(1 minute) match { + case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_,_,_,_,_)) => true + case _ => false + }) + assert(probe.receiveOne(1 minute) match { + case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true + case _ => false + }) } } } @@ -324,15 +226,19 @@ object VehicleSpawnPadControlTest { import net.psforever.objects.Tool import net.psforever.types.CharacterGender - val zone = new Zone("test-zone", map, 0) { override def SetupNumberPools() = { } } val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy) val weapon = vehicle.WeaponControlledFromSeat(1).get.asInstanceOf[Tool] - val guid : NumberPoolHub = new NumberPoolHub(LimitedNumberSource(5)) - guid.AddPool("test-pool", (0 to 2).toList) - guid.register(vehicle, "test-pool") - guid.register(weapon, "test-pool") - guid.register(weapon.AmmoSlot.Box, "test-pool") - zone.GUID(guid) + val zone = new Zone("test-zone", map, 0) { + override def SetupNumberPools() = { + val guid : NumberPoolHub = new NumberPoolHub(LimitedNumberSource(5)) + guid.AddPool("test-pool", (0 to 2).toList) + //do not do this under normal conditions + guid.register(vehicle, "test-pool") + guid.register(weapon, "test-pool") + guid.register(weapon.AmmoSlot.Box, "test-pool") + GUID(guid) + } + } zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), s"test-zone-${System.nanoTime()}") zone.Actor ! Zone.Init() vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), s"vehicle-control-${System.nanoTime()}") diff --git a/common/src/test/scala/objects/terminal/ProximityTest.scala b/common/src/test/scala/objects/terminal/ProximityTest.scala index cd796176..46b8b2b9 100644 --- a/common/src/test/scala/objects/terminal/ProximityTest.scala +++ b/common/src/test/scala/objects/terminal/ProximityTest.scala @@ -4,7 +4,6 @@ package objects.terminal import akka.actor.Props import akka.testkit.TestProbe import base.ActorTest -import net.psforever.objects.guid.TaskResolver import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.structures.{Building, StructureType} import net.psforever.objects.serverobject.terminals.{ProximityTerminal, ProximityTerminalControl, ProximityUnit, Terminal} @@ -13,8 +12,8 @@ import net.psforever.objects.{Avatar, GlobalDefinitions, Player} import net.psforever.packet.game.PlanetSideGUID import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire} import org.specs2.mutable.Specification -import services.{Service, ServiceManager} -import services.local.{LocalResponse, LocalService, LocalServiceResponse} +import services.Service +import services.local.LocalService import scala.concurrent.duration._ @@ -96,19 +95,14 @@ class ProximityTest extends Specification { class ProximityTerminalControlStartTest extends ActorTest { "ProximityTerminalControl" should { //setup - val probe = new TestProbe(system) - val service = ServiceManager.boot(system) - service ! ServiceManager.Register(Props(classOf[ProximityTest.ProbedLocalService], probe), "local") - service ! ServiceManager.Register(Props[TaskResolver], "taskResolver") - service ! ServiceManager.Register(Props[TaskResolver], "cluster") - val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) - terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox") val zone : Zone = new Zone("test", new ZoneMap("test-map"), 0) { Actor = system.actorOf(Props(classOf[ZoneActor], this), "test-zone") override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } + val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) + terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox") new Building(building_guid = 0, map_id = 0, zone, StructureType.Facility, GlobalDefinitions.building) { Amenities = terminal Faction = PlanetSideEmpire.VS @@ -122,17 +116,18 @@ class ProximityTerminalControlStartTest extends ActorTest { terminal.GUID = PlanetSideGUID(2) terminal.Actor ! Service.Startup() expectNoMsg(500 milliseconds) //spacer + val probe1 = new TestProbe(system, "local-events") + val probe2 = new TestProbe(system, "target-callback") + zone.LocalEvents = probe1.ref "send out a start message" in { assert(terminal.NumberUsers == 0) assert(terminal.Owner.Continent.equals("test")) - terminal.Actor ! CommonMessages.Use(avatar, Some(avatar)) - val msg = probe.receiveOne(500 milliseconds) + terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref) + probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect]) + probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action]) assert(terminal.NumberUsers == 1) - assert(msg.isInstanceOf[LocalServiceResponse]) - val resp = msg.asInstanceOf[LocalServiceResponse] - assert(resp.replyMessage == LocalResponse.ProximityTerminalEffect(PlanetSideGUID(2), true)) } } } @@ -140,50 +135,50 @@ class ProximityTerminalControlStartTest extends ActorTest { class ProximityTerminalControlTwoUsersTest extends ActorTest { "ProximityTerminalControl" should { //setup - val probe = new TestProbe(system) - val service = ServiceManager.boot(system) - service ! ServiceManager.Register(Props(classOf[ProximityTest.ProbedLocalService], probe), "local") - service ! ServiceManager.Register(Props[TaskResolver], "taskResolver") - service ! ServiceManager.Register(Props[TaskResolver], "cluster") - val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) - terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox") val zone : Zone = new Zone("test", new ZoneMap("test-map"), 0) { Actor = system.actorOf(Props(classOf[ZoneActor], this), "test-zone") override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } + val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) + terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox") new Building(building_guid = 0, map_id = 0, zone, StructureType.Facility, GlobalDefinitions.building) { Amenities = terminal Faction = PlanetSideEmpire.VS } + val avatar = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) avatar.Continent = "test" avatar.Spawn avatar.Health = 50 + val avatar2 = Player(Avatar("TestCharacter2", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) + avatar2.Continent = "test" + avatar2.Spawn + avatar2.Health = 50 avatar.GUID = PlanetSideGUID(1) - terminal.GUID = PlanetSideGUID(2) + avatar.GUID = PlanetSideGUID(2) + terminal.GUID = PlanetSideGUID(3) terminal.Actor ! Service.Startup() expectNoMsg(500 milliseconds) //spacer + val probe1 = new TestProbe(system, "local-events") + val probe2 = new TestProbe(system, "target-callback-1") + val probe3 = new TestProbe(system, "target-callback-2") + zone.LocalEvents = probe1.ref - "will not send out a start message if not the first user" in { + "not send out a start message if not the first user" in { assert(terminal.NumberUsers == 0) assert(terminal.Owner.Continent.equals("test")) - terminal.Actor ! CommonMessages.Use(avatar, Some(avatar)) - val msg = probe.receiveOne(500 milliseconds) - assert(terminal.NumberUsers == 1) - assert(msg.isInstanceOf[LocalServiceResponse]) - val resp = msg.asInstanceOf[LocalServiceResponse] - assert(resp.replyMessage == LocalResponse.ProximityTerminalEffect(PlanetSideGUID(2), true)) + terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref) + probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect]) + probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action]) - val avatar2 = Player(Avatar("TestCharacter2", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) - avatar2.Continent = "test" - avatar2.Spawn - avatar2.Health = 50 - terminal.Actor ! CommonMessages.Use(avatar2, Some(avatar2)) - probe.expectNoMsg(500 milliseconds) + terminal.Actor.tell(CommonMessages.Use(avatar2, Some(avatar2)), probe3.ref) + probe1.expectNoMsg(1 second) + probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action]) + probe3.expectMsgClass(1 second, classOf[ProximityUnit.Action]) assert(terminal.NumberUsers == 2) } } @@ -192,19 +187,14 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest { class ProximityTerminalControlStopTest extends ActorTest { "ProximityTerminalControl" should { //setup - val probe = new TestProbe(system) - val service = ServiceManager.boot(system) - service ! ServiceManager.Register(Props(classOf[ProximityTest.ProbedLocalService], probe), "local") - service ! ServiceManager.Register(Props[TaskResolver], "taskResolver") - service ! ServiceManager.Register(Props[TaskResolver], "cluster") - val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) - terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox") val zone : Zone = new Zone("test", new ZoneMap("test-map"), 0) { Actor = system.actorOf(Props(classOf[ZoneActor], this), "test-zone") override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } + val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) + terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox") new Building(building_guid = 0, map_id = 0, zone, StructureType.Facility, GlobalDefinitions.building) { Amenities = terminal Faction = PlanetSideEmpire.VS @@ -218,24 +208,21 @@ class ProximityTerminalControlStopTest extends ActorTest { terminal.GUID = PlanetSideGUID(2) terminal.Actor ! Service.Startup() expectNoMsg(500 milliseconds) //spacer + val probe1 = new TestProbe(system, "local-events") + val probe2 = new TestProbe(system, "target-callback-1") + zone.LocalEvents = probe1.ref "send out a stop message" in { assert(terminal.NumberUsers == 0) assert(terminal.Owner.Continent.equals("test")) - terminal.Actor ! CommonMessages.Use(avatar, Some(avatar)) - val msg1 = probe.receiveOne(500 milliseconds) - assert(terminal.NumberUsers == 1) - assert(msg1.isInstanceOf[LocalServiceResponse]) - val resp1 = msg1.asInstanceOf[LocalServiceResponse] - assert(resp1.replyMessage == LocalResponse.ProximityTerminalEffect(PlanetSideGUID(2), true)) + terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref) + probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect]) + probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action]) terminal.Actor ! CommonMessages.Unuse(avatar, Some(avatar)) - val msg2 = probe.receiveWhile(500 milliseconds) { - case LocalServiceResponse(_, _, replyMessage) => replyMessage - } + probe1.expectMsgClass(1 second, classOf[Terminal.StopProximityEffect]) assert(terminal.NumberUsers == 0) - assert(msg2.last == LocalResponse.ProximityTerminalEffect(PlanetSideGUID(2), false)) } } } @@ -243,58 +230,59 @@ class ProximityTerminalControlStopTest extends ActorTest { class ProximityTerminalControlNotStopTest extends ActorTest { "ProximityTerminalControl" should { //setup - val probe = new TestProbe(system) - val service = ServiceManager.boot(system) - service ! ServiceManager.Register(Props(classOf[ProximityTest.ProbedLocalService], probe), "local") - service ! ServiceManager.Register(Props[TaskResolver], "taskResolver") - service ! ServiceManager.Register(Props[TaskResolver], "cluster") - val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) - terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox") val zone : Zone = new Zone("test", new ZoneMap("test-map"), 0) { Actor = system.actorOf(Props(classOf[ZoneActor], this), "test-zone") override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } + val probe = new TestProbe(system) + zone.LocalEvents = probe.ref + val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) + terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox") new Building(building_guid = 0, map_id = 0, zone, StructureType.Facility, GlobalDefinitions.building) { Amenities = terminal Faction = PlanetSideEmpire.VS } + val avatar = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) avatar.Continent = "test" avatar.Spawn avatar.Health = 50 + val avatar2 = Player(Avatar("TestCharacter2", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) + avatar2.Continent = "test" + avatar2.Spawn + avatar2.Health = 50 avatar.GUID = PlanetSideGUID(1) - terminal.GUID = PlanetSideGUID(2) + avatar.GUID = PlanetSideGUID(2) + terminal.GUID = PlanetSideGUID(3) terminal.Actor ! Service.Startup() expectNoMsg(500 milliseconds) //spacer + val probe1 = new TestProbe(system, "local-events") + val probe2 = new TestProbe(system, "target-callback-1") + val probe3 = new TestProbe(system, "target-callback-2") + zone.LocalEvents = probe1.ref "will not send out one stop message until last user" in { assert(terminal.NumberUsers == 0) assert(terminal.Owner.Continent.equals("test")) - terminal.Actor ! CommonMessages.Use(avatar, Some(avatar)) - val msg = probe.receiveOne(500 milliseconds) + terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref) + probe1.expectMsgClass(100 millisecond, classOf[Terminal.StartProximityEffect]) assert(terminal.NumberUsers == 1) - assert(msg.isInstanceOf[LocalServiceResponse]) - val resp = msg.asInstanceOf[LocalServiceResponse] - assert(resp.replyMessage == LocalResponse.ProximityTerminalEffect(PlanetSideGUID(2), true)) - val avatar2 = Player(Avatar("TestCharacter2", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) - avatar2.Continent = "test" - avatar2.Spawn - avatar2.Health = 50 - terminal.Actor ! CommonMessages.Use(avatar2, Some(avatar2)) - probe.expectNoMsg(500 milliseconds) + terminal.Actor.tell(CommonMessages.Use(avatar2, Some(avatar2)), probe3.ref) + probe1.expectNoMsg(100 millisecond) assert(terminal.NumberUsers == 2) terminal.Actor ! CommonMessages.Unuse(avatar, Some(avatar)) - val msg2 = probe.receiveWhile(500 milliseconds) { - case LocalServiceResponse(_, _, replyMessage) => replyMessage - } + probe1.expectNoMsg(100 millisecond) assert(terminal.NumberUsers == 1) - assert(!msg2.contains(LocalResponse.ProximityTerminalEffect(PlanetSideGUID(2), false))) + + terminal.Actor ! CommonMessages.Unuse(avatar2, Some(avatar2)) + probe1.expectMsgClass(100 millisecond, classOf[Terminal.StopProximityEffect]) + assert(terminal.NumberUsers == 0) } } } @@ -302,7 +290,7 @@ class ProximityTerminalControlNotStopTest extends ActorTest { object ProximityTest { class SampleTerminal extends Terminal(GlobalDefinitions.dropship_vehicle_terminal) with ProximityUnit - class ProbedLocalService(probe : TestProbe) extends LocalService { + class ProbedLocalService(probe : TestProbe, zone : Zone) extends LocalService(zone) { self.tell(Service.Join("test"), probe.ref) } } diff --git a/common/src/test/scala/service/AvatarServiceTest.scala b/common/src/test/scala/service/AvatarServiceTest.scala index d7bf7da4..989e92dd 100644 --- a/common/src/test/scala/service/AvatarServiceTest.scala +++ b/common/src/test/scala/service/AvatarServiceTest.scala @@ -19,7 +19,7 @@ class AvatarService1Test extends ActorTest { "AvatarService" should { "construct" in { ServiceManager.boot(system) - system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) assert(true) } } @@ -29,7 +29,7 @@ class AvatarService2Test extends ActorTest { "AvatarService" should { "subscribe" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") assert(true) } @@ -40,7 +40,7 @@ class AvatarService3Test extends ActorTest { "AvatarService" should { ServiceManager.boot(system) "subscribe to a specific channel" in { - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! Service.Leave() assert(true) @@ -52,7 +52,7 @@ class AvatarService4Test extends ActorTest { "AvatarService" should { "subscribe" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! Service.LeaveAll() assert(true) @@ -64,7 +64,7 @@ class AvatarService5Test extends ActorTest { "AvatarService" should { "pass an unhandled message" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! "hello" expectNoMsg() @@ -76,7 +76,7 @@ class ArmorChangedTest extends ActorTest { "AvatarService" should { "pass ArmorChanged" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.ArmorChanged(PlanetSideGUID(10), ExoSuitType.Reinforced, 0)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ArmorChanged(ExoSuitType.Reinforced, 0))) @@ -88,7 +88,7 @@ class ConcealPlayerTest extends ActorTest { "AvatarService" should { "pass ConcealPlayer" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.ConcealPlayer(PlanetSideGUID(10))) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ConcealPlayer())) @@ -97,11 +97,8 @@ class ConcealPlayerTest extends ActorTest { } class EquipmentInHandTest extends ActorTest { - ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val service = system.actorOf(Props[AvatarService], "release-test-service") - val zone = new Zone("test", new ZoneMap("test-map"), 0) - val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver") - + ServiceManager.boot(system) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service") val toolDef = GlobalDefinitions.beamer val tool = Tool(toolDef) tool.GUID = PlanetSideGUID(40) @@ -123,8 +120,8 @@ class EquipmentInHandTest extends ActorTest { } class DeployItemTest extends ActorTest { - ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val service = system.actorOf(Props[AvatarService], "deploy-item-test-service") + ServiceManager.boot(system) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "deploy-item-test-service") val objDef = GlobalDefinitions.motionalarmsensor val obj = new SensorDeployable(objDef) obj.Position = Vector3(1,2,3) @@ -146,13 +143,8 @@ class DeployItemTest extends ActorTest { } class DroptItemTest extends ActorTest { - ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val service = system.actorOf(Props[AvatarService], "release-test-service") - val zone = new Zone("test", new ZoneMap("test-map"), 0) - val taskResolver = system.actorOf(Props[TaskResolver], "drop-item-test-resolver") - zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "drop-item-test-zone") - zone.Actor ! Zone.Init() - + ServiceManager.boot(system) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service") val toolDef = GlobalDefinitions.beamer val tool = Tool(toolDef) tool.Position = Vector3(1,2,3) @@ -171,7 +163,7 @@ class DroptItemTest extends ActorTest { "AvatarService" should { "pass DropItem" in { service ! Service.Join("test") - service ! AvatarServiceMessage("test", AvatarAction.DropItem(PlanetSideGUID(10), tool, zone)) + service ! AvatarServiceMessage("test", AvatarAction.DropItem(PlanetSideGUID(10), tool, Zone.Nowhere)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.DropItem(pkt))) } } @@ -191,7 +183,7 @@ class LoadPlayerTest extends ActorTest { "AvatarService" should { "pass LoadPlayer" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") //no parent data service ! AvatarServiceMessage("test", AvatarAction.LoadPlayer( @@ -211,7 +203,7 @@ class ObjectDeleteTest extends ActorTest { "AvatarService" should { "pass ObjectDelete" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11))) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 0))) @@ -226,7 +218,7 @@ class ObjectHeldTest extends ActorTest { "AvatarService" should { "pass ObjectHeld" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.ObjectHeld(PlanetSideGUID(10), 1)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectHeld(1))) @@ -238,7 +230,7 @@ class PutDownFDUTest extends ActorTest { "AvatarService" should { "pass PutDownFDU" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.PutDownFDU(PlanetSideGUID(10))) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PutDownFDU(PlanetSideGUID(10)))) @@ -250,7 +242,7 @@ class PlanetsideAttributeTest extends ActorTest { "AvatarService" should { "pass PlanetsideAttribute" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.PlanetsideAttribute(PlanetSideGUID(10), 5, 1200L)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlanetsideAttribute(5, 1200L))) @@ -264,7 +256,7 @@ class PlayerStateTest extends ActorTest { "AvatarService" should { "pass PlayerState" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.PlayerState(PlanetSideGUID(10), Vector3(3694.1094f, 2735.4531f, 90.84375f), Some(Vector3(4.375f, 2.59375f, 0.0f)), 61.875f, 351.5625f, 0.0f, 136, false, false, false, false, false, false)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlayerState(Vector3(3694.1094f, 2735.4531f, 90.84375f), Some(Vector3(4.375f, 2.59375f, 0.0f)), 61.875f, 351.5625f, 0.0f, 136, false, false, false, false, false, false))) @@ -290,7 +282,7 @@ class PickupItemATest extends ActorTest { "pass PickUpItem as EquipmentInHand (visible pistol slot)" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.PickupItem(PlanetSideGUID(10), Zone.Nowhere, obj, 0, tool)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentInHand(pkt))) @@ -304,7 +296,7 @@ class PickupItemBTest extends ActorTest { "pass PickUpItem as ObjectDelete (not visible inventory space)" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.PickupItem(PlanetSideGUID(10), Zone.Nowhere, obj, 6, tool)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(tool.GUID, 0))) @@ -315,7 +307,7 @@ class ReloadTest extends ActorTest { "AvatarService" should { "pass Reload" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.Reload(PlanetSideGUID(10), PlanetSideGUID(40))) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.Reload(PlanetSideGUID(40)))) @@ -330,7 +322,7 @@ class ChangeAmmoTest extends ActorTest { "AvatarService" should { "pass ChangeAmmo" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.ChangeAmmo(PlanetSideGUID(10), PlanetSideGUID(40), 0, PlanetSideGUID(40), ammoDef.ObjectId, PlanetSideGUID(41), ammoDef.Packet.ConstructorData(ammoBox).get)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeAmmo(PlanetSideGUID(40), 0, PlanetSideGUID(40), ammoDef.ObjectId, PlanetSideGUID(41), ammoDef.Packet.ConstructorData(ammoBox).get))) @@ -345,7 +337,7 @@ class ChangeFireModeTest extends ActorTest { "AvatarService" should { "pass ChangeFireMode" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.ChangeFireMode(PlanetSideGUID(10), PlanetSideGUID(40), 0)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireMode(PlanetSideGUID(40), 0))) @@ -357,7 +349,7 @@ class ChangeFireStateStartTest extends ActorTest { "AvatarService" should { "pass ChangeFireState_Start" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Start(PlanetSideGUID(10), PlanetSideGUID(40))) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireState_Start(PlanetSideGUID(40)))) @@ -369,7 +361,7 @@ class ChangeFireStateStopTest extends ActorTest { "AvatarService" should { "pass ChangeFireState_Stop" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Stop(PlanetSideGUID(10), PlanetSideGUID(40))) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireState_Stop(PlanetSideGUID(40)))) @@ -387,7 +379,7 @@ class DamageTest extends ActorTest { "AvatarService" should { "pass Damage" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.Damage(PlanetSideGUID(10), player, test_func_ref)) val msg = receiveOne(1 seconds) @@ -408,7 +400,7 @@ class WeaponDryFireTest extends ActorTest { "AvatarService" should { "pass WeaponDryFire" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.WeaponDryFire(PlanetSideGUID(10), PlanetSideGUID(40))) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.WeaponDryFire(PlanetSideGUID(40)))) @@ -422,7 +414,7 @@ class AvatarStowEquipmentTest extends ActorTest { "AvatarService" should { "pass StowEquipment" in { ServiceManager.boot(system) - val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName) + val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName) service ! Service.Join("test") service ! AvatarServiceMessage("test", AvatarAction.StowEquipment(PlanetSideGUID(10), PlanetSideGUID(11), 2, tool)) expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.StowEquipment(PlanetSideGUID(11), 2, tool))) @@ -448,8 +440,8 @@ Even with all this work, the tests have a high chance of failure just due to bei */ class AvatarReleaseTest extends ActorTest { ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val service = system.actorOf(Props[AvatarService], "release-test-service") val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } + val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver") zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone") zone.Actor ! Zone.Init() @@ -497,8 +489,8 @@ class AvatarReleaseTest extends ActorTest { class AvatarReleaseEarly1Test extends ActorTest { ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val service = system.actorOf(Props[AvatarService], "release-test-service") val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } + val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver") zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone") zone.Actor ! Zone.Init() @@ -547,8 +539,8 @@ class AvatarReleaseEarly1Test extends ActorTest { class AvatarReleaseEarly2Test extends ActorTest { ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver") - val service = system.actorOf(Props[AvatarService], "release-test-service") val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } } + val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver") zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone") zone.Actor ! Zone.Init() diff --git a/common/src/test/scala/service/LocalServiceTest.scala b/common/src/test/scala/service/LocalServiceTest.scala index 3c597595..cf13a310 100644 --- a/common/src/test/scala/service/LocalServiceTest.scala +++ b/common/src/test/scala/service/LocalServiceTest.scala @@ -6,6 +6,7 @@ import base.ActorTest import net.psforever.objects.{GlobalDefinitions, SensorDeployable, Vehicle} import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.terminals.{ProximityTerminal, Terminal} +import net.psforever.objects.zones.Zone import net.psforever.packet.game._ import net.psforever.types.{PlanetSideEmpire, Vector3} import services.{Service, ServiceManager} @@ -16,7 +17,7 @@ class LocalService1Test extends ActorTest { "LocalService" should { "construct" in { - system.actorOf(Props[LocalService], "l_service") + system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") assert(true) } } @@ -27,7 +28,7 @@ class LocalService2Test extends ActorTest { "LocalService" should { "subscribe" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") assert(true) } @@ -39,7 +40,7 @@ class LocalService3Test extends ActorTest { "LocalService" should { "subscribe to a specific channel" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! Service.Leave() assert(true) @@ -52,7 +53,7 @@ class LocalService4Test extends ActorTest { "LocalService" should { "subscribe" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! Service.LeaveAll() assert(true) @@ -65,7 +66,7 @@ class LocalService5Test extends ActorTest { "LocalService" should { "pass an unhandled message" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! "hello" expectNoMsg() @@ -79,7 +80,7 @@ class AlertDestroyDeployableTest extends ActorTest { "LocalService" should { "pass AlertDestroyDeployable" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.AlertDestroyDeployable(PlanetSideGUID(10), obj)) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(0), LocalResponse.AlertDestroyDeployable(obj))) @@ -92,7 +93,7 @@ class DeployableMapIconTest extends ActorTest { "LocalService" should { "pass DeployableMapIcon" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.DeployableMapIcon( @@ -116,7 +117,7 @@ class DoorClosesTest extends ActorTest { "LocalService" should { "pass DoorCloses" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.DoorCloses(PlanetSideGUID(10), PlanetSideGUID(40))) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.DoorCloses(PlanetSideGUID(40)))) @@ -134,7 +135,7 @@ class HackClearTest extends ActorTest { "LocalService" should { "pass HackClear" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.HackClear(PlanetSideGUID(10), obj, 0L, 1000L)) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.HackClear(PlanetSideGUID(40), 0L, 1000L))) @@ -144,7 +145,7 @@ class HackClearTest extends ActorTest { class ProximityTerminalEffectOnTest extends ActorTest { ServiceManager.boot(system) - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) terminal.GUID = PlanetSideGUID(1) @@ -159,7 +160,7 @@ class ProximityTerminalEffectOnTest extends ActorTest { class ProximityTerminalEffectOffTest extends ActorTest { ServiceManager.boot(system) - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal) terminal.GUID = PlanetSideGUID(1) @@ -177,7 +178,7 @@ class RouterTelepadTransportTest extends ActorTest { "LocalService" should { "pass RouterTelepadTransport" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.RouterTelepadTransport(PlanetSideGUID(10), PlanetSideGUID(11), PlanetSideGUID(12), PlanetSideGUID(13))) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.RouterTelepadTransport(PlanetSideGUID(11), PlanetSideGUID(12), PlanetSideGUID(13)))) @@ -191,7 +192,7 @@ class SetEmpireTest extends ActorTest { "LocalService" should { "pass SetEmpire" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.SetEmpire(PlanetSideGUID(10), PlanetSideEmpire.TR)) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(0), LocalResponse.SetEmpire(PlanetSideGUID(10), PlanetSideEmpire.TR))) @@ -205,7 +206,7 @@ class ToggleTeleportSystemTest extends ActorTest { "LocalService" should { "pass ToggleTeleportSystem" in { val router = Vehicle(GlobalDefinitions.router) - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.ToggleTeleportSystem(PlanetSideGUID(10), router, None)) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.ToggleTeleportSystem(router, None))) @@ -218,7 +219,7 @@ class TriggerEffectTest extends ActorTest { "LocalService" should { "pass TriggerEffect (1)" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.TriggerEffect(PlanetSideGUID(10), "on", PlanetSideGUID(40))) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.TriggerEffect(PlanetSideGUID(40), "on", None, None))) @@ -231,7 +232,7 @@ class TriggerEffectInfoTest extends ActorTest { "LocalService" should { "pass TriggerEffect (2)" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.TriggerEffectInfo(PlanetSideGUID(10), "on", PlanetSideGUID(40), true, 1000)) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.TriggerEffect(PlanetSideGUID(40), "on", Some(TriggeredEffect(true, 1000)), None))) @@ -244,7 +245,7 @@ class TriggerEffectLocationTest extends ActorTest { "LocalService" should { "pass TriggerEffect (3)" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.TriggerEffectLocation(PlanetSideGUID(10), "spawn_object_failed_effect", Vector3(1.1f, 2.2f, 3.3f), Vector3(4.4f, 5.5f, 6.6f))) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.TriggerEffect(PlanetSideGUID(0), "spawn_object_failed_effect", None, Some(TriggeredEffectLocation(Vector3(1.1f, 2.2f, 3.3f), Vector3(4.4f, 5.5f, 6.6f)))))) @@ -258,7 +259,7 @@ class TriggerSoundTest extends ActorTest { "LocalService" should { "pass TriggerSound" in { - val service = system.actorOf(Props[LocalService], "l_service") + val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") service ! Service.Join("test") service ! LocalServiceMessage("test", LocalAction.TriggerSound(PlanetSideGUID(10), TriggeredSound.LockedOut, Vector3(1.1f, 2.2f, 3.3f), 0, 0.75f)) expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.TriggerSound(TriggeredSound.LockedOut, Vector3(1.1f, 2.2f, 3.3f), 0, 0.75f))) diff --git a/common/src/test/scala/service/VehicleServiceTest.scala b/common/src/test/scala/service/VehicleServiceTest.scala index 5242c49c..1508d40e 100644 --- a/common/src/test/scala/service/VehicleServiceTest.scala +++ b/common/src/test/scala/service/VehicleServiceTest.scala @@ -4,6 +4,7 @@ package service import akka.actor.Props import base.ActorTest import net.psforever.objects._ +import net.psforever.objects.zones.Zone import net.psforever.packet.game.PlanetSideGUID import net.psforever.types._ import services.{Service, ServiceManager} @@ -14,7 +15,7 @@ class VehicleService1Test extends ActorTest { "VehicleService" should { "construct" in { - system.actorOf(Props[VehicleService], "v-service") + system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") assert(true) } } @@ -25,7 +26,7 @@ class VehicleService2Test extends ActorTest { "VehicleService" should { "subscribe" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") assert(true) } @@ -37,7 +38,7 @@ class VehicleService3Test extends ActorTest { "VehicleService" should { "subscribe to a specific channel" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! Service.Leave() assert(true) @@ -50,7 +51,7 @@ class VehicleService4Test extends ActorTest { "VehicleService" should { "subscribe" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! Service.LeaveAll() assert(true) @@ -63,7 +64,7 @@ class VehicleService5Test extends ActorTest { "VehicleService" should { "pass an unhandled message" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! "hello" expectNoMsg() @@ -76,7 +77,7 @@ class OwnershipTest extends ActorTest { "VehicleService" should { "pass Awareness" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.Ownership(PlanetSideGUID(10), PlanetSideGUID(11))) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.Ownership(PlanetSideGUID(11)))) @@ -89,7 +90,7 @@ class ChildObjectStateTest extends ActorTest { "VehicleService" should { "pass ChildObjectState" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.ChildObjectState(PlanetSideGUID(10), PlanetSideGUID(11), 1.2f, 3.4f)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.ChildObjectState(PlanetSideGUID(11), 1.2f, 3.4f))) @@ -102,7 +103,7 @@ class DeployRequestTest extends ActorTest { "VehicleService" should { "pass DeployRequest" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.DeployRequest(PlanetSideGUID(10), PlanetSideGUID(11), DriveState.Mobile, 0, false, Vector3(1.2f, 3.4f, 5.6f))) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.DeployRequest(PlanetSideGUID(11), DriveState.Mobile, 0, false, Vector3(1.2f, 3.4f, 5.6f)))) @@ -115,7 +116,7 @@ class DismountVehicleTest extends ActorTest { "VehicleService" should { "pass DismountVehicle" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.DismountVehicle(PlanetSideGUID(10), BailType.Normal, false)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.DismountVehicle(BailType.Normal, false))) @@ -131,7 +132,7 @@ class InventoryStateTest extends ActorTest { "VehicleService" should { "pass InventoryState" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.InventoryState(PlanetSideGUID(10), tool, PlanetSideGUID(11), 0, cdata)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.InventoryState(tool, PlanetSideGUID(11), 0, cdata))) @@ -147,7 +148,7 @@ class InventoryState2Test extends ActorTest { "VehicleService" should { "pass InventoryState2" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.InventoryState2(PlanetSideGUID(10), PlanetSideGUID(11), PlanetSideGUID(12), 13)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.InventoryState2(PlanetSideGUID(11), PlanetSideGUID(12), 13))) @@ -160,7 +161,7 @@ class KickPassengerTest extends ActorTest { "VehicleService" should { "pass KickPassenger" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.KickPassenger(PlanetSideGUID(10), 0, false, PlanetSideGUID(11))) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.KickPassenger(0, false, PlanetSideGUID(11)))) @@ -175,7 +176,7 @@ class LoadVehicleTest extends ActorTest { "VehicleService" should { "pass LoadVehicle" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.LoadVehicle(PlanetSideGUID(10), vehicle, 12, PlanetSideGUID(11), cdata)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.LoadVehicle(vehicle, 12, PlanetSideGUID(11), cdata))) @@ -188,7 +189,7 @@ class MountVehicleTest extends ActorTest { "VehicleService" should { "pass MountVehicle" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.MountVehicle(PlanetSideGUID(10), PlanetSideGUID(11), 0)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.MountVehicle(PlanetSideGUID(11), 0))) @@ -201,7 +202,7 @@ class SeatPermissionsTest extends ActorTest { "VehicleService" should { "pass SeatPermissions" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.SeatPermissions(PlanetSideGUID(10), PlanetSideGUID(11), 0, 12L)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.SeatPermissions(PlanetSideGUID(11), 0, 12L))) @@ -219,7 +220,7 @@ class StowEquipmentTest extends ActorTest { "StowEquipment" should { "pass StowEquipment" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.StowEquipment(PlanetSideGUID(10), PlanetSideGUID(11), 0, tool)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.StowEquipment(PlanetSideGUID(11), 0, toolDef.ObjectId, tool.GUID, cdata))) @@ -232,7 +233,7 @@ class UnstowEquipmentTest extends ActorTest { "VehicleService" should { "pass UnstowEquipment" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.UnstowEquipment(PlanetSideGUID(10), PlanetSideGUID(11))) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.UnstowEquipment(PlanetSideGUID(11)))) @@ -245,7 +246,7 @@ class VehicleStateTest extends ActorTest { "VehicleService" should { "pass VehicleState" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.VehicleState(PlanetSideGUID(10), PlanetSideGUID(11), 0, Vector3(1.2f, 3.4f, 5.6f), Vector3(7.8f, 9.1f, 2.3f), Some(Vector3(4.5f, 6.7f, 8.9f)), Option(1), 2, 3, 4, false, true)) expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.VehicleState(PlanetSideGUID(11), 0, Vector3(1.2f, 3.4f, 5.6f), Vector3(7.8f, 9.1f, 2.3f), Some(Vector3(4.5f, 6.7f, 8.9f)), Option(1), 2, 3, 4, false, true))) @@ -258,7 +259,7 @@ class TransferPassengerChannelTest extends ActorTest { "VehicleService" should { "pass TransferPassengerChannel" in { - val service = system.actorOf(Props[VehicleService], "v-service") + val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service") val fury = Vehicle(GlobalDefinitions.fury) service ! Service.Join("test") service ! VehicleServiceMessage("test", VehicleAction.TransferPassengerChannel(PlanetSideGUID(10), "old_channel", "new_channel", fury)) @@ -267,18 +268,18 @@ class TransferPassengerChannelTest extends ActorTest { } } -class TransferPassengerTest extends ActorTest { - ServiceManager.boot(system) - "VehicleService" should { - "pass TransferPassenger" in { - val fury = Vehicle(GlobalDefinitions.fury) - val service = system.actorOf(Props[VehicleService], "v-service") - service ! Service.Join("test") - service ! VehicleServiceMessage("test", VehicleAction.TransferPassenger(PlanetSideGUID(10), "temp_channel", fury, PlanetSideGUID(11))) - expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.TransferPassenger("temp_channel", fury, PlanetSideGUID(11)))) - } - } -} +//class TransferPassengerTest extends ActorTest { +// ServiceManager.boot(system) +// "VehicleService" should { +// "pass TransferPassenger" in { +// val fury = Vehicle(GlobalDefinitions.fury) +// val service = system.actorOf(Props[VehicleService], "v-service") +// service ! Service.Join("test") +// service ! VehicleServiceMessage("test", VehicleAction.TransferPassenger(PlanetSideGUID(10), "temp_channel", fury, PlanetSideGUID(11))) +// expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.TransferPassenger("temp_channel", fury, PlanetSideGUID(11)))) +// } +// } +//} object VehicleServiceTest { //decoy diff --git a/pslogin/src/main/scala/PsLogin.scala b/pslogin/src/main/scala/PsLogin.scala index 7a62a3c2..f7bb24e1 100644 --- a/pslogin/src/main/scala/PsLogin.scala +++ b/pslogin/src/main/scala/PsLogin.scala @@ -19,12 +19,9 @@ import org.slf4j import org.fusesource.jansi.Ansi._ import org.fusesource.jansi.Ansi.Color._ import services.ServiceManager -import services.avatar._ import services.chat.ChatService import services.galaxy.GalaxyService -import services.local._ import services.teamwork.SquadService -import services.vehicle.VehicleService import scala.collection.JavaConverters._ import scala.concurrent.Await @@ -69,7 +66,7 @@ object PsLogin { s"""|~~~ System Information ~~~ |SYS: ${System.getProperty("os.name")} (v. ${System.getProperty("os.version")}, ${System.getProperty("os.arch")}) - |CPU: ${processorString} + |CPU: $processorString |MEM: ${maxMemory}MB available to the JVM (tune with -Xmx flag) |JVM: ${System.getProperty("java.vm.name")} (build ${System.getProperty("java.version")}), ${System.getProperty("java.vendor")} - ${System.getProperty("java.vendor.url")} """.stripMargin @@ -177,7 +174,7 @@ object PsLogin { loadConfig(configDirectory) - println(s"Initializing logging from ${loggingConfigFile}...") + println(s"Initializing logging from $loggingConfigFile...") initializeLogging(loggingConfigFile) /** Initialize the PSCrypto native library @@ -259,30 +256,11 @@ object PsLogin { val continentList = createContinents() val serviceManager = ServiceManager.boot serviceManager ! ServiceManager.Register(RandomPool(50).props(Props[TaskResolver]), "taskResolver") - serviceManager ! ServiceManager.Register(Props[AvatarService], "avatar") - serviceManager ! ServiceManager.Register(Props[LocalService], "local") serviceManager ! ServiceManager.Register(Props[ChatService], "chat") - serviceManager ! ServiceManager.Register(Props[VehicleService], "vehicle") serviceManager ! ServiceManager.Register(Props[GalaxyService], "galaxy") serviceManager ! ServiceManager.Register(Props[SquadService], "squad") serviceManager ! ServiceManager.Register(Props(classOf[InterstellarCluster], continentList), "cluster") - //attach event bus entry point to each zone - import akka.pattern.ask - import akka.util.Timeout - import scala.concurrent.ExecutionContext.Implicits.global - import scala.concurrent.Future - import scala.util.{Failure, Success} - implicit val timeout = Timeout(5 seconds) - val requestVehicleEventBus : Future[ServiceManager.LookupResult] = - (ServiceManager.serviceManager ask ServiceManager.Lookup("vehicle")).mapTo[ServiceManager.LookupResult] - requestVehicleEventBus.onComplete { - case Success(ServiceManager.LookupResult(_, bus)) => - continentList.foreach { _.VehicleEvents = bus } - case Failure(_) => ; - //TODO how to fail - } - /** Create two actors for handling the login and world server endpoints */ loginRouter = Props(new SessionRouter("Login", loginTemplate)) worldRouter = Props(new SessionRouter("World", worldTemplate)) @@ -301,6 +279,7 @@ object PsLogin { def createContinents() : List[Zone] = { import Zones._ List( + Zone.Nowhere, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, home1, tzshtr, tzdrtr, tzcotr, home2, tzshnc, tzdrnc, tzconc, diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index df3b5fdd..76a9ba89 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -33,7 +33,6 @@ import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech import net.psforever.objects.serverobject.locks.IFFLock import net.psforever.objects.serverobject.mblocker.Locker import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} -import net.psforever.objects.serverobject.pad.process.{AutoDriveControls, VehicleSpawnControlGuided} import net.psforever.objects.serverobject.resourcesilo.ResourceSilo import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate} import net.psforever.objects.serverobject.terminals._ @@ -49,7 +48,7 @@ import net.psforever.packet.game.{HotSpotInfo => PacketHotSpotInfo} import net.psforever.types._ import services.{RemoverActor, vehicle, _} import services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse} -import services.galaxy.{GalaxyResponse, GalaxyServiceResponse} +import services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage, GalaxyServiceResponse} import services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse} import services.chat._ import services.vehicle.support.TurretUpgrader @@ -80,10 +79,7 @@ class WorldSessionActor extends Actor with MDCContextAware { var sessionId : Long = 0 var leftRef : ActorRef = ActorRef.noSender var rightRef : ActorRef = ActorRef.noSender - var avatarService : ActorRef = ActorRef.noSender - var localService : ActorRef = ActorRef.noSender var chatService: ActorRef = ActorRef.noSender - var vehicleService : ActorRef = ActorRef.noSender var galaxyService : ActorRef = ActorRef.noSender var squadService : ActorRef = ActorRef.noSender var taskResolver : ActorRef = Actor.noSender @@ -184,10 +180,10 @@ class WorldSessionActor extends Actor with MDCContextAware { reviveTimer.cancel respawnTimer.cancel PlayerActionsToCancel() - localService ! Service.Leave() chatService ! Service.Leave() - vehicleService ! Service.Leave() - avatarService ! Service.Leave() + continent.AvatarEvents ! Service.Leave() + continent.LocalEvents ! Service.Leave() + continent.VehicleEvents ! Service.Leave() galaxyService ! Service.Leave() LivePlayerList.Remove(sessionId) if(player != null && player.HasGUID) { @@ -213,11 +209,11 @@ class WorldSessionActor extends Actor with MDCContextAware { player.VehicleSeated match { case Some(_) => //quickly and briefly kill player to avoid disembark animation? - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0)) DismountVehicleOnLogOut() case _ => ; } - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid)) taskResolver ! GUIDTask.UnregisterAvatar(player)(continent.GUID) //TODO normally, the actual player avatar persists a minute or so after the user disconnects } @@ -230,21 +226,21 @@ class WorldSessionActor extends Actor with MDCContextAware { FriskCorpse(player) //TODO eliminate dead letters if(!WellLootedCorpse(player)) { continent.Population ! Zone.Corpse.Add(player) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.Release(player, continent)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.Release(player, continent)) taskResolver ! GUIDTask.UnregisterLocker(player.Locker)(continent.GUID) //rest of player will be cleaned up with corpses } else { //no items in inventory; leave no corpse val player_guid = player.GUID player.Position = Vector3.Zero //save character before doing this - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid)) taskResolver ! GUIDTask.UnregisterAvatar(player)(continent.GUID) } case Some(_) => val player_guid = player.GUID player.Position = Vector3.Zero //save character before doing this - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid)) taskResolver ! GUIDTask.UnregisterAvatar(player)(continent.GUID) DismountVehicleOnLogOut() } @@ -280,8 +276,8 @@ class WorldSessionActor extends Actor with MDCContextAware { def SpecialCaseDisownVehicle() : Option[Vehicle] = { DisownVehicle() match { case out @ Some(vehicle) => - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(vehicle), continent)) - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(vehicle, continent, + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(vehicle), continent)) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(vehicle, continent, if(vehicle.Flying) { Some(0 seconds) //immediate deconstruction } @@ -309,10 +305,7 @@ class WorldSessionActor extends Actor with MDCContextAware { rightRef = sender() } context.become(Started) - ServiceManager.serviceManager ! Lookup("avatar") - ServiceManager.serviceManager ! Lookup("local") ServiceManager.serviceManager ! Lookup("chat") - ServiceManager.serviceManager ! Lookup("vehicle") ServiceManager.serviceManager ! Lookup("taskResolver") ServiceManager.serviceManager ! Lookup("cluster") ServiceManager.serviceManager ! Lookup("galaxy") @@ -324,18 +317,9 @@ class WorldSessionActor extends Actor with MDCContextAware { } def Started : Receive = { - case ServiceManager.LookupResult("avatar", endpoint) => - avatarService = endpoint - log.info("ID: " + sessionId + " Got avatar service " + endpoint) - case ServiceManager.LookupResult("local", endpoint) => - localService = endpoint - log.info("ID: " + sessionId + " Got local service " + endpoint) case ServiceManager.LookupResult("chat", endpoint) => chatService = endpoint log.info("ID: " + sessionId + " Got chat service " + endpoint) - case ServiceManager.LookupResult("vehicle", endpoint) => - vehicleService = endpoint - log.info("ID: " + sessionId + " Got vehicle service " + endpoint) case ServiceManager.LookupResult("taskResolver", endpoint) => taskResolver = endpoint log.info("ID: " + sessionId + " Got task resolver service " + endpoint) @@ -376,6 +360,24 @@ class WorldSessionActor extends Actor with MDCContextAware { ) case GalaxyResponse.MapUpdate(msg) => sendResponse(msg) + + case GalaxyResponse.TransferPassenger(temp_channel, vehicle, vehicle_to_delete) => + vehicle.PassengerInSeat(player) match { + case Some(_) => + galaxyService ! Service.Leave(Some(temp_channel)) //temporary vehicle-specific channel (see above) + deadState = DeadState.Release + sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, player.Faction, true)) + interstellarFerry = Some(vehicle) //on the other continent and registered to that continent's GUID system + interstellarFerryTopLevelGUID = Some(vehicle_to_delete) //vehicle.GUID, or previously a higher level parent + LoadZonePhysicalSpawnPoint(vehicle.Continent, vehicle.Position, vehicle.Orientation, 1) + case None => + interstellarFerry match { + case None => + continent.VehicleEvents ! Service.Leave(Some(temp_channel)) //no longer being transferred between zones + case Some(_) => ; + //wait patiently + } + } } case LocalServiceResponse(toChannel, guid, reply) => @@ -473,15 +475,15 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(SquadMemberEvent.Add(squad_supplement_id, ourMember.CharId, ourIndex, ourMember.Name, ourMember.ZoneId, unk7 = 0)) //repeat of our entry val playerGuid = player.GUID //turn lfs off - val factionOnContinentChannel = s"${continent.Id}/${player.Faction}" + val factionChannel = s"${player.Faction}" if(avatar.LFS) { avatar.LFS = false sendResponse(PlanetsideAttributeMessage(playerGuid, 53, 0)) - avatarService ! AvatarServiceMessage(factionOnContinentChannel, AvatarAction.PlanetsideAttribute(playerGuid, 53, 0)) + continent.AvatarEvents ! AvatarServiceMessage(factionChannel, AvatarAction.PlanetsideAttribute(playerGuid, 53, 0)) } //squad colors GiveSquadColorsInZone() - avatarService ! AvatarServiceMessage(factionOnContinentChannel, AvatarAction.PlanetsideAttribute(playerGuid, 31, squad_supplement_id)) + continent.AvatarEvents ! AvatarServiceMessage(factionChannel, AvatarAction.PlanetsideAttribute(playerGuid, 31, squad_supplement_id)) //associate with member position in squad sendResponse(PlanetsideAttributeMessage(playerGuid, 32, ourIndex)) //a finalization? what does this do? @@ -523,7 +525,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val playerGuid = player.GUID sendResponse(SquadMemberEvent.Remove(squad_supplement_id, ourMember, ourIndex)) //repeat of our entry sendResponse(PlanetsideAttributeMessage(playerGuid, 31, 0)) //disassociate with squad? - avatarService ! AvatarServiceMessage(s"${continent.Id}/${player.Faction}", AvatarAction.PlanetsideAttribute(playerGuid, 31, 0)) + continent.AvatarEvents ! AvatarServiceMessage(s"${player.Faction}", AvatarAction.PlanetsideAttribute(playerGuid, 31, 0)) sendResponse(PlanetsideAttributeMessage(playerGuid, 32, 0)) //disassociate with member position in squad? sendResponse(PlanetsideAttributeMessage(playerGuid, 34, 4294967295L)) //unknown, perhaps unrelated? lfsm = false @@ -553,13 +555,13 @@ class WorldSessionActor extends Actor with MDCContextAware { case SquadResponse.PromoteMember(squad, char_id, from_index, to_index) => val charId = player.CharId val guid = player.GUID - lazy val factionOnContinentChannel = s"${continent.Id}/${player.Faction}" + lazy val factionChannel = s"${player.Faction}" //are we being demoted? if(squadUI(charId).index == 0) { //lfsm -> lfs if(lfsm) { sendResponse(PlanetsideAttributeMessage(guid, 53, 0)) - avatarService ! AvatarServiceMessage(factionOnContinentChannel, AvatarAction.PlanetsideAttribute(guid, 53, 0)) + continent.AvatarEvents ! AvatarServiceMessage(factionChannel, AvatarAction.PlanetsideAttribute(guid, 53, 0)) } lfsm = false sendResponse(PlanetsideAttributeMessage(guid, 32, from_index)) //associate with member position in squad @@ -568,7 +570,7 @@ class WorldSessionActor extends Actor with MDCContextAware { else if(charId == char_id) { sendResponse(PlanetsideAttributeMessage(guid, 32, 0)) //associate with member position in squad } - avatarService ! AvatarServiceMessage(factionOnContinentChannel, AvatarAction.PlanetsideAttribute(guid, 31, squad_supplement_id)) + continent.AvatarEvents ! AvatarServiceMessage(factionChannel, AvatarAction.PlanetsideAttribute(guid, 31, squad_supplement_id)) //we must fix the squad cards backend SwapSquadUIElements(squad, from_index, to_index) @@ -632,7 +634,7 @@ class WorldSessionActor extends Actor with MDCContextAware { log.info(s"DeployRequest: $obj transitioning to deploy state") obj.Velocity = Some(Vector3.Zero) //no velocity sendResponse(DeployRequestMessage(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) DeploymentActivities(obj) import scala.concurrent.ExecutionContext.Implicits.global context.system.scheduler.scheduleOnce(obj.DeployTime milliseconds, obj.Actor, Deployment.TryDeploy(DriveState.Deployed)) @@ -640,7 +642,7 @@ class WorldSessionActor extends Actor with MDCContextAware { else if(state == DriveState.Deployed) { log.info(s"DeployRequest: $obj has been Deployed") sendResponse(DeployRequestMessage(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) DeploymentActivities(obj) //... } @@ -653,7 +655,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(state == DriveState.Undeploying) { log.info(s"DeployRequest: $obj transitioning to undeploy state") sendResponse(DeployRequestMessage(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) DeploymentActivities(obj) import scala.concurrent.ExecutionContext.Implicits.global context.system.scheduler.scheduleOnce(obj.UndeployTime milliseconds, obj.Actor, Deployment.TryUndeploy(DriveState.Mobile)) @@ -661,7 +663,7 @@ class WorldSessionActor extends Actor with MDCContextAware { else if(state == DriveState.Mobile) { log.info(s"DeployRequest: $obj is Mobile") sendResponse(DeployRequestMessage(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, vehicle_guid, state, 0, false, Vector3.Zero)) DeploymentActivities(obj) //... } @@ -682,68 +684,6 @@ class WorldSessionActor extends Actor with MDCContextAware { antDischargingTick = context.system.scheduler.scheduleOnce(1000 milliseconds, self, NtuDischarging(player, continent.GUID(vehicle_guid).get.asInstanceOf[Vehicle], silo_guid)) } - case VehicleSpawnPad.StartPlayerSeatedInVehicle(vehicle, pad) => - val vehicle_guid = vehicle.GUID - PlayerActionsToCancel() - if(player.VisibleSlots.contains(player.DrawnSlot)) { - player.DrawnSlot = Player.HandsDownSlot - sendResponse(ObjectHeldMessage(player.GUID, Player.HandsDownSlot, true)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot)) - } - sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off - sendResponse(PlanetsideAttributeMessage(player.GUID, 21, vehicle_guid)) //ownership - - case VehicleSpawnPad.PlayerSeatedInVehicle(vehicle, pad) => - val vehicle_guid = vehicle.GUID - sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 0L)) //mount points on - ReloadVehicleAccessPermissions(vehicle) - ServerVehicleLock(vehicle) - - case VehicleSpawnPad.ServerVehicleOverrideStart(vehicle, pad) => - val vdef = vehicle.Definition - if(vehicle.Seats(0).isOccupied) { - // todo: shouldn't the vehicle already be detached by this point? I'm going to disable the below for now as it's causing duplicate ODM packets -// sendResponse(ObjectDetachMessage(pad.GUID, vehicle.GUID, pad.Position + Vector3.z(0.5f), pad.Orientation.z)) - } - ServerVehicleOverride(vehicle, vdef.AutoPilotSpeed1, GlobalDefinitions.isFlightVehicle(vdef) : Int) - - case VehicleSpawnControlGuided.GuidedControl(cmd, vehicle, data) => - cmd match { - case AutoDriveControls.State.Drive => - val speed : Int = data.getOrElse({ - vehicle.Definition.AutoPilotSpeed1 - }).asInstanceOf[Int] - ServerVehicleOverride(vehicle, speed) - - case AutoDriveControls.State.Climb => - ServerVehicleOverride(vehicle, controlled.getOrElse(0), GlobalDefinitions.isFlightVehicle(vehicle.Definition) : Int) - - case AutoDriveControls.State.Turn => - //TODO how to turn hovering/flying vehicle? - val direction = data.getOrElse(15).asInstanceOf[Int] - sendResponse(VehicleStateMessage(vehicle.GUID, 0, vehicle.Position, vehicle.Orientation, vehicle.Velocity, None, 0, 0, direction, false, false)) - - case AutoDriveControls.State.Stop => - ServerVehicleOverride(vehicle, 0) - - case _ => ; - } - - case VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, pad) => - sendResponse(GenericObjectActionMessage(pad.GUID, 92)) //reset spawn pad - DriverVehicleControl(vehicle, vehicle.Definition.AutoPilotSpeed2) - - case VehicleSpawnPad.PeriodicReminder(cause, data) => - val msg : String = (cause match { - case VehicleSpawnPad.Reminders.Blocked => - s"The vehicle spawn where you placed your order is blocked. ${data.getOrElse("")}" - case VehicleSpawnPad.Reminders.Queue => - s"Your position in the vehicle spawn queue is ${data.getOrElse("last")}." - case VehicleSpawnPad.Reminders.Cancelled => - "Your vehicle order has been cancelled." - }) - sendResponse(ChatMsg(ChatMessageType.CMT_OPEN, true, "", msg, None)) - case CheckCargoDismount(cargo_guid, carrier_guid, mountPoint, iteration) => HandleCheckCargoDismounting(cargo_guid, carrier_guid, mountPoint, iteration) @@ -867,22 +807,22 @@ class WorldSessionActor extends Actor with MDCContextAware { continent.GUID(item.Companion) match { case Some(obj : BoomerDeployable) => val guid = obj.GUID - val factionOnContinentChannel = s"${continent.Id}/${player.Faction}" + val factionChannel = s"${player.Faction}" obj.AssignOwnership(None) avatar.Deployables.Remove(obj) UpdateDeployableUIElements(avatar.Deployables.UpdateUIElement(obj.Definition.Item)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent)) sendResponse(SetEmpireMessage(guid, PlanetSideEmpire.NEUTRAL)) - avatarService ! AvatarServiceMessage(factionOnContinentChannel, AvatarAction.SetEmpire(playerGUID, guid, PlanetSideEmpire.NEUTRAL)) + continent.AvatarEvents ! AvatarServiceMessage(factionChannel, AvatarAction.SetEmpire(playerGUID, guid, PlanetSideEmpire.NEUTRAL)) val info = DeployableInfo(guid, DeployableIcon.Boomer, obj.Position, PlanetSideGUID(0)) sendResponse(DeployableObjectsInfoMessage(DeploymentAction.Dismiss, info)) - localService ! LocalServiceMessage(factionOnContinentChannel, LocalAction.DeployableMapIcon(playerGUID, DeploymentAction.Dismiss, info)) + continent.LocalEvents ! LocalServiceMessage(factionChannel, LocalAction.DeployableMapIcon(playerGUID, DeploymentAction.Dismiss, info)) PutItemOnGround(item, pos, orient) case Some(_) | None => //pointless trigger val guid = item.GUID continent.Ground ! Zone.Ground.RemoveItem(guid) //undo; no callback - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(PlanetSideGUID(0), guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(PlanetSideGUID(0), guid)) taskResolver ! GUIDTask.UnregisterObjectTask(item)(continent.GUID) } @@ -909,17 +849,17 @@ class WorldSessionActor extends Actor with MDCContextAware { val guid = obj.GUID val playerGUID = player.GUID val faction = player.Faction - val factionOnContinentChannel = s"${continent.Id}/${faction}" + val factionChannel = s"$faction" obj.AssignOwnership(player) obj.Faction = faction avatar.Deployables.Add(obj) UpdateDeployableUIElements(avatar.Deployables.UpdateUIElement(obj.Definition.Item)) - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(obj), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(obj), continent)) sendResponse(SetEmpireMessage(guid, faction)) - avatarService ! AvatarServiceMessage(factionOnContinentChannel, AvatarAction.SetEmpire(playerGUID, guid, faction)) + continent.AvatarEvents ! AvatarServiceMessage(factionChannel, AvatarAction.SetEmpire(playerGUID, guid, faction)) val info = DeployableInfo(obj.GUID, DeployableIcon.Boomer, obj.Position, obj.Owner.get) sendResponse(DeployableObjectsInfoMessage(DeploymentAction.Build, info)) - localService ! LocalServiceMessage(factionOnContinentChannel, LocalAction.DeployableMapIcon(playerGUID, DeploymentAction.Build, info)) + continent.LocalEvents ! LocalServiceMessage(factionChannel, LocalAction.DeployableMapIcon(playerGUID, DeploymentAction.Build, info)) case Some(_) | None => ; //pointless trigger; see Zone.Ground.ItemOnGround(BoomerTrigger, ...) } } @@ -946,10 +886,10 @@ class WorldSessionActor extends Actor with MDCContextAware { if(avatar.Deployables.Accept(obj) || (avatar.Deployables.Valid(obj) && !avatar.Deployables.Contains(obj))) { tool.Definition match { case GlobalDefinitions.ace => - localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffectLocation(player.GUID, "spawn_object_effect", obj.Position, obj.Orientation)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffectLocation(player.GUID, "spawn_object_effect", obj.Position, obj.Orientation)) case GlobalDefinitions.advanced_ace => sendResponse(GenericObjectActionMessage(player.GUID, 212)) //put fdu down; it will be removed from the client's holster - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PutDownFDU(player.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PutDownFDU(player.GUID)) case GlobalDefinitions.router_telepad => ; case _ => log.warn(s"Zone.Deployable.DeployableIsBuilt: not sure what kind of construction item to animate - ${tool.Definition}") @@ -991,7 +931,7 @@ class WorldSessionActor extends Actor with MDCContextAware { DeployableBuildActivity(obj) //TODO sufficiently delete the tool sendResponse(ObjectDeleteMessage(tool.GUID, 0)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, tool.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, tool.GUID)) taskResolver ! GUIDTask.UnregisterEquipment(tool)(continent.GUID) val trigger = new BoomerTrigger trigger.Companion = obj.GUID @@ -1003,7 +943,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } else { //don't know where boomer trigger should go; drop it on the ground - taskResolver ! NewItemDrop(player, continent, avatarService)(trigger) + taskResolver ! NewItemDrop(player, continent, continent.AvatarEvents)(trigger) } StopBundlingPackets() @@ -1019,7 +959,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //motion alarm sensor and sensor disruptor StartBundlingPackets() DeployableBuildActivity(obj) - localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffectInfo(player.GUID, "on", obj.GUID, true, 1000)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffectInfo(player.GUID, "on", obj.GUID, true, 1000)) CommonDestroyConstructionItem(tool, index) FindReplacementConstructionItem(tool, index) StopBundlingPackets() @@ -1037,7 +977,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(vehicle.Health == 0) { //the Telepad was successfully deployed; but, before it could configure, its Router was destroyed sendResponse(ChatMsg(ChatMessageType.UNK_229, false, "", "@Telepad_NoDeploy_RouterLost", None)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) } else { log.info(s"FinalizeDeployable: setup for telepad #${guid.guid} in zone ${continent.Id}") @@ -1046,13 +986,13 @@ class WorldSessionActor extends Actor with MDCContextAware { CommonDestroyConstructionItem(tool, index) StopBundlingPackets() //it takes 60s for the telepad to become properly active - localService ! LocalServiceMessage.Telepads(RouterTelepadActivation.AddTask(obj, continent)) + continent.LocalEvents ! LocalServiceMessage.Telepads(RouterTelepadActivation.AddTask(obj, continent)) } case _ => //the Telepad was successfully deployed; but, before it could configure, its Router was deconstructed sendResponse(ChatMsg(ChatMessageType.UNK_229, false, "", "@Telepad_NoDeploy_RouterLost", None)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) } } StopBundlingPackets() @@ -1095,9 +1035,6 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list sendResponse(FriendsResponse(FriendAction.InitializeFriendList, 0, true, true, Nil)) sendResponse(FriendsResponse(FriendAction.InitializeIgnoreList, 0, true, true, Nil)) - avatarService ! Service.Join(avatar.name) //channel will be player.Name - localService ! Service.Join(avatar.name) //channel will be player.Name - vehicleService ! Service.Join(avatar.name) //channel will be player.Name galaxyService ! Service.Join("galaxy") //for galaxy-wide messages galaxyService ! Service.Join(s"${avatar.faction}") //for hotspots squadService ! Service.Join(s"${avatar.faction}") //channel will be player.Faction @@ -1106,14 +1043,9 @@ class WorldSessionActor extends Actor with MDCContextAware { case InterstellarCluster.GiveWorld(zoneId, zone) => log.info(s"Zone $zoneId will now load") - val continentId = continent.Id - val factionOnContinentChannel = s"$continentId/${avatar.faction}" - avatarService ! Service.Leave(Some(continentId)) - avatarService ! Service.Leave(Some(factionOnContinentChannel)) - localService ! Service.Leave(Some(continentId)) - localService ! Service.Leave(Some(factionOnContinentChannel)) - vehicleService ! Service.Leave(Some(continentId)) - vehicleService ! Service.Leave(Some(factionOnContinentChannel)) + continent.AvatarEvents ! Service.Leave() + continent.LocalEvents ! Service.Leave() + continent.VehicleEvents ! Service.Leave() player.Continent = zoneId continent = zone continent.Population ! Zone.Population.Join(avatar) @@ -1175,7 +1107,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //tank_traps val guid = target.GUID val health = target.Health - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health)) if(health <= 0) { AnnounceDestroyDeployable(target, None) } @@ -1184,7 +1116,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //sensors val guid = target.GUID val health = target.Health - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health)) if(health <= 0) { AnnounceDestroyDeployable(target, Some(0 seconds)) } @@ -1194,7 +1126,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(target.Health <= 0) { //update if destroyed val guid = target.GUID - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, guid)) AnnounceDestroyDeployable(target, Some(0 seconds)) } @@ -1205,7 +1137,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //shield_generators val health = target.Health val guid = target.GUID - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 0, health)) if(health <= 0) { AnnounceDestroyDeployable(target, None) } @@ -1217,7 +1149,7 @@ class WorldSessionActor extends Actor with MDCContextAware { log.warn(s"Vital target ${target.Definition.Name} damage resolution not supported using this method") case Vehicle.UpdateShieldsCharge(vehicle) => - vehicleService ! VehicleServiceMessage(s"${vehicle.Actor}", VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), vehicle.GUID, 68, vehicle.Shields)) + continent.VehicleEvents ! VehicleServiceMessage(s"${vehicle.Actor}", VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), vehicle.GUID, 68, vehicle.Shields)) case ResponseToSelf(pkt) => log.info(s"Received a direct message: $pkt") @@ -1311,21 +1243,19 @@ class WorldSessionActor extends Actor with MDCContextAware { } case AvatarResponse.ConcealPlayer() => - if(tplayer_guid != guid) { - sendResponse(GenericObjectActionMessage(guid, 36)) - } + sendResponse(GenericObjectActionMessage(guid, 36)) case AvatarResponse.EnvironmentalDamage(target, amount) => if(player.isAlive) { val originalHealth = player.Health player.Health = player.Health - amount sendResponse(PlanetsideAttributeMessage(target, 0, player.Health)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(target, 0, player.Health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(target, 0, player.Health)) damageLog.info(s"${player.Name}-infantry: BEFORE=$originalHealth, AFTER=${player.Health}, CHANGE=$amount") if(amount != 0) { val playerGUID = player.GUID sendResponse(PlanetsideAttributeMessage(playerGUID, 0, player.Health)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, player.Health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, player.Health)) if(player.Health == 0 && player.isAlive) { KillPlayer(player) } @@ -1349,8 +1279,8 @@ class WorldSessionActor extends Actor with MDCContextAware { val playerGUID = player.GUID sendResponse(PlanetsideAttributeMessage(playerGUID, 0, health)) sendResponse(PlanetsideAttributeMessage(playerGUID, 4, armor)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, health)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 4, armor)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 0, health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(playerGUID, 4, armor)) if(health == 0 && player.isAlive) { KillPlayer(player) } @@ -1576,7 +1506,7 @@ class WorldSessionActor extends Actor with MDCContextAware { continent.GUID(door_guid) match { case Some(door : Door) => sendResponse(GenericObjectStateMsg(door_guid, 16)) - localService ! LocalServiceMessage(continent.Id, LocalAction.DoorOpens(tplayer.GUID, continent, door)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.DoorOpens(tplayer.GUID, continent, door)) case _ => log.warn(s"door $door_guid wanted to be opened but could not be found") @@ -1584,7 +1514,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case Door.CloseEvent() => sendResponse(GenericObjectStateMsg(door_guid, 17)) - localService ! LocalServiceMessage(continent.Id, LocalAction.DoorCloses(tplayer.GUID, door_guid)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.DoorCloses(tplayer.GUID, door_guid)) case Door.NoEvent() => ; } @@ -1842,7 +1772,7 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PlanetsideAttributeMessage(obj_guid, 68, 0)) //shield health sendResponse(PlanetsideAttributeMessage(obj_guid, 113, 0)) //capacitor if(seat_num == 0) { - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(obj), continent)) //clear timer + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(obj), continent)) //clear timer //simplistic vehicle ownership management obj.Owner match { case Some(owner_guid) => @@ -1896,7 +1826,7 @@ class WorldSessionActor extends Actor with MDCContextAware { DismountAction(tplayer, obj, seat_num) } else { - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, seat_num, true, obj.GUID)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, seat_num, true, obj.GUID)) } case Mountable.CanDismount(obj : PlanetSideGameObject with WeaponTurret, seat_num) => @@ -1957,7 +1887,7 @@ class WorldSessionActor extends Actor with MDCContextAware { tplayer.History(HealFromExoSuitChange(PlayerSource(tplayer), exosuit)) tplayer.Armor = toMaxArmor sendResponse(PlanetsideAttributeMessage(tplayer.GUID, 4, toMaxArmor)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, toMaxArmor)) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, toMaxArmor)) } else { tplayer.Armor = originalArmor @@ -1966,18 +1896,18 @@ class WorldSessionActor extends Actor with MDCContextAware { if(tplayer.DrawnSlot != Player.HandsDownSlot) { tplayer.DrawnSlot = Player.HandsDownSlot sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, tplayer.LastDrawnSlot)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, tplayer.LastDrawnSlot)) } //delete everything not dropped (beforeHolsters ++ beforeInventory).foreach({ elem => sendResponse(ObjectDeleteMessage(elem.obj.GUID, 0)) }) beforeHolsters.foreach({ elem => - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectDelete(tplayer.GUID, elem.obj.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectDelete(tplayer.GUID, elem.obj.GUID)) }) //report change sendResponse(ArmorChangedMessage(tplayer.GUID, exosuit, subtype)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ArmorChanged(tplayer.GUID, exosuit, subtype)) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.ArmorChanged(tplayer.GUID, exosuit, subtype)) //sterilize holsters val normalHolsters = if(originalSuit == ExoSuitType.MAX) { val (maxWeapons, normalWeapons) = beforeHolsters.partition(elem => elem.obj.Size == EquipmentSize.Max) @@ -2013,7 +1943,7 @@ class WorldSessionActor extends Actor with MDCContextAware { definition.Packet.DetailedConstructorData(obj).get ) ) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, player.GUID, index, obj)) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, player.GUID, index, obj)) case None => ; } }) @@ -2164,7 +2094,7 @@ class WorldSessionActor extends Actor with MDCContextAware { tplayer.History(HealFromExoSuitChange(PlayerSource(tplayer), nextSuit)) tplayer.Armor = toMaxArmor sendResponse(PlanetsideAttributeMessage(tplayer.GUID, 4, toMaxArmor)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, toMaxArmor)) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(tplayer.GUID, 4, toMaxArmor)) } else { tplayer.Armor = originalArmor @@ -2173,7 +2103,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(tplayer.DrawnSlot != Player.HandsDownSlot) { tplayer.DrawnSlot = Player.HandsDownSlot sendResponse(ObjectHeldMessage(tplayer.GUID, Player.HandsDownSlot, true)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, tplayer.LastDrawnSlot)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectHeld(tplayer.GUID, tplayer.LastDrawnSlot)) } //a change due to exo-suit permissions mismatch will result in (more) items being re-arranged and/or dropped //dropped items can be forgotten safely @@ -2215,7 +2145,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } //delete everything (not dropped) beforeHolsters.foreach({ elem => - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectDelete(tplayer.GUID, elem.obj.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectDelete(tplayer.GUID, elem.obj.GUID)) }) (beforeHolsters ++ beforeInventory).foreach({ elem => sendResponse(ObjectDeleteMessage(elem.obj.GUID, 0)) @@ -2223,7 +2153,7 @@ class WorldSessionActor extends Actor with MDCContextAware { }) //report change sendResponse(ArmorChangedMessage(tplayer.GUID, nextSuit, nextSubtype)) - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ArmorChanged(tplayer.GUID, nextSuit, nextSubtype)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ArmorChanged(tplayer.GUID, nextSuit, nextSubtype)) if(nextSuit == ExoSuitType.MAX) { val (maxWeapons, otherWeapons) = afterHolsters.partition(entry => { entry.obj.Size == EquipmentSize.Max }) taskResolver ! DelayedObjectHeld(tplayer, 0, List(PutEquipmentInSlot(tplayer, maxWeapons.head.obj, 0))) @@ -2276,7 +2206,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val existingBox = existingWeapon.AmmoSlots(index).Box existingBox.Capacity = savedWeapon.AmmoSlots(index).Box.Capacity //use VehicleAction.InventoryState2; VehicleAction.InventoryState temporarily glitches ammo count in ui - vehicleService ! VehicleServiceMessage(channel, VehicleAction.InventoryState2(PlanetSideGUID(0), existingBox.GUID, existingWeapon.GUID, existingBox.Capacity)) + continent.VehicleEvents ! VehicleServiceMessage(channel, VehicleAction.InventoryState2(PlanetSideGUID(0), existingBox.GUID, existingWeapon.GUID, existingBox.Capacity)) }) }) afterInventory @@ -2437,9 +2367,8 @@ class WorldSessionActor extends Actor with MDCContextAware { val toFaction = tplayer.Faction val pad = continent.GUID(pad_guid).get.asInstanceOf[VehicleSpawnPad] vehicle.Faction = toFaction - vehicle.Continent = continent.Id vehicle.Position = pad.Position - vehicle.Orientation = pad.Orientation + vehicle.Orientation = pad.Orientation + Vector3.z(pad.Definition.VehicleCreationZOrientOffset) //default loadout, weapons val vWeapons = vehicle.Weapons weapons.foreach(entry => { @@ -2590,8 +2519,7 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(GenericObjectActionMessage(pad_guid, 92)) case VehicleResponse.RevealPlayer(player_guid) => - //TODO see note in ConcealPlayer - sendResponse(PlanetsideAttributeMessage(player_guid, 29, 0)) + sendResponse(GenericObjectActionMessage(player_guid, 40)) case VehicleResponse.SeatPermissions(vehicle_guid, seat_group, permission) => if(tplayer_guid != guid) { @@ -2633,25 +2561,8 @@ class WorldSessionActor extends Actor with MDCContextAware { case VehicleResponse.TransferPassengerChannel(old_channel, temp_channel, vehicle) => if(tplayer_guid != guid) { interstellarFerry = Some(vehicle) - vehicleService ! Service.Leave(Some(old_channel)) //old vehicle-specific channel (was s"${vehicle.Actor}") - vehicleService ! Service.Join(temp_channel) //temporary vehicle-specific channel (driver name, plus extra) - } - case VehicleResponse.TransferPassenger(temp_channel, vehicle, vehicle_to_delete) => - vehicle.PassengerInSeat(player) match { - case Some(_) => - vehicleService ! Service.Leave(Some(temp_channel)) //temporary vehicle-specific channel (see above) - deadState = DeadState.Release - sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, player.Faction, true)) - interstellarFerry = Some(vehicle) //on the other continent and registered to that continent's GUID system - interstellarFerryTopLevelGUID = Some(vehicle_to_delete) //vehicle.GUID, or previously a higher level parent - LoadZonePhysicalSpawnPoint(vehicle.Continent, vehicle.Position, vehicle.Orientation, 1) - case None => - interstellarFerry match { - case None => - vehicleService ! Service.Leave(Some(temp_channel)) //no longer being transferred between zones - case Some(_) => ; - //wait patiently - } + continent.VehicleEvents ! Service.Leave(Some(old_channel)) //old vehicle-specific channel (was s"${vehicle.Actor}") + galaxyService ! Service.Join(temp_channel) //temporary vehicle-specific channel (driver name, plus extra) } case VehicleResponse.ForceDismountVehicleCargo(cargo_guid, bailed, requestedByPassenger, kicked) => @@ -2673,6 +2584,42 @@ class WorldSessionActor extends Actor with MDCContextAware { } } + case VehicleResponse.StartPlayerSeatedInVehicle(vehicle, pad) => + val vehicle_guid = vehicle.GUID + PlayerActionsToCancel() + if(player.VisibleSlots.contains(player.DrawnSlot)) { + player.DrawnSlot = Player.HandsDownSlot + sendResponse(ObjectHeldMessage(player.GUID, Player.HandsDownSlot, true)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot)) + } + sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off + sendResponse(PlanetsideAttributeMessage(player.GUID, 21, vehicle_guid)) //ownership + vehicle.Actor ! Mountable.TryMount(player, 0) + + case VehicleResponse.PlayerSeatedInVehicle(vehicle, pad) => + val vehicle_guid = vehicle.GUID + sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 0L)) //mount points on + ReloadVehicleAccessPermissions(vehicle) + ServerVehicleLock(vehicle) + + case VehicleResponse.ServerVehicleOverrideStart(vehicle, pad) => + val vdef = vehicle.Definition + ServerVehicleOverride(vehicle, vdef.AutoPilotSpeed1, GlobalDefinitions.isFlightVehicle(vdef) : Int) + + case VehicleResponse.ServerVehicleOverrideEnd(vehicle, pad) => + DriverVehicleControl(vehicle, vehicle.Definition.AutoPilotSpeed2) + + case VehicleResponse.PeriodicReminder(cause, data) => + val msg : String = (cause match { + case VehicleSpawnPad.Reminders.Blocked => + s"The vehicle spawn where you placed your order is blocked. ${data.getOrElse("")}" + case VehicleSpawnPad.Reminders.Queue => + s"Your position in the vehicle spawn queue is ${data.getOrElse("last")}." + case VehicleSpawnPad.Reminders.Cancelled => + "Your vehicle order has been cancelled." + }) + sendResponse(ChatMsg(ChatMessageType.CMT_OPEN, true, "", msg, None)) + case _ => ; } } @@ -2727,7 +2674,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(distance > 225) { //cargo vehicle has moved far enough away; close the carrier's hold door log.info(s"HandleCheckCargoDismounting: dismount of cargo vehicle from carrier complete at distance of $distance") - vehicleService ! VehicleServiceMessage( + continent.VehicleEvents ! VehicleServiceMessage( continent.Id, VehicleAction.SendResponse( player.GUID, @@ -2802,8 +2749,8 @@ class WorldSessionActor extends Actor with MDCContextAware { cargo.MountedIn = carrierGUID hold.Occupant = cargo cargo.Velocity = None - vehicleService ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health))) - vehicleService ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 68, cargo.Shields))) + continent.VehicleEvents ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health))) + continent.VehicleEvents ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 68, cargo.Shields))) StartBundlingPackets() val (attachMsg, mountPointMsg) = CargoMountBehaviorForAll(carrier, cargo, mountPoint) StopBundlingPackets() @@ -2813,7 +2760,7 @@ class WorldSessionActor extends Actor with MDCContextAware { else if(distance > 625 || iteration >= 40) { //vehicles moved too far away or took too long to get into proper position; abort mounting log.info("HandleCheckCargoMounting: cargo vehicle is too far away or didn't mount within allocated time - aborting") - vehicleService ! VehicleServiceMessage( + continent.VehicleEvents ! VehicleServiceMessage( continent.Id, VehicleAction.SendResponse( player.GUID, @@ -2943,8 +2890,8 @@ class WorldSessionActor extends Actor with MDCContextAware { */ def CargoMountMessagesForOthers(attachMessage : ObjectAttachMessage, mountPointStatusMessage : CargoMountPointStatusMessage) : Unit = { val pguid = player.GUID - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(pguid, attachMessage)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(pguid, mountPointStatusMessage)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(pguid, attachMessage)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(pguid, mountPointStatusMessage)) } /** @@ -2985,8 +2932,8 @@ class WorldSessionActor extends Actor with MDCContextAware { //alert to vehicle death (hence, occupants' deaths) HandleVehicleDestructionAwareness(target, shot) } - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) - vehicleService ! VehicleServiceMessage(s"${target.Actor}", VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 68, target.Shields)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) + continent.VehicleEvents ! VehicleServiceMessage(s"${target.Actor}", VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 68, target.Shields)) case None => ; } } @@ -3003,7 +2950,7 @@ class WorldSessionActor extends Actor with MDCContextAware { seat.isOccupied && seat.Occupant.get.isAlive }).foreach(seat => { val tplayer = seat.Occupant.get - avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID)) }) //alert cargo occupants to damage source target.CargoHolds.values.foreach(hold => { @@ -3033,8 +2980,8 @@ class WorldSessionActor extends Actor with MDCContextAware { }).foreach(seat => { val tplayer = seat.Occupant.get val tplayerGUID = tplayer.GUID - avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) - avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) + continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self }) //vehicle wreckage has no weapons target.Weapons.values @@ -3043,7 +2990,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } .foreach(slot => { val wep = slot.Equipment.get - avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) }) target.CargoHolds.values.foreach(hold => { hold.Occupant match { @@ -3062,12 +3009,12 @@ class WorldSessionActor extends Actor with MDCContextAware { case GlobalDefinitions.router => target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying) BeforeUnloadVehicle(target) - localService ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), target, None)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), target, None)) case _ => ; } - avatarService ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, playerGUID, playerGUID, target.Position)) - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), continent)) - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, continent, Some(1 minute))) + continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, playerGUID, playerGUID, target.Position)) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), continent)) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, continent, Some(1 minute))) } /** @@ -3088,8 +3035,8 @@ class WorldSessionActor extends Actor with MDCContextAware { .foreach(seat => { val tplayer = seat.Occupant.get val tplayerGUID = tplayer.GUID - avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) - avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) + continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self }) //destroy weapons target.Weapons.values @@ -3097,11 +3044,11 @@ class WorldSessionActor extends Actor with MDCContextAware { .collect { case Some(weapon) => val wguid = weapon.GUID sendResponse(ObjectDeleteMessage(wguid, 0)) - avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(player.GUID, wguid)) + continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(player.GUID, wguid)) } AnnounceDestroyDeployable(target, None) } - avatarService ! AvatarServiceMessage(continentId, AvatarAction.PlanetsideAttribute(guid, 0, health)) + continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.PlanetsideAttribute(guid, 0, health)) } def HandleFacilityTurretDamageResolution(target : FacilityTurret) : Unit = { @@ -3115,7 +3062,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //alert occupants to damage source players.foreach(seat => { val tplayer = seat.Occupant.get - avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(playerGUID, tplayer.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(playerGUID, tplayer.GUID)) }) } else { @@ -3123,8 +3070,8 @@ class WorldSessionActor extends Actor with MDCContextAware { players.foreach(seat => { val tplayer = seat.Occupant.get val tplayerGUID = tplayer.GUID - avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) - avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID)) + continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self }) //turret wreckage has no weapons // target.Weapons.values @@ -3133,17 +3080,17 @@ class WorldSessionActor extends Actor with MDCContextAware { // } // .foreach(slot => { // val wep = slot.Equipment.get -// avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) +// continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID)) // }) -// avatarService ! AvatarServiceMessage(continentId, AvatarAction.Destroy(targetGUID, playerGUID, playerGUID, player.Position)) +// continent.AvatarEvents ! AvatarServiceMessage(continentId, AvatarAction.Destroy(targetGUID, playerGUID, playerGUID, player.Position)) target.Health = 1 - vehicleService ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.MaxHealth)) //TODO not necessary + continent.VehicleEvents ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.MaxHealth)) //TODO not necessary if(target.Upgrade != TurretUpgrade.None) { - vehicleService ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), continent)) - vehicleService ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, continent, TurretUpgrade.None)) + continent.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), continent)) + continent.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, continent, TurretUpgrade.None)) } } - vehicleService ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) + continent.VehicleEvents ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health)) } /** @@ -3157,8 +3104,8 @@ class WorldSessionActor extends Actor with MDCContextAware { // Charging vehicle.Capacitor += 100 sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 45, scala.math.ceil((vehicle.Capacitor.toFloat / vehicle.Definition.MaximumCapacitor.toFloat) * 10).toInt)) // set ntu on vehicle UI - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 1L)) // panel glow on - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 49, 1L)) // orb particle effect on + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 1L)) // panel glow on + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 49, 1L)) // orb particle effect on antChargingTick = context.system.scheduler.scheduleOnce(1000 milliseconds, self, NtuCharging(player, vehicle)) // Repeat until fully charged } @@ -3179,8 +3126,8 @@ class WorldSessionActor extends Actor with MDCContextAware { */ def HandleNtuDischarging(tplayer : Player, vehicle : Vehicle, silo_guid : PlanetSideGUID) : Unit = { log.trace(s"NtuDischarging: Vehicle ${vehicle.GUID} is discharging NTU into silo $silo_guid") - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 49, 0L)) // orb particle effect off - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 1L)) // panel glow on + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 49, 0L)) // orb particle effect off + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 1L)) // panel glow on var silo = continent.GUID(silo_guid).get.asInstanceOf[ResourceSilo] // Check vehicle is still deployed before continuing. User can undeploy manually or vehicle may not longer be present. @@ -3191,7 +3138,7 @@ class WorldSessionActor extends Actor with MDCContextAware { var chargeToDeposit = Math.min(Math.min(vehicle.Capacitor, 100), (silo.MaximumCharge - silo.ChargeLevel)) vehicle.Capacitor -= chargeToDeposit silo.Actor ! ResourceSilo.UpdateChargeLevel(chargeToDeposit) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 1L)) // panel glow on & orb particles on + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 1L)) // panel glow on & orb particles on sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 45, scala.math.ceil((vehicle.Capacitor.toFloat / vehicle.Definition.MaximumCapacitor.toFloat) * 10).toInt)) // set ntu on vehicle UI //todo: grant BEP to user @@ -3209,7 +3156,7 @@ class WorldSessionActor extends Actor with MDCContextAware { log.trace(s"NtuDischarging: ANT NTU empty or Silo NTU full.") // Turning off glow/orb effects on ANT doesn't seem to work when deployed. Try to undeploy ANT from server side context.system.scheduler.scheduleOnce(vehicle.UndeployTime milliseconds, vehicle.Actor, Deployment.TryUndeploy(DriveState.Undeploying)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 0L)) // panel glow off & orb particles off + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 0L)) // panel glow off & orb particles off antDischargingTick.cancel() } } @@ -3218,15 +3165,15 @@ class WorldSessionActor extends Actor with MDCContextAware { log.warn(s"NtuDischarging: Invalid discharge state. ANT Capacitor: ${vehicle.Capacitor} Silo Capacitor: ${silo.ChargeLevel}") // Turning off glow/orb effects on ANT doesn't seem to work when deployed. Try to undeploy ANT from server side context.system.scheduler.scheduleOnce(vehicle.UndeployTime milliseconds, vehicle.Actor, Deployment.TryUndeploy(DriveState.Undeploying)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 0L)) // panel glow off & orb particles off + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 0L)) // panel glow off & orb particles off antDischargingTick.cancel() } } else { log.trace(s"NtuDischarging: Vehicle is no longer deployed. Removing effects") // Vehicle has changed from deployed and this should be the last timer tick sent - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 0L)) // panel glow off - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 0L)) // panel glow off & orb particles off + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 0L)) // panel glow off + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(silo_guid, 49, 0L)) // panel glow off & orb particles off antDischargingTick.cancel() } } @@ -3326,7 +3273,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //looking for squad (members) if(tplayer.LFS || lfsm) { sendResponse(PlanetsideAttributeMessage(guid, 53, 1)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 53, 1)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(guid, 53, 1)) } sendResponse(AvatarSearchCriteriaMessage(guid, List(0, 0, 0, 0, 0, 0))) (1 to 73).foreach(i => { @@ -3360,7 +3307,7 @@ class WorldSessionActor extends Actor with MDCContextAware { continent.GUID(player.VehicleOwned) match { case Some(vehicle : Vehicle) if vehicle.OwnerName.contains(tplayer.Name) => vehicle.Owner = guid - vehicleService ! VehicleServiceMessage(s"${continent.Id}/${tplayer.Faction}", VehicleAction.Ownership(guid, vehicle.GUID)) + continent.VehicleEvents ! VehicleServiceMessage(s"${tplayer.Faction}", VehicleAction.Ownership(guid, vehicle.GUID)) case _ => player.VehicleOwned = None } @@ -3414,7 +3361,7 @@ class WorldSessionActor extends Actor with MDCContextAware { def RespawnSquadSetup() : Unit = { if(squadUI.nonEmpty) { sendResponse(PlanetsideAttributeMessage(player.GUID, 31, squad_supplement_id)) - avatarService ! AvatarServiceMessage(s"${continent.Id}/${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 31, squad_supplement_id)) + continent.AvatarEvents ! AvatarServiceMessage(s"${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 31, squad_supplement_id)) sendResponse(PlanetsideAttributeMessage(player.GUID, 32, squadUI(player.CharId).index)) } } @@ -3591,7 +3538,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case Some((mountPoint, _)) => //begin the mount process - open the cargo door val reply = CargoMountPointStatusMessage(cargo_vehicle_guid, PlanetSideGUID(0), vehicle_guid, PlanetSideGUID(0), mountPoint, CargoStatus.InProgress, 0) log.debug(reply.toString) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player.GUID, reply)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player.GUID, reply)) sendResponse(reply) import scala.concurrent.duration._ @@ -3640,13 +3587,16 @@ class WorldSessionActor extends Actor with MDCContextAware { val continentId = continent.Id traveler.zone = continentId val faction = player.Faction - val factionOnContinentChannel = s"$continentId/$faction" - avatarService ! Service.Join(continentId) - avatarService ! Service.Join(factionOnContinentChannel) - localService ! Service.Join(continentId) - localService ! Service.Join(factionOnContinentChannel) - vehicleService ! Service.Join(continentId) - vehicleService ! Service.Join(factionOnContinentChannel) + val factionChannel = s"$faction" + continent.AvatarEvents ! Service.Join(avatar.name) + continent.AvatarEvents ! Service.Join(continentId) + continent.AvatarEvents ! Service.Join(factionChannel) + continent.LocalEvents ! Service.Join(avatar.name) + continent.LocalEvents ! Service.Join(continentId) + continent.LocalEvents ! Service.Join(factionChannel) + continent.VehicleEvents ! Service.Join(avatar.name) + continent.VehicleEvents ! Service.Join(continentId) + continent.VehicleEvents ! Service.Join(factionChannel) configZone(continent) sendResponse(TimeOfDayMessage(1191182336)) //custom @@ -3658,7 +3608,7 @@ class WorldSessionActor extends Actor with MDCContextAware { //find and reclaim own deployables, if any val guid = player.GUID val foundDeployables = continent.DeployableList.filter(obj => obj.OwnerName.contains(player.Name) && obj.Health > 0) - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(foundDeployables, continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(foundDeployables, continent)) foundDeployables.foreach(obj => { if(avatar.Deployables.Add(obj)) { obj.Owner = guid @@ -3900,7 +3850,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case None => ; } } - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.UpdateAmsSpawnPoint(continent)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.UpdateAmsSpawnPoint(continent)) chatService ! Service.Join("local") chatService ! Service.Join("squad") @@ -4012,14 +3962,14 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(UnuseItemMessage(guid, guid)) accessedContainer = None } - case None => ; - } - val wepInHand : Boolean = player.Slot(player.DrawnSlot).Equipment match { - case Some(item) => item.Definition == GlobalDefinitions.bolt_driver - case None => false - } - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlayerState(avatar_guid, player.Position, player.Velocity, yaw, pitch, yaw_upper, seq_time, is_crouching, is_jumping, jump_thrust, is_cloaking, spectator, wepInHand)) - updateSquad() + case None => ; + } + val wepInHand : Boolean = player.Slot(player.DrawnSlot).Equipment match { + case Some(item) => item.Definition == GlobalDefinitions.bolt_driver + case None => false + } + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlayerState(avatar_guid, player.Position, player.Velocity, yaw, pitch, yaw_upper, seq_time, is_crouching, is_jumping, jump_thrust, is_cloaking, spectator, wepInHand)) + updateSquad() case msg @ ChildObjectStateMessage(object_guid, pitch, yaw) => //the majority of the following check retrieves information to determine if we are in control of the child @@ -4028,7 +3978,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(tool.GUID == object_guid) { //TODO set tool orientation? player.Orientation = Vector3(0f, pitch, yaw) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.ChildObjectState(player.GUID, object_guid, pitch, yaw)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.ChildObjectState(player.GUID, object_guid, pitch, yaw)) } else { log.warn(s"ChildObjectState: ${player.Name} is using a different controllable agent than #${object_guid.guid}") @@ -4063,7 +4013,7 @@ class WorldSessionActor extends Actor with MDCContextAware { obj.Velocity = None obj.Flying = false } - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.VehicleState(player.GUID, vehicle_guid, unk1, obj.Position, ang, obj.Velocity, if(obj.Flying) { flying } else { None }, unk6, unk7, wheels, unk9, obj.Cloaked)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.VehicleState(player.GUID, vehicle_guid, unk1, obj.Position, ang, obj.Velocity, if(obj.Flying) { flying } else { None }, unk6, unk7, wheels, unk9, obj.Cloaked)) updateSquad() case (None, _) => //log.error(s"VehicleState: no vehicle $vehicle_guid found in zone") @@ -4105,20 +4055,20 @@ class WorldSessionActor extends Actor with MDCContextAware { if(!WellLootedCorpse(player)) { TurnPlayerIntoCorpse(player) continent.Population ! Zone.Corpse.Add(player) //TODO move back out of this match case when changing below issue - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.Release(player, continent)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.Release(player, continent)) } else { //no items in inventory; leave no corpse val player_guid = player.GUID sendResponse(ObjectDeleteMessage(player_guid, 0)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 0)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 0)) taskResolver ! GUIDTask.UnregisterPlayer(player)(continent.GUID) } case Some(_) => val player_guid = player.GUID sendResponse(ObjectDeleteMessage(player_guid, 0)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 0)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 0)) self ! PacketCoding.CreateGamePacket(0, DismountVehicleMsg(player_guid, BailType.Normal, true)) //let vehicle try to clean up its fields import scala.concurrent.ExecutionContext.Implicits.global @@ -4187,7 +4137,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } case None => player.Position = pos - //avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID)) + //continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID)) LoadZonePhysicalSpawnPoint(zone, pos, Vector3.Zero, 0) case _ => //seated in something that is not a vehicle or the vehicle is cargo, in which case we can't move deadState = DeadState.Alive @@ -4358,7 +4308,7 @@ class WorldSessionActor extends Actor with MDCContextAware { else { log.info(s"ChangeFireMode: changing $tool_guid to fire mode $modeIndex") sendResponse(ChangeFireModeMessage(tool_guid, modeIndex)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireMode(player.GUID, tool_guid, modeIndex)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireMode(player.GUID, tool_guid, modeIndex)) } case Some(_) => log.error(s"ChangeFireMode: the object that was found for $item_guid does not possess fire modes") @@ -4386,7 +4336,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case Some(_) => //permissible, for now prefire = None shooting = Some(item_guid) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(player.GUID, item_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(player.GUID, item_guid)) case None => log.error(s"ChangeFireState_Start: can not find $item_guid") } @@ -4397,7 +4347,7 @@ class WorldSessionActor extends Actor with MDCContextAware { prefire = None val weapon : Option[Equipment] = if(shooting.contains(item_guid)) { shooting = None - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, item_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, item_guid)) FindEquipment } else { @@ -4426,7 +4376,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } case Some(trigger : BoomerTrigger) => val playerGUID = player.GUID - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(playerGUID, item_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Start(playerGUID, item_guid)) continent.GUID(trigger.Companion) match { case Some(boomer : BoomerDeployable) => val boomerGUID = boomer.GUID @@ -4434,10 +4384,10 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(TriggerEffectMessage(boomerGUID, "detonate_boomer")) sendResponse(PlanetsideAttributeMessage(boomerGUID, 29, 1)) sendResponse(ObjectDeleteMessage(boomerGUID, 0)) - localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffect(playerGUID, "detonate_boomer", boomerGUID)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(boomerGUID, 29, 1)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(playerGUID, boomerGUID)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(boomer, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.TriggerEffect(playerGUID, "detonate_boomer", boomerGUID)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(boomerGUID, 29, 1)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(playerGUID, boomerGUID)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(boomer, continent, Some(0 seconds))) case Some(_) | None => ; } FindEquipmentToDelete(item_guid, trigger) @@ -4519,7 +4469,7 @@ class WorldSessionActor extends Actor with MDCContextAware { log.info(s"ReloadMessage: success, $tool <- $actualReloadValue ${tool.AmmoType}") tool.Magazine = actualReloadValue sendResponse(ReloadMessage(item_guid, actualReloadValue, unk1)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.Reload(player.GUID, item_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.Reload(player.GUID, item_guid)) } } else { @@ -4541,7 +4491,7 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(ObjectHeldMessage(avatar_guid, 0, true)) } else if((player.DrawnSlot = held_holsters) != before) { - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot)) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot)) // Ignore non-equipment holsters //todo: check current suit holster slots? @@ -4550,7 +4500,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case Some(unholsteredItem : Equipment) => if(unholsteredItem.Definition == GlobalDefinitions.remote_electronics_kit) { // Player has unholstered a REK - we need to set an atttribute on the REK itself to change the beam/icon colour to the correct one for the player's hack level - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(unholsteredItem.GUID, 116, GetPlayerHackLevel())) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttribute(unholsteredItem.GUID, 116, GetPlayerHackLevel())) } case None => ; } @@ -4570,7 +4520,6 @@ class WorldSessionActor extends Actor with MDCContextAware { case msg @ AvatarJumpMessage(state) => //log.info("AvatarJump: " + msg) player.Stamina = player.Stamina - 10 - if(player.Stamina < 0) player.Stamina = 0 sendResponse(PlanetsideAttributeMessage(player.GUID, 2, player.Stamina)) case msg @ ZipLineMessage(player_guid,origin_side,action,id,pos) => @@ -4598,8 +4547,8 @@ class WorldSessionActor extends Actor with MDCContextAware { if((player.VehicleOwned.contains(object_guid) && vehicle.Owner.contains(player.GUID)) || (player.Faction == vehicle.Faction && ((vehicle.Owner.isEmpty || continent.GUID(vehicle.Owner.get).isEmpty) || vehicle.Health == 0))) { - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(vehicle), continent)) - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(vehicle, continent, Some(0 seconds))) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(vehicle), continent)) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(vehicle, continent, Some(0 seconds))) log.info(s"RequestDestroy: vehicle $vehicle") } else { @@ -4611,7 +4560,7 @@ class WorldSessionActor extends Actor with MDCContextAware { continent.GUID(obj.Companion) match { case Some(boomer : BoomerDeployable) => boomer.Trigger = None - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(boomer, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(boomer, continent, Some(0 seconds))) //continent.Deployables ! Zone.Deployable.Dismiss(boomer) case Some(thing) => log.info(s"RequestDestroy: BoomerTrigger object connected to wrong object - $thing") @@ -4640,7 +4589,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } case Some(obj : BoomerDeployable) => - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) obj.Trigger match { case Some(trigger) => obj.Trigger = None @@ -4654,20 +4603,20 @@ class WorldSessionActor extends Actor with MDCContextAware { log.warn(s"RequestDestroy: boomer_trigger@$guid has been found but it seems to be orphaned") case _ => ; } - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(PlanetSideGUID(0), guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(PlanetSideGUID(0), guid)) GUIDTask.UnregisterObjectTask(trigger)(continent.GUID) case None => ; } case Some(obj : TelepadDeployable) => - localService ! LocalServiceMessage.Telepads(SupportActor.ClearSpecific(List(obj), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(obj), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage.Telepads(SupportActor.ClearSpecific(List(obj), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(obj), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) case Some(obj : PlanetSideGameObject with Deployable) => - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(obj), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(obj), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) case Some(thing) => log.warn(s"RequestDestroy: not allowed to delete object $thing") @@ -4779,7 +4728,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if (avatar.Implants(slot).Initialized) { if(action == ImplantAction.Activation && status == 1) { // active avatar.Implants(slot).Active = true - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, avatar.Implant(slot).id * 2 + 1)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, avatar.Implant(slot).id * 2 + 1)) if (avatar.Implant(slot).id == 3) { timeDL = System.currentTimeMillis() player.Stamina = player.Stamina - 3 @@ -4788,7 +4737,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if (avatar.Implant(slot).id == 9) timeSurge = System.currentTimeMillis() } else if(action == ImplantAction.Activation && status == 0) { //desactive avatar.Implants(slot).Active = false - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, avatar.Implant(slot).id * 2)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 28, avatar.Implant(slot).id * 2)) if (avatar.Implant(slot).id == 3) timeDL = 0 if (avatar.Implant(slot).id == 9) timeSurge = 0 } @@ -4893,7 +4842,7 @@ class WorldSessionActor extends Actor with MDCContextAware { player.History(HealFromKit(PlayerSource(player), 25, kit.Definition)) player.Health = player.Health + 25 sendResponse(PlanetsideAttributeMessage(avatar_guid, 0, player.Health)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(avatar_guid, 0, player.Health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(avatar_guid, 0, player.Health)) case None => log.error(s"UseItem: anticipated a $kit, but can't find it") } @@ -4917,7 +4866,7 @@ class WorldSessionActor extends Actor with MDCContextAware { player.History(HealFromKit(PlayerSource(player), 100, kit.Definition)) player.Health = player.Health + 100 sendResponse(PlanetsideAttributeMessage(avatar_guid, 0, player.Health)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(avatar_guid, 0, player.Health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(avatar_guid, 0, player.Health)) case None => log.error(s"UseItem: anticipated a $kit, but can't find it") } @@ -4941,7 +4890,7 @@ class WorldSessionActor extends Actor with MDCContextAware { player.History(RepairFromKit(PlayerSource(player), 200, kit.Definition)) player.Armor = player.Armor + 200 sendResponse(PlanetsideAttributeMessage(avatar_guid, 4, player.Armor)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(avatar_guid, 4, player.Armor)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(avatar_guid, 4, player.Armor)) case None => log.error(s"UseItem: anticipated a $kit, but can't find it") } @@ -4994,13 +4943,12 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, obj.GUID, tool.Magazine)) val RepairPercent: Int = tplayer.Armor * 100 / tplayer.MaxArmor sendResponse(RepairMessage(object_guid, RepairPercent)) - - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 4, tplayer.Armor)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 4, tplayer.Armor)) } else if (player.GUID == tplayer.GUID && !player.isMoving && tplayer.MaxArmor > 0) { player.Armor += 15 tool.Discharge sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, obj.GUID, tool.Magazine)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttributeToAll(player.GUID, 4, player.Armor)) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttributeToAll(player.GUID, 4, player.Armor)) } case _ => ; } @@ -5022,17 +4970,17 @@ class WorldSessionActor extends Actor with MDCContextAware { if(!tplayer.isAlive && tplayer.Health == tplayer.MaxHealth) { tplayer.Revive - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.Revive(tplayer.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Continent, AvatarAction.Revive(tplayer.GUID)) } if(tplayer.isAlive) { - avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 0, tplayer.Health)) + continent.AvatarEvents ! AvatarServiceMessage(tplayer.Continent, AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 0, tplayer.Health)) } } else if (player.GUID == tplayer.GUID && !player.isMoving && tplayer.MaxHealth > 0 && player.isAlive) { player.Health += 10 tool.Discharge sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, obj.GUID, tool.Magazine)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttributeToAll(player.GUID, 0, player.Health)) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.PlanetsideAttributeToAll(player.GUID, 0, player.Health)) } case _ => ; } @@ -5125,7 +5073,7 @@ class WorldSessionActor extends Actor with MDCContextAware { // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) val RepairPercent: Int = obj.Health * 100 / obj.MaxHealth sendResponse(RepairMessage(object_guid, RepairPercent)) - avatarService ! AvatarServiceMessage(obj.Continent, AvatarAction.PlanetsideAttribute(obj.GUID, 0, obj.Health)) + continent.AvatarEvents ! AvatarServiceMessage(obj.Continent, AvatarAction.PlanetsideAttribute(obj.GUID, 0, obj.Health)) } } else if(tool.Definition == GlobalDefinitions.trek) { @@ -5167,7 +5115,7 @@ class WorldSessionActor extends Actor with MDCContextAware { // sendResponse(QuantityUpdateMessage(PlanetSideGUID(8214),ammo_quantity_left)) val RepairPercent: Int = obj.Health * 100 / obj.MaxHealth sendResponse(RepairMessage(object_guid, RepairPercent)) - avatarService ! AvatarServiceMessage(obj.Continent, AvatarAction.PlanetsideAttribute(obj.GUID, 0, obj.Health)) + continent.AvatarEvents ! AvatarServiceMessage(obj.Continent, AvatarAction.PlanetsideAttribute(obj.GUID, 0, obj.Health)) } } @@ -5301,7 +5249,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } case msg @ ProximityTerminalUseMessage(player_guid, object_guid, _) => - log.info(s"ProximityTerminalUse: $msg") + log.trace(s"ProximityTerminalUse: $msg") continent.GUID(object_guid) match { case Some(obj : Terminal with ProximityUnit) => HandleProximityTerminalUse(obj) @@ -5379,7 +5327,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(action == 15) { //max deployment log.info(s"GenericObject: $player is anchored") player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 19, 1)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 19, 1)) definition match { case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster => val tool = toolOpt.get @@ -5397,7 +5345,7 @@ class WorldSessionActor extends Actor with MDCContextAware { else if(action == 16) { //max deployment log.info(s"GenericObject: $player has released the anchors") player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 19, 0)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 19, 0)) definition match { case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster => val tool = toolOpt.get @@ -5416,24 +5364,24 @@ class WorldSessionActor extends Actor with MDCContextAware { if(squadUI.nonEmpty) { if(!lfsm && squadUI(player.CharId).index == 0) { lfsm = true - avatarService ! AvatarServiceMessage(s"${continent.Id}/${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 53, 1)) + continent.AvatarEvents ! AvatarServiceMessage(s"${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 53, 1)) } } else if(!avatar.LFS) { avatar.LFS = true - avatarService ! AvatarServiceMessage(s"${continent.Id}/${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 53, 1)) + continent.AvatarEvents ! AvatarServiceMessage(s"${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 53, 1)) } } else if(action == 37) { //Looking For Squad OFF if(squadUI.nonEmpty) { if(lfsm && squadUI(player.CharId).index == 0) { lfsm = false - avatarService ! AvatarServiceMessage(s"${continent.Id}/${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 53, 0)) + continent.AvatarEvents ! AvatarServiceMessage(s"${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 53, 0)) } } else if(avatar.LFS) { avatar.LFS = false - avatarService ! AvatarServiceMessage(s"${continent.Id}/${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 53, 0)) + continent.AvatarEvents ! AvatarServiceMessage(s"${player.Faction}", AvatarAction.PlanetsideAttribute(player.GUID, 53, 0)) } } @@ -5500,7 +5448,7 @@ class WorldSessionActor extends Actor with MDCContextAware { log.info("WeaponDryFireMessage: "+msg) FindWeapon match { case Some(tool : Tool) => - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.WeaponDryFire(player.GUID, weapon_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.WeaponDryFire(player.GUID, weapon_guid)) case _ => ; } @@ -5730,8 +5678,8 @@ class WorldSessionActor extends Actor with MDCContextAware { //todo: kick cargo passengers out. To be added after PR #216 is merged obj match { case v : Vehicle if bailType == BailType.Bailed && seat_num == 0 && v.Flying => - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(obj), continent)) - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(obj, continent, Some(0 seconds))) // Immediately deconstruct vehicle + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(obj), continent)) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(obj, continent, Some(0 seconds))) // Immediately deconstruct vehicle case _ => ; } @@ -5819,7 +5767,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case Some(allow) => val group = AccessPermissionGroup(attribute_type - 10) log.info(s"Vehicle attributes: vehicle ${vehicle.GUID} access permission $group changed to $allow") - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SeatPermissions(player.GUID, vehicle.GUID, attribute_type, attribute_value)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.SeatPermissions(player.GUID, vehicle.GUID, attribute_type, attribute_value)) //kick players who should not be seated in the vehicle due to permission changes if(allow == VehicleLockState.Locked) { //TODO only important permission atm vehicle.Definition.MountPoints.values.foreach(mountpoint_num => { @@ -5830,7 +5778,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(vehicle.SeatPermissionGroup(mountpoint_num).contains(group) && tplayer != player) { //can not kick self seat.Occupant = None tplayer.VehicleSeated = None - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(tplayer.GUID, 4, false, object_guid)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(tplayer.GUID, 4, false, object_guid)) } case None => ; // No player seated } @@ -6015,7 +5963,7 @@ class WorldSessionActor extends Actor with MDCContextAware { private val localIndex = index private val localObject = obj private val localAnnounce = self - private val localService = avatarService + private val localService = continent.AvatarEvents override def isComplete : Task.Resolution.Value = { if(localTarget.Slot(localIndex).Equipment.contains(localObject)) { @@ -6164,7 +6112,7 @@ class WorldSessionActor extends Actor with MDCContextAware { private val localPad = pad.Actor private val localSession : String = sessionId.toString private val localPlayer = player - private val localVehicleService = vehicleService + private val localVehicleService = continent.VehicleEvents private val localZone = continent override def isComplete : Task.Resolution.Value = { @@ -6310,7 +6258,7 @@ class WorldSessionActor extends Actor with MDCContextAware { private val localObject = obj private val localObjectGUID = obj.GUID private val localAnnounce = self //self may not be the same when it executes - private val localService = avatarService + private val localService = continent.AvatarEvents private val localContinent = continent.Id override def isComplete : Task.Resolution.Value = { @@ -6376,7 +6324,7 @@ class WorldSessionActor extends Actor with MDCContextAware { private val localPlayer = player private val localSlot = index private val localAnnounce = self - private val localService = avatarService + private val localService = continent.AvatarEvents override def isComplete : Task.Resolution.Value = { if(localPlayer.DrawnSlot == localSlot) { @@ -6514,12 +6462,12 @@ class WorldSessionActor extends Actor with MDCContextAware { import scala.concurrent.ExecutionContext.Implicits.global ask(target.Actor, CommonMessages.Hack(player))(1 second).mapTo[Boolean].onComplete { case Success(_) => - localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerSound(player.GUID, target.HackSound, player.Position, 30, 0.49803925f)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.TriggerSound(player.GUID, target.HackSound, player.Position, 30, 0.49803925f)) target match { case term: CaptureTerminal => val isResecured = player.Faction == target.Faction - localService ! LocalServiceMessage(continent.Id, LocalAction.HackCaptureTerminal(player.GUID, continent, term, unk, 8L, isResecured)) - case _ => localService ! LocalServiceMessage(continent.Id, LocalAction.HackTemporarily(player.GUID, continent, target, unk, target.HackEffectDuration(GetPlayerHackLevel()))) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.HackCaptureTerminal(player.GUID, continent, term, unk, 8L, isResecured)) + case _ => continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.HackTemporarily(player.GUID, continent, target, unk, target.HackEffectDuration(GetPlayerHackLevel()))) } case scala.util.Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}") } @@ -6559,7 +6507,7 @@ class WorldSessionActor extends Actor with MDCContextAware { seat.Occupant = None tplayer.VehicleSeated = None if(tplayer.HasGUID) { - vehicleService ! VehicleServiceMessage(tplayer.Continent, VehicleAction.KickPassenger(tplayer.GUID, 4, unk2 = false, target.GUID)) + continent.VehicleEvents ! VehicleServiceMessage(tplayer.Continent, VehicleAction.KickPassenger(tplayer.GUID, 4, unk2 = false, target.GUID)) } case None => ; } @@ -6568,8 +6516,8 @@ class WorldSessionActor extends Actor with MDCContextAware { // If the vehicle can fly and is flying deconstruct it, and well played to whomever managed to hack a plane in mid air. I'm impressed. if(target.Definition.CanFly && target.Flying) { // todo: Should this force the vehicle to land in the same way as when a pilot bails with passengers on board? - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), continent)) - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, continent, Some(0 seconds))) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), continent)) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, continent, Some(0 seconds))) } else { // Otherwise handle ownership transfer as normal // Remove ownership of our current vehicle, if we have one player.VehicleOwned match { @@ -6601,10 +6549,10 @@ class WorldSessionActor extends Actor with MDCContextAware { // And broadcast the faction change to other clients sendResponse(SetEmpireMessage(target.GUID, player.Faction)) - avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.SetEmpire(player.GUID, target.GUID, player.Faction)) + continent.AvatarEvents ! AvatarServiceMessage(player.Continent, AvatarAction.SetEmpire(player.GUID, target.GUID, player.Faction)) } - localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerSound(player.GUID, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.TriggerSound(player.GUID, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)) // Clean up after specific vehicles, e.g. remove router telepads // If AMS is deployed, swap it to the new faction @@ -6614,7 +6562,7 @@ class WorldSessionActor extends Actor with MDCContextAware { RemoveTelepads(target) case GlobalDefinitions.ams if(target.DeploymentState == DriveState.Deployed) => - vehicleService ! VehicleServiceMessage.AMSDeploymentChange(continent) + continent.VehicleEvents ! VehicleServiceMessage.AMSDeploymentChange(continent) case _ => ; } } @@ -6625,7 +6573,7 @@ class WorldSessionActor extends Actor with MDCContextAware { * @param lock the `IFFLock` object that has been resecured */ private def FinishResecuringIFFLock(lock: IFFLock)() : Unit = { - localService ! LocalServiceMessage(continent.Id, LocalAction.ClearTemporaryHack(player.GUID, lock)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.ClearTemporaryHack(player.GUID, lock)) } /** @@ -6644,8 +6592,8 @@ class WorldSessionActor extends Actor with MDCContextAware { private def FinishUpgradingMannedTurret(target : FacilityTurret, upgrade : TurretUpgrade.Value) : Unit = { log.info(s"Converting manned wall turret weapon to $upgrade") - vehicleService ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), continent)) - vehicleService ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, continent, upgrade)) + continent.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), continent)) + continent.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, continent, upgrade)) } /** @@ -6699,7 +6647,7 @@ class WorldSessionActor extends Actor with MDCContextAware { tplayer.VehicleOwned = vehicle.GUID vehicle.AssignOwnership(playerOpt) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.Ownership(player.GUID, vehicle.GUID)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.Ownership(player.GUID, vehicle.GUID)) ReloadVehicleAccessPermissions(vehicle) Some(vehicle) case None => @@ -6745,13 +6693,13 @@ class WorldSessionActor extends Actor with MDCContextAware { val pguid = tplayer.GUID if(vehicle.Owner.contains(pguid)) { vehicle.AssignOwnership(None) - val factionOnContinent = s"${continent.Id}/${vehicle.Faction}" - vehicleService ! VehicleServiceMessage(factionOnContinent, VehicleAction.Ownership(pguid, PlanetSideGUID(0))) + val factionChannel = s"${vehicle.Faction}" + continent.VehicleEvents ! VehicleServiceMessage(factionChannel, VehicleAction.Ownership(pguid, PlanetSideGUID(0))) val vguid = vehicle.GUID val empire = VehicleLockState.Empire.id (0 to 2).foreach(group => { vehicle.PermissionGroup(group, empire) - vehicleService ! VehicleServiceMessage(factionOnContinent, VehicleAction.SeatPermissions(pguid, vguid, group, empire)) + continent.VehicleEvents ! VehicleServiceMessage(factionChannel, VehicleAction.SeatPermissions(pguid, vguid, group, empire)) }) ReloadVehicleAccessPermissions(vehicle) Some(vehicle) @@ -6796,7 +6744,7 @@ class WorldSessionActor extends Actor with MDCContextAware { * @param vehicle the vehicle */ def AccessContents(vehicle : Vehicle) : Unit = { - vehicleService ! Service.Join(s"${vehicle.Actor}") + continent.VehicleEvents ! Service.Join(s"${vehicle.Actor}") val parent_guid = vehicle.GUID vehicle.Trunk.Items.foreach(entry => { val obj = entry.obj @@ -6819,7 +6767,7 @@ class WorldSessionActor extends Actor with MDCContextAware { * @param vehicle the vehicle */ def UnAccessContents(vehicle : Vehicle) : Unit = { - vehicleService ! Service.Leave(Some(s"${vehicle.Actor}")) + continent.VehicleEvents ! Service.Leave(Some(s"${vehicle.Actor}")) vehicle.Trunk.Items.foreach(entry =>{ sendResponse(ObjectDeleteMessage(entry.obj.GUID, 0)) }) @@ -7036,7 +6984,7 @@ class WorldSessionActor extends Actor with MDCContextAware { private def DeleteEquipmentFromVehicle(obj : Vehicle)(start : Int, item : Equipment) : Unit = { val item_guid = item.GUID DeleteEquipment(obj)(start, item) - vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player.GUID, item_guid)) + continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player.GUID, item_guid)) } /** @@ -7063,7 +7011,7 @@ class WorldSessionActor extends Actor with MDCContextAware { */ private def ModifyAmmunitionInVehicle(obj : Vehicle)(box : AmmoBox, reloadValue : Int) : Unit = { val capacity = ModifyAmmunition(obj)(box, reloadValue) - vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.InventoryState(player.GUID, box, obj.GUID, obj.Find(box).get, box.Definition.Packet.DetailedConstructorData(box).get)) + continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.InventoryState(player.GUID, box, obj.GUID, obj.Find(box).get, box.Definition.Packet.DetailedConstructorData(box).get)) } /** @@ -7089,7 +7037,7 @@ class WorldSessionActor extends Actor with MDCContextAware { */ def StowEquipmentInVehicles(obj : Vehicle)(index : Int, item : AmmoBox) : Unit = { StowEquipment(obj)(index, item) - vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player.GUID, obj.GUID, index, item)) + continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player.GUID, obj.GUID, index, item)) } /** @@ -7121,7 +7069,7 @@ class WorldSessionActor extends Actor with MDCContextAware { def StowNewEquipmentInVehicle(obj : Vehicle)(index : Int, item : Equipment) : TaskResolver.GiveTask = { TaskResolver.GiveTask( new Task() { - private val localService = vehicleService + private val localService = continent.VehicleEvents private val localPlayer = player private val localVehicle = obj private val localIndex = index @@ -7179,10 +7127,10 @@ class WorldSessionActor extends Actor with MDCContextAware { indexSlot.Equipment = None source match { case obj : Vehicle => - vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item_guid)) + continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item_guid)) case obj : Player => if(obj.isBackpack || source.VisibleSlots.contains(index)) { //corpse being looted, or item was in hands - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, item_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, item_guid)) } case _ => ; } @@ -7201,10 +7149,10 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(ObjectDetachMessage(destination_guid, item2_guid, Vector3.Zero, 0f)) destination match { case obj : Vehicle => - vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item2_guid)) + continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item2_guid)) case obj : Player => if(obj.isBackpack || destination.VisibleSlots.contains(dest)) { //corpse being looted, or item was accessible - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, item2_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, item2_guid)) //put hand down locally if(dest == player.DrawnSlot) { player.DrawnSlot = Player.HandsDownSlot @@ -7230,14 +7178,14 @@ class WorldSessionActor extends Actor with MDCContextAware { source match { case obj : Vehicle => item2.Faction = PlanetSideEmpire.NEUTRAL - vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player_guid, source_guid, index, item2)) + continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player_guid, source_guid, index, item2)) case obj : Player => item2.Faction = obj.Faction if(source.VisibleSlots.contains(index)) { //item is put in hands - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(player_guid, source_guid, index, item2)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(player_guid, source_guid, index, item2)) } else if(obj.isBackpack) { //corpse being given item - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.StowEquipment(player_guid, source_guid, index, item2)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.StowEquipment(player_guid, source_guid, index, item2)) } case _ => item2.Faction = PlanetSideEmpire.NEUTRAL @@ -7253,11 +7201,11 @@ class WorldSessionActor extends Actor with MDCContextAware { val objDef = item2.Definition destination match { case obj : Vehicle => - vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item2_guid)) + continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.UnstowEquipment(player_guid, item2_guid)) case _ => ; //Player does not require special case; the act of dropping forces the item and icon to change } - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.DropItem(player_guid, item2, continent)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.DropItem(player_guid, item2, continent)) } case None => ; @@ -7281,15 +7229,15 @@ class WorldSessionActor extends Actor with MDCContextAware { destination match { case obj : Vehicle => item.Faction = PlanetSideEmpire.NEUTRAL - vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player_guid, destination_guid, dest, item)) + continent.VehicleEvents ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.StowEquipment(player_guid, destination_guid, dest, item)) case obj : Player => if(destination.VisibleSlots.contains(dest)) { //item is put in hands item.Faction = obj.Faction - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(player_guid, destination_guid, dest, item)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(player_guid, destination_guid, dest, item)) } else if(obj.isBackpack) { //corpse being given item item.Faction = PlanetSideEmpire.NEUTRAL - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.StowEquipment(player_guid, destination_guid, dest, item)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.StowEquipment(player_guid, destination_guid, dest, item)) } case _ => item.Faction = PlanetSideEmpire.NEUTRAL @@ -7361,7 +7309,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val box_guid = box.GUID val tool_guid = tool.GUID sendResponse(ChangeAmmoMessage(tool_guid, box.Capacity)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeAmmo(player.GUID, tool_guid, ammoSlotIndex,previous_box_guid, boxDef.ObjectId, box.GUID, boxDef.Packet.ConstructorData(box).get)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeAmmo(player.GUID, tool_guid, ammoSlotIndex,previous_box_guid, boxDef.ObjectId, box.GUID, boxDef.Packet.ConstructorData(box).get)) //handle inventory contents box.Capacity = (if(sumReloadValue <= fullMagazine) { @@ -7409,9 +7357,9 @@ class WorldSessionActor extends Actor with MDCContextAware { case Some(index) => stowFunc(index, previousBox) case None => - NormalItemDrop(player, continent, avatarService)(previousBox) + NormalItemDrop(player, continent, continent.AvatarEvents)(previousBox) } - val dropFunc : (Equipment)=>TaskResolver.GiveTask = NewItemDrop(player, continent, avatarService) + val dropFunc : (Equipment)=>TaskResolver.GiveTask = NewItemDrop(player, continent, continent.AvatarEvents) AmmoBox.Split(previousBox) match { case Nil | _ :: Nil => ; //done (the former case is technically not possible) case _ :: xs => @@ -7577,10 +7525,10 @@ class WorldSessionActor extends Actor with MDCContextAware { if(vehicle.Definition == GlobalDefinitions.ams) { state match { case DriveState.Deployed => - vehicleService ! VehicleServiceMessage.AMSDeploymentChange(continent) + continent.VehicleEvents ! VehicleServiceMessage.AMSDeploymentChange(continent) sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 81, 1)) case DriveState.Undeploying => - vehicleService ! VehicleServiceMessage.AMSDeploymentChange(continent) + continent.VehicleEvents ! VehicleServiceMessage.AMSDeploymentChange(continent) sendResponse(PlanetsideAttributeMessage(vehicle.GUID, 81, 0)) case DriveState.Mobile | DriveState.State7 => case _ => ; @@ -7602,8 +7550,8 @@ class WorldSessionActor extends Actor with MDCContextAware { antChargingTick.cancel() // Stop charging NTU if charging } - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 0L)) // panel glow off - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 49, 0L)) // orb particles off + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 52, 0L)) // panel glow off + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(vehicle.GUID, 49, 0L)) // orb particles off case DriveState.Mobile | DriveState.State7 | DriveState.Deploying => case _ => ; } @@ -7620,7 +7568,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } case DriveState.Deployed => //let the timer do all the work - localService ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), vehicle, TelepadLike.AppraiseTeleportationSystem(vehicle, continent))) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), vehicle, TelepadLike.AppraiseTeleportationSystem(vehicle, continent))) case DriveState.Undeploying => //deactivate internal router before trying to reset the system vehicle.Utility(UtilityType.internal_router_telepad_deployable) match { @@ -7628,12 +7576,12 @@ class WorldSessionActor extends Actor with MDCContextAware { //any telepads linked with internal mechanism must be deconstructed continent.GUID(util.Telepad) match { case Some(telepad : TelepadDeployable) => - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, continent, Some(0 milliseconds))) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, continent, Some(0 milliseconds))) case Some(_) | None => ; } util.Active = false - localService ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), vehicle, None)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), vehicle, None)) case _ => log.warn(s"DeploymentActivities: could not find internal telepad in router@${vehicle.GUID.guid} while $state") } @@ -7654,7 +7602,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val mobileShift : String = if(obj.DeploymentState != DriveState.Mobile) { obj.DeploymentState = DriveState.Mobile sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, false, Vector3.Zero)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, obj.GUID, DriveState.Mobile, 0, false, Vector3.Zero)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.DeployRequest(player.GUID, obj.GUID, DriveState.Mobile, 0, false, Vector3.Zero)) "; enforcing Mobile deployment state" } else { @@ -7858,7 +7806,7 @@ class WorldSessionActor extends Actor with MDCContextAware { timeSurge = 0 sendResponse(PlanetsideAttributeMessage(player_guid, 0, 0)) sendResponse(PlanetsideAttributeMessage(player_guid, 2, 0)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0)) sendResponse(DestroyMessage(player_guid, player_guid, PlanetSideGUID(0), pos)) //how many players get this message? sendResponse(AvatarDeadStateMessage(DeadState.Dead, respawnTimer, respawnTimer, pos, player.Faction, true)) if(tplayer.VehicleSeated.nonEmpty) { @@ -7870,7 +7818,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } //make player invisible (if not, the cadaver sticks out the side in a seated position) sendResponse(PlanetsideAttributeMessage(player_guid, 29, 1)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 29, 1)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 29, 1)) } PlayerActionsToCancel() //TODO other methods of death? @@ -7893,9 +7841,9 @@ class WorldSessionActor extends Actor with MDCContextAware { }) match { case Some(shot) => continent.Activity ! Zone.HotSpot.Activity(pentry, shot.projectile.owner, shot.hit_pos) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.DestroyDisplay(shot.projectile.owner, pentry, shot.projectile.attribute_to)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.DestroyDisplay(shot.projectile.owner, pentry, shot.projectile.attribute_to)) case None => - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.DestroyDisplay(pentry, pentry, 0)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.DestroyDisplay(pentry, pentry, 0)) } if(shotsWhileDead > 0) { log.warn(s"KillPlayer/SHOTS_WHILE_DEAD: client of ${avatar.name} fired $shotsWhileDead rounds while character was dead on server") @@ -7936,7 +7884,7 @@ class WorldSessionActor extends Actor with MDCContextAware { shooting match { case Some(guid) => sendResponse(ChangeFireStateMessage_Stop(guid)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, guid)) prefire = None shooting = None case None => ; @@ -8007,7 +7955,7 @@ class WorldSessionActor extends Actor with MDCContextAware { .collect { case hold if hold.isOccupied => hold.Occupant.get } .foreach { _.MountedIn = guid } continent.Transport ! Zone.Vehicle.Spawn(vehicle) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.LoadVehicle(player.GUID, vehicle, vdef.ObjectId, guid, data)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.LoadVehicle(player.GUID, vehicle, vdef.ObjectId, guid, data)) carrierInfo match { case (Some(carrier), Some((index, _))) => CargoMountBehaviorForOthers(carrier, vehicle, index) @@ -8034,7 +7982,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val data = packet.DetailedConstructorData(player).get val guid = player.GUID sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, guid, data)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.LoadPlayer(guid, ObjectClass.avatar, guid, packet.ConstructorData(player).get, None)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.LoadPlayer(guid, ObjectClass.avatar, guid, packet.ConstructorData(player).get, None)) //log.info(s"AvatarCreate: $guid -> $data") log.trace(s"AvatarCreate: ${player.Name}") } @@ -8129,7 +8077,7 @@ class WorldSessionActor extends Actor with MDCContextAware { data ) ) - avatarService ! AvatarServiceMessage(vehicle.Continent, AvatarAction.LoadPlayer(guid, pdef.ObjectId, guid, pdef.Packet.ConstructorData(player).get, Some(parent))) + continent.AvatarEvents ! AvatarServiceMessage(vehicle.Continent, AvatarAction.LoadPlayer(guid, pdef.ObjectId, guid, pdef.Packet.ConstructorData(player).get, Some(parent))) AccessContents(vehicle) UpdateWeaponAtSeatPosition(vehicle, seat) //log.info(s"AvatarCreateInVehicle: $guid -> $data") @@ -8187,12 +8135,12 @@ class WorldSessionActor extends Actor with MDCContextAware { continent.GUID(boomer) match { case Some(obj : BoomerDeployable) => obj.OwnerName = None - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent)) case Some(_) | None => ; } }) val triggers = RemoveBoomerTriggersFromInventory() - triggers.foreach(trigger => { NormalItemDrop(obj, continent, avatarService)(trigger) }) + triggers.foreach(trigger => { NormalItemDrop(obj, continent, continent.AvatarEvents)(trigger) }) } } @@ -8227,7 +8175,7 @@ class WorldSessionActor extends Actor with MDCContextAware { */ def TryDisposeOfLootedCorpse(obj : Player) : Boolean = { if(WellLootedCorpse(obj)) { - avatarService ! AvatarServiceMessage.Corpse(RemoverActor.HurrySpecific(List(obj), continent)) + continent.AvatarEvents ! AvatarServiceMessage.Corpse(RemoverActor.HurrySpecific(List(obj), continent)) true } else { @@ -8303,13 +8251,13 @@ class WorldSessionActor extends Actor with MDCContextAware { */ def StartUsingProximityUnit(terminal : Terminal with ProximityUnit, target : PlanetSideGameObject) : Unit = { val term_guid = terminal.GUID + //log.trace(s"StartUsingProximityUnit: ${player.Name} wants to use ${terminal.Definition.Name}@${term_guid.guid} on $target") if(player.isAlive) { - log.info(s"StartUsingProximityUnit: ${player.Name} wants to use ${terminal.Definition.Name}@${term_guid.guid} on $target") target match { case _ : Player => terminal.Actor ! CommonMessages.Use(player, Some(target)) case _ : Vehicle => - terminal.Actor ! CommonMessages.Use(player, Some((target, vehicleService))) + terminal.Actor ! CommonMessages.Use(player, Some((target, continent.VehicleEvents))) case _ => log.error(s"StartUsingProximityUnit: can not deal with target $target") } @@ -8344,7 +8292,7 @@ class WorldSessionActor extends Actor with MDCContextAware { */ def StopUsingProximityUnit(terminal : Terminal with ProximityUnit) : Unit = { val term_guid = terminal.GUID - log.info(s"StopUsingProximityUnit: attempting to stop using proximity unit ${terminal.Definition.Name}@${term_guid.guid}") + //log.trace(s"StopUsingProximityUnit: attempting to stop using proximity unit ${terminal.Definition.Name}@${term_guid.guid}") val targets = FindProximityUnitTargetsInScope(terminal) if(targets.nonEmpty) { if(usingMedicalTerminal.contains(term_guid)) { @@ -8427,7 +8375,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val player_guid = tplayer.GUID tplayer.Health = tplayer.Health + healValue sendResponse(PlanetsideAttributeMessage(player_guid, 0, tplayer.Health)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, tplayer.Health)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, tplayer.Health)) tplayer.Health == tplayer.MaxHealth } @@ -8443,7 +8391,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val player_guid = tplayer.GUID tplayer.Armor = tplayer.Armor + repairValue sendResponse(PlanetsideAttributeMessage(player_guid, 4, tplayer.Armor)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 4, tplayer.Armor)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 4, tplayer.Armor)) tplayer.Armor == tplayer.MaxArmor } @@ -8610,7 +8558,7 @@ class WorldSessionActor extends Actor with MDCContextAware { PlayerActionsToCancel() log.info(s"MountVehicleMsg: $player_guid mounts $obj @ $seatNum") sendResponse(ObjectAttachMessage(obj_guid, player_guid, seatNum)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.MountVehicle(player_guid, obj_guid, seatNum)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.MountVehicle(player_guid, obj_guid, seatNum)) } /** @@ -8623,7 +8571,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val player_guid : PlanetSideGUID = tplayer.GUID log.info(s"DismountVehicleMsg: ${tplayer.Name} dismounts $obj from $seatNum") sendResponse(DismountVehicleMsg(player_guid, BailType.Normal, false)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, BailType.Normal, false)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, BailType.Normal, false)) } /** @@ -8641,13 +8589,13 @@ class WorldSessionActor extends Actor with MDCContextAware { target match { case obj : Player => //damage is synchronized on the target player's `WSA` (results distributed from there) - avatarService ! AvatarServiceMessage(obj.Name, AvatarAction.Damage(player.GUID, obj, func)) + continent.AvatarEvents ! AvatarServiceMessage(obj.Name, AvatarAction.Damage(player.GUID, obj, func)) case obj : Vehicle => //damage is synchronized on the vehicle actor (results returned to and distributed from this `WSA`) obj.Actor ! Vitality.Damage(func) case obj : Deployable => //damage is synchronized on `LSA` (results returned to and distributed from this `WSA`) - localService ! Vitality.DamageOn(obj, func) + continent.LocalEvents ! Vitality.DamageOn(obj, func) case obj : FacilityTurret => //damage is synchronized on the turret actor (results returned to and distributed from this `WSA`) obj.Actor ! Vitality.Damage(func) @@ -8912,12 +8860,12 @@ class WorldSessionActor extends Actor with MDCContextAware { removed match { case Some(telepad : TelepadDeployable) => telepad.AssignOwnership(None) - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, continent, Some(0 seconds))) //normal decay + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, continent, Some(0 seconds))) //normal decay case Some(old) => old.AssignOwnership(None) - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(old), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(old, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(old), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(old, continent, Some(0 seconds))) if(msg) { //max test sendResponse(ChatMsg(ChatMessageType.UNK_229, false, "", s"@${definition.Descriptor}OldestDestroyed", None)) } @@ -8940,11 +8888,11 @@ class WorldSessionActor extends Actor with MDCContextAware { UpdateDeployableUIElements(avatar.Deployables.UpdateUIElement(item)) sendResponse(GenericObjectActionMessage(guid, 84)) //reset build cooldown sendResponse(ObjectCreateMessage(definition.ObjectId, guid, definition.Packet.ConstructorData(obj).get)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.DeployItem(player.GUID, obj)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.DeployItem(player.GUID, obj)) //map icon val deployInfo = DeployableInfo(guid, Deployable.Icon(item), obj.Position, obj.Owner.getOrElse(PlanetSideGUID(0))) sendResponse(DeployableObjectsInfoMessage(DeploymentAction.Build, deployInfo)) - localService ! LocalServiceMessage(s"${continent.Id}/${player.Faction}", LocalAction.DeployableMapIcon(player.GUID, DeploymentAction.Build, deployInfo)) + continent.LocalEvents ! LocalServiceMessage(s"${player.Faction}", LocalAction.DeployableMapIcon(player.GUID, DeploymentAction.Build, deployInfo)) } /** @@ -9011,7 +8959,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } }) { sendResponse(ObjectDeleteMessage(tool.GUID, 0)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, tool.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, tool.GUID)) true } else { @@ -9057,11 +9005,11 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(ChangeAmmoMessage(obj.GUID, ammoType)) } if(player.VisibleSlots.contains(index)) { - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(guid, guid, index, obj)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.EquipmentInHand(guid, guid, index, obj)) if(player.DrawnSlot == Player.HandsDownSlot) { player.DrawnSlot = index sendResponse(ObjectHeldMessage(guid, index, false)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectHeld(guid, index)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectHeld(guid, index)) } } } @@ -9115,8 +9063,8 @@ class WorldSessionActor extends Actor with MDCContextAware { if(continent.EquipmentOnGround.contains(obj)) { obj.Position = Vector3.Zero continent.Ground ! Zone.Ground.RemoveItem(object_guid) - avatarService ! AvatarServiceMessage.Ground(RemoverActor.ClearSpecific(List(obj), continent)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(PlanetSideGUID(0), object_guid)) + continent.AvatarEvents ! AvatarServiceMessage.Ground(RemoverActor.ClearSpecific(List(obj), continent)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(PlanetSideGUID(0), object_guid)) log.info(s"RequestDestroy: equipment $obj on ground") true } @@ -9199,16 +9147,16 @@ class WorldSessionActor extends Actor with MDCContextAware { target.OwnerName match { case Some(owner) => target.OwnerName = None - localService ! LocalServiceMessage(owner, LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target)) + continent.LocalEvents ! LocalServiceMessage(owner, LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target)) case None => ; } - localService ! LocalServiceMessage(s"${continent.Id}/${target.Faction}", LocalAction.DeployableMapIcon( + continent.LocalEvents ! LocalServiceMessage(s"${target.Faction}", LocalAction.DeployableMapIcon( PlanetSideGUID(0), DeploymentAction.Dismiss, DeployableInfo(target.GUID, Deployable.Icon(target.Definition.Item), target.Position, PlanetSideGUID(0))) ) - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(target), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(target, continent, time)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(target), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(target, continent, time)) } /** @@ -9229,7 +9177,7 @@ class WorldSessionActor extends Actor with MDCContextAware { player.Slot(index).Equipment = None sendResponse(ObjectDeleteMessage(obj.GUID, 0)) if(player.VisibleSlots.contains(index)) { - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, obj.GUID)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, obj.GUID)) } obj }) @@ -9252,12 +9200,12 @@ class WorldSessionActor extends Actor with MDCContextAware { .partition(_.isInstanceOf[BoomerDeployable]) //do not change the OwnerName field at this time boomers.collect({ case obj : BoomerDeployable => - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) //near-instant + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent, Some(0 seconds))) //near-instant obj.Owner = None obj.Trigger = None }) deployables.foreach(obj => { - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent)) //normal decay + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(obj, continent)) //normal decay obj.Owner = None }) boomers ++ deployables @@ -9320,7 +9268,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case _ => //player is deconstructing self val player_guid = player.GUID sendResponse(ObjectDeleteMessage(player_guid, 4)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 4)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 4)) player.Position = pos player.Orientation = ori LoadZoneAsPlayer(player, zone_id) @@ -9439,7 +9387,7 @@ class WorldSessionActor extends Actor with MDCContextAware { val pguid = player.GUID val toChannel = TransportVehicleChannelName(vehicle) //standard passengers - vehicleService ! VehicleServiceMessage(s"${vehicle.Actor}", VehicleAction.TransferPassengerChannel(pguid, s"${vehicle.Actor}", toChannel, vehicle)) + continent.VehicleEvents ! VehicleServiceMessage(s"${vehicle.Actor}", VehicleAction.TransferPassengerChannel(pguid, s"${vehicle.Actor}", toChannel, vehicle)) //cargo val occupiedCargoHolds = vehicle.CargoHolds.values.collect { case hold if hold.isOccupied => @@ -9448,7 +9396,7 @@ class WorldSessionActor extends Actor with MDCContextAware { occupiedCargoHolds.foreach{ cargo => cargo.Seats(0).Occupant match { case Some(occupant) => - vehicleService ! VehicleServiceMessage(s"${occupant.Name}", VehicleAction.TransferPassengerChannel(pguid, s"${cargo.Actor}", toChannel, cargo)) + continent.VehicleEvents ! VehicleServiceMessage(s"${occupant.Name}", VehicleAction.TransferPassengerChannel(pguid, s"${cargo.Actor}", toChannel, cargo)) case _ => log.error("LoadZoneInVehicleAsDriver: abort; vehicle in cargo hold missing driver") HandleDismountVehicleCargo(player.GUID, cargo.GUID, cargo, vehicle.GUID, vehicle, false, false, true) @@ -9468,7 +9416,7 @@ class WorldSessionActor extends Actor with MDCContextAware { interstellarFerryTopLevelGUID = (if(vehicle.Seats.values.count(_.isOccupied) == 1 && occupiedCargoHolds.size == 0) { //do not delete if vehicle has passengers or cargo val vehicleToDelete = interstellarFerryTopLevelGUID.orElse(player.VehicleSeated).getOrElse(PlanetSideGUID(0)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.UnloadVehicle(pguid, continent, vehicle, vehicleToDelete)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.UnloadVehicle(pguid, continent, vehicle, vehicleToDelete)) None } else { @@ -9530,7 +9478,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(NoVehicleOccupantsInZone(vehicle, continentId)) { //do not dispatch delete action if any hierarchical occupant has not gotten this far through the summoning process val vehicleToDelete = interstellarFerryTopLevelGUID.orElse(player.VehicleSeated).getOrElse(PlanetSideGUID(0)) - vehicleService ! VehicleServiceMessage(continentId, VehicleAction.UnloadVehicle(player.GUID, continent, vehicle, vehicleToDelete)) + continent.VehicleEvents ! VehicleServiceMessage(continentId, VehicleAction.UnloadVehicle(player.GUID, continent, vehicle, vehicleToDelete)) } interstellarFerryTopLevelGUID = None //unregister avatar + GiveWorld @@ -9585,14 +9533,14 @@ class WorldSessionActor extends Actor with MDCContextAware { * @param vehicleToDelete the vehicle as it was identified in the zone that it is being moved from */ def LoadZoneTransferPassengerMessages(player_guid : PlanetSideGUID, toZoneId : String, toChannel : String, vehicle : Vehicle, vehicleToDelete : PlanetSideGUID) : Unit = { - vehicleService ! VehicleServiceMessage(toChannel, VehicleAction.TransferPassenger(player_guid, toChannel, vehicle, vehicleToDelete)) + galaxyService ! GalaxyServiceMessage(toChannel, GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, vehicleToDelete)) vehicle.CargoHolds.values .collect { case hold if hold.isOccupied => val cargo = hold.Occupant.get cargo.Continent = toZoneId //point to the cargo vehicle to instigate cargo vehicle driver transportation - vehicleService ! VehicleServiceMessage(toChannel, VehicleAction.TransferPassenger(player_guid, toChannel, cargo, vehicleToDelete)) + galaxyService ! GalaxyServiceMessage(toChannel, GalaxyAction.TransferPassenger(player_guid, toChannel, cargo, vehicleToDelete)) } } @@ -9639,7 +9587,7 @@ class WorldSessionActor extends Actor with MDCContextAware { case None => PlanetSideGUID(0) //item is being introduced into the world upon drop } - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.DropItem(exclusionId, item, continent)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.DropItem(exclusionId, item, continent)) } /** @@ -9667,7 +9615,7 @@ class WorldSessionActor extends Actor with MDCContextAware { definition.Packet.DetailedConstructorData(item).get ) ) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PickupItem(player_guid, continent, player, slotNum, item)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PickupItem(player_guid, continent, player, slotNum, item)) true case None => continent.Ground ! Zone.Ground.DropItem(item, item.Position, item.Orientation) //restore previous state @@ -9776,9 +9724,9 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(PlayerStateShiftMessage(ShiftState(0, dest.Position, player.Orientation.z))) UseRouterTelepadEffect(pguid, sguid, dguid) StopBundlingPackets() - // vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(router), continent)) - // vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(router, continent, router.Definition.DeconstructionTime)) - localService ! LocalServiceMessage(continent.Id, LocalAction.RouterTelepadTransport(pguid, pguid, sguid, dguid)) + // continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(router), continent)) + // continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(router, continent, router.Definition.DeconstructionTime)) + continent.LocalEvents ! LocalServiceMessage(continent.Id, LocalAction.RouterTelepadTransport(pguid, pguid, sguid, dguid)) } else { log.warn(s"UseRouterTelepadSystem: can not teleport") @@ -9807,7 +9755,7 @@ class WorldSessionActor extends Actor with MDCContextAware { vehicle.Definition match { case GlobalDefinitions.ams if vehicle.Faction == player.Faction => log.info("BeforeUnload: cleaning up after a mobile spawn vehicle ...") - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.UpdateAmsSpawnPoint(continent)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.UpdateAmsSpawnPoint(continent)) None case GlobalDefinitions.router => //this may repeat for multiple players on the same continent but that's okay(?) @@ -9829,8 +9777,8 @@ class WorldSessionActor extends Actor with MDCContextAware { case Some(telepad : TelepadDeployable) => log.info(s"BeforeUnload: deconstructing telepad $telepad that was linked to router $vehicle ...") telepad.Active = false - localService ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), continent)) - localService ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, continent, Some(0 seconds))) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.ClearSpecific(List(telepad), continent)) + continent.LocalEvents ! LocalServiceMessage.Deployables(RemoverActor.AddTask(telepad, continent, Some(0 seconds))) case _ => ; } } @@ -9857,9 +9805,9 @@ class WorldSessionActor extends Actor with MDCContextAware { tool.Magazine = 0 sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, weapon_guid, 0)) sendResponse(ChangeFireStateMessage_Stop(weapon_guid)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, weapon_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ChangeFireState_Stop(player.GUID, weapon_guid)) sendResponse(WeaponDryFireMessage(weapon_guid)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.WeaponDryFire(player.GUID, weapon_guid)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.WeaponDryFire(player.GUID, weapon_guid)) } /** @@ -9895,8 +9843,8 @@ class WorldSessionActor extends Actor with MDCContextAware { carrier.Position } StartBundlingPackets() - vehicleService ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health))) - vehicleService ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 68, cargo.Shields))) + continent.VehicleEvents ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health))) + continent.VehicleEvents ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 68, cargo.Shields))) if(carrier.Flying) { //the carrier vehicle is flying; eject the cargo vehicle val ejectCargoMsg = CargoMountPointStatusMessage(carrierGUID, PlanetSideGUID(0), PlanetSideGUID(0), cargoGUID, mountPoint, CargoStatus.InProgress, 0) @@ -9904,15 +9852,15 @@ class WorldSessionActor extends Actor with MDCContextAware { val resetCargoMsg = CargoMountPointStatusMessage(carrierGUID, PlanetSideGUID(0), PlanetSideGUID(0), cargoGUID, mountPoint, CargoStatus.Empty, 0) sendResponse(ejectCargoMsg) //dismount vehicle on UI and disable "shield" effect on lodestar sendResponse(detachCargoMsg) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(player_guid, ejectCargoMsg)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(player_guid, detachCargoMsg)) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(PlanetSideGUID(0), resetCargoMsg)) //lazy + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(player_guid, ejectCargoMsg)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(player_guid, detachCargoMsg)) + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(PlanetSideGUID(0), resetCargoMsg)) //lazy log.debug(ejectCargoMsg.toString) log.debug(detachCargoMsg.toString) if(driverOpt.isEmpty) { //TODO cargo should drop like a rock like normal; until then, deconstruct it - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(cargo), continent)) - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(cargo, continent, Some(0 seconds))) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(cargo), continent)) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(cargo, continent, Some(0 seconds))) } } else { @@ -9921,11 +9869,11 @@ class WorldSessionActor extends Actor with MDCContextAware { val cargoDetachMessage = ObjectDetachMessage(carrierGUID, cargoGUID, cargoHoldPosition + Vector3.z(1f), rotation) sendResponse(cargoStatusMessage) sendResponse(cargoDetachMessage) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player_guid, cargoStatusMessage)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player_guid, cargoDetachMessage)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player_guid, cargoStatusMessage)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.SendResponse(player_guid, cargoDetachMessage)) driverOpt match { case Some(driver) => - vehicleService ! VehicleServiceMessage(s"${driver.Name}", VehicleAction.KickCargo(player_guid, cargo, cargo.Definition.AutoPilotSpeed2, 2500)) + continent.VehicleEvents ! VehicleServiceMessage(s"${driver.Name}", VehicleAction.KickCargo(player_guid, cargo, cargo.Definition.AutoPilotSpeed2, 2500)) import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global @@ -9934,10 +9882,10 @@ class WorldSessionActor extends Actor with MDCContextAware { cargoDismountTimer = context.system.scheduler.scheduleOnce(250 milliseconds, self, CheckCargoDismount(cargoGUID, carrierGUID, mountPoint, iteration = 0)) case None => val resetCargoMsg = CargoMountPointStatusMessage(carrierGUID, PlanetSideGUID(0), PlanetSideGUID(0), cargoGUID, mountPoint, CargoStatus.Empty, 0) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(PlanetSideGUID(0), resetCargoMsg)) //lazy + continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.SendResponse(PlanetSideGUID(0), resetCargoMsg)) //lazy //TODO cargo should back out like normal; until then, deconstruct it - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(cargo), continent)) - vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(cargo, continent, Some(0 seconds))) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(cargo), continent)) + continent.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(cargo, continent, Some(0 seconds))) } } StopBundlingPackets()