* basic information processing actor for projecting hotspot information back to the clients

* added measurements to the continents to keep track of their coordinate-sizes; corrected an old regex issue affecting some (few) CSR zone names

* started on zone storage for active hot spots

* moved (Zone)HotSpotProjector onto the top of each of the zones and adjusting the GalaxyService workflow; added a map blanking routine for outdated hotspots; different damage targets cause different amounts of hotpot lifespan (test)

* separated hotspots by the faction that should have those specific hotspots depicted; hard cap on the number of entries that can be added to the packet HotSpotUpdateMessage to correspond to the capacity of the size field; increased hotspot sector mapping (64 -> 80) and lowered the blanking period delay (30 -> 15)

* adding comments to the majority of classes involved in hotspot management; moved hotspot coordination mapping and duration selection functions into the zone itself rather than the projector (though calls will still be made to perform updates to the existing projectiles through the projector); the formal continents have been assigned some default hotspot functionality

* rebase, plus 'galaxy' channel name

* capped the amount of heat a hotspot can accumulate to avoid overflow; vehicles being damaged now generate hotspots; corrected a long-standing issue involving cargo vehicles when the ferrying vehicle is destroyed

* from > to <
This commit is contained in:
Fate-JH 2019-08-21 10:40:29 -04:00 committed by GitHub
parent 2048fa19cb
commit 1fb35bacd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 949 additions and 90 deletions

View file

@ -42,8 +42,9 @@ import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.serverobject.turret.{FacilityTurret, TurretUpgrade, WeaponTurret}
import net.psforever.objects.vehicles.{AccessPermissionGroup, Cargo, Utility, VehicleLockState, _}
import net.psforever.objects.vital._
import net.psforever.objects.zones.{InterstellarCluster, Zone}
import net.psforever.objects.zones.{InterstellarCluster, Zone, ZoneHotSpotProjector}
import net.psforever.packet.game.objectcreate._
import net.psforever.packet.game.{HotSpotInfo => PacketHotSpotInfo}
import net.psforever.types._
import services.{RemoverActor, vehicle, _}
import services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse}
@ -308,6 +309,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
case GalaxyServiceResponse(_, reply) =>
reply match {
case GalaxyResponse.HotSpotUpdate(zone_index, priority, hot_spot_info) =>
sendResponse(
HotSpotUpdateMessage(
zone_index,
priority,
hot_spot_info.map { spot => PacketHotSpotInfo(spot.DisplayLocation.x, spot.DisplayLocation.y, 40) }
)
)
case GalaxyResponse.MapUpdate(msg) =>
sendResponse(msg)
}
@ -502,7 +511,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(ZoneInfoMessage(continentNumber, true, 0))
sendResponse(ZoneLockInfoMessage(continentNumber, false, true))
sendResponse(ZoneForcedCavernConnectionsMessage(continentNumber, 0))
sendResponse(HotSpotUpdateMessage(continentNumber, 1, Nil)) //normally set in bulk; should be fine doing per continent
sendResponse(HotSpotUpdateMessage(
continentNumber,
1,
ZoneHotSpotProjector.SpecificHotSpotInfo(player.Faction, zone.HotSpots)
.map { spot => PacketHotSpotInfo(spot.DisplayLocation.x, spot.DisplayLocation.y, 40) }
)) //normally set for all zones in bulk; should be fine manually updating per zone like this
case Zone.Population.PlayerHasLeft(zone, None) =>
log.info(s"$avatar does not have a body on ${zone.Id}")
@ -520,7 +534,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
case Zone.Lattice.SpawnPoint(zone_id, spawn_tube) =>
var (pos, ori) = spawn_tube.SpecificPoint(continent.GUID(player.VehicleSeated) match {
case Some(obj) =>
case Some(obj : Vehicle) if obj.Health > 0 =>
obj
case _ =>
player
@ -790,6 +804,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
avatarService ! Service.Join(avatar.name) //channel will be player.Name
localService ! Service.Join(avatar.name) //channel will be player.Name
vehicleService ! Service.Join(avatar.name) //channel will be player.Name
galaxyService ! Service.Join("galaxy") //for galaxy-wide messages
galaxyService ! Service.Join(s"${avatar.faction}") //for hotspots
cluster ! InterstellarCluster.GetWorld("home3")
case InterstellarCluster.GiveWorld(zoneId, zone) =>
@ -990,7 +1006,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
//first damage entry -> most recent damage source -> killing blow
target.History.find(p => p.isInstanceOf[DamagingActivity]) match {
case Some(data : DamageFromProjectile) =>
data.data.projectile.owner match {
val owner = data.data.projectile.owner
owner match {
case pSource : PlayerSource =>
continent.LivePlayers.find(_.Name == pSource.Name) match {
case Some(tplayer) =>
@ -1001,6 +1018,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(DamageWithPositionMessage(damageToHealth + damageToArmor, vSource.Position))
case _ => ;
}
continent.Activity ! Zone.HotSpot.Activity(owner, data.Target, target.Position)
case _ => ;
}
}
@ -2273,6 +2291,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
log.info(s"HandleCheckCargoMounting: mounting cargo vehicle in carrier at distance of $distance")
cargo.MountedIn = carrierGUID
hold.Occupant = cargo
cargo.Velocity = None
vehicleService ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health)))
vehicleService ! VehicleServiceMessage(s"${cargo.Actor}", VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 68, cargo.Shields)))
StartBundlingPackets()
@ -2441,56 +2460,104 @@ class WorldSessionActor extends Actor with MDCContextAware {
def HandleVehicleDamageResolution(target : Vehicle) : Unit = {
val targetGUID = target.GUID
val playerGUID = player.GUID
val continentId = continent.Id
val players = target.Seats.values.filter(seat => {
seat.isOccupied && seat.Occupant.get.isAlive
})
if(target.Health > 0) {
//alert occupants to damage source
players.foreach(seat => {
val tplayer = seat.Occupant.get
avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(playerGUID, tplayer.GUID))
})
}
else {
//alert to vehicle death (hence, occupants' deaths)
players.foreach(seat => {
val tplayer = seat.Occupant.get
val tplayerGUID = tplayer.GUID
avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID))
avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self
})
//vehicle wreckage has no weapons
target.Weapons.values
.filter {
_.Equipment.nonEmpty
target.LastShot match { //TODO: collision damage from/in history
case Some(shot) =>
if(target.Health > 0) {
//activity on map
continent.Activity ! Zone.HotSpot.Activity(shot.target, shot.projectile.owner, shot.hit_pos)
//alert occupants to damage source
HandleVehicleDamageAwareness(target, playerGUID, shot)
}
.foreach(slot => {
val wep = slot.Equipment.get
avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID))
})
target.CargoHolds.values.foreach(hold => {
hold.Occupant match {
case Some(cargo) =>
else {
//alert to vehicle death (hence, occupants' deaths)
HandleVehicleDestructionAwareness(target, shot)
}
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health))
vehicleService ! VehicleServiceMessage(s"${target.Actor}", VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 68, target.Shields))
case None => ;
}
}
case None => ;
}
})
target.Definition match {
case GlobalDefinitions.ams =>
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
case GlobalDefinitions.router =>
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
BeforeUnloadVehicle(target)
localService ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), target, None))
case _ => ;
/**
* na
* @param target na
* @param attribution na
* @param lastShot na
*/
def HandleVehicleDamageAwareness(target : Vehicle, attribution : PlanetSideGUID, lastShot : ResolvedProjectile) : Unit = {
//alert occupants to damage source
target.Seats.values.filter(seat => {
seat.isOccupied && seat.Occupant.get.isAlive
}).foreach(seat => {
val tplayer = seat.Occupant.get
avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.HitHint(attribution, tplayer.GUID))
})
//alert cargo occupants to damage source
target.CargoHolds.values.foreach(hold => {
hold.Occupant match {
case Some(cargo) =>
cargo.Health = 0
cargo.Shields = 0
cargo.History(lastShot)
HandleVehicleDamageAwareness(cargo, attribution, lastShot)
case None => ;
}
avatarService ! AvatarServiceMessage(continentId, AvatarAction.Destroy(targetGUID, playerGUID, playerGUID, target.Position))
vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), continent))
vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, continent, Some(1 minute)))
})
}
/**
* na
* @param target na
* @param attribution na
* @param lastShot na
*/
def HandleVehicleDestructionAwareness(target : Vehicle, lastShot : ResolvedProjectile) : Unit = {
val playerGUID = player.GUID
val continentId = continent.Id
//alert to vehicle death (hence, occupants' deaths)
target.Seats.values.filter(seat => {
seat.isOccupied && seat.Occupant.get.isAlive
}).foreach(seat => {
val tplayer = seat.Occupant.get
val tplayerGUID = tplayer.GUID
avatarService ! AvatarServiceMessage(tplayer.Name, AvatarAction.KilledWhileInVehicle(tplayerGUID))
avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(tplayerGUID, tplayerGUID)) //dead player still sees self
})
//vehicle wreckage has no weapons
target.Weapons.values
.filter {
_.Equipment.nonEmpty
}
.foreach(slot => {
val wep = slot.Equipment.get
avatarService ! AvatarServiceMessage(continentId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID))
})
target.CargoHolds.values.foreach(hold => {
hold.Occupant match {
case Some(cargo) =>
cargo.Health = 0
cargo.Shields = 0
cargo.Position += Vector3.z(1)
cargo.History(lastShot) //necessary to kill cargo vehicle occupants //TODO: collision damage
HandleVehicleDestructionAwareness(cargo, lastShot) //might cause redundant packets
case None => ;
}
})
target.Definition match {
case GlobalDefinitions.ams =>
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
case GlobalDefinitions.router =>
target.Actor ! Deployment.TryDeploymentChange(DriveState.Undeploying)
BeforeUnloadVehicle(target)
localService ! LocalServiceMessage(continent.Id, LocalAction.ToggleTeleportSystem(PlanetSideGUID(0), target, None))
case _ => ;
}
vehicleService ! VehicleServiceMessage(continentId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, target.Health))
vehicleService ! VehicleServiceMessage(s"${target.Actor}", VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 68, target.Shields))
avatarService ! AvatarServiceMessage(continentId, AvatarAction.Destroy(target.GUID, playerGUID, playerGUID, target.Position))
vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), continent))
vehicleService ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, continent, Some(1 minute)))
}
/**
@ -2932,7 +2999,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
localService ! Service.Join(factionOnContinentChannel)
vehicleService ! Service.Join(continentId)
vehicleService ! Service.Join(factionOnContinentChannel)
galaxyService ! Service.Join("galaxy")
configZone(continent)
sendResponse(TimeOfDayMessage(1191182336))
//custom
@ -3265,11 +3331,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
obj.Position = pos
obj.Orientation = ang
obj.Velocity = vel
if(obj.Definition.CanFly) {
obj.Flying = flight.nonEmpty //usually Some(7)
if(obj.MountedIn.isEmpty) {
obj.Velocity = vel
if(obj.Definition.CanFly) {
obj.Flying = flight.nonEmpty //usually Some(7)
}
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.VehicleState(player.GUID, vehicle_guid, unk1, pos, ang, vel, flight, unk6, unk7, wheels, unk9, unkA))
}
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.VehicleState(player.GUID, vehicle_guid, unk1, pos, ang, vel, flight, unk6, unk7, wheels, unk9, unkA))
case (None, _) =>
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone")
//TODO placing a "not driving" warning here may trigger as we are disembarking the vehicle
@ -6668,6 +6736,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}) match {
case Some(shot) =>
continent.Activity ! Zone.HotSpot.Activity(pentry, shot.projectile.owner, shot.hit_pos)
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.DestroyDisplay(shot.projectile.owner, pentry, shot.projectile.attribute_to))
case None =>
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.DestroyDisplay(pentry, pentry, 0))
@ -7011,8 +7080,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
else {
continent.GUID(player.VehicleSeated) match {
case Some(_ : Vehicle) =>
cluster ! Zone.Lattice.RequestSpawnPoint(sanctNumber, tplayer, 12) //warp gates
case Some(obj : Vehicle) if obj.Health > 0 =>
cluster ! Zone.Lattice.RequestSpawnPoint(sanctNumber, tplayer, 12) //warp gates for functioning vehicles
case None =>
cluster ! Zone.Lattice.RequestSpawnPoint(sanctNumber, tplayer, 7) //player character spawns
case _ =>