Load Vehicle (#797)

* vehicle will not try to introduce itself to zone if already in zone; vehicle spawn pad construction uses generic messages rather than class-specific ones

* better seat locking while server controlled

* copious amounts of ant deployment check-ery
This commit is contained in:
Fate-JH 2021-04-29 09:38:51 -04:00 committed by GitHub
parent feeb1ba795
commit 9c0a3754d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 145 additions and 107 deletions

View file

@ -36,7 +36,7 @@ class VehicleSpawnControl2Test extends ActorTest {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
vehicle.Seats(0).mount(player) vehicle.Seats(0).mount(player)
@ -72,7 +72,7 @@ class VehicleSpawnControl3Test extends ActorTest {
case _ => false case _ => false
}) })
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
vehicle.Seats(0).mount(player) vehicle.Seats(0).mount(player)
@ -132,7 +132,7 @@ class VehicleSpawnControl5Test extends ActorTest() {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
vehicle.Health = 0 //problem vehicle.Health = 0 //problem
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
@ -159,7 +159,7 @@ class VehicleSpawnControl6Test extends ActorTest() {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
player.Die player.Die
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
@ -187,7 +187,7 @@ class VehicleSpawnControl7Test extends ActorTest {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.LoadVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])

View file

@ -193,7 +193,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
var loadConfZone: Boolean = false var loadConfZone: Boolean = false
var noSpawnPointHere: Boolean = false var noSpawnPointHere: Boolean = false
var usingMedicalTerminal: Option[PlanetSideGUID] = None var usingMedicalTerminal: Option[PlanetSideGUID] = None
var controlled: Option[Int] = None var serverVehicleControlVelocity: Option[Int] = None
var deadState: DeadState.Value = DeadState.Dead var deadState: DeadState.Value = DeadState.Dead
val projectiles: Array[Option[Projectile]] = val projectiles: Array[Option[Projectile]] =
Array.fill[Option[Projectile]](Projectile.rangeUID - Projectile.baseUID)(None) Array.fill[Option[Projectile]](Projectile.rangeUID - Projectile.baseUID)(None)
@ -502,41 +502,45 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
accountPersistence ! AccountPersistenceService.Kick(player.Name, time) accountPersistence ! AccountPersistenceService.Kick(player.Name, time)
case SetZone(zoneId, position) => case SetZone(zoneId, position) =>
PlayerActionsToCancel() if (serverVehicleControlVelocity.isEmpty) {
continent.GUID(player.VehicleSeated) match { PlayerActionsToCancel()
case Some(vehicle: Vehicle) if vehicle.MountedIn.isEmpty => continent.GUID(player.VehicleSeated) match {
vehicle.PassengerInSeat(player) match { case Some(vehicle : Vehicle) if vehicle.MountedIn.isEmpty =>
case Some(0) => vehicle.PassengerInSeat(player) match {
deadState = DeadState.Release // cancel movement updates case Some(0) =>
vehicle.Position = position deadState = DeadState.Release // cancel movement updates
LoadZonePhysicalSpawnPoint(zoneId, position, Vector3.Zero, 0 seconds) vehicle.Position = position
case _ => // not seated as the driver, in which case we can't move LoadZonePhysicalSpawnPoint(zoneId, position, Vector3.Zero, 0 seconds)
} case _ => // not seated as the driver, in which case we can't move
case None => }
deadState = DeadState.Release // cancel movement updates case None =>
player.Position = position deadState = DeadState.Release // cancel movement updates
// continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID)) player.Position = position
LoadZonePhysicalSpawnPoint(zoneId, position, Vector3.Zero, 0 seconds) // continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID))
case _ => // seated in something that is not a vehicle or the vehicle is cargo, in which case we can't move LoadZonePhysicalSpawnPoint(zoneId, position, Vector3.Zero, 0 seconds)
case _ => // seated in something that is not a vehicle or the vehicle is cargo, in which case we can't move
}
} }
case SetPosition(position) => case SetPosition(position) =>
PlayerActionsToCancel() if (serverVehicleControlVelocity.isEmpty) {
continent.GUID(player.VehicleSeated) match { PlayerActionsToCancel()
case Some(vehicle: Vehicle) if vehicle.MountedIn.isEmpty => continent.GUID(player.VehicleSeated) match {
vehicle.PassengerInSeat(player) match { case Some(vehicle : Vehicle) if vehicle.MountedIn.isEmpty =>
case Some(0) => vehicle.PassengerInSeat(player) match {
deadState = DeadState.Release // cancel movement updates case Some(0) =>
vehicle.Position = position deadState = DeadState.Release // cancel movement updates
LoadZonePhysicalSpawnPoint(continent.id, position, Vector3.z(vehicle.Orientation.z), 0 seconds) vehicle.Position = position
case _ => // not seated as the driver, in which case we can't move LoadZonePhysicalSpawnPoint(continent.id, position, Vector3.z(vehicle.Orientation.z), 0 seconds)
} case _ => // not seated as the driver, in which case we can't move
case None => }
deadState = DeadState.Release // cancel movement updates case None =>
player.Position = position deadState = DeadState.Release // cancel movement updates
sendResponse(PlayerStateShiftMessage(ShiftState(0, position, player.Orientation.z, None))) player.Position = position
deadState = DeadState.Alive // must be set here sendResponse(PlayerStateShiftMessage(ShiftState(0, position, player.Orientation.z, None)))
case _ => // seated in something that is not a vehicle or the vehicle is cargo, in which case we can't move deadState = DeadState.Alive // must be set here
case _ => // seated in something that is not a vehicle or the vehicle is cargo, in which case we can't move
}
} }
case SetConnectionState(state) => case SetConnectionState(state) =>
@ -2762,6 +2766,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
val tplayer_guid = if (player.HasGUID) player.GUID else PlanetSideGUID(0) val tplayer_guid = if (player.HasGUID) player.GUID else PlanetSideGUID(0)
reply match { reply match {
case VehicleResponse.AttachToRails(vehicle_guid, pad_guid) => case VehicleResponse.AttachToRails(vehicle_guid, pad_guid) =>
serverVehicleControlVelocity = Some(0)
sendResponse(ObjectAttachMessage(pad_guid, vehicle_guid, 3)) sendResponse(ObjectAttachMessage(pad_guid, vehicle_guid, 3))
case VehicleResponse.ChildObjectState(object_guid, pitch, yaw) => case VehicleResponse.ChildObjectState(object_guid, pitch, yaw) =>
@ -2936,7 +2941,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
if (strafe > 1) 0 if (strafe > 1) 0
else speed else speed
//strafe or reverse, not both //strafe or reverse, not both
controlled = Some(reverseSpeed) serverVehicleControlVelocity = Some(reverseSpeed)
sendResponse(ServerVehicleOverrideMsg(true, true, true, false, 0, strafe, reverseSpeed, Some(0))) sendResponse(ServerVehicleOverrideMsg(true, true, true, false, 0, strafe, reverseSpeed, Some(0)))
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
context.system.scheduler.scheduleOnce( context.system.scheduler.scheduleOnce(
@ -2945,7 +2950,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
VehicleServiceResponse(toChannel, PlanetSideGUID(0), VehicleResponse.KickCargo(vehicle, 0, delay)) VehicleServiceResponse(toChannel, PlanetSideGUID(0), VehicleResponse.KickCargo(vehicle, 0, delay))
) )
} else { } else {
controlled = None serverVehicleControlVelocity = None
sendResponse(ServerVehicleOverrideMsg(false, false, false, false, 0, 0, 0, None)) sendResponse(ServerVehicleOverrideMsg(false, false, false, false, 0, 0, 0, None))
} }
} }
@ -3316,16 +3321,18 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
* only the zone-specific squad members will receive the important messages about their squad member's spawn. * only the zone-specific squad members will receive the important messages about their squad member's spawn.
*/ */
def RespawnSquadSetup(): Unit = { def RespawnSquadSetup(): Unit = {
squadUI.get(player.CharId) match { if (squad_supplement_id > 0) {
case Some(elem) => squadUI.get(player.CharId) match {
sendResponse(PlanetsideAttributeMessage(player.GUID, 31, squad_supplement_id)) case Some(elem) =>
continent.AvatarEvents ! AvatarServiceMessage( sendResponse(PlanetsideAttributeMessage(player.GUID, 31, squad_supplement_id))
s"${player.Faction}", continent.AvatarEvents ! AvatarServiceMessage(
AvatarAction.PlanetsideAttribute(player.GUID, 31, squad_supplement_id) s"${player.Faction}",
) AvatarAction.PlanetsideAttribute(player.GUID, 31, squad_supplement_id)
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, elem.index)) )
case _ => sendResponse(PlanetsideAttributeMessage(player.GUID, 32, elem.index))
log.warn(s"RespawnSquadSetup: asked to redraw squad information, but ${player.Name} has no squad element for squad $squad_supplement_id") case _ =>
log.warn(s"RespawnSquadSetup: asked to redraw squad information, but ${player.Name} has no squad element for squad $squad_supplement_id")
}
} }
} }
@ -5556,7 +5563,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
destinationBuildingGuid, destinationBuildingGuid,
context.self context.self
) )
log.info(s"${player.Name} is trying to use a warp gate") log.info(s"${player.Name} wants to use a warp gate")
case Some(wg: WarpGate) if !wg.Active => case Some(wg: WarpGate) if !wg.Active =>
log.warn(s"WarpgateRequest: ${player.Name} is knocking on an inactive warp gate") log.warn(s"WarpgateRequest: ${player.Name} is knocking on an inactive warp gate")
@ -5600,13 +5607,13 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
) )
None None
}) match { }) match {
case Some(_) if serverVehicleControlVelocity.nonEmpty =>
log.debug(
s"DismountVehicleMsg: ${player.Name} can not dismount from vehicle while server has asserted control; please wait"
)
case Some(obj: Mountable) => case Some(obj: Mountable) =>
obj.PassengerInSeat(player) match { obj.PassengerInSeat(player) match {
case Some(0) if controlled.nonEmpty => case Some(seat_num) =>
log.warn(
s"DismountVehicleMsg: ${player.Name} can not dismount from vehicle as driver while server has asserted control; please wait ..."
)
case Some(seat_num) =>
obj.Actor ! Mountable.TryDismount(player, seat_num) obj.Actor ! Mountable.TryDismount(player, seat_num)
if (interstellarFerry.isDefined) { if (interstellarFerry.isDefined) {
//short-circuit the temporary channel for transferring between zones, the player is no longer doing that //short-circuit the temporary channel for transferring between zones, the player is no longer doing that
@ -5668,11 +5675,12 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
} }
case msg @ DeployRequestMessage(player_guid, vehicle_guid, deploy_state, unk2, unk3, pos) => case msg @ DeployRequestMessage(player_guid, vehicle_guid, deploy_state, unk2, unk3, pos) =>
if (player.avatar.vehicle.contains(vehicle_guid)) { val vehicle = player.avatar.vehicle
if (player.avatar.vehicle == player.VehicleSeated) { if (vehicle.contains(vehicle_guid)) {
if (vehicle == player.VehicleSeated) {
continent.GUID(vehicle_guid) match { continent.GUID(vehicle_guid) match {
case Some(obj: Vehicle) => case Some(obj: Vehicle) =>
log.info(s"${player.Name} is requesting a deployment change for ${obj.Definition.Name}") log.info(s"${player.Name} is requesting a deployment change for ${obj.Definition.Name} - $deploy_state")
obj.Actor ! Deployment.TryDeploymentChange(deploy_state) obj.Actor ! Deployment.TryDeploymentChange(deploy_state)
case _ => case _ =>
@ -7019,6 +7027,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
progressBarUpdate.cancel() progressBarUpdate.cancel()
progressBarValue = None progressBarValue = None
lastTerminalOrderFulfillment = true lastTerminalOrderFulfillment = true
serverVehicleControlVelocity = None
accessedContainer match { accessedContainer match {
case Some(v: Vehicle) => case Some(v: Vehicle) =>
val vguid = v.GUID val vguid = v.GUID
@ -7100,7 +7109,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation) vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation)
val vdata = if (seat == 0) { val vdata = if (seat == 0) {
//driver //driver
continent.Transport ! Zone.Vehicle.Spawn(vehicle) if (vehicle.Zone ne continent) {
continent.Transport ! Zone.Vehicle.Spawn(vehicle)
}
//as the driver, we must temporarily exclude ourselves from being in the vehicle during its creation //as the driver, we must temporarily exclude ourselves from being in the vehicle during its creation
val mount = vehicle.Seats(0) val mount = vehicle.Seats(0)
mount.unmount(player) mount.unmount(player)
@ -7738,7 +7749,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
* Set the vehicle to move in reverse * Set the vehicle to move in reverse
*/ */
def ServerVehicleLockReverse(): Unit = { def ServerVehicleLockReverse(): Unit = {
controlled = Some(0) serverVehicleControlVelocity = Some(0)
sendResponse( sendResponse(
ServerVehicleOverrideMsg( ServerVehicleOverrideMsg(
lock_accelerator = true, lock_accelerator = true,
@ -7759,7 +7770,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
* Set the vehicle to strafe right * Set the vehicle to strafe right
*/ */
def ServerVehicleLockStrafeRight(): Unit = { def ServerVehicleLockStrafeRight(): Unit = {
controlled = Some(0) serverVehicleControlVelocity = Some(0)
sendResponse( sendResponse(
ServerVehicleOverrideMsg( ServerVehicleOverrideMsg(
lock_accelerator = true, lock_accelerator = true,
@ -7780,7 +7791,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
* Set the vehicle to strafe left * Set the vehicle to strafe left
*/ */
def ServerVehicleLockStrafeLeft(): Unit = { def ServerVehicleLockStrafeLeft(): Unit = {
controlled = Some(0) serverVehicleControlVelocity = Some(0)
sendResponse( sendResponse(
ServerVehicleOverrideMsg( ServerVehicleOverrideMsg(
lock_accelerator = true, lock_accelerator = true,
@ -7801,7 +7812,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
* @param vehicle the vehicle being controlled * @param vehicle the vehicle being controlled
*/ */
def ServerVehicleLock(vehicle: Vehicle): Unit = { def ServerVehicleLock(vehicle: Vehicle): Unit = {
controlled = Some(0) serverVehicleControlVelocity = Some(0)
sendResponse(ServerVehicleOverrideMsg(true, true, false, false, 0, 1, 0, Some(0))) sendResponse(ServerVehicleOverrideMsg(true, true, false, false, 0, 1, 0, Some(0)))
} }
@ -7812,7 +7823,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
* @param flight whether the vehicle is ascending or not, if the vehicle is an applicable type * @param flight whether the vehicle is ascending or not, if the vehicle is an applicable type
*/ */
def ServerVehicleOverride(vehicle: Vehicle, speed: Int = 0, flight: Int = 0): Unit = { def ServerVehicleOverride(vehicle: Vehicle, speed: Int = 0, flight: Int = 0): Unit = {
controlled = Some(speed) serverVehicleControlVelocity = Some(speed)
sendResponse(ServerVehicleOverrideMsg(true, true, false, false, flight, 0, speed, Some(0))) sendResponse(ServerVehicleOverrideMsg(true, true, false, false, flight, 0, speed, Some(0)))
} }
@ -7824,8 +7835,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
* @param flight whether the vehicle is ascending or not, if the vehicle is an applicable type * @param flight whether the vehicle is ascending or not, if the vehicle is an applicable type
*/ */
def DriverVehicleControl(vehicle: Vehicle, speed: Int = 0, flight: Int = 0): Unit = { def DriverVehicleControl(vehicle: Vehicle, speed: Int = 0, flight: Int = 0): Unit = {
if (controlled.nonEmpty) { if (serverVehicleControlVelocity.nonEmpty) {
controlled = None serverVehicleControlVelocity = None
sendResponse(ServerVehicleOverrideMsg(false, false, false, true, flight, 0, speed, None)) sendResponse(ServerVehicleOverrideMsg(false, false, false, true, flight, 0, speed, None))
} }
} }
@ -7837,8 +7848,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
* @param vehicle the vehicle * @param vehicle the vehicle
*/ */
def TotalDriverVehicleControl(vehicle: Vehicle): Unit = { def TotalDriverVehicleControl(vehicle: Vehicle): Unit = {
if (controlled.nonEmpty) { if (serverVehicleControlVelocity.nonEmpty) {
controlled = None serverVehicleControlVelocity = None
sendResponse(ServerVehicleOverrideMsg(false, false, false, false, 0, 0, 0, None)) sendResponse(ServerVehicleOverrideMsg(false, false, false, false, 0, 0, 0, None))
} }
} }
@ -9542,8 +9553,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
val projectilePlace = projectiles(projectileIndex) val projectilePlace = projectiles(projectileIndex)
if ( if (
projectilePlace match { projectilePlace match {
case Some(projectile) => !projectile.isResolved case Some(projectile) =>
case None => false !projectile.isResolved && System.currentTimeMillis() - projectile.fire_time < projectile.profile.Lifespan.toLong
case None =>
false
} }
) { ) {
log.debug( log.debug(

View file

@ -6797,6 +6797,7 @@ object GlobalDefinitions {
dropship.Seats += 5 -> bailableSeat dropship.Seats += 5 -> bailableSeat
dropship.Seats += 6 -> bailableSeat dropship.Seats += 6 -> bailableSeat
dropship.Seats += 7 -> bailableSeat dropship.Seats += 7 -> bailableSeat
dropship.Seats += 8 -> bailableSeat
dropship.Seats += 9 -> new SeatDefinition() { dropship.Seats += 9 -> new SeatDefinition() {
bailable = true bailable = true
restriction = MaxOnly restriction = MaxOnly

View file

@ -44,12 +44,6 @@ object VehicleSpawnPad {
*/ */
final case class RevealPlayer(player_guid: PlanetSideGUID) final case class RevealPlayer(player_guid: PlanetSideGUID)
/**
* Message to properly introduce the vehicle into the zone.
* @param vehicle the vehicle being spawned
*/
final case class LoadVehicle(vehicle: Vehicle)
/** /**
* Message to attach the vehicle to the spawn pad's lifting platform ("put on rails"). * 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. * The attachment process (to the third slot) itself begins autonomous operation of the lifting platform.

View file

@ -1,9 +1,12 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.pad.process package net.psforever.objects.serverobject.pad.process
import akka.actor.Props import akka.actor.{Cancellable, Props}
import net.psforever.objects.GlobalDefinitions import net.psforever.objects.{Default, GlobalDefinitions}
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.objects.zones.Zone
import net.psforever.services.Service
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.Vector3 import net.psforever.types.Vector3
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
@ -25,6 +28,13 @@ class VehicleSpawnControlLoadVehicle(pad: VehicleSpawnPad) extends VehicleSpawnC
val railJack = context.actorOf(Props(classOf[VehicleSpawnControlRailJack], pad), s"${context.parent.path.name}-rails") val railJack = context.actorOf(Props(classOf[VehicleSpawnControlRailJack], pad), s"${context.parent.path.name}-rails")
var temp: Cancellable = Default.Cancellable
override def postStop() : Unit = {
temp.cancel()
super.postStop()
}
def receive: Receive = { def receive: Receive = {
case order @ VehicleSpawnControl.Order(driver, vehicle) => case order @ VehicleSpawnControl.Order(driver, vehicle) =>
if (driver.Continent == pad.Continent && vehicle.Health > 0 && driver.isAlive) { if (driver.Continent == pad.Continent && vehicle.Health > 0 && driver.isAlive) {
@ -33,17 +43,48 @@ class VehicleSpawnControlLoadVehicle(pad: VehicleSpawnPad) extends VehicleSpawnC
if (GlobalDefinitions.isFlightVehicle(vehicle.Definition)) 9 else 5 if (GlobalDefinitions.isFlightVehicle(vehicle.Definition)) 9 else 5
) //appear below the trench and doors ) //appear below the trench and doors
vehicle.Cloaked = vehicle.Definition.CanCloak && driver.Cloaked vehicle.Cloaked = vehicle.Definition.CanCloak && driver.Cloaked
pad.Zone.VehicleEvents ! VehicleSpawnPad.LoadVehicle(vehicle) pad.Zone.Transport.tell(Zone.Vehicle.Spawn(vehicle), self)
context.system.scheduler.scheduleOnce(100 milliseconds, railJack, order) temp = context.system.scheduler.scheduleOnce(
delay = 100 milliseconds,
self,
VehicleSpawnControlLoadVehicle.WaitOnSpawn(order)
)
} else { } else {
trace("owner lost or vehicle in poor condition; abort order fulfillment") trace("owner lost or vehicle in poor condition; abort order fulfillment")
VehicleSpawnControl.DisposeVehicle(order.vehicle, pad.Zone) VehicleSpawnControl.DisposeVehicle(order.vehicle, pad.Zone)
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
} }
case Zone.Vehicle.HasSpawned(zone, vehicle) =>
val definition = vehicle.Definition
val vtype = definition.ObjectId
val vguid = vehicle.GUID
val vdata = definition.Packet.ConstructorData(vehicle).get
zone.VehicleEvents ! VehicleServiceMessage(
zone.id,
VehicleAction.LoadVehicle(Service.defaultPlayerGUID, vehicle, vtype, vguid, vdata)
)
case VehicleSpawnControlLoadVehicle.WaitOnSpawn(order) =>
if (pad.Zone.Vehicles.contains(order.vehicle)) {
railJack ! order
} else {
VehicleSpawnControl.DisposeVehicle(order.vehicle, pad.Zone)
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
}
case Zone.Vehicle.CanNotSpawn(_, _, reason) =>
trace(s"vehicle $reason; abort order fulfillment")
temp.cancel()
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) => case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
context.parent ! msg context.parent ! msg
case _ => ; case _ => ;
} }
} }
object VehicleSpawnControlLoadVehicle {
private case class WaitOnSpawn(order: VehicleSpawnControl.Order)
}

View file

@ -58,7 +58,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
ntuChargingTick.cancel() ntuChargingTick.cancel()
val obj = ChargeTransferObject val obj = ChargeTransferObject
//log.trace(s"NtuCharging: Vehicle $guid is charging NTU capacitor.") //log.trace(s"NtuCharging: Vehicle $guid is charging NTU capacitor.")
if (obj.NtuCapacitor < obj.Definition.MaxNtuCapacitor) { if (obj.NtuCapacitor < obj.Definition.MaxNtuCapacitor && obj.DeploymentState == DriveState.Deployed) {
//charging //charging
panelAnimationFunc = InitialCharge panelAnimationFunc = InitialCharge
transferTarget = Some(target) transferTarget = Some(target)
@ -96,7 +96,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
def HandleDischargingEvent(target: TransferContainer): Boolean = { def HandleDischargingEvent(target: TransferContainer): Boolean = {
//log.trace(s"NtuDischarging: Vehicle $guid is discharging NTU into silo $silo_guid") //log.trace(s"NtuDischarging: Vehicle $guid is discharging NTU into silo $silo_guid")
val obj = ChargeTransferObject val obj = ChargeTransferObject
if (obj.NtuCapacitor > 0) { if (obj.NtuCapacitor > 0 && obj.DeploymentState == DriveState.Deployed) {
panelAnimationFunc = InitialDischarge panelAnimationFunc = InitialDischarge
transferTarget = Some(target) transferTarget = Some(target)
transferEvent = TransferBehavior.Event.Discharging transferEvent = TransferBehavior.Event.Discharging
@ -177,8 +177,8 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = {} def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = {}
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = { def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = {
if (transferEvent == TransferBehavior.Event.Discharging) { val chargeable = ChargeTransferObject
val chargeable = ChargeTransferObject if (chargeable.DeploymentState == DriveState.Deployed && transferEvent == TransferBehavior.Event.Discharging) {
val chargeToDeposit = if (min == 0) { val chargeToDeposit = if (min == 0) {
transferTarget match { transferTarget match {
case Some(silo: ResourceSilo) => case Some(silo: ResourceSilo) =>
@ -194,18 +194,21 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
chargeable.NtuCapacitor -= chargeToDeposit chargeable.NtuCapacitor -= chargeToDeposit
UpdateNtuUI(chargeable) UpdateNtuUI(chargeable)
sender ! Ntu.Grant(chargeable, chargeToDeposit) sender ! Ntu.Grant(chargeable, chargeToDeposit)
} else {
TryStopChargingEvent(chargeable)
sender ! Ntu.Grant(chargeable, 0)
} }
} }
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit = { def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit = {
if (transferEvent == TransferBehavior.Event.Charging) { val obj = ChargeTransferObject
val obj = ChargeTransferObject if (obj.DeploymentState == DriveState.Deployed &&
if (ReceiveAndDepositUntilFull(obj, amount)) { transferEvent == TransferBehavior.Event.Charging &&
panelAnimationFunc() ReceiveAndDepositUntilFull(obj, amount)) {
} else { panelAnimationFunc()
TryStopChargingEvent(obj) } else {
sender ! Ntu.Request(0, 0) TryStopChargingEvent(obj)
} sender ! Ntu.Request(0, 0)
} }
} }
} }

View file

@ -338,20 +338,6 @@ class VehicleService(zone: Zone) extends Actor {
) )
) )
case VehicleSpawnPad.LoadVehicle(vehicle) =>
val definition = vehicle.Definition
val vtype = definition.ObjectId
val vguid = vehicle.GUID
val vdata = definition.Packet.ConstructorData(vehicle).get
zone.Transport ! Zone.Vehicle.Spawn(vehicle)
VehicleEvents.publish(
VehicleServiceResponse(
s"/${zone.id}/Vehicle",
Service.defaultPlayerGUID,
VehicleResponse.LoadVehicle(vehicle, vtype, vguid, vdata)
)
)
//correspondence from WorldSessionActor //correspondence from WorldSessionActor
case VehicleServiceMessage.AMSDeploymentChange(_) => case VehicleServiceMessage.AMSDeploymentChange(_) =>
VehicleEvents.publish( VehicleEvents.publish(