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 9dcc5193..054ef0f3 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
@@ -49,97 +49,85 @@ class VehicleSpawnControl(pad : VehicleSpawnPad) extends VehicleSpawnControlBase
trace(s"order from $player for $vehicle received")
orders = orders :+ VehicleSpawnControl.Order(player, vehicle, sender)
if(trackedOrder.isEmpty && orders.length == 1) {
- self ! VehicleSpawnControl.ProcessControl.GetOrder
+ SelectOrder()
}
else {
sender ! VehicleSpawnControl.RenderOrderRemainderMsg(orders.length + 1)
}
- case VehicleSpawnControl.ProcessControl.GetOrder =>
- 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 =>
- (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
- }
-
- case VehicleSpawnControl.ProcessControl.CancelOrder =>
- VehicleSpawnControl.recursiveFindOrder(orders.iterator, sender) match {
- case None => ;
- case Some(index) =>
- val dequeuedOrder = orders(index)
- orders = orders.take(index - 1) ++ orders.drop(index + 1)
- trace(s"${dequeuedOrder.driver}'s vehicle order has been cancelled")
- }
-
case VehicleSpawnControl.ProcessControl.GetNewOrder =>
if(sender == concealPlayer) {
trackedOrder = None //guard off
- self ! VehicleSpawnControl.ProcessControl.GetOrder
+ SelectOrder()
}
+ /*
+ When the vehicle is spawned and added to the pad, it will "occupy" the pad and block it from further action.
+ Normally, the player who wanted to spawn the vehicle will be automatically put into the driver seat.
+ If this is blocked, the vehicle will idle on the pad and must be moved far enough away from the point of origin.
+ During this time, a periodic message about the spawn pad being blocked
+ will be broadcast to all current customers in the order queue.
+ */
case VehicleSpawnControl.ProcessControl.Reminder =>
- /*
- When the vehicle is spawned and added to the pad, it will "occupy" the pad and block it from further action.
- Normally, the player who wanted to spawn the vehicle will be automatically put into the driver seat.
- If this is blocked, the vehicle will idle on the pad and must be moved far enough away from the point of origin.
- During this time, a periodic message about the spawn pad being blocked
- will be broadcast to all current customers in the order queue.
- */
- if(periodicReminder.isCancelled) {
- trace(s"the pad has become blocked by ${trackedOrder.get.vehicle.Definition.Name}")
- periodicReminder = context.system.scheduler.schedule(
- VehicleSpawnControl.initialReminderDelay,
- VehicleSpawnControl.periodicReminderDelay,
- self, VehicleSpawnControl.ProcessControl.Reminder
- )
- }
- else {
- VehicleSpawnControl.BlockedReminder(trackedOrder, trackedOrder.get +: orders)
+ trackedOrder match {
+ case Some(entry) =>
+ if(periodicReminder.isCancelled) {
+ trace (s"the pad has become blocked by ${entry.vehicle.Definition.Name}")
+ periodicReminder = context.system.scheduler.schedule(
+ VehicleSpawnControl.initialReminderDelay,
+ VehicleSpawnControl.periodicReminderDelay,
+ self, VehicleSpawnControl.ProcessControl.Reminder
+ )
+ }
+ else {
+ VehicleSpawnControl.BlockedReminder(entry, entry +: orders)
+ }
+ case None => ;
+ periodicReminder.cancel
}
case _ => ;
}
+
+ def SelectOrder() : Unit = {
+ 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 =>
+ (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
+ }
+ }
}
object VehicleSpawnControl {
private final val initialReminderDelay : FiniteDuration = 10000 milliseconds
private final val periodicReminderDelay : FiniteDuration = 10000 milliseconds
- /**
- * A `TaskResolver` to assist with the deconstruction of vehicles.
- * Treated like a `lazy val`, this only gets defined once and then keeps getting reused.
- * Since the use case is "if something goes wrong," a limited implementation should be fine.
- */
- private var emergencyResolver : Option[ActorRef] = None
-
/**
* An `Enumeration` of non-data control messages for the vehicle spawn process.
*/
object ProcessControl extends Enumeration {
val
Reminder,
- GetOrder,
- GetNewOrder,
- CancelOrder
+ GetNewOrder
= Value
}
/**
@@ -170,23 +158,46 @@ object VehicleSpawnControl {
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.
- * @see `VehicleSpawnControl.emergencyResolver`
+ * 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 net.psforever.objects.guid.GUIDTask
- emergencyResolver.getOrElse({
- import akka.routing.SmallestMailboxPool
- import net.psforever.objects.guid.TaskResolver
- val resolver = context.actorOf(SmallestMailboxPool(10).props(Props[TaskResolver]), "vehicle-spawn-control-emergency-decon-resolver")
- emergencyResolver = Some(resolver)
- resolver
- }) ! GUIDTask.UnregisterVehicle(entry.vehicle)(zone.GUID)
+ 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))
+ )
}
+
/**
* Properly clean up a vehicle that has been registered and spawned into the game world.
* @param entry the order being cancelled
@@ -204,7 +215,7 @@ object VehicleSpawnControl {
* @return an index-appropriate `VehicleSpawnPad.PeriodicReminder` object
*/
def RenderOrderRemainderMsg(position : Int) : VehicleSpawnPad.PeriodicReminder = {
- VehicleSpawnPad.PeriodicReminder(s"Your position in the vehicle spawn queue is $position.")
+ VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"$position"))
}
/**
@@ -212,42 +223,38 @@ object VehicleSpawnControl {
* @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 : Option[VehicleSpawnControl.Order], recipients : Seq[VehicleSpawnControl.Order]) : Unit = {
- blockedOrder match {
- case Some(entry) =>
- val msg : String = if(entry.vehicle.Health == 0) {
- "The vehicle spawn where you placed your order is blocked by wreckage."
- }
- else {
- "The vehicle spawn where you placed your order is blocked."
- }
- VehicleSpawnControl.recursiveBlockedReminder(recipients.iterator, msg)
- case None => ;
- }
- }
-
- @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)
+ def BlockedReminder(blockedOrder : VehicleSpawnControl.Order, recipients : Seq[VehicleSpawnControl.Order]) : Unit = {
+ val wrecked : Option[Any] = if(blockedOrder.vehicle.Health == 0) {
+ Option("Clear the wreckage.")
}
else {
- recursiveFindOrder(iter, target, index + 1)
+ None
}
- }
+ VehicleSpawnControl.recursiveBlockedReminder(recipients.iterator, wrecked)
}
- @tailrec private final def recursiveBlockedReminder(iter : Iterator[VehicleSpawnControl.Order], msg : String) : Unit = {
+// @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
if(recipient.sendTo != ActorRef.noSender) {
- recipient.sendTo ! VehicleSpawnPad.PeriodicReminder(msg)
+ recipient.sendTo ! VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, cause)
}
- recursiveBlockedReminder(iter, msg)
+ recursiveBlockedReminder(iter, cause)
}
}
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 46e8f891..9a4c1abe 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
@@ -18,13 +18,12 @@ import net.psforever.packet.game.PlanetSideGUID
*/
class VehicleSpawnPad(spDef : VehicleSpawnPadDefinition) extends Amenity {
/**
- * USE THIS BOOLEAN FOR DEVELOPMENT PURPOSES!
- * Purpose: use the ingame railed platform to lift the spawned vehicle out of the trench.
- * When set, the client performs the standard vehicle entry procedure, including rail animations.
+ * 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.
- * The main reason to disable this feature is to avoid an `ObjectAttachMessage` that may be dispatched for an incorrect object.
- * Unset if not guaranteed to have the correct ingame globally unique id of the spawn pad.
+ * 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
@@ -41,7 +40,7 @@ class VehicleSpawnPad(spDef : VehicleSpawnPadDefinition) extends Amenity {
object VehicleSpawnPad {
/**
- * Communicate to the spawn pad that it should enqueue the following vehicle.
+ * Message to the spawn pad to enqueue the following vehicle order.
* This is the entry point to vehicle spawn pad functionality.
* @param player the player who submitted the order (the "owner")
* @param vehicle the vehicle produced from the order
@@ -49,53 +48,115 @@ object VehicleSpawnPad {
final case class VehicleOrder(player : Player, vehicle : Vehicle)
/**
- * The first callback step in spawning the vehicle.
- * An packet `GenericObjectActionMessage(/player/, 36)`, when used on a player character,
- * will cause that player character's model to fade into transparency.
+ * 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)
/**
- * Undoes the above message.
+ * 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)
/**
- * A callback step in spawning the vehicle.
- * The vehicle is properly introduced into the game world.
- * If information about the vehicle itself that is important to its spawning has not yet been set,
- * this callback is the last ideal situation to set that properties without having to adjust the vehicle visually.
- * The primary operation that should occur is a content-appropriate `ObjectCreateMessage` packet and
- * having the player sit down in the driver's seat (seat 0) of the vehicle.
+ * 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)
+ /**
+ * Message to attach the vehicle to the spawn pad's lifting platform ("put on rails").
+ * The attachment process (to the third slot) itself begins autonomous operation of the lifting platform.
+ * @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)
+ /**
+ * 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)
+ /**
+ * 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)
+
+ /**
+ * 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 vehicle the vehicle being spawned
+ * @param pad the spawn pad
+ */
final case class StartPlayerSeatedInVehicle(vehicle : Vehicle, pad : VehicleSpawnPad)
/**
- * A TEMPORARY callback step in spawning the vehicle.
- * From a state of transparency, while the vehicle is attached to the lifting platform of the spawn pad,
- * the player designated the "owner" by callback is made to sit in the driver's seat (always seat 0).
- * This message is the next step after that.
+ * 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 vehicle the vehicle being spawned
+ * @param pad the spawn pad
*/
final case class PlayerSeatedInVehicle(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 vehicle the vehicle
+ * @param pad the spawn pad
+ */
final case class ServerVehicleOverrideStart(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 vehicle the vehicle
+ * @param pad the spawn pad
+ */
final case class ServerVehicleOverrideEnd(vehicle : Vehicle, pad : VehicleSpawnPad)
- final case class ResetSpawnPad(pad : VehicleSpawnPad, zone_id : String)
-
- final case class PeriodicReminder(msg : String)
-
+ /**
+ * 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)
+ /**
+ * Message to send targeted messages to the clients of specific users.
+ * @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)
+
+ /**
+ * An `Enumeration` of reasons for sending a periodic reminder to the user.
+ */
+ object Reminders extends Enumeration {
+ val
+ Queue, //optional data is the numeric position in the queue
+ Blocked //optional data is a message regarding the blockage
+ = Value
+ }
+
/**
* Overloaded constructor.
* @param spDef the spawn pad's definition entry
@@ -109,7 +170,7 @@ object VehicleSpawnPad {
import net.psforever.types.Vector3
/**
- * Instantiate an configure a `VehicleSpawnPad` object
+ * Instantiate and configure a `VehicleSpawnPad` object
* @param pos the position (used to determine spawn point)
* @param orient the orientation (used to indicate spawn direction)
* @param id the unique id that will be assigned to this entity
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 5c356c06..a7c3f59d 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
@@ -27,7 +27,7 @@ class VehicleSpawnControlConcealPlayer(pad : VehicleSpawnPad) extends VehicleSpa
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.isAlive && driver.Continent == Continent.Id && driver.VehicleSeated.isEmpty) {
+ if(entry.sendTo != ActorRef.noSender && driver.Continent == Continent.Id && 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))
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 5ee0d14b..e278f51f 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
@@ -23,7 +23,7 @@ import scala.concurrent.duration._
class VehicleSpawnControlLoadVehicle(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
def LogId = "-loader"
- val seatDriver = context.actorOf(Props(classOf[VehicleSpawnControlSeatDriver], pad), s"${context.parent.path.name}-seat")
+ val railJack = context.actorOf(Props(classOf[VehicleSpawnControlRailJack], pad), s"${context.parent.path.name}-rails")
def receive : Receive = {
case VehicleSpawnControl.Process.LoadVehicle(entry) =>
@@ -32,12 +32,12 @@ class VehicleSpawnControlLoadVehicle(pad : VehicleSpawnPad) extends VehicleSpawn
trace(s"loading the ${vehicle.Definition.Name}")
vehicle.Position = vehicle.Position - Vector3(0, 0, if(GlobalDefinitions.isFlightVehicle(vehicle.Definition)) 9 else 5)
Continent.VehicleEvents ! VehicleSpawnPad.LoadVehicle(vehicle, Continent)
- context.system.scheduler.scheduleOnce(100 milliseconds, seatDriver, VehicleSpawnControl.Process.SeatDriver(entry))
+ context.system.scheduler.scheduleOnce(100 milliseconds, railJack, VehicleSpawnControl.Process.RailJackAction(entry))
}
else {
trace("owner lost; abort order fulfillment")
VehicleSpawnControl.DisposeVehicle(entry, Continent)
- context.parent ! VehicleSpawnControl.ProcessControl.GetOrder
+ context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
}
case VehicleSpawnControl.ProcessControl.Reminder =>
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 6d09c0bd..7fd19eee 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
@@ -22,20 +22,25 @@ import scala.concurrent.duration._
class VehicleSpawnControlRailJack(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
def LogId = "-lifter"
- val vehicleOverride = context.actorOf(Props(classOf[VehicleSpawnControlServerVehicleOverride], pad), s"${context.parent.path.name}-override")
+ val seatDriver = context.actorOf(Props(classOf[VehicleSpawnControlSeatDriver], pad), s"${context.parent.path.name}-seat")
def receive : Receive = {
case VehicleSpawnControl.Process.RailJackAction(entry) =>
if(entry.vehicle.Health == 0) {
- //TODO detach vehicle from pad rails if necessary
- trace(s"vehicle was already destroyed")
+ trace("vehicle was already destroyed; clean it up")
VehicleSpawnControl.DisposeSpawnedVehicle(entry, Continent)
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
}
else {
- trace(s"extending rails with vehicle attached")
+ 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 temporarily in pad trench")
+ }
context.parent ! VehicleSpawnControl.ProcessControl.Reminder
- context.system.scheduler.scheduleOnce(10 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
+ context.system.scheduler.scheduleOnce(10 milliseconds, seatDriver, VehicleSpawnControl.Process.SeatDriver(entry))
}
case VehicleSpawnControl.ProcessControl.GetNewOrder =>
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 a36d215a..5c6eb8ef 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
@@ -25,34 +25,32 @@ import scala.concurrent.duration._
class VehicleSpawnControlSeatDriver(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
def LogId = "-usher"
- val railJack = context.actorOf(Props(classOf[VehicleSpawnControlRailJack], pad), s"${context.parent.path.name}-rails")
+ val vehicleOverride = context.actorOf(Props(classOf[VehicleSpawnControlServerVehicleOverride], pad), s"${context.parent.path.name}-override")
def receive : Receive = {
case VehicleSpawnControl.Process.SeatDriver(entry) =>
if(entry.vehicle.Actor == ActorRef.noSender) { //wait for the component of the vehicle needed for seating to be loaded
- context.system.scheduler.scheduleOnce(50 milliseconds, railJack, VehicleSpawnControl.Process.SeatDriver(entry))
+ context.system.scheduler.scheduleOnce(50 milliseconds, self, VehicleSpawnControl.Process.SeatDriver(entry))
}
else {
val driver = entry.driver
if(entry.vehicle.Health == 0) {
trace("vehicle was already destroyed; clean it up")
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
+ }
VehicleSpawnControl.DisposeSpawnedVehicle(entry, Continent)
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
}
+ else if(entry.sendTo != ActorRef.noSender && driver.isAlive && driver.Continent == Continent.Id && 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(1000 milliseconds, self, VehicleSpawnControl.Process.AwaitDriverInSeat(entry))
+ }
else {
- if(entry.sendTo != ActorRef.noSender && driver.isAlive && driver.Continent == Continent.Id && 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(1000 milliseconds, self, VehicleSpawnControl.Process.AwaitDriverInSeat(entry))
- }
- else {
- if(pad.Railed) {
- Continent.VehicleEvents ! VehicleSpawnPad.AttachToRails(entry.vehicle, pad, Continent.Id)
- }
- trace("driver lost; vehicle stranded on pad")
- context.system.scheduler.scheduleOnce(1000 milliseconds, railJack, VehicleSpawnControl.Process.RailJackAction(entry))
- }
+ trace("driver lost; vehicle stranded on pad")
+ context.system.scheduler.scheduleOnce(1000 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
}
}
@@ -60,40 +58,42 @@ class VehicleSpawnControlSeatDriver(pad : VehicleSpawnPad) extends VehicleSpawnC
val driver = entry.driver
if(entry.vehicle.Health == 0) {
trace("vehicle was already destroyed; clean it up")
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
+ }
VehicleSpawnControl.DisposeSpawnedVehicle(entry, Continent)
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
}
- else if(entry.sendTo == ActorRef.noSender) {
+ else if(entry.sendTo == ActorRef.noSender || driver.Continent != Continent.Id) {
trace("driver lost, but operations can continue")
- self ! VehicleSpawnControl.Process.RailJackAction(entry)
+ vehicleOverride ! VehicleSpawnControl.Process.ServerVehicleOverride(entry)
}
- else if(driver.isAlive && driver.Continent == Continent.Id && driver.VehicleSeated.isEmpty) {
+ else if(driver.isAlive && driver.VehicleSeated.isEmpty) {
context.system.scheduler.scheduleOnce(100 milliseconds, self, VehicleSpawnControl.Process.AwaitDriverInSeat(entry))
}
else {
trace(s"driver is sitting down")
- context.system.scheduler.scheduleOnce(
- VehicleSpawnControlSeatDriver.RaillessSeatAnimationTimes(entry.vehicle.Definition.Name) milliseconds,
- self,
- VehicleSpawnControl.Process.DriverInSeat(entry)
- )
+ val time = if(pad.Railed) 1000 else VehicleSpawnControlSeatDriver.RaillessSeatAnimationTimes(entry.vehicle.Definition.Name)
+ context.system.scheduler.scheduleOnce(time milliseconds, self, VehicleSpawnControl.Process.DriverInSeat(entry))
}
case VehicleSpawnControl.Process.DriverInSeat(entry) =>
if(entry.vehicle.Health == 0) {
- //TODO detach vehicle from pad rails if necessary
trace(s"vehicle was already destroyed; clean it up")
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
+ }
VehicleSpawnControl.DisposeSpawnedVehicle(entry, Continent)
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
}
- else if(entry.sendTo != ActorRef.noSender) {
+ else if(entry.sendTo != ActorRef.noSender || entry.driver.Continent != Continent.Id) {
trace(s"driver ${entry.driver.Name} has taken the wheel")
entry.sendTo ! VehicleSpawnPad.PlayerSeatedInVehicle(entry.vehicle, pad)
- context.system.scheduler.scheduleOnce(10 milliseconds, railJack, VehicleSpawnControl.Process.RailJackAction(entry))
+ context.system.scheduler.scheduleOnce(10 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
}
else {
trace("driver lost, but operations can continue")
- context.system.scheduler.scheduleOnce(10 milliseconds, railJack, VehicleSpawnControl.Process.RailJackAction(entry))
+ context.system.scheduler.scheduleOnce(10 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
}
case VehicleSpawnControl.ProcessControl.Reminder =>
@@ -118,6 +118,7 @@ object VehicleSpawnControlSeatDriver {
"fury" -> 600,
"quadassault" -> 600,
"quadstealth" -> 600,
+ "two_man_assault_buggy" -> 1000,
"skyguard" -> 1300,
"threemanheavybuggy" -> 1000,
"twomanheavybuggy" -> 1800,
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 798e0ffe..7b2c48f4 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
@@ -26,25 +26,31 @@ class VehicleSpawnControlServerVehicleOverride(pad : VehicleSpawnPad) extends Ve
def receive : Receive = {
case VehicleSpawnControl.Process.ServerVehicleOverride(entry) =>
val vehicle = entry.vehicle
- //TODO detach vehicle from pad rails
+ Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad, Continent.Id)
if(vehicle.Health == 0) {
trace(s"vehicle was already destroyed; but, everything is fine")
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
+ }
finalClear ! VehicleSpawnControl.Process.FinalClearance(entry)
}
- else if(entry.sendTo != ActorRef.noSender && entry.driver.VehicleSeated.contains(vehicle.GUID)) {
+ else if(entry.sendTo != ActorRef.noSender && entry.driver.isAlive && entry.driver.Continent == Continent.Id && entry.driver.VehicleSeated.contains(vehicle.GUID)) {
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, self, VehicleSpawnControl.Process.DriverVehicleControl(entry))
}
else {
if(pad.Railed) {
- Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad, Continent.Id)
+ Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
}
finalClear ! VehicleSpawnControl.Process.FinalClearance(entry)
}
case VehicleSpawnControl.Process.DriverVehicleControl(entry) =>
val vehicle = entry.vehicle
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
+ }
if(vehicle.Health == 0) {
trace(s"vehicle was already destroyed; but, everything is fine")
}
@@ -59,9 +65,6 @@ class VehicleSpawnControlServerVehicleOverride(pad : VehicleSpawnPad) extends Ve
}
}
else {
- if(pad.Railed) {
- Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
- }
trace("can not properly return control to driver")
}
finalClear ! VehicleSpawnControl.Process.FinalClearance(entry)
diff --git a/common/src/main/scala/net/psforever/objects/zones/ZoneActor.scala b/common/src/main/scala/net/psforever/objects/zones/ZoneActor.scala
index 0f93d918..f14f31bb 100644
--- a/common/src/main/scala/net/psforever/objects/zones/ZoneActor.scala
+++ b/common/src/main/scala/net/psforever/objects/zones/ZoneActor.scala
@@ -55,10 +55,10 @@ class ZoneActor(zone : Zone) extends Actor {
zone.Ground forward msg
//frwd to Vehicle Actor
- case msg @ Zone.SpawnVehicle =>
+ case msg @ Zone.Vehicle.Spawn =>
zone.Transport forward msg
- case msg @ Zone.DespawnVehicle =>
+ case msg @ Zone.Vehicle.Despawn =>
zone.Transport forward msg
//own
diff --git a/common/src/test/scala/objects/VehicleSpawnPadTest.scala b/common/src/test/scala/objects/VehicleSpawnPadTest.scala
index 697a7dcc..9ee32ea6 100644
--- a/common/src/test/scala/objects/VehicleSpawnPadTest.scala
+++ b/common/src/test/scala/objects/VehicleSpawnPadTest.scala
@@ -2,16 +2,17 @@
package objects
import akka.actor.{ActorRef, ActorSystem, Props}
+import akka.testkit.TestProbe
+import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
-import net.psforever.objects.serverobject.structures.{Building, StructureType}
-import net.psforever.objects.vehicles.VehicleControl
-import net.psforever.objects.zones.Zone
+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.{CharacterGender, PlanetSideEmpire, Vector3}
+import net.psforever.types.{PlanetSideEmpire, Vector3}
import org.specs2.mutable.Specification
-import scala.concurrent.duration.Duration
+import scala.concurrent.duration._
class VehicleSpawnPadTest extends Specification {
"VehicleSpawnPadDefinition" should {
@@ -25,6 +26,14 @@ class VehicleSpawnPadTest extends Specification {
val obj = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
obj.Actor mustEqual ActorRef.noSender
obj.Definition mustEqual GlobalDefinitions.spawn_pad
+ obj.Railed mustEqual true
+ }
+
+ "un-railed" in {
+ val obj = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
+ obj.Railed mustEqual true
+ obj.Railed = false
+ obj.Railed mustEqual false
}
}
}
@@ -39,78 +48,465 @@ class VehicleSpawnControl1Test extends ActorTest() {
}
}
-class VehicleSpawnControl2Test extends ActorTest() {
+class VehicleSpawnControl2aTest extends ActorTest() {
+ // This long runs for a long time.
"VehicleSpawnControl" should {
- "spawn a vehicle" in {
- val (player, pad) = VehicleSpawnPadControl.SetUpAgents(PlanetSideEmpire.TR)
- player.Spawn
- val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
- vehicle.GUID = PlanetSideGUID(1)
- vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle")
+ "complete on a vehicle order (block a second one until the first is done and the spawn pad is cleared)" 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.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle)
- val reply = receiveOne(Duration.create(10000, "ms"))
- assert(reply == VehicleSpawnPad.ConcealPlayer) //explicit: isInstanceOf does not work
+ pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref) //first order
+ pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe2.ref) //second order
- val reply2 = receiveOne(Duration.create(10000, "ms"))
- assert(reply2.isInstanceOf[VehicleSpawnPad.LoadVehicle])
- assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].vehicle == vehicle)
-// assert(reply2.asInstanceOf[VehicleSpawnPad.LoadVehicle].pad == pad)
-//
-// player.VehicleOwned = Some(vehicle.GUID)
-// val reply3 = receiveOne(Duration.create(10000, "ms"))
-// assert(reply3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle])
-// assert(reply3.asInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle].vehicle == vehicle)
-//
-// val reply4 = receiveOne(Duration.create(10000, "ms"))
-// assert(reply4.isInstanceOf[VehicleSpawnPad.SpawnPadBlockedWarning])
-// assert(reply4.asInstanceOf[VehicleSpawnPad.SpawnPadBlockedWarning].vehicle == vehicle)
-// assert(reply4.asInstanceOf[VehicleSpawnPad.SpawnPadBlockedWarning].warning_count > 0)
-//
-// vehicle.Position = Vector3(11f, 0f, 0f) //greater than 10m
-// val reply5 = receiveOne(Duration.create(10000, "ms"))
-// assert(reply5.isInstanceOf[VehicleSpawnPad.SpawnPadUnblocked])
-// assert(reply5.asInstanceOf[VehicleSpawnPad.SpawnPadUnblocked].vehicle_guid == vehicle.GUID)
+ 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(200 milliseconds)
+ 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(10 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 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
+ vehicle.Position = Vector3(0,0,11)
+ player.VehicleSeated = None //since shared between orders, is necessary
+ 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 long 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(3 seconds)
+ assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle])
+
+ val probe3Msg4 = probe3.receiveOne(200 milliseconds)
+ 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(10 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
+ vehicle.Position = Vector3(0,0,11)
+ player.VehicleSeated = None //since shared between orders, is necessary
+ val probe3Msg6 = probe3.receiveOne(4 seconds)
+ assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
}
}
}
class VehicleSpawnControl3Test extends ActorTest() {
"VehicleSpawnControl" should {
- "not spawn a vehicle if player is dead" in {
- val (player, pad) = VehicleSpawnPadControl.SetUpAgents(PlanetSideEmpire.TR)
- val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
- vehicle.GUID = PlanetSideGUID(1)
- vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle")
+ "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
- pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle)
- val reply = receiveOne(Duration.create(5000, "ms"))
- assert(reply == null)
+ 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 {
- "not spawn a vehicle if vehicle Actor is missing" in {
- val (player, pad) = VehicleSpawnPadControl.SetUpAgents(PlanetSideEmpire.TR)
- player.Spawn
- val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
- vehicle.GUID = PlanetSideGUID(1)
+ "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 ! VehicleSpawnPad.VehicleOrder(player, vehicle)
- val reply = receiveOne(Duration.create(5000, "ms"))
- assert(reply == null)
+ 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
}
}
}
-object VehicleSpawnPadControl {
- def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, VehicleSpawnPad) = {
- val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
- pad.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], pad), "test-pad")
- pad.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
- pad.Owner.Faction = faction
- (Player(Avatar("test", faction, CharacterGender.Male, 0, 0)), pad)
+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 VehicleSpawnControl5bTest extends ActorTest() {
+ "VehicleSpawnControl" should {
+ "player dies right after vehicle partially loads; the vehicle spawns and blocks the pad" 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])
+ 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 probe1Msg = probe1.receiveOne(10 seconds)
+ assert(probe1Msg.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
+ assert(probe1Msg.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
+ }
+ }
+}
+
+class VehicleSpawnControl6aTest extends ActorTest() {
+ "VehicleSpawnControl" should {
+ "the vehicle is destroyed while the player is sitting down; 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])
+
+ val probe3Msg3 = probe3.receiveOne(3 seconds)
+ assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.AttachToRails])
+
+ val probe1Msg1 = probe1.receiveOne(200 milliseconds)
+ assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
+ vehicle.Health = 0 //problem
+
+ val probe3Msg5 = probe3.receiveOne(4 seconds)
+ assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
+ val probe3Msg6 = probe3.receiveOne(100 milliseconds)
+ assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.DisposeVehicle])
+ val probe3Msg7 = probe3.receiveOne(100 milliseconds)
+ assert(probe3Msg7.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
+ }
+ }
+}
+
+//TODO test was poor; attempting to check the "if(vehicle.Health ..." cases in VehicleSpawnControlSeatDriver
+//class VehicleSpawnControl6bTest extends ActorTest() {
+// "VehicleSpawnControl" should {
+// "player on wrong continent; the vehicle is then destroyed after being partially spawned, but 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])
+//
+// val probe3Msg3 = probe3.receiveOne(3 seconds)
+// assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.AttachToRails])
+//
+// val probe1Msg1 = probe1.receiveOne(200 milliseconds)
+// assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
+// player.Continent = "problem" //problem 1
+//
+// vehicle.Health = 0 //problem 2
+// val probe3Msg3b = probe3.receiveOne(3 seconds)
+// assert(probe3Msg3b.isInstanceOf[VehicleSpawnPad.DetachFromRails])
+//
+// val probe3Msg4 = probe3.receiveOne(3 seconds)
+// assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
+// val probe3Msg5 = probe3.receiveOne(1 seconds)
+// assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.DisposeVehicle])
+// val probe3Msg6 = probe3.receiveOne(1 seconds)
+// assert(probe3Msg6.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 VehicleSpawnControl6cTest extends ActorTest() {
+ "VehicleSpawnControl" should {
+ "the player can not sit in vehicle; vehicle spawns and blocks the pad" 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])
+ player.Continent = "problem" //problem 1
+ 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.ResetSpawnPad])
+
+ val probe1Msg2 = probe1.receiveOne(10 seconds)
+ assert(probe1Msg2.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
+ assert(probe1Msg2.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
+ }
+ }
+}
+
+class VehicleSpawnControl7aTest extends ActorTest() {
+ "VehicleSpawnControl" should {
+ "the vehicle is destroyed while attached to the rails; it 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])
+
+ val probe3Msg3 = probe3.receiveOne(3 seconds)
+ 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])
+ vehicle.Health = 0 //problem
+
+ val probe3Msg4 = probe3.receiveOne(200 milliseconds)
+ assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
+ val probe3Msg5 = probe3.receiveOne(200 milliseconds)
+ assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
+
+ probe1.receiveOne(200 milliseconds) //Mountable.MountMessage
+ val probe1Msg4 = probe1.receiveOne(10 seconds)
+ assert(probe1Msg4.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
+ assert(probe1Msg4.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
+ }
+ }
+}
+
+class VehicleSpawnControl7bTest extends ActorTest() {
+ "VehicleSpawnControl" should {
+ "player dies after getting in driver seat; the vehicle blocks the pad" 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 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])
+ player.Die //problem
+
+ val probe3Msg4 = probe3.receiveOne(3 seconds)
+ assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
+ val probe3Msg5 = probe3.receiveOne(100 milliseconds)
+ assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
+
+ val probe1Msg4 = probe1.receiveOne(10 seconds)
+ assert(probe1Msg4.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
+ assert(probe1Msg4.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
+ }
+ }
+}
+
+object VehicleSpawnPadControlTest {
+ import net.psforever.objects.zones.ZoneMap
+ private val map = new ZoneMap("test-map")
+
+ def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Vehicle, Player, VehicleSpawnPad, Zone) = {
+ import net.psforever.objects.guid.NumberPoolHub
+ import net.psforever.objects.guid.source.LimitedNumberSource
+ import net.psforever.objects.serverobject.structures.Building
+ import net.psforever.objects.vehicles.VehicleControl
+ import net.psforever.objects.zones.ZoneActor
+ import net.psforever.objects.Tool
+ import net.psforever.types.CharacterGender
+
+ val zone = new Zone("test-zone", map, 0)
+ val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
+ val weapon = vehicle.WeaponControlledFromSeat(1).get.asInstanceOf[Tool]
+ val guid : NumberPoolHub = new NumberPoolHub(LimitedNumberSource(3))
+ 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)
+ 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()}")
+
+ val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
+ pad.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], pad), s"test-pad-${System.nanoTime()}")
+ pad.Owner = new Building(0, zone, StructureType.Building)
+ pad.Owner.Faction = faction
+ val player = Player(Avatar("test", faction, CharacterGender.Male, 0, 0))
+ player.GUID = PlanetSideGUID(10)
+ player.Continent = zone.Id
+ player.Spawn
+ //note: pad and vehicle are both at Vector3(0,0,0) so they count as blocking
+ (vehicle, player, pad, zone)
}
}
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index 03c3a542..8df74569 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -1025,9 +1025,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
case VehicleSpawnPad.StartPlayerSeatedInVehicle(vehicle, pad) =>
val vehicle_guid = vehicle.GUID
- if(pad.Railed) {
- sendResponse(ObjectAttachMessage(pad.GUID, vehicle_guid, 3))
- }
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off?
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 21, player.GUID.guid)) //fte and ownership?
@@ -1053,7 +1050,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(GenericObjectActionMessage(pad.GUID, 92)) //reset spawn pad
sendResponse(ServerVehicleOverrideMsg.Auto(vehicle.Definition.AutoPilotSpeed2))
- case VehicleSpawnPad.PeriodicReminder(msg) =>
+ 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.get}."
+ })
sendResponse(ChatMsg(ChatMessageType.CMT_OPEN, true, "", msg, None))
case ListAccountCharacters =>
diff --git a/pslogin/src/main/scala/services/vehicle/support/DeconstructionActor.scala b/pslogin/src/main/scala/services/vehicle/support/DeconstructionActor.scala
index 97c3223a..9d7a3efa 100644
--- a/pslogin/src/main/scala/services/vehicle/support/DeconstructionActor.scala
+++ b/pslogin/src/main/scala/services/vehicle/support/DeconstructionActor.scala
@@ -81,11 +81,7 @@ class DeconstructionActor extends Actor {
vehiclesToScrap.foreach(entry => {
val vehicle = entry.vehicle
val zone = entry.zone
-<<<<<<< 18a068c10272376450c412425118c86612af7397
vehicle.Position = Vector3.Zero //somewhere it will not disturb anything
-=======
- vehicle.Position = Vector3.Zero
->>>>>>> Splitting single vehicle spawn control process into several subtasks with their own control Actor objects. Importing SouNourS copy of ServerVehicleOverrideMessage packet and tests.
entry.zone.Transport ! Zone.Vehicle.Despawn(vehicle)
context.parent ! DeconstructionActor.DeleteVehicle(vehicle.GUID, zone.Id) //call up to the main event system
taskResolver ! DeconstructionTask(vehicle, zone)