Cargo vehicle Mounting and Gating Fix (#749)

* reorganizing flags that allow for cargo vehicle mounting; eliminating double zone transfer messaging that was interfering in cargo vehicle transfer

* insufficient dismount repaired so that vehicle mounts correctly; vehicle HasSpawned message on deconstruct actually goes somewhere now
This commit is contained in:
Fate-JH 2021-04-07 09:42:19 -04:00 committed by GitHub
parent 430c5d8890
commit ee969b2737
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 79 additions and 58 deletions

View file

@ -559,26 +559,34 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
sendResponse(msg) sendResponse(msg)
case GalaxyResponse.TransferPassenger(temp_channel, vehicle, vehicle_to_delete, manifest) => case GalaxyResponse.TransferPassenger(temp_channel, vehicle, vehicle_to_delete, manifest) =>
(manifest.passengers.find { case (name, _) => player.Name.equals(name) } match { val playerName = player.Name
case Some((name, index)) if vehicle.Seats(index).occupant.isEmpty => log.debug(s"TransferPassenger: $playerName received the summons to transfer to ${vehicle.Zone.id} ...")
vehicle.Seats(index).mount(player) (manifest.passengers.find { _.name.equals(playerName) } match {
case Some(entry) if vehicle.Seats(entry.mount).occupant.isEmpty =>
player.VehicleSeated = None
vehicle.Seats(entry.mount).mount(player)
player.VehicleSeated = vehicle.GUID
Some(vehicle) Some(vehicle)
case Some((name, index)) => case Some(entry) if vehicle.Seats(entry.mount).occupant.contains(player) =>
log.warn(s"TransferPassenger: $player tried to mount seat $index when it was already occupied, and was rebuked") Some(vehicle)
case Some(entry) =>
log.warn(s"TransferPassenger: $playerName tried to mount seat ${entry.mount} during summoning, but it was already occupied, and ${player.Sex.pronounSubject} was rebuked")
None None
case None => case None =>
//log.warn(s"TransferPassenger: $playerName is missing from the manifest of a summoning ${vehicle.Definition.Name} from ${vehicle.Zone.id}")
None None
}).orElse(manifest.cargo.find { case (name, _) => player.Name.equals(name) } match { }).orElse {
case Some((name, index)) => manifest.cargo.find { _.name.equals(playerName) } match {
vehicle.CargoHolds(index).occupant match { case Some(entry) =>
case Some(cargo) => vehicle.CargoHolds(entry.mount).occupant match {
cargo.Seats(0).occupants.find(_.Name.equals(name)) case out @ Some(cargo) if cargo.Seats(0).occupants.exists(_.Name.equals(playerName)) =>
case None => out
case _ =>
None None
} }
case None => case None =>
None None
}) match { }} match {
case Some(v: Vehicle) => case Some(v: Vehicle) =>
galaxyService ! Service.Leave(Some(temp_channel)) //temporary vehicle-specific channel (see above) galaxyService ! Service.Leave(Some(temp_channel)) //temporary vehicle-specific channel (see above)
deadState = DeadState.Release deadState = DeadState.Release
@ -2886,6 +2894,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
Some(old_channel) Some(old_channel)
) //old vehicle-specific channel (was s"${vehicle.Actor}") ) //old vehicle-specific channel (was s"${vehicle.Actor}")
galaxyService ! Service.Join(temp_channel) //temporary vehicle-specific channel galaxyService ! Service.Join(temp_channel) //temporary vehicle-specific channel
log.debug(s"TransferPassengerChannel: ${player.Name} now subscribed to $temp_channel for vehicle gating")
} }
case VehicleResponse.KickCargo(vehicle, speed, delay) => case VehicleResponse.KickCargo(vehicle, speed, delay) =>
@ -5800,7 +5809,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
} }
def Execute(resolver: ActorRef): Unit = { def Execute(resolver: ActorRef): Unit = {
log.trace(s"Player $localPlayer is registered") log.trace(s"Player ${localPlayer.Name} is newly registered")
resolver ! Success(this) resolver ! Success(this)
localAnnounce ! NewPlayerLoaded(localPlayer) //alerts WorldSessionActor localAnnounce ! NewPlayerLoaded(localPlayer) //alerts WorldSessionActor
} }
@ -5990,6 +5999,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
} }
def Execute(resolver: ActorRef): Unit = { def Execute(resolver: ActorRef): Unit = {
log.trace(s"${localDriver.Name} 's vehicle ${localVehicle.Definition.Name} is registered")
localDriver.VehicleSeated = localVehicle.GUID localDriver.VehicleSeated = localVehicle.GUID
Vehicles.Own(localVehicle, localDriver) Vehicles.Own(localVehicle, localDriver)
localAnnounce ! NewPlayerLoaded(localDriver) //alerts WorldSessionActor localAnnounce ! NewPlayerLoaded(localDriver) //alerts WorldSessionActor
@ -6000,7 +6010,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
localAnnounce ! PlayerFailedToLoad(localDriver) //alerts SessionActor localAnnounce ! PlayerFailedToLoad(localDriver) //alerts SessionActor
} }
}, },
List(RegisterNewAvatar(driver), GUIDTask.RegisterVehicle(obj)(continent.GUID)) List(GUIDTask.RegisterAvatar(driver)(continent.GUID), GUIDTask.RegisterVehicle(obj)(continent.GUID))
) )
} }
@ -7012,12 +7022,13 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
//driver //driver
continent.Transport ! Zone.Vehicle.Spawn(vehicle) 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 seat = vehicle.Seats(0) val mount = vehicle.Seats(0)
seat.unmount(player) mount.unmount(player)
player.VehicleSeated = None player.VehicleSeated = None
val data = vdef.Packet.ConstructorData(vehicle).get val data = vdef.Packet.ConstructorData(vehicle).get
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data)) sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data))
seat.mount(player) mount.mount(player)
player.VehicleSeated = vguid
Vehicles.Own(vehicle, player) Vehicles.Own(vehicle, player)
vehicle.CargoHolds.values vehicle.CargoHolds.values
.collect { case hold if hold.isOccupied => hold.occupant.get } .collect { case hold if hold.isOccupied => hold.occupant.get }
@ -8615,14 +8626,14 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
VehicleAction.TransferPassengerChannel(pguid, s"${vehicle.Actor}", toChannel, vehicle, topLevel) VehicleAction.TransferPassengerChannel(pguid, s"${vehicle.Actor}", toChannel, vehicle, topLevel)
) )
manifest.cargo.foreach { manifest.cargo.foreach {
case ("MISSING_DRIVER", index) => case ManifestPassengerEntry("MISSING_DRIVER", index) =>
val cargo = vehicle.CargoHolds(index).occupant.get val cargo = vehicle.CargoHolds(index).occupant.get
log.warn(s"LoadZoneInVehicleAsDriver: ${player.Name} must eject cargo in hold $index; vehicle is missing driver") log.warn(s"LoadZoneInVehicleAsDriver: ${player.Name} must eject cargo in hold $index; vehicle is missing driver")
CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, vehicle.GUID, vehicle, false, false, true) CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, vehicle.GUID, vehicle, false, false, true)
case (name, index) => case entry =>
val cargo = vehicle.CargoHolds(index).occupant.get val cargo = vehicle.CargoHolds(entry.mount).occupant.get
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! VehicleServiceMessage(
name, entry.name,
VehicleAction.TransferPassengerChannel(pguid, s"${cargo.Actor}", toChannel, cargo, topLevel) VehicleAction.TransferPassengerChannel(pguid, s"${cargo.Actor}", toChannel, cargo, topLevel)
) )
} }
@ -8649,9 +8660,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
player.VehicleSeated = vehicle.GUID player.VehicleSeated = vehicle.GUID
player.Continent = zoneId //forward-set the continent id to perform a test player.Continent = zoneId //forward-set the continent id to perform a test
interstellarFerryTopLevelGUID = interstellarFerryTopLevelGUID =
if ( if (manifest.passengers.isEmpty && manifest.cargo.count { !_.name.equals("MISSING_DRIVER") } == 0) {
manifest.passengers.isEmpty && manifest.cargo.count { case (name, _) => !name.equals("MISSING_DRIVER") } == 0
) {
//do not delete if vehicle has passengers or cargo //do not delete if vehicle has passengers or cargo
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! VehicleServiceMessage(
continent.id, continent.id,
@ -8741,10 +8750,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
val cargo = hold.occupant.get val cargo = hold.occupant.get
cargo.Continent = toZoneId cargo.Continent = toZoneId
//point to the cargo vehicle to instigate cargo vehicle driver transportation //point to the cargo vehicle to instigate cargo vehicle driver transportation
galaxyService ! GalaxyServiceMessage( // galaxyService ! GalaxyServiceMessage(
toChannel, // toChannel,
GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest) // GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest)
) // )
} }
case None => case None =>
log.error(s"LoadZoneTransferPassengerMessages: ${player.Name} expected a manifest for zone transfer; got nothing") log.error(s"LoadZoneTransferPassengerMessages: ${player.Name} expected a manifest for zone transfer; got nothing")

View file

@ -5,7 +5,7 @@ import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.deploy.Deployment import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.objects.serverobject.transfer.TransferContainer import net.psforever.objects.serverobject.transfer.TransferContainer
import net.psforever.objects.serverobject.structures.{StructureType, WarpGate} import net.psforever.objects.serverobject.structures.{StructureType, WarpGate}
import net.psforever.objects.vehicles.{CargoBehavior, Utility, UtilityType, VehicleLockState} import net.psforever.objects.vehicles._
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.TriggeredSound import net.psforever.packet.game.TriggeredSound
import net.psforever.types.{DriveState, PlanetSideGUID, Vector3} import net.psforever.types.{DriveState, PlanetSideGUID, Vector3}
@ -192,12 +192,14 @@ object Vehicles {
val vzone = vehicle.Zone val vzone = vehicle.Zone
vehicle.PreviousGatingManifest() match { vehicle.PreviousGatingManifest() match {
case Some(manifest) if vzone != manifest.origin => case Some(manifest) if vzone != manifest.origin =>
val manifestPassengers = manifest.passengers.collect { case (name, _) => name } :+ manifest.driverName val manifestPassengers = manifest.passengers.collect {
val manifestPassengerResults = manifestPassengers.map { name => vzone.Players.exists(_.name.equals(name)) } case ManifestPassengerEntry(name, _) => name
manifestPassengerResults.forall(_ == true) && } :+ manifest.driverName
vehicle.CargoHolds.values manifestPassengers.forall { name => vzone.Players.exists(_.name.equals(name)) } &&
.collect { case hold if hold.isOccupied => AllGatedOccupantsInSameZone(hold.occupant.get) } vehicle.CargoHolds.values.forall {
.forall(_ == true) case hold if hold.isOccupied => AllGatedOccupantsInSameZone(hold.occupant.get)
case _ => true
}
case _ => case _ =>
false false
} }

View file

@ -113,7 +113,7 @@ object CargoBehavior {
case Some(carrier: Vehicle) => case Some(carrier: Vehicle) =>
HandleCheckCargoMounting(cargoGUID, cargo, carrierGUID, carrier, mountPoint, iteration) HandleCheckCargoMounting(cargoGUID, cargo, carrierGUID, carrier, mountPoint, iteration)
case carrier if iteration > 0 => case carrier if iteration > 0 =>
log.error(s"HandleCheckCargoMounting: participant vehicles changed in the middle of a mounting event") log.warn(s"HandleCheckCargoMounting: participant vehicles changed in the middle of a mounting event")
LogCargoEventMissingVehicleError("HandleCheckCargoMounting: carrier", carrier, carrierGUID) LogCargoEventMissingVehicleError("HandleCheckCargoMounting: carrier", carrier, carrierGUID)
false false
case _ => case _ =>
@ -148,8 +148,8 @@ object CargoBehavior {
if (distance <= 64) { if (distance <= 64) {
//cargo vehicle is close enough to assume to be physically within the carrier's hold; mount it //cargo vehicle is close enough to assume to be physically within the carrier's hold; mount it
log.debug(s"HandleCheckCargoMounting: mounting cargo vehicle in carrier at distance of $distance") log.debug(s"HandleCheckCargoMounting: mounting cargo vehicle in carrier at distance of $distance")
cargo.MountedIn = carrierGUID
hold.mount(cargo) hold.mount(cargo)
cargo.MountedIn = carrierGUID
cargo.Velocity = None cargo.Velocity = None
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! VehicleServiceMessage(
s"${cargo.Actor}", s"${cargo.Actor}",
@ -159,7 +159,7 @@ object CargoBehavior {
s"${cargo.Actor}", s"${cargo.Actor}",
VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 68, cargo.Shields)) VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 68, cargo.Shields))
) )
val (attachMsg, mountPointMsg) = CargoMountBehaviorForAll(carrier, cargo, mountPoint) CargoMountBehaviorForAll(carrier, cargo, mountPoint)
false false
} else if (distance > 625 || iteration >= 40) { } else if (distance > 625 || iteration >= 40) {
//vehicles moved too far away or took too long to get into proper position; abort mounting //vehicles moved too far away or took too long to get into proper position; abort mounting
@ -286,8 +286,8 @@ object CargoBehavior {
//obviously, don't do this //obviously, don't do this
} else if (iteration > 40) { } else if (iteration > 40) {
//cargo vehicle has spent too long not getting far enough away; restore the cargo's mount in the carrier hold //cargo vehicle has spent too long not getting far enough away; restore the cargo's mount in the carrier hold
cargo.MountedIn = carrierGUID
hold.mount(cargo) hold.mount(cargo)
cargo.MountedIn = carrierGUID
CargoMountBehaviorForAll(carrier, cargo, mountPoint) CargoMountBehaviorForAll(carrier, cargo, mountPoint)
false false
} else { } else {

View file

@ -301,7 +301,7 @@ class VehicleControl(vehicle: Vehicle)
zone.id, zone.id,
VehicleAction.UnloadVehicle(Service.defaultPlayerGUID, vehicle, vehicle.GUID) VehicleAction.UnloadVehicle(Service.defaultPlayerGUID, vehicle, vehicle.GUID)
) )
zone.Transport ! Zone.Vehicle.Despawn(vehicle) zone.Transport.tell(Zone.Vehicle.Despawn(vehicle), zone.Transport)
case _ => case _ =>
} }

View file

@ -2,11 +2,18 @@
package net.psforever.objects.vehicles package net.psforever.objects.vehicles
import net.psforever.objects.Vehicle import net.psforever.objects.Vehicle
import net.psforever.objects.serverobject.mount.Seat
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
/** /**
* na * A record that records some passenger information.
* @param name the passenger name for direct vehicle passengers;
* the driver name for cargo vehicles
* @param mount the mount index
*/
final case class ManifestPassengerEntry(name: String, mount: Int)
/**
* A record of accounting of the the vehicle's state at a given time.
* @param file the id of this manifest entry; * @param file the id of this manifest entry;
* used as the channel name for summoning passengers to the vehicle * used as the channel name for summoning passengers to the vehicle
* after it has been loaded to a new location or to a new zone; * after it has been loaded to a new location or to a new zone;
@ -23,30 +30,29 @@ final case class VehicleManifest(
vehicle: Vehicle, vehicle: Vehicle,
origin: Zone, origin: Zone,
driverName: String, driverName: String,
passengers: List[(String, Int)], passengers: List[ManifestPassengerEntry],
cargo: List[(String, Int)] cargo: List[ManifestPassengerEntry]
) )
object VehicleManifest { object VehicleManifest {
def apply(vehicle: Vehicle): VehicleManifest = { def apply(vehicle: Vehicle): VehicleManifest = {
val driverName = vehicle.Seats(0).occupant match { val driverName = vehicle.Seats(0).occupant match {
case Some(driver) => driver.Name case Some(driver) => driver.Name
case None => "MISSING_DRIVER" case None => "MISSING_DRIVER"
} }
val passengers = vehicle.Seats.collect { val passengers = vehicle.Seats.toList
case (index: Int, seat: Seat) if index > 0 && seat.isOccupied => .filter { case (index, mount) => index > 0 && mount.isOccupied }
(seat.occupant.get.Name, index) .map { case (index, mount) => ManifestPassengerEntry(mount.occupant.get.Name, index) }
} val cargo = vehicle.CargoHolds.toList
val cargo = vehicle.CargoHolds.collect { .collect {
case (index: Int, hold: Cargo) if hold.occupant.nonEmpty => case (index: Int, hold: Cargo) if hold.occupant.nonEmpty =>
hold.occupant.get.Seats(0).occupant match { hold.occupant.get.Seats(0).occupant match {
case Some(driver) => case Some(driver) => ManifestPassengerEntry(driver.Name, index)
(driver.Name, index) case None => ManifestPassengerEntry("MISSING_DRIVER", index)
case None => }
("MISSING_DRIVER", index) }
} VehicleManifest(ManifestChannelName(vehicle), vehicle, vehicle.Zone, driverName, passengers, cargo)
}
VehicleManifest(ManifestChannelName(vehicle), vehicle, vehicle.Zone, driverName, passengers.toList, cargo.toList)
} }
def ManifestChannelName(vehicle: Vehicle): String = { def ManifestChannelName(vehicle: Vehicle): String = {

View file

@ -57,6 +57,10 @@ class ZoneVehicleActor(zone: Zone, vehicleList: ListBuffer[Vehicle]) extends Act
sender() ! Zone.Vehicle.CanNotDespawn(zone, vehicle, "can not find") sender() ! Zone.Vehicle.CanNotDespawn(zone, vehicle, "can not find")
} }
case Zone.Vehicle.HasDespawned(_, _) => ;
case Zone.Vehicle.CanNotDespawn(_, _, _) => ;
case _ => ; case _ => ;
} }
} }