mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
deployable ownership should be asserted during both re-zoning and revival; refactoring of code in ZoningOperations
This commit is contained in:
parent
3c4907c107
commit
1703a7a0a0
1 changed files with 253 additions and 232 deletions
|
|
@ -8,8 +8,9 @@ import akka.pattern.ask
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import net.psforever.actors.session.spectator.SpectatorMode
|
import net.psforever.actors.session.spectator.SpectatorMode
|
||||||
import net.psforever.login.WorldSession
|
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.avatar.scoring.{CampaignStatistics, ScoreCard, SessionStatistics}
|
||||||
|
import net.psforever.objects.definition.converter.OCM
|
||||||
import net.psforever.objects.inventory.InventoryItem
|
import net.psforever.objects.inventory.InventoryItem
|
||||||
import net.psforever.objects.serverobject.interior.Sidedness
|
import net.psforever.objects.serverobject.interior.Sidedness
|
||||||
import net.psforever.objects.serverobject.mount.Seat
|
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.actors.session.{AvatarActor, SessionActor}
|
||||||
import net.psforever.login.WorldSession.RemoveOldEquipmentFromInventory
|
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.avatar.{Award, AwardCategory, PlayerControl, Shortcut => AvatarShortcut}
|
||||||
import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem, TelepadLike}
|
import net.psforever.objects.ce.{Deployable, DeployableCategory, DeployedItem, TelepadLike}
|
||||||
import net.psforever.objects.definition.SpecialExoSuitDefinition
|
import net.psforever.objects.definition.SpecialExoSuitDefinition
|
||||||
|
|
@ -215,104 +216,13 @@ class ZoningOperations(
|
||||||
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
||||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
|
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
|
||||||
|
|
||||||
//find and reclaim own deployables, if any
|
val deployables = continent.DeployableList
|
||||||
val foundDeployables = continent.DeployableList.filter {
|
reclaimOurDeployables(deployables, name, manageDeployablesWith(player.GUID, avatar.deployables))
|
||||||
case _: BoomerDeployable => false //if we do find boomers for any reason, ignore them
|
drawDeployableIconsOnMap(
|
||||||
case dobj => dobj.OwnerName.contains(player.Name) && dobj.Health > 0
|
depictDeployables(deployables).filter(_.Faction == faction)
|
||||||
}
|
|
||||||
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
|
|
||||||
)
|
)
|
||||||
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
|
//render Equipment that was dropped into zone before the player arrived
|
||||||
continent.EquipmentOnGround.foreach(item => {
|
continent.EquipmentOnGround.foreach { item =>
|
||||||
val definition = item.Definition
|
val definition = item.Definition
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
ObjectCreateMessage(
|
||||||
|
|
@ -324,26 +234,19 @@ class ZoningOperations(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
//load active players in zone (excepting players who are seated or players who are us)
|
//load active players in zone (excepting players who are seated or players who are us)
|
||||||
val live = continent.LivePlayers
|
val live = continent.LivePlayers
|
||||||
live
|
live
|
||||||
.filterNot(tplayer => {
|
.filterNot { tplayer =>
|
||||||
tplayer.GUID == player.GUID || tplayer.VehicleSeated.nonEmpty
|
tplayer.GUID == player.GUID || tplayer.VehicleSeated.nonEmpty
|
||||||
})
|
}
|
||||||
.foreach(targetPlayer => {
|
.foreach { targetPlayer =>
|
||||||
val targetDefinition = player.avatar.definition
|
sendResponse(OCM.apply(targetPlayer))
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(
|
|
||||||
targetDefinition.ObjectId,
|
|
||||||
targetPlayer.GUID,
|
|
||||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (targetPlayer.UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored) {
|
if (targetPlayer.UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored) {
|
||||||
sendResponse(PlanetsideAttributeMessage(targetPlayer.GUID, 19, 1))
|
sendResponse(PlanetsideAttributeMessage(targetPlayer.GUID, 19, 1))
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
//load corpses in zone
|
//load corpses in zone
|
||||||
continent.Corpses.foreach {
|
continent.Corpses.foreach {
|
||||||
spawn.DepictPlayerAsCorpse
|
spawn.DepictPlayerAsCorpse
|
||||||
|
|
@ -376,10 +279,7 @@ class ZoningOperations(
|
||||||
//active vehicles (and some wreckage)
|
//active vehicles (and some wreckage)
|
||||||
vehicles.foreach { vehicle =>
|
vehicles.foreach { vehicle =>
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
val vdefinition = vehicle.Definition
|
sendResponse(OCM.apply(vehicle))
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(vdefinition.ObjectId, vguid, vdefinition.Packet.ConstructorData(vehicle).get)
|
|
||||||
)
|
|
||||||
//occupants other than driver (with exceptions)
|
//occupants other than driver (with exceptions)
|
||||||
vehicle.Seats
|
vehicle.Seats
|
||||||
.filter {
|
.filter {
|
||||||
|
|
@ -393,15 +293,10 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
.foreach {
|
.foreach {
|
||||||
case (index, seat) =>
|
case (index, seat) =>
|
||||||
val targetPlayer = seat.occupant.get
|
|
||||||
val targetDefiniton = targetPlayer.avatar.definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(seat.occupant.get)
|
||||||
targetDefiniton.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
targetPlayer.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(vguid, index)))
|
||||||
ObjectCreateMessageParent(vguid, index),
|
|
||||||
targetDefiniton.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
vehicle.SubsystemMessages().foreach { sendResponse }
|
vehicle.SubsystemMessages().foreach { sendResponse }
|
||||||
|
|
@ -411,8 +306,8 @@ class ZoningOperations(
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
||||||
}
|
}
|
||||||
//our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate
|
//our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate
|
||||||
usedVehicle.headOption match {
|
usedVehicle.headOption.collect {
|
||||||
case Some(vehicle) =>
|
case vehicle =>
|
||||||
//subsystems
|
//subsystems
|
||||||
vehicle.Actor ! Vehicle.UpdateSubsystemStates(player.Name, Some(false))
|
vehicle.Actor ! Vehicle.UpdateSubsystemStates(player.Name, Some(false))
|
||||||
//depict any other passengers already in this zone
|
//depict any other passengers already in this zone
|
||||||
|
|
@ -430,15 +325,10 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
.foreach {
|
.foreach {
|
||||||
case (index, seat) =>
|
case (index, seat) =>
|
||||||
val targetPlayer = seat.occupant.get
|
|
||||||
val targetDefinition = targetPlayer.avatar.definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(seat.occupant.get)
|
||||||
targetDefinition.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
targetPlayer.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(vguid, index)))
|
||||||
ObjectCreateMessageParent(vguid, index),
|
|
||||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
//since we would have only subscribed recently, we need to reload mount access states
|
//since we would have only subscribed recently, we need to reload mount access states
|
||||||
|
|
@ -449,10 +339,9 @@ class ZoningOperations(
|
||||||
if (vehicle.Shields > 0) {
|
if (vehicle.Shields > 0) {
|
||||||
sendResponse(PlanetsideAttributeMessage(vguid, vehicle.Definition.shieldUiAttribute, vehicle.Shields))
|
sendResponse(PlanetsideAttributeMessage(vguid, vehicle.Definition.shieldUiAttribute, vehicle.Shields))
|
||||||
}
|
}
|
||||||
case _ => () //no vehicle
|
|
||||||
}
|
}
|
||||||
//vehicle wreckages
|
//vehicle wreckages
|
||||||
wreckages.foreach(vehicle => {
|
wreckages.foreach { vehicle =>
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
ObjectCreateMessage(
|
||||||
vehicle.Definition.DestroyedModel.get.id,
|
vehicle.Definition.DestroyedModel.get.id,
|
||||||
|
|
@ -460,17 +349,14 @@ class ZoningOperations(
|
||||||
DestroyedVehicleConverter.converter.ConstructorData(vehicle).get
|
DestroyedVehicleConverter.converter.ConstructorData(vehicle).get
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
//cargo occupants (including our own vehicle as cargo)
|
//cargo occupants (including our own vehicle as cargo)
|
||||||
allActiveVehicles.collect {
|
allActiveVehicles.collect {
|
||||||
case vehicle if vehicle.CargoHolds.nonEmpty =>
|
case vehicle if vehicle.CargoHolds.nonEmpty =>
|
||||||
vehicle.CargoHolds.collect {
|
vehicle.CargoHolds.collect {
|
||||||
case (_index, hold: Cargo) if hold.isOccupied =>
|
case (_index, hold: Cargo) if hold.isOccupied =>
|
||||||
CarrierBehavior.CargoMountBehaviorForAll(
|
//CargoMountBehaviorForUs can fail to attach the cargo vehicle on some clients
|
||||||
vehicle,
|
CarrierBehavior.CargoMountBehaviorForAll(vehicle, hold.occupant.get, _index)
|
||||||
hold.occupant.get,
|
|
||||||
_index
|
|
||||||
) //CargoMountBehaviorForUs can fail to attach the cargo vehicle on some clients
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//special deploy states
|
//special deploy states
|
||||||
|
|
@ -492,8 +378,8 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
deployedVehicles.filter(_.Definition == GlobalDefinitions.router).foreach { obj =>
|
deployedVehicles.filter(_.Definition == GlobalDefinitions.router).foreach { obj =>
|
||||||
//the router won't work if it doesn't completely deploy
|
//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.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.Deployed, 0, unk3 = false, Vector3.Zero))
|
||||||
sessionLogic.general.toggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent))
|
sessionLogic.general.toggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent))
|
||||||
}
|
}
|
||||||
ServiceManager.serviceManager
|
ServiceManager.serviceManager
|
||||||
|
|
@ -504,41 +390,30 @@ class ZoningOperations(
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
//implant terminals
|
//implant terminals
|
||||||
continent.map.terminalToInterface.foreach({
|
continent.map.terminalToInterface.foreach {
|
||||||
case (terminal_guid, interface_guid) =>
|
case (terminal_guid, interface_guid) =>
|
||||||
val parent_guid = PlanetSideGUID(terminal_guid)
|
val parent_guid = PlanetSideGUID(terminal_guid)
|
||||||
continent.GUID(interface_guid) match {
|
continent.GUID(interface_guid).collect {
|
||||||
case Some(obj: Terminal) =>
|
case obj: Terminal =>
|
||||||
val objDef = obj.Definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(obj)
|
||||||
objDef.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
PlanetSideGUID(interface_guid),
|
.copy(parentInfo = Some(ObjectCreateMessageParent(parent_guid, 1)))
|
||||||
ObjectCreateMessageParent(parent_guid, 1),
|
|
||||||
objDef.Packet.ConstructorData(obj).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
case _ => ()
|
|
||||||
}
|
}
|
||||||
//mount terminal occupants
|
//mount terminal occupants
|
||||||
continent.GUID(terminal_guid) match {
|
continent.GUID(terminal_guid).collect {
|
||||||
case Some(obj: Mountable) =>
|
case obj: Mountable =>
|
||||||
obj.Seats(0).occupant match {
|
obj.Seats(0).occupant.collect {
|
||||||
case Some(targetPlayer: Player) =>
|
case occupant: Player =>
|
||||||
val targetDefinition = targetPlayer.avatar.definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(occupant)
|
||||||
targetDefinition.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
targetPlayer.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(parent_guid, 0)))
|
||||||
ObjectCreateMessageParent(parent_guid, 0),
|
|
||||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
case _ => ()
|
|
||||||
}
|
}
|
||||||
case _ => ()
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
//facility turrets
|
//facility turrets
|
||||||
continent.map.turretToWeapon
|
continent.map.turretToWeapon
|
||||||
.map { case (turret_guid: Int, _) => continent.GUID(turret_guid) }
|
.map { case (turret_guid: Int, _) => continent.GUID(turret_guid) }
|
||||||
|
|
@ -549,14 +424,10 @@ class ZoningOperations(
|
||||||
if (!turret.isUpgrading) {
|
if (!turret.isUpgrading) {
|
||||||
turret.ControlledWeapon(wepNumber = 1).foreach {
|
turret.ControlledWeapon(wepNumber = 1).foreach {
|
||||||
case obj: Tool =>
|
case obj: Tool =>
|
||||||
val objDef = obj.Definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(obj)
|
||||||
objDef.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
obj.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(pguid, 1)))
|
||||||
ObjectCreateMessageParent(pguid, 1),
|
|
||||||
objDef.Packet.ConstructorData(obj).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
@ -564,38 +435,19 @@ class ZoningOperations(
|
||||||
//reserved ammunition?
|
//reserved ammunition?
|
||||||
//TODO need to register if it exists
|
//TODO need to register if it exists
|
||||||
//mount turret occupant
|
//mount turret occupant
|
||||||
turret.Seats(0).occupant match {
|
turret.Seats(0).occupant.collect {
|
||||||
case Some(targetPlayer: Player) =>
|
case occupant: Player =>
|
||||||
val targetDefinition = targetPlayer.avatar.definition
|
|
||||||
sendResponse(
|
sendResponse(
|
||||||
ObjectCreateMessage(
|
OCM.apply(occupant)
|
||||||
targetDefinition.ObjectId,
|
.asInstanceOf[ObjectCreateMessage]
|
||||||
targetPlayer.GUID,
|
.copy(parentInfo = Some(ObjectCreateMessageParent(pguid, 0)))
|
||||||
ObjectCreateMessageParent(pguid, 0),
|
|
||||||
targetDefinition.Packet.ConstructorData(targetPlayer).get
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
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
|
//remote projectiles and radiation clouds
|
||||||
continent.Projectiles.foreach { projectile =>
|
continent.Projectiles.foreach { projectile =>
|
||||||
val definition = projectile.Definition
|
sendResponse(OCM.apply(projectile))
|
||||||
sendResponse(
|
|
||||||
ObjectCreateMessage(
|
|
||||||
definition.ObjectId,
|
|
||||||
projectile.GUID,
|
|
||||||
definition.Packet.ConstructorData(projectile).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
//spawn point update request
|
//spawn point update request
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(
|
continent.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
|
@ -1166,14 +1018,7 @@ class ZoningOperations(
|
||||||
// sync capture flags
|
// sync capture flags
|
||||||
case llu: CaptureFlag =>
|
case llu: CaptureFlag =>
|
||||||
// Create LLU
|
// Create LLU
|
||||||
sendResponse(
|
sendResponse(OCM.apply(llu))
|
||||||
ObjectCreateMessage(
|
|
||||||
llu.Definition.ObjectId,
|
|
||||||
llu.GUID,
|
|
||||||
llu.Definition.Packet.ConstructorData(llu).get
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Attach it to a player if it has a carrier
|
// Attach it to a player if it has a carrier
|
||||||
if (llu.Carrier.nonEmpty) {
|
if (llu.Carrier.nonEmpty) {
|
||||||
continent.LocalEvents ! LocalServiceMessage(
|
continent.LocalEvents ! LocalServiceMessage(
|
||||||
|
|
@ -1755,6 +1600,188 @@ class ZoningOperations(
|
||||||
*/
|
*/
|
||||||
def NormalKeepAlive(): Unit = {}
|
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 */
|
/* nested class - spawn operations */
|
||||||
|
|
||||||
class SpawnOperations() {
|
class SpawnOperations() {
|
||||||
|
|
@ -2298,10 +2325,11 @@ class ZoningOperations(
|
||||||
//vehicle and driver/passenger
|
//vehicle and driver/passenger
|
||||||
interstellarFerry = None
|
interstellarFerry = None
|
||||||
val vdef = vehicle.Definition
|
val vdef = vehicle.Definition
|
||||||
|
val vObjectId = vdef.ObjectId
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
vehicle.Position = shiftPosition.getOrElse(vehicle.Position)
|
vehicle.Position = shiftPosition.getOrElse(vehicle.Position)
|
||||||
vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation)
|
vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation)
|
||||||
val vdata = if (seat == 0) {
|
if (seat == 0) {
|
||||||
//driver
|
//driver
|
||||||
if (vehicle.Zone ne continent) {
|
if (vehicle.Zone ne continent) {
|
||||||
continent.Transport ! Zone.Vehicle.Spawn(vehicle)
|
continent.Transport ! Zone.Vehicle.Spawn(vehicle)
|
||||||
|
|
@ -2311,7 +2339,7 @@ class ZoningOperations(
|
||||||
mount.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(vObjectId, vguid, data))
|
||||||
mount.mount(player)
|
mount.mount(player)
|
||||||
player.VehicleSeated = vguid
|
player.VehicleSeated = vguid
|
||||||
Vehicles.Own(vehicle, player)
|
Vehicles.Own(vehicle, player)
|
||||||
|
|
@ -2320,7 +2348,7 @@ class ZoningOperations(
|
||||||
.foreach { _.MountedIn = vguid }
|
.foreach { _.MountedIn = vguid }
|
||||||
events ! VehicleServiceMessage(
|
events ! VehicleServiceMessage(
|
||||||
zoneid,
|
zoneid,
|
||||||
VehicleAction.LoadVehicle(player.GUID, vehicle, vdef.ObjectId, vguid, data)
|
VehicleAction.LoadVehicle(player.GUID, vehicle, vObjectId, vguid, data)
|
||||||
)
|
)
|
||||||
carrierInfo match {
|
carrierInfo match {
|
||||||
case (Some(carrier), Some((index, _))) =>
|
case (Some(carrier), Some((index, _))) =>
|
||||||
|
|
@ -2329,18 +2357,15 @@ class ZoningOperations(
|
||||||
vehicle.MountedIn = None
|
vehicle.MountedIn = None
|
||||||
}
|
}
|
||||||
vehicle.allowInteraction = true
|
vehicle.allowInteraction = true
|
||||||
data
|
|
||||||
} else {
|
} else {
|
||||||
//passenger
|
//passenger
|
||||||
//non-drivers are not rendered in the vehicle at this time
|
//non-drivers are not rendered in the vehicle at this time
|
||||||
val data = vdef.Packet.ConstructorData(vehicle).get
|
sendResponse(OCM.apply(vehicle))
|
||||||
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, data))
|
|
||||||
carrierInfo match {
|
carrierInfo match {
|
||||||
case (Some(carrier), Some((index, _))) =>
|
case (Some(carrier), Some((index, _))) =>
|
||||||
CargoMountBehaviorForUs(carrier, vehicle, index)
|
CargoMountBehaviorForUs(carrier, vehicle, index)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
data
|
|
||||||
}
|
}
|
||||||
val originalSeated = player.VehicleSeated
|
val originalSeated = player.VehicleSeated
|
||||||
player.VehicleSeated = vguid
|
player.VehicleSeated = vguid
|
||||||
|
|
@ -2357,25 +2382,26 @@ class ZoningOperations(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
||||||
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name}")
|
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vdef.Name}")
|
||||||
log.trace(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.Name} - $vguid -> $vdata")
|
|
||||||
AvatarCreateInVehicle(player, vehicle, seat)
|
AvatarCreateInVehicle(player, vehicle, seat)
|
||||||
|
|
||||||
case _ =>
|
case _ =>
|
||||||
player.VehicleSeated = None
|
player.VehicleSeated = None
|
||||||
val packet = player.avatar.definition.Packet
|
val definition = player.avatar.definition
|
||||||
val data = packet.DetailedConstructorData(player).get
|
val guid = player.GUID
|
||||||
val guid = player.GUID
|
sendResponse(OCM.detailed(player))
|
||||||
sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, guid, data))
|
|
||||||
continent.AvatarEvents ! AvatarServiceMessage(
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
zoneid,
|
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)
|
continent.Population ! Zone.Population.Spawn(avatar, player, avatarActor)
|
||||||
avatarActor ! AvatarActor.RefreshPurchaseTimes()
|
avatarActor ! AvatarActor.RefreshPurchaseTimes()
|
||||||
|
drawDeployableIconsOnMap(
|
||||||
|
depictDeployablesUponRevival(
|
||||||
|
reclaimOurDeployables(continent.DeployableList, player.Name, reassignDeployablesTo(player.GUID))
|
||||||
|
)
|
||||||
|
)
|
||||||
//begin looking for conditions to set the avatar
|
//begin looking for conditions to set the avatar
|
||||||
context.system.scheduler.scheduleOnce(delay = 250 millisecond, context.self, SessionActor.SetCurrentAvatar(player, 200))
|
context.system.scheduler.scheduleOnce(delay = 250 millisecond, context.self, SessionActor.SetCurrentAvatar(player, 200))
|
||||||
}
|
}
|
||||||
|
|
@ -2403,11 +2429,9 @@ class ZoningOperations(
|
||||||
val pguid = tplayer.GUID
|
val pguid = tplayer.GUID
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
tplayer.VehicleSeated = None
|
tplayer.VehicleSeated = None
|
||||||
val pdata = pdef.Packet.DetailedConstructorData(tplayer).get
|
|
||||||
tplayer.VehicleSeated = vguid
|
tplayer.VehicleSeated = vguid
|
||||||
log.debug(s"AvatarCreateInVehicle: ${player.Name}")
|
log.debug(s"AvatarCreateInVehicle: ${player.Name}")
|
||||||
log.trace(s"AvatarCreateInVehicle: ${player.Name} - $pguid -> $pdata")
|
sendResponse(OCM.detailed(tplayer))
|
||||||
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
|
|
||||||
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
||||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||||
sessionLogic.general.accessContainer(vehicle)
|
sessionLogic.general.accessContainer(vehicle)
|
||||||
|
|
@ -2459,13 +2483,10 @@ class ZoningOperations(
|
||||||
sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
|
sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
|
||||||
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
||||||
//vehicle and driver/passenger
|
//vehicle and driver/passenger
|
||||||
val vdef = vehicle.Definition
|
|
||||||
val vguid = vehicle.GUID
|
val vguid = vehicle.GUID
|
||||||
val vdata = vdef.Packet.ConstructorData(vehicle).get
|
sendResponse(OCM.apply(vehicle))
|
||||||
sendResponse(ObjectCreateMessage(vehicle.Definition.ObjectId, vguid, vdata))
|
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, continent.id)
|
Vehicles.ReloadAccessPermissions(vehicle, continent.id)
|
||||||
log.debug(s"AvatarCreate (vehicle): ${player.Name}'s ${vehicle.Definition.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")
|
|
||||||
val pdef = player.avatar.definition
|
val pdef = player.avatar.definition
|
||||||
val pguid = player.GUID
|
val pguid = player.GUID
|
||||||
player.VehicleSeated = None
|
player.VehicleSeated = None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue