deployable ownership should be asserted during both re-zoning and revival; refactoring of code in ZoningOperations

This commit is contained in:
Fate-JH 2024-08-12 13:28:21 -04:00
parent 3c4907c107
commit 1703a7a0a0

View file

@ -8,8 +8,9 @@ import akka.pattern.ask
import akka.util.Timeout
import net.psforever.actors.session.spectator.SpectatorMode
import net.psforever.login.WorldSession
import net.psforever.objects.avatar.BattleRank
import net.psforever.objects.avatar.{BattleRank, DeployableToolbox}
import net.psforever.objects.avatar.scoring.{CampaignStatistics, ScoreCard, SessionStatistics}
import net.psforever.objects.definition.converter.OCM
import net.psforever.objects.inventory.InventoryItem
import net.psforever.objects.serverobject.interior.Sidedness
import net.psforever.objects.serverobject.mount.Seat
@ -28,7 +29,7 @@ import scala.util.Success
//
import net.psforever.actors.session.{AvatarActor, SessionActor}
import net.psforever.login.WorldSession.RemoveOldEquipmentFromInventory
import net.psforever.objects.avatar.{Avatar, DeployableToolbox}
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.avatar.{Award, AwardCategory, PlayerControl, Shortcut => AvatarShortcut}
import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem, TelepadLike}
import net.psforever.objects.definition.SpecialExoSuitDefinition
@ -215,104 +216,13 @@ class ZoningOperations(
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
//find and reclaim own deployables, if any
val foundDeployables = continent.DeployableList.filter {
case _: BoomerDeployable => false //if we do find boomers for any reason, ignore them
case dobj => dobj.OwnerName.contains(player.Name) && dobj.Health > 0
}
foundDeployables.collect {
case obj if avatar.deployables.AddOverLimit(obj) =>
obj.Actor ! Deployable.Ownership(player)
}
//render deployable objects
val (turrets, normal) = continent.DeployableList.partition(obj =>
DeployableToolbox.UnifiedType(obj.Definition.Item) == DeployedItem.portable_manned_turret
val deployables = continent.DeployableList
reclaimOurDeployables(deployables, name, manageDeployablesWith(player.GUID, avatar.deployables))
drawDeployableIconsOnMap(
depictDeployables(deployables).filter(_.Faction == faction)
)
normal.foreach(obj => {
val definition = obj.Definition
sendResponse(
ObjectCreateMessage(
definition.ObjectId,
obj.GUID,
definition.Packet.ConstructorData(obj).get
)
)
})
turrets.foreach(obj => {
val objGUID = obj.GUID
val definition = obj.Definition
sendResponse(
ObjectCreateMessage(
definition.ObjectId,
objGUID,
definition.Packet.ConstructorData(obj).get
)
)
//seated players
obj
.asInstanceOf[Mountable]
.Seats
.values
.map(_.occupant)
.collect {
case Some(occupant) =>
if (occupant.isAlive) {
val targetDefinition = occupant.avatar.definition
sendResponse(
ObjectCreateMessage(
targetDefinition.ObjectId,
occupant.GUID,
ObjectCreateMessageParent(objGUID, 0),
targetDefinition.Packet.ConstructorData(occupant).get
)
)
}
}
//auto turret behavior
(obj match {
case turret: AutomatedTurret with JammableUnit => turret.Target
case _ => None
}).collect {
target =>
val guid = obj.GUID
val turret = obj.asInstanceOf[AutomatedTurret]
sendResponse(ObjectDetectedMessage(guid, guid, 0, List(target.GUID)))
if (!obj.asInstanceOf[JammableUnit].Jammed) {
sendResponse(ChangeFireStateMessage_Start(turret.Weapons.values.head.Equipment.get.GUID))
}
}
})
//sensor animation
normal
.filter(obj =>
obj.Definition.DeployCategory == DeployableCategory.Sensors &&
!obj.Destroyed &&
(obj match {
case jObj: JammableUnit => !jObj.Jammed
case _ => true
})
)
.foreach(obj => {
sendResponse(TriggerEffectMessage(obj.GUID, "on", unk1=true, 1000))
})
//update the health of our faction's deployables (if necessary)
//draw our faction's deployables on the map
continent.DeployableList
.filter(obj => obj.Faction == faction && !obj.Destroyed)
.foreach(obj => {
if (obj.Health != obj.DefaultHealth) {
sendResponse(PlanetsideAttributeMessage(obj.GUID, 0, obj.Health))
}
val deployInfo = DeployableInfo(
obj.GUID,
Deployable.Icon(obj.Definition.Item),
obj.Position,
obj.OwnerGuid.getOrElse(PlanetSideGUID(0))
)
sendResponse(DeployableObjectsInfoMessage(DeploymentAction.Build, deployInfo))
})
//render Equipment that was dropped into zone before the player arrived
continent.EquipmentOnGround.foreach(item => {
continent.EquipmentOnGround.foreach { item =>
val definition = item.Definition
sendResponse(
ObjectCreateMessage(
@ -324,26 +234,19 @@ class ZoningOperations(
)
)
)
})
}
//load active players in zone (excepting players who are seated or players who are us)
val live = continent.LivePlayers
live
.filterNot(tplayer => {
.filterNot { tplayer =>
tplayer.GUID == player.GUID || tplayer.VehicleSeated.nonEmpty
})
.foreach(targetPlayer => {
val targetDefinition = player.avatar.definition
sendResponse(
ObjectCreateMessage(
targetDefinition.ObjectId,
targetPlayer.GUID,
targetDefinition.Packet.ConstructorData(targetPlayer).get
)
)
}
.foreach { targetPlayer =>
sendResponse(OCM.apply(targetPlayer))
if (targetPlayer.UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored) {
sendResponse(PlanetsideAttributeMessage(targetPlayer.GUID, 19, 1))
}
})
}
//load corpses in zone
continent.Corpses.foreach {
spawn.DepictPlayerAsCorpse
@ -376,10 +279,7 @@ class ZoningOperations(
//active vehicles (and some wreckage)
vehicles.foreach { vehicle =>
val vguid = vehicle.GUID
val vdefinition = vehicle.Definition
sendResponse(
ObjectCreateMessage(vdefinition.ObjectId, vguid, vdefinition.Packet.ConstructorData(vehicle).get)
)
sendResponse(OCM.apply(vehicle))
//occupants other than driver (with exceptions)
vehicle.Seats
.filter {
@ -393,15 +293,10 @@ class ZoningOperations(
}
.foreach {
case (index, seat) =>
val targetPlayer = seat.occupant.get
val targetDefiniton = targetPlayer.avatar.definition
sendResponse(
ObjectCreateMessage(
targetDefiniton.ObjectId,
targetPlayer.GUID,
ObjectCreateMessageParent(vguid, index),
targetDefiniton.Packet.ConstructorData(targetPlayer).get
)
OCM.apply(seat.occupant.get)
.asInstanceOf[ObjectCreateMessage]
.copy(parentInfo = Some(ObjectCreateMessageParent(vguid, index)))
)
}
vehicle.SubsystemMessages().foreach { sendResponse }
@ -411,8 +306,8 @@ class ZoningOperations(
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
}
//our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate
usedVehicle.headOption match {
case Some(vehicle) =>
usedVehicle.headOption.collect {
case vehicle =>
//subsystems
vehicle.Actor ! Vehicle.UpdateSubsystemStates(player.Name, Some(false))
//depict any other passengers already in this zone
@ -430,15 +325,10 @@ class ZoningOperations(
}
.foreach {
case (index, seat) =>
val targetPlayer = seat.occupant.get
val targetDefinition = targetPlayer.avatar.definition
sendResponse(
ObjectCreateMessage(
targetDefinition.ObjectId,
targetPlayer.GUID,
ObjectCreateMessageParent(vguid, index),
targetDefinition.Packet.ConstructorData(targetPlayer).get
)
OCM.apply(seat.occupant.get)
.asInstanceOf[ObjectCreateMessage]
.copy(parentInfo = Some(ObjectCreateMessageParent(vguid, index)))
)
}
//since we would have only subscribed recently, we need to reload mount access states
@ -449,10 +339,9 @@ class ZoningOperations(
if (vehicle.Shields > 0) {
sendResponse(PlanetsideAttributeMessage(vguid, vehicle.Definition.shieldUiAttribute, vehicle.Shields))
}
case _ => () //no vehicle
}
//vehicle wreckages
wreckages.foreach(vehicle => {
wreckages.foreach { vehicle =>
sendResponse(
ObjectCreateMessage(
vehicle.Definition.DestroyedModel.get.id,
@ -460,17 +349,14 @@ class ZoningOperations(
DestroyedVehicleConverter.converter.ConstructorData(vehicle).get
)
)
})
}
//cargo occupants (including our own vehicle as cargo)
allActiveVehicles.collect {
case vehicle if vehicle.CargoHolds.nonEmpty =>
vehicle.CargoHolds.collect {
case (_index, hold: Cargo) if hold.isOccupied =>
CarrierBehavior.CargoMountBehaviorForAll(
vehicle,
hold.occupant.get,
_index
) //CargoMountBehaviorForUs can fail to attach the cargo vehicle on some clients
//CargoMountBehaviorForUs can fail to attach the cargo vehicle on some clients
CarrierBehavior.CargoMountBehaviorForAll(vehicle, hold.occupant.get, _index)
}
}
//special deploy states
@ -492,8 +378,8 @@ class ZoningOperations(
}
deployedVehicles.filter(_.Definition == GlobalDefinitions.router).foreach { obj =>
//the router won't work if it doesn't completely deploy
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deploying, 0, unk3=false, Vector3.Zero))
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deployed, 0, unk3=false, Vector3.Zero))
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deploying, 0, unk3 = false, Vector3.Zero))
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deployed, 0, unk3 = false, Vector3.Zero))
sessionLogic.general.toggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent))
}
ServiceManager.serviceManager
@ -504,41 +390,30 @@ class ZoningOperations(
case _ =>
}
//implant terminals
continent.map.terminalToInterface.foreach({
continent.map.terminalToInterface.foreach {
case (terminal_guid, interface_guid) =>
val parent_guid = PlanetSideGUID(terminal_guid)
continent.GUID(interface_guid) match {
case Some(obj: Terminal) =>
val objDef = obj.Definition
continent.GUID(interface_guid).collect {
case obj: Terminal =>
sendResponse(
ObjectCreateMessage(
objDef.ObjectId,
PlanetSideGUID(interface_guid),
ObjectCreateMessageParent(parent_guid, 1),
objDef.Packet.ConstructorData(obj).get
)
OCM.apply(obj)
.asInstanceOf[ObjectCreateMessage]
.copy(parentInfo = Some(ObjectCreateMessageParent(parent_guid, 1)))
)
case _ => ()
}
//mount terminal occupants
continent.GUID(terminal_guid) match {
case Some(obj: Mountable) =>
obj.Seats(0).occupant match {
case Some(targetPlayer: Player) =>
val targetDefinition = targetPlayer.avatar.definition
continent.GUID(terminal_guid).collect {
case obj: Mountable =>
obj.Seats(0).occupant.collect {
case occupant: Player =>
sendResponse(
ObjectCreateMessage(
targetDefinition.ObjectId,
targetPlayer.GUID,
ObjectCreateMessageParent(parent_guid, 0),
targetDefinition.Packet.ConstructorData(targetPlayer).get
)
OCM.apply(occupant)
.asInstanceOf[ObjectCreateMessage]
.copy(parentInfo = Some(ObjectCreateMessageParent(parent_guid, 0)))
)
case _ => ()
}
case _ => ()
}
})
}
//facility turrets
continent.map.turretToWeapon
.map { case (turret_guid: Int, _) => continent.GUID(turret_guid) }
@ -549,14 +424,10 @@ class ZoningOperations(
if (!turret.isUpgrading) {
turret.ControlledWeapon(wepNumber = 1).foreach {
case obj: Tool =>
val objDef = obj.Definition
sendResponse(
ObjectCreateMessage(
objDef.ObjectId,
obj.GUID,
ObjectCreateMessageParent(pguid, 1),
objDef.Packet.ConstructorData(obj).get
)
OCM.apply(obj)
.asInstanceOf[ObjectCreateMessage]
.copy(parentInfo = Some(ObjectCreateMessageParent(pguid, 1)))
)
case _ => ()
}
@ -564,38 +435,19 @@ class ZoningOperations(
//reserved ammunition?
//TODO need to register if it exists
//mount turret occupant
turret.Seats(0).occupant match {
case Some(targetPlayer: Player) =>
val targetDefinition = targetPlayer.avatar.definition
turret.Seats(0).occupant.collect {
case occupant: Player =>
sendResponse(
ObjectCreateMessage(
targetDefinition.ObjectId,
targetPlayer.GUID,
ObjectCreateMessageParent(pguid, 0),
targetDefinition.Packet.ConstructorData(targetPlayer).get
)
OCM.apply(occupant)
.asInstanceOf[ObjectCreateMessage]
.copy(parentInfo = Some(ObjectCreateMessageParent(pguid, 0)))
)
case _ => ()
}
turret.Target.collect {
target =>
val guid = turret.GUID
sendResponse(ObjectDetectedMessage(guid, guid, 0, List(target.GUID)))
if (!turret.Jammed) {
sendResponse(ChangeFireStateMessage_Start(turret.Weapons.values.head.Equipment.get.GUID))
}
}
triggerAutomatedTurretFire(turret)
}
//remote projectiles and radiation clouds
continent.Projectiles.foreach { projectile =>
val definition = projectile.Definition
sendResponse(
ObjectCreateMessage(
definition.ObjectId,
projectile.GUID,
definition.Packet.ConstructorData(projectile).get
)
)
sendResponse(OCM.apply(projectile))
}
//spawn point update request
continent.VehicleEvents ! VehicleServiceMessage(
@ -1166,14 +1018,7 @@ class ZoningOperations(
// sync capture flags
case llu: CaptureFlag =>
// Create LLU
sendResponse(
ObjectCreateMessage(
llu.Definition.ObjectId,
llu.GUID,
llu.Definition.Packet.ConstructorData(llu).get
)
)
sendResponse(OCM.apply(llu))
// Attach it to a player if it has a carrier
if (llu.Carrier.nonEmpty) {
continent.LocalEvents ! LocalServiceMessage(
@ -1755,6 +1600,188 @@ class ZoningOperations(
*/
def NormalKeepAlive(): Unit = {}
/**
* Find all deployables that internally keep track of a player's name as its owner
* and change the GUID associated with that owner (reclaim it).
* @param deployables list of deployables
* @param name owner name
* @param reclamationStrategy what happens to deployables to re-assign ownership
* @return the list of deployables whose owenrship has been re-assigned
*/
def reclaimOurDeployables(
deployables: List[Deployable],
name: String,
reclamationStrategy: Deployable => Option[Deployable]
): List[Deployable] = {
deployables
.filter {
case _: BoomerDeployable => false //always ignore
case obj => obj.OwnerName.contains(name) && !obj.Destroyed && obj.Health > 0
}
.flatMap(reclamationStrategy)
}
/**
* If the deployable was added to a management collection, reassign its internal owner GUID.
* Hence, it can fail.
* @param toGuid anticipated ownership GUID
* @param managedDeployables collection for logically organizing deployables
* @param obj deployable designated for ownership
* @return the deployable, if it was capable of being managed and ownership was re-assigned
*/
def manageDeployablesWith(toGuid: PlanetSideGUID, managedDeployables: DeployableToolbox)(obj: Deployable): Option[Deployable] = {
if (managedDeployables.AddOverLimit(obj)) {
reassignDeployablesTo(toGuid)(obj)
} else {
None
}
}
/**
* Reassign the internal owner GUID on this deployable.
* @param toGuid anticipated ownership GUID
* @param obj deployable designated for ownership
* @return the deployable, but now assigned to the GUID
*/
def reassignDeployablesTo(toGuid: PlanetSideGUID)(obj: Deployable): Option[Deployable] = {
obj.OwnerGuid = toGuid
Some(obj)
}
/**
* Render and animate all provided deployables.
* Animation includes occupants for mountable deployables and ongoing behaviors for automated deployables.
* @param deployables list of deployables
* @return list of working deployables
* @see `OCM.apply`
*/
def depictDeployables(deployables: List[Deployable]): List[Deployable] = {
val (smallTurrets, largeTurrets, sensors, normal, brokenThings) = {
val (broken, working) = deployables.partition { obj =>
obj.Destroyed || obj.Health == 0 || (obj match {
case jammable: JammableUnit => jammable.Jammed
case _ => false
})
}
val (small, remainder1) = working.partition { obj => obj.Definition.DeployCategory == DeployableCategory.SmallTurrets }
val (large, remainder2) = remainder1.partition { obj => obj.Definition.DeployCategory == DeployableCategory.FieldTurrets }
val (sensor, remainder3) = remainder2.partition { obj => obj.Definition.DeployCategory == DeployableCategory.Sensors }
(small, large, sensor, remainder3, broken)
}
val miscThings = normal ++ sensors ++ smallTurrets
(brokenThings ++ miscThings).foreach { obj =>
sendResponse(OCM.apply(obj))
}
largeTurrets.foreach { obj =>
sendResponse(OCM.apply(obj))
//seated players
obj
.asInstanceOf[Mountable]
.Seats
.values
.map(_.occupant)
.collect {
case Some(occupant) if occupant.isAlive =>
sendResponse(
OCM.apply(occupant)
.asInstanceOf[ObjectCreateMessage]
.copy(parentInfo = Some(ObjectCreateMessageParent(obj.GUID, 0)))
)
}
}
triggerAutomatedTurretFire(smallTurrets)
triggerSensorDeployables(sensors)
miscThings ++ largeTurrets
}
/**
* Render and animate all provided deployables.
* Animation includes ongoing behaviors for automated deployables.
* @param deployables list of deployables
* @return list of working deployables
* @see `OCM.apply`
*/
def depictDeployablesUponRevival(deployables: List[Deployable]): List[Deployable] = {
val (smallTurrets, sensors, normal) = {
val (_, working) = deployables.partition { obj =>
obj.Destroyed || obj.Health == 0 || (obj match {
case jammable: JammableUnit => jammable.Jammed
case _ => false
})
}
val (small, remainder1) = working.partition { obj => obj.Definition.DeployCategory == DeployableCategory.SmallTurrets }
val (sensor, remainder2) = remainder1.partition { obj => obj.Definition.DeployCategory == DeployableCategory.Sensors }
(small, sensor, remainder2)
}
val miscThings = normal ++ sensors ++ smallTurrets
miscThings.foreach { obj =>
sendResponse(OCM.apply(obj))
}
triggerAutomatedTurretFire(smallTurrets)
triggerSensorDeployables(sensors)
miscThings
}
/**
* Treat the deployables as sensor-types and provide appropriate animation.
* This animation is the glowing halo-ing effect on its sensor bulb.
* @param sensors list of deployables
* @see `TriggerEffectMessage`
*/
def triggerSensorDeployables(sensors: List[Deployable]): Unit = {
sensors.foreach { obj =>
sendResponse(TriggerEffectMessage(obj.GUID, effect = "on", unk1 = true, unk2 = 1000))
}
}
/**
* Treat the deployables as small turret-types and provide appropriate animation.
* This animation is related to its automation - tracking and shooting.
* @param turrets list of deployables
*/
def triggerAutomatedTurretFire(turrets: List[Deployable]): Unit = {
turrets.collect { case turret: AutomatedTurret =>
triggerAutomatedTurretFire(turret)
}
}
/**
* Provide appropriate animation to the small turret deployable.
* This animation is related to its automation - tracking and shooting.
* @param turret small turret deployable
* @see `ChangeFireStateMessage_Start`
* @see `ObjectDetectedMessage`
*/
def triggerAutomatedTurretFire(turret: AutomatedTurret): Unit = {
turret.Target.foreach { target =>
val guid = turret.GUID
sendResponse(ObjectDetectedMessage(guid, guid, 0, List(target.GUID)))
sendResponse(ChangeFireStateMessage_Start(turret.Weapons.values.head.Equipment.get.GUID))
}
}
/**
* Draw or redraw deployment map icons related to deployable presence and deployable management (if the owner).
* Assert deployable health as a precaution.
* @param deployables list of deployables
* @see `DeployableObjectsInfoMessage`
*/
def drawDeployableIconsOnMap(deployables: List[Deployable]): Unit = {
deployables
.foreach { obj =>
val guid = obj.GUID
val health = obj.Health
if (health != obj.DefaultHealth) {
sendResponse(PlanetsideAttributeMessage(guid, 0, health))
}
sendResponse(DeployableObjectsInfoMessage(DeploymentAction.Build, DeployableInfo(
guid,
Deployable.Icon(obj.Definition.Item),
obj.Position,
obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID)
)))
}
}
/* nested class - spawn operations */
class SpawnOperations() {
@ -2298,10 +2325,11 @@ class ZoningOperations(
//vehicle and driver/passenger
interstellarFerry = None
val vdef = vehicle.Definition
val vObjectId = vdef.ObjectId
val vguid = vehicle.GUID
vehicle.Position = shiftPosition.getOrElse(vehicle.Position)
vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation)
val vdata = if (seat == 0) {
if (seat == 0) {
//driver
if (vehicle.Zone ne continent) {
continent.Transport ! Zone.Vehicle.Spawn(vehicle)
@ -2311,7 +2339,7 @@ class ZoningOperations(
mount.unmount(player)
player.VehicleSeated = None
val data = vdef.Packet.ConstructorData(vehicle).get
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data))
sendResponse(ObjectCreateMessage(vObjectId, vguid, data))
mount.mount(player)
player.VehicleSeated = vguid
Vehicles.Own(vehicle, player)
@ -2320,7 +2348,7 @@ class ZoningOperations(
.foreach { _.MountedIn = vguid }
events ! VehicleServiceMessage(
zoneid,
VehicleAction.LoadVehicle(player.GUID, vehicle, vdef.ObjectId, vguid, data)
VehicleAction.LoadVehicle(player.GUID, vehicle, vObjectId, vguid, data)
)
carrierInfo match {
case (Some(carrier), Some((index, _))) =>
@ -2329,18 +2357,15 @@ class ZoningOperations(
vehicle.MountedIn = None
}
vehicle.allowInteraction = true
data
} else {
//passenger
//non-drivers are not rendered in the vehicle at this time
val data = vdef.Packet.ConstructorData(vehicle).get
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data))
sendResponse(OCM.apply(vehicle))
carrierInfo match {
case (Some(carrier), Some((index, _))) =>
CargoMountBehaviorForUs(carrier, vehicle, index)
case _ => ()
}
data
}
val originalSeated = player.VehicleSeated
player.VehicleSeated = vguid
@ -2357,25 +2382,26 @@ class ZoningOperations(
)
}
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name}")
log.trace(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name} - $vguid -> $vdata")
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vdef.Name}")
AvatarCreateInVehicle(player, vehicle, seat)
case _ =>
player.VehicleSeated = None
val packet = player.avatar.definition.Packet
val data = packet.DetailedConstructorData(player).get
val guid = player.GUID
sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, guid, data))
val definition = player.avatar.definition
val guid = player.GUID
sendResponse(OCM.detailed(player))
continent.AvatarEvents ! AvatarServiceMessage(
zoneid,
AvatarAction.LoadPlayer(guid, ObjectClass.avatar, guid, packet.ConstructorData(player).get, None)
AvatarAction.LoadPlayer(guid, definition.ObjectId, guid, definition.Packet.ConstructorData(player).get, None)
)
log.debug(s"AvatarCreate: ${player.Name}")
log.trace(s"AvatarCreate: ${player.Name} - $guid -> $data")
}
continent.Population ! Zone.Population.Spawn(avatar, player, avatarActor)
avatarActor ! AvatarActor.RefreshPurchaseTimes()
drawDeployableIconsOnMap(
depictDeployablesUponRevival(
reclaimOurDeployables(continent.DeployableList, player.Name, reassignDeployablesTo(player.GUID))
)
)
//begin looking for conditions to set the avatar
context.system.scheduler.scheduleOnce(delay = 250 millisecond, context.self, SessionActor.SetCurrentAvatar(player, 200))
}
@ -2403,11 +2429,9 @@ class ZoningOperations(
val pguid = tplayer.GUID
val vguid = vehicle.GUID
tplayer.VehicleSeated = None
val pdata = pdef.Packet.DetailedConstructorData(tplayer).get
tplayer.VehicleSeated = vguid
log.debug(s"AvatarCreateInVehicle: ${player.Name}")
log.trace(s"AvatarCreateInVehicle: ${player.Name} - $pguid -> $pdata")
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
sendResponse(OCM.detailed(tplayer))
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
sessionLogic.general.accessContainer(vehicle)
@ -2459,13 +2483,10 @@ class ZoningOperations(
sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
//vehicle and driver/passenger
val vdef = vehicle.Definition
val vguid = vehicle.GUID
val vdata = vdef.Packet.ConstructorData(vehicle).get
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, vdata))
sendResponse(OCM.apply(vehicle))
Vehicles.ReloadAccessPermissions(vehicle, continent.id)
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name}")
log.trace(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name} - $vguid -> $vdata")
val pdef = player.avatar.definition
val pguid = player.GUID
player.VehicleSeated = None