mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-02-28 19:13:40 +00:00
deconstruction message for would-be driver when vehicle is abandoned on spawn pad; tempo on message delivery is different than usual
This commit is contained in:
parent
2e901ae904
commit
b3b62c94cc
5 changed files with 147 additions and 90 deletions
|
|
@ -14,7 +14,7 @@ import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
|||
import net.psforever.packet.game.{ChangeAmmoMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, HitHint, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ReloadMessage, ServerVehicleOverrideMsg, VehicleStateMessage, WeaponDryFireMessage}
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.vehicle.{VehicleResponse, VehicleServiceResponse}
|
||||
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3}
|
||||
import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
|
||||
|
||||
object VehicleHandlerLogic {
|
||||
def apply(ops: SessionVehicleHandlers): VehicleHandlerLogic = {
|
||||
|
|
@ -329,13 +329,13 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
|
|||
sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
|
||||
|
||||
case VehicleResponse.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, data) =>
|
||||
sendResponse(ChatMsg(
|
||||
ChatMessageType.CMT_OPEN,
|
||||
wideContents=true,
|
||||
recipient="",
|
||||
s"The vehicle spawn where you placed your order is blocked. ${data.getOrElse("")}",
|
||||
note=None
|
||||
))
|
||||
val str = s"${data.getOrElse("The vehicle spawn pad where you placed your order is blocked.")}"
|
||||
val msg = if (str.contains("@")) {
|
||||
ChatMsg(ChatMessageType.UNK_229, str)
|
||||
} else {
|
||||
ChatMsg(ChatMessageType.CMT_OPEN, wideContents = true, recipient = "", str, note = None)
|
||||
}
|
||||
sendResponse(msg)
|
||||
|
||||
case VehicleResponse.PeriodicReminder(_, data) =>
|
||||
val (isType, flag, msg): (ChatMessageType, Boolean, String) = data match {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
|||
/** how to process either the first order or every subsequent order */
|
||||
private var handleOrderFunc: VehicleSpawnPad.VehicleOrder => Unit = NewTasking
|
||||
|
||||
/** ... */
|
||||
private var reminderSeq: Seq[Int] = Seq()
|
||||
|
||||
def LogId = ""
|
||||
|
||||
/**
|
||||
|
|
@ -113,33 +116,8 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
|||
case VehicleSpawnControl.ProcessControl.QueueManagement =>
|
||||
queueManagementTask()
|
||||
|
||||
/*
|
||||
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 mount.
|
||||
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 the order queue.
|
||||
*/
|
||||
case VehicleSpawnControl.ProcessControl.Reminder =>
|
||||
trackedOrder
|
||||
.collect {
|
||||
case entry =>
|
||||
if (periodicReminder.isCancelled) {
|
||||
trace(s"the pad has become blocked by a ${entry.vehicle.Definition.Name} in its current order")
|
||||
periodicReminder = context.system.scheduler.scheduleWithFixedDelay(
|
||||
VehicleSpawnControl.periodicReminderTestDelay,
|
||||
VehicleSpawnControl.periodicReminderTestDelay,
|
||||
self,
|
||||
VehicleSpawnControl.ProcessControl.Reminder
|
||||
)
|
||||
} else {
|
||||
BlockedReminder(entry, orders)
|
||||
}
|
||||
trackedOrder
|
||||
}
|
||||
.orElse {
|
||||
periodicReminder.cancel()
|
||||
None
|
||||
}
|
||||
evaluateBlockedReminder()
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.Flush =>
|
||||
periodicReminder.cancel()
|
||||
|
|
@ -324,37 +302,6 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
private def BlockedReminder(blockedOrder: VehicleSpawnControl.Order, recipients: Seq[VehicleSpawnPad.VehicleOrder]): Unit = {
|
||||
val user = blockedOrder.vehicle
|
||||
.Seats(0).occupant
|
||||
.orElse(pad.Zone.GUID(blockedOrder.vehicle.OwnerGuid))
|
||||
.orElse(pad.Zone.GUID(blockedOrder.DriverGUID))
|
||||
val relevantRecipients: Iterator[VehicleSpawnPad.VehicleOrder] = user match {
|
||||
case Some(p: Player) if !p.HasGUID =>
|
||||
recipients.iterator
|
||||
case Some(_: Player) =>
|
||||
(VehicleSpawnPad.VehicleOrder(
|
||||
blockedOrder.driver,
|
||||
blockedOrder.vehicle,
|
||||
null //permissible
|
||||
) +: recipients).iterator //one who took possession of the vehicle
|
||||
case _ =>
|
||||
recipients.iterator
|
||||
}
|
||||
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
|
||||
|
|
@ -381,6 +328,105 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the vehicle is spawned and added to the pad, it will "occupy" the pad and block it from further action.
|
||||
* During this time, a periodic message about the spawn pad being blocked will be broadcast to the order queue.<br>
|
||||
* The vehicle is also queued to deconstruct in 30s if no one assumes the driver seat.
|
||||
*/
|
||||
private def evaluateBlockedReminder(): Unit = {
|
||||
/*
|
||||
Normally, the player who wanted to spawn the vehicle will be automatically put into the driver mount.
|
||||
If this is blocked or aborted, the vehicle will idle on the pad and must be moved far enough away from the point of origin.
|
||||
*/
|
||||
trackedOrder
|
||||
.collect {
|
||||
case entry =>
|
||||
if (reminderSeq.isEmpty) {
|
||||
//begin reminder
|
||||
trace(s"the pad has become blocked by a ${entry.vehicle.Definition.Name} in its current order")
|
||||
retimePeriodicReminder(
|
||||
shaveOffFirstElementAndDiffSecondElement(pad.Definition.BlockedReminderMessageDelays)
|
||||
)
|
||||
} else if (reminderSeq.size == 1) {
|
||||
//end reminder
|
||||
periodicReminder.cancel()
|
||||
periodicReminder = Default.Cancellable
|
||||
reminderSeq = List()
|
||||
} else {
|
||||
//continue reminder
|
||||
BlockedReminder(entry, orders)
|
||||
retimePeriodicReminder(
|
||||
shaveOffFirstElementAndDiffSecondElement(reminderSeq)
|
||||
)
|
||||
}
|
||||
trackedOrder
|
||||
}
|
||||
.orElse {
|
||||
periodicReminder.cancel()
|
||||
periodicReminder = Default.Cancellable
|
||||
reminderSeq = List()
|
||||
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
|
||||
*/
|
||||
private def BlockedReminder(blockedOrder: VehicleSpawnControl.Order, recipients: Seq[VehicleSpawnPad.VehicleOrder]): Unit = {
|
||||
//everyone else
|
||||
recursiveBlockedReminder(
|
||||
recipients.iterator,
|
||||
if (blockedOrder.vehicle.Health == 0)
|
||||
Option("The vehicle spawn pad where you placed your order is blocked. Clearing the wreckage ...")
|
||||
else
|
||||
Option("The vehicle spawn pad where you placed your order is blocked.")
|
||||
)
|
||||
//would-be driver
|
||||
blockedOrder.vehicle
|
||||
.Seats(0).occupant
|
||||
.orElse(pad.Zone.GUID(blockedOrder.vehicle.OwnerGuid))
|
||||
.orElse(pad.Zone.GUID(blockedOrder.DriverGUID)) collect {
|
||||
case p: Player if p.isAlive =>
|
||||
recursiveBlockedReminder(
|
||||
Seq(VehicleSpawnPad.VehicleOrder(
|
||||
blockedOrder.driver,
|
||||
blockedOrder.vehicle,
|
||||
null //permissible
|
||||
)).iterator,
|
||||
Some(s"@PadDeconstruct_secsA^${reminderSeq.head}~")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clip the first entry in a list of numbers and
|
||||
* get the difference between the clipped entry and the next entry.
|
||||
* The clipped-off list will be made to be the new sequence of reminder delays.
|
||||
* @param sequence reminder delay test values
|
||||
* @return difference between first delay and second delay
|
||||
*/
|
||||
private def shaveOffFirstElementAndDiffSecondElement(sequence: Seq[Int]): Int = {
|
||||
val startTime = sequence.take(1).headOption.getOrElse(0)
|
||||
val restTimes = sequence.drop(1)
|
||||
val headOfRestTimes = restTimes.headOption.getOrElse(startTime)
|
||||
reminderSeq = restTimes
|
||||
startTime - headOfRestTimes
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single instance of the "periodic reminder" to this kind of delay.
|
||||
* @param delay how long until the next reminder
|
||||
*/
|
||||
private def retimePeriodicReminder(delay: Int): Unit = {
|
||||
periodicReminder = context.system.scheduler.scheduleOnce(
|
||||
delay.seconds,
|
||||
self,
|
||||
VehicleSpawnControl.ProcessControl.Reminder
|
||||
)
|
||||
}
|
||||
|
||||
@tailrec private final def recursiveBlockedReminder(
|
||||
iter: Iterator[VehicleSpawnPad.VehicleOrder],
|
||||
cause: Option[Any]
|
||||
|
|
@ -414,19 +460,16 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
|
|||
}
|
||||
|
||||
object VehicleSpawnControl {
|
||||
private final val periodicReminderTestDelay: FiniteDuration = 10 seconds
|
||||
|
||||
/**
|
||||
* Control messages for the vehicle spawn process.
|
||||
*/
|
||||
sealed trait ProcessControlOperation
|
||||
object ProcessControl {
|
||||
sealed trait ProcessControl
|
||||
|
||||
case object Flush extends ProcessControl
|
||||
case object OrderCancelled extends ProcessControl
|
||||
case object GetNewOrder extends ProcessControl
|
||||
case object Reminder extends ProcessControl
|
||||
case object QueueManagement extends ProcessControl
|
||||
case object Flush extends ProcessControlOperation
|
||||
case object OrderCancelled extends ProcessControlOperation
|
||||
case object GetNewOrder extends ProcessControlOperation
|
||||
case object Reminder extends ProcessControlOperation
|
||||
case object QueueManagement extends ProcessControlOperation
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ class VehicleSpawnPadDefinition(objectId: Int) extends AmenityDefinition(objectI
|
|||
|
||||
// Different pads require a Z offset to stop vehicles falling through the world after the pad rises from the floor, these values are found in game_objects.adb.lst
|
||||
private var vehicle_creation_z_offset = 0f
|
||||
|
||||
// Different pads also require an orientation offset when detaching vehicles from the rails associated with the spawn pad, again in game_objects.adb.lst
|
||||
// For example: 9754:add_property dropship_pad_doors vehiclecreationzorientoffset 90
|
||||
// However, it seems these values need to be reversed to turn CCW to CW rotation (e.g. +90 to -90)
|
||||
|
|
@ -35,6 +34,12 @@ class VehicleSpawnPadDefinition(objectId: Int) extends AmenityDefinition(objectI
|
|||
* @see `net.psforever.objects.serverobject.pad.process.VehicleSpawnControlRailJack` */
|
||||
var killBox: (VehicleSpawnPad, Boolean)=>(PlanetSideGameObject, PlanetSideGameObject, Float)=> Boolean =
|
||||
VehicleSpawnPadDefinition.prepareKillBox(forwardLimit = 0, backLimit = 0, sideLimit = 0, aboveLimit = 0)
|
||||
|
||||
private val blockedReminderMessageDelays: Seq[Int] = Seq(30, 23, 15, 8, 0)
|
||||
|
||||
def VehicleCreationDeconstructTime: Int = blockedReminderMessageDelays.head
|
||||
|
||||
def BlockedReminderMessageDelays: Seq[Int] = blockedReminderMessageDelays
|
||||
}
|
||||
|
||||
object VehicleSpawnPadDefinition {
|
||||
|
|
|
|||
|
|
@ -50,26 +50,35 @@ class VehicleSpawnControlFinalClearance(pad: VehicleSpawnPad) extends VehicleSpa
|
|||
self ! VehicleSpawnControlFinalClearance.Test(order)
|
||||
|
||||
case test @ VehicleSpawnControlFinalClearance.Test(entry) =>
|
||||
//the vehicle has an initial decay of 30s in which time it needs to be mounted
|
||||
//the vehicle has an initial decay in which time it needs to be mounted
|
||||
//once mounted, it will complain to the current driver that it is blocking the spawn pad
|
||||
//no time limit exists for that state
|
||||
val vehicle = entry.vehicle
|
||||
if (Vector3.DistanceSquared(vehicle.Position, pad.Position) > 144) { //12m away from pad
|
||||
trace("pad cleared")
|
||||
pad.Zone.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad)
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
} else if (vehicle.Destroyed) {
|
||||
trace("clearing the pad of vehicle wreckage")
|
||||
val distanceTest = Vector3.DistanceSquared(vehicle.Position, pad.Position) > 144 //12m away from pad
|
||||
if (vehicle.Destroyed) {
|
||||
trace("pad cleared of vehicle wreckage")
|
||||
val delay = if (distanceTest) { 2000 } else { 5000 }
|
||||
VehicleSpawnControl.DisposeVehicle(vehicle, pad.Zone)
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
temp = context.system.scheduler.scheduleOnce(delay.milliseconds, self, VehicleSpawnControlFinalClearance.NextOrder)
|
||||
} else if (distanceTest) {
|
||||
trace("pad cleared")
|
||||
val delay = if (vehicle.Seats.head._2.occupant.isEmpty) { 4500 } else { 2000 }
|
||||
temp = context.system.scheduler.scheduleOnce(delay.milliseconds, self, VehicleSpawnControlFinalClearance.NextOrder)
|
||||
} else {
|
||||
temp = context.system.scheduler.scheduleOnce(2000 milliseconds, self, test)
|
||||
//retry test
|
||||
temp = context.system.scheduler.scheduleOnce(delay = 2000.milliseconds, self, test)
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
case VehicleSpawnControlFinalClearance.NextOrder =>
|
||||
pad.Zone.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad)
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
object VehicleSpawnControlFinalClearance {
|
||||
private final case class Test(entry: VehicleSpawnControl.Order)
|
||||
private case class Test(entry: VehicleSpawnControl.Order)
|
||||
|
||||
private case object NextOrder
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.pad.process
|
||||
|
||||
import akka.actor.Props
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import net.psforever.objects.{Default, Vehicle}
|
||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ import scala.concurrent.duration._
|
|||
class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
|
||||
def LogId = "-usher"
|
||||
|
||||
val vehicleOverride = context.actorOf(
|
||||
val vehicleOverride: ActorRef = context.actorOf(
|
||||
Props(classOf[VehicleSpawnControlServerVehicleOverride], pad),
|
||||
s"${context.parent.path.name}-override"
|
||||
)
|
||||
|
|
@ -43,7 +43,7 @@ class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnCo
|
|||
val driver = entry.driver
|
||||
val vehicle = entry.vehicle
|
||||
//avoid unattended vehicle blocking the pad; user should mount (and does so normally) to reset decon timer
|
||||
vehicle.Actor ! Vehicle.Deconstruct(Some(30 seconds))
|
||||
vehicle.Actor ! Vehicle.Deconstruct(Some(pad.Definition.VehicleCreationDeconstructTime.seconds))
|
||||
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) {
|
||||
trace("driver to be made seated in vehicle")
|
||||
pad.Zone.VehicleEvents ! VehicleSpawnPad.StartPlayerSeatedInVehicle(driver.Name, vehicle, pad)
|
||||
|
|
@ -67,7 +67,7 @@ class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnCo
|
|||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||
context.parent ! msg
|
||||
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue