From a568e52590d95426406faeb9ada84d6c4de34021 Mon Sep 17 00:00:00 2001 From: FateJH Date: Fri, 20 Dec 2019 00:47:22 -0500 Subject: [PATCH] moved common jammering behavior into a mixin trait and redundant code out of the specific object control actors; created placeholder PlayerControl actor but am not ready to move damage/jammering functionality out from WSA; common jammering behavior modified for WSA use --- .../scala/net/psforever/objects/Player.scala | 6 +- .../scala/net/psforever/objects/Vehicle.scala | 3 +- .../objects/avatar/PlayerControl.scala | 15 +++ .../objects/equipment/JammingUnit.scala | 111 +++++++++++++++++- .../serverobject/turret/FacilityTurret.scala | 2 + .../turret/FacilityTurretControl.scala | 71 ++--------- .../objects/vehicles/VehicleControl.scala | 78 ++---------- .../objects/zones/ZonePopulationActor.scala | 12 +- .../game/PlanetsideAttributeMessage.scala | 4 +- .../src/main/scala/WorldSessionActor.scala | 111 ++++++++++-------- 10 files changed, 222 insertions(+), 191 deletions(-) create mode 100644 common/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala diff --git a/common/src/main/scala/net/psforever/objects/Player.scala b/common/src/main/scala/net/psforever/objects/Player.scala index a0c84a0b..08e7150a 100644 --- a/common/src/main/scala/net/psforever/objects/Player.scala +++ b/common/src/main/scala/net/psforever/objects/Player.scala @@ -3,8 +3,9 @@ package net.psforever.objects import net.psforever.objects.avatar.LoadoutManager import net.psforever.objects.definition.{AvatarDefinition, ExoSuitDefinition, SpecialExoSuitDefinition} -import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot} +import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot, JammableUnit} import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem} +import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.vital.resistance.ResistanceProfile import net.psforever.objects.vital.{DamageResistanceModel, Vitality} @@ -16,11 +17,12 @@ import net.psforever.types._ import scala.annotation.tailrec import scala.util.{Success, Try} -class Player(private val core : Avatar) extends PlanetSideGameObject +class Player(private val core : Avatar) extends PlanetSideServerObject with FactionAffinity with Vitality with ResistanceProfile with Container + with JammableUnit with ZoneAware { private var alive : Boolean = false private var backpack : Boolean = false diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala index 1330af04..a9adc2ba 100644 --- a/common/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala @@ -3,7 +3,7 @@ package net.psforever.objects import akka.actor.ActorRef import net.psforever.objects.definition.VehicleDefinition -import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot} +import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot, JammableUnit} import net.psforever.objects.inventory.{Container, GridInventory, InventoryTile} import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.PlanetSideServerObject @@ -73,6 +73,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends AmenityOwner with Vitality with OwnableByPlayer with StandardResistanceProfile + with JammableUnit with Container { private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR private var health : Int = 1 diff --git a/common/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala b/common/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala new file mode 100644 index 00000000..6071b018 --- /dev/null +++ b/common/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala @@ -0,0 +1,15 @@ +// Copyright (c) 2019 PSForever +package net.psforever.objects.avatar + +import akka.actor.Actor +import net.psforever.objects.Player + +/** + * na; + * stub for future development + */ +class PlayerControl(player : Player) extends Actor { + def receive : Receive = { + case _ => ; + } +} diff --git a/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala b/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala index cbc58a62..a6c6705c 100644 --- a/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala +++ b/common/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala @@ -1,11 +1,19 @@ // Copyright (c) 2019 PSForever package net.psforever.objects.equipment -import net.psforever.objects.PlanetSideGameObject +import akka.actor.{Actor, Cancellable} +import net.psforever.objects.{DefaultCancellable, PlanetSideGameObject, Tool} import net.psforever.objects.ballistics.ResolvedProjectile +import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.terminals.TargetValidation +import net.psforever.objects.vehicles.MountedWeapons +import net.psforever.objects.zones.ZoneAware +import net.psforever.types.Vector3 +import services.Service +import services.vehicle.{VehicleAction, VehicleServiceMessage} import scala.collection.mutable +import scala.concurrent.duration._ trait JammableUnit { private var jammed : Boolean = false @@ -49,3 +57,104 @@ object JammingUnit { targets.map { target => FindJammerDuration(jammer, target) } } } + +trait JammableBehavior { + _ : Actor => + protected var jammeredSoundTimer : Cancellable = DefaultCancellable.obj + protected var jammeredStatusTimer : Cancellable = DefaultCancellable.obj + + def JammableObject : PlanetSideServerObject with JammableUnit with ZoneAware + + def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit + + def StartJammeredSound(target : Any, dur : Int = 30000) : Unit = { + import scala.concurrent.ExecutionContext.Implicits.global + jammeredSoundTimer.cancel + jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, JammableUnit.ClearJammeredSound()) + } + + def StartJammeredStatus(target : Any, dur : Int) : Unit = { + JammableObject.Jammed = true + jammeredStatusTimer.cancel + import scala.concurrent.ExecutionContext.Implicits.global + jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, JammableUnit.ClearJammeredStatus()) + } + + def CancelJammeredSound(target : Any) : Unit = { + jammeredSoundTimer.cancel + } + + def CancelJammeredStatus(target : Any) : Unit = { + JammableObject.Jammed = false + jammeredStatusTimer.cancel + } + + def jammableBehavior : Receive = { + case JammableUnit.Jammered(cause) => + TryJammerEffectActivate(JammableObject, cause) + + case JammableUnit.ClearJammeredSound() => + CancelJammeredSound(JammableObject) + + case JammableUnit.ClearJammeredStatus() => + CancelJammeredStatus(JammableObject) + } +} + +trait JammableMountedWeapons extends Actor with JammableBehavior { + _ : Actor => + + def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match { + case obj : PlanetSideServerObject with MountedWeapons => + val radius = cause.projectile.profile.DamageRadius + JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match { + case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius => + StartJammeredSound(obj) + StartJammeredStatus(obj, dur) + case _ => ; + } + case _ => ; + } + + override def StartJammeredSound(target : Any, dur : Int) : Unit = target match { + case obj : PlanetSideServerObject with MountedWeapons => + obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1)) + super.StartJammeredSound(obj, dur) + case _ => ; + } + + override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match { + case obj : PlanetSideServerObject with MountedWeapons => + JammableMountedWeapons.JammeredStatus(obj, 1) + super.StartJammeredStatus(obj, dur) + case _ => ; + } + + override def CancelJammeredSound(target : Any) : Unit = target match { + case obj : PlanetSideServerObject => + obj.Zone.VehicleEvents ! VehicleServiceMessage(obj.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0)) + super.CancelJammeredSound(obj) + case _ => ; + } + + override def CancelJammeredStatus(target : Any) : Unit = target match { + case obj : PlanetSideServerObject with MountedWeapons => + JammableMountedWeapons.JammeredStatus(obj, 0) + super.CancelJammeredStatus(obj) + case _ => ; + } +} + +object JammableMountedWeapons { + def JammeredStatus(target : PlanetSideServerObject with MountedWeapons, statusCode : Int) : Unit = { + val zone = target.Zone + val zoneId = zone.Id + zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 27, statusCode)) + target.Weapons.values + .map { _.Equipment } + .collect { + case Some(item : Tool) => + zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, item.GUID, 27, statusCode)) + } + } +} diff --git a/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala index 4a09e220..5edb2384 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurret.scala @@ -1,12 +1,14 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.turret +import net.psforever.objects.equipment.JammableUnit import net.psforever.objects.serverobject.structures.Amenity import net.psforever.types.Vector3 import net.psforever.objects.vital.{DamageResistanceModel, StandardResistanceProfile, Vitality} class FacilityTurret(tDef : TurretDefinition) extends Amenity with WeaponTurret + with JammableUnit with Vitality with StandardResistanceProfile { /** some turrets can be updated; they all start without updates */ diff --git a/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala index 2d79b22e..dbb8e7b1 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala @@ -1,25 +1,19 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.turret -import akka.actor.{Actor, Cancellable} -import net.psforever.objects.{DefaultCancellable, Tool} +import akka.actor.Actor import net.psforever.objects.ballistics.ResolvedProjectile -import net.psforever.objects.equipment.{JammableUnit, JammingUnit} -import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit} import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior} import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} -import net.psforever.objects.vehicles.MountedWeapons import net.psforever.objects.vital.Vitality import net.psforever.objects.zones.Zone import net.psforever.packet.game.PlanetSideGUID -import net.psforever.types.Vector3 import services.Service import services.avatar.{AvatarAction, AvatarServiceMessage} import services.vehicle.{VehicleAction, VehicleServiceMessage} import services.vehicle.support.TurretUpgrader -import scala.concurrent.duration._ - /** * An `Actor` that handles messages being dispatched to a specific `MannedTurret`.
*
@@ -30,11 +24,12 @@ import scala.concurrent.duration._ */ class FacilityTurretControl(turret : FacilityTurret) extends Actor with FactionAffinityBehavior.Check - with MountableBehavior.Dismount { - var jammeredSoundTimer : Cancellable = DefaultCancellable.obj - var jammeredStatusTimer : Cancellable = DefaultCancellable.obj + with MountableBehavior.Dismount + with JammableMountedWeapons { - def MountableObject = turret //do not add type! + def MountableObject = turret + + def JammableObject = turret def FactionObject : FactionAffinity = turret @@ -70,48 +65,8 @@ class FacilityTurretControl(turret : FacilityTurret) extends Actor } } - case JammableUnit.Jammered(cause) => - TryJammerWithProjectile(turret, cause) - - case JammableUnit.ClearJammeredSound() => - CancelJammeredSound(turret) - - case JammableUnit.ClearJammeredStatus() => - StopJammeredStatus(turret) - case _ => ; } - - def TryJammerWithProjectile(target : FacilityTurret, cause : ResolvedProjectile) : Unit = { - val radius = cause.projectile.profile.DamageRadius - JammingUnit.FindJammerDuration(cause.projectile.profile, target) match { - case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius => - //jammered sound - target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 54, 1)) - import scala.concurrent.ExecutionContext.Implicits.global - jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, JammableUnit.ClearJammeredSound()) - //jammered status - StartJammeredStatus(target, dur) - case _ => ; - } - } - - def StartJammeredStatus(target : PlanetSideServerObject with MountedWeapons, dur : Int) : Unit = { - jammeredStatusTimer.cancel - FacilityTurretControl.JammeredStatus(target, 1) - import scala.concurrent.ExecutionContext.Implicits.global - jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, JammableUnit.ClearJammeredStatus()) - } - - def StopJammeredStatus(target : PlanetSideServerObject with MountedWeapons) : Boolean = { - FacilityTurretControl.JammeredStatus(target, 0) - jammeredStatusTimer.cancel - } - - def CancelJammeredSound(target : PlanetSideServerObject) : Unit = { - jammeredSoundTimer.cancel - target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 54, 0)) - } } object FacilityTurretControl { @@ -195,16 +150,4 @@ object FacilityTurretControl { zone.VehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, zone, TurretUpgrade.None)) } } - - def JammeredStatus(target : PlanetSideServerObject with MountedWeapons, statusCode : Int) : Unit = { - val zone = target.Zone - val zoneId = zone.Id - zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 27, statusCode)) - target.Weapons.values - .map { _.Equipment } - .collect { - case Some(item : Tool) => - zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, item.GUID, 27, statusCode)) - } - } } diff --git a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala index cb091b58..85933857 100644 --- a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala +++ b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala @@ -1,11 +1,10 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.vehicles -import akka.actor.{Actor, ActorRef, Cancellable} -import net.psforever.objects.{DefaultCancellable, GlobalDefinitions, Tool, Vehicle} +import akka.actor.{Actor, ActorRef} +import net.psforever.objects.{GlobalDefinitions, Vehicle} import net.psforever.objects.ballistics.{ResolvedProjectile, VehicleSource} -import net.psforever.objects.equipment.{JammableUnit, JammingUnit} -import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.objects.equipment.{JammableMountedWeapons, JammableUnit} import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior} import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior} @@ -18,8 +17,6 @@ import services.avatar.{AvatarAction, AvatarServiceMessage} import services.local.{LocalAction, LocalServiceMessage} import services.vehicle.{VehicleAction, VehicleService, VehicleServiceMessage} -import scala.concurrent.duration._ - /** * An `Actor` that handles messages being dispatched to a specific `Vehicle`.
*
@@ -31,15 +28,16 @@ class VehicleControl(vehicle : Vehicle) extends Actor with FactionAffinityBehavior.Check with DeploymentBehavior with MountableBehavior.Mount - with MountableBehavior.Dismount { - var jammeredSoundTimer : Cancellable = DefaultCancellable.obj - var jammeredStatusTimer : Cancellable = DefaultCancellable.obj + with MountableBehavior.Dismount + with JammableMountedWeapons { //make control actors belonging to utilities when making control actor belonging to vehicle vehicle.Utilities.foreach({case (_, util) => util.Setup }) def MountableObject = vehicle + def JammableObject = vehicle + def FactionObject = vehicle def DeploymentObject = vehicle @@ -57,6 +55,7 @@ class VehicleControl(vehicle : Vehicle) extends Actor def Enabled : Receive = checkBehavior .orElse(deployBehavior) .orElse(dismountBehavior) + .orElse(jammableBehavior) .orElse { case Mountable.TryMount(user, seat_num) => val exosuit = user.ExoSuit @@ -116,16 +115,9 @@ class VehicleControl(vehicle : Vehicle) extends Actor } sender ! FactionAffinity.AssertFactionAffinity(vehicle, faction) - case JammableUnit.Jammered(cause) => - TryJammerWithProjectile(vehicle, cause) - - case JammableUnit.ClearJammeredSound() => - CancelJammeredSound(vehicle) - - case JammableUnit.ClearJammeredStatus() => - StopJammeredStatus(vehicle) - case Vehicle.PrepareForDeletion => + CancelJammeredSound(vehicle) + CancelJammeredStatus(vehicle) context.become(Disabled) case _ => ; @@ -134,49 +126,11 @@ class VehicleControl(vehicle : Vehicle) extends Actor def Disabled : Receive = checkBehavior .orElse(dismountBehavior) .orElse { - case JammableUnit.ClearJammeredSound() => - CancelJammeredSound(vehicle) - - case JammableUnit.ClearJammeredStatus() => - StopJammeredStatus(vehicle) - case Vehicle.Reactivate => context.become(Enabled) case _ => ; } - - def TryJammerWithProjectile(target : Vehicle, cause : ResolvedProjectile) : Unit = { - val radius = cause.projectile.profile.DamageRadius - JammingUnit.FindJammerDuration(cause.projectile.profile, target) match { - case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius => - //jammered sound - jammeredSoundTimer.cancel - target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 54, 1)) - import scala.concurrent.ExecutionContext.Implicits.global - jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, JammableUnit.ClearJammeredSound()) - //jammered status - StartJammeredStatus(target, dur) - case _ => ; - } - } - - def StartJammeredStatus(target : PlanetSideServerObject with MountedWeapons, dur : Int) : Unit = { - jammeredStatusTimer.cancel - VehicleControl.JammeredStatus(target, 1) - import scala.concurrent.ExecutionContext.Implicits.global - jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, JammableUnit.ClearJammeredStatus()) - } - - def StopJammeredStatus(target : PlanetSideServerObject with MountedWeapons) : Boolean = { - VehicleControl.JammeredStatus(target, 0) - jammeredStatusTimer.cancel - } - - def CancelJammeredSound(target : PlanetSideServerObject) : Unit = { - jammeredSoundTimer.cancel - target.Zone.VehicleEvents ! VehicleServiceMessage(target.Zone.Id, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 54, 0)) - } } object VehicleControl { @@ -310,16 +264,4 @@ object VehicleControl { zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(target), zone)) zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(target, zone, Some(1 minute))) } - - def JammeredStatus(target : PlanetSideServerObject with MountedWeapons, statusCode : Int) : Unit = { - val zone = target.Zone - val zoneId = zone.Id - zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 27, statusCode)) - target.Weapons.values - .map { _.Equipment } - .collect { - case Some(item : Tool) => - zone.VehicleEvents ! VehicleServiceMessage(zoneId, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, item.GUID, 27, statusCode)) - } - } } diff --git a/common/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala b/common/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala index a22e9b43..f43ecb26 100644 --- a/common/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala +++ b/common/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala @@ -1,7 +1,9 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.zones -import akka.actor.Actor +import akka.actor.{Actor, ActorRef, Props} +import net.psforever.objects.avatar.PlayerControl +import net.psforever.objects.vehicles.VehicleControl import net.psforever.objects.{Avatar, Player} import scala.annotation.tailrec @@ -34,16 +36,22 @@ class ZonePopulationActor(zone : Zone, playerMap : TrieMap[Avatar, Option[Player case Zone.Population.Spawn(avatar, player) => PopulationSpawn(avatar, player, playerMap) match { case Some(tplayer) => + tplayer.Zone = zone if(tplayer ne player) { sender ! Zone.Population.PlayerAlreadySpawned(zone, player) } + else { + player.Actor = context.actorOf(Props(classOf[PlayerControl], player), s"${player.Name}_${player.GUID.guid}") + } case None => sender ! Zone.Population.PlayerCanNotSpawn(zone, player) } case Zone.Population.Release(avatar) => PopulationRelease(avatar, playerMap) match { - case Some(_) => ; + case Some(tplayer) => + tplayer.Actor ! akka.actor.PoisonPill + tplayer.Actor = ActorRef.noSender case None => sender ! Zone.Population.PlayerHasLeft(zone, None) } diff --git a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala index b09ffb41..ba67539b 100644 --- a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala +++ b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala @@ -115,7 +115,7 @@ import scodec.codecs._ * 45 : Advanced Engineering (= Fortification Engineering + Assault Engineering) Must have Combat Engineering
* `25 - Forget certifications (same order as 24)`
* `26 - Certification reset timer (in seconds)` - * `27 - PA_JAMMED - plays jammed buzzing sound`
+ * `27 - PA_JAMMED - plays jammed buzzing sound in vicinity of target, jams weapon discharge`
* `28 - PA_IMPLANT_ACTIVE - Plays implant sounds. Valid values seem to be up to 20.`
* `29 - PA_VAPORIZED - Visible ?! That's not the cloaked effect, Maybe for spectator mode ?. Value is 0 to visible, 1 to invisible.`
* `31 - Looking for Squad info (marquee and ui):`
@@ -162,7 +162,7 @@ import scodec.codecs._ * `13 - Trunk permissions (same)`
* `21 - Declare a player the vehicle's owner, by globally unique identifier`
* `22 - Toggles gunner and passenger mount points (1 = hides, 0 = reveals; this also locks their permissions)`
- * `54 - Vehicle EMP? Plays sound as if vehicle had been hit by EMP`
+ * `54 - Plays jammed buzzing sound in vicinity of target`
* `68 - Vehicle shield health`
* `79 - ???`
* `80 - Damage vehicle (unknown value)`
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 6db3e6d7..f986a8ad 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -71,7 +71,9 @@ import services.support.SupportActor import scala.collection.mutable -class WorldSessionActor extends Actor with MDCContextAware { +class WorldSessionActor extends Actor + with MDCContextAware + with JammableBehavior { import WorldSessionActor._ private[this] val log = org.log4s.getLogger @@ -165,8 +167,6 @@ class WorldSessionActor extends Actor with MDCContextAware { var cargoDismountTimer : Cancellable = DefaultCancellable.obj var antChargingTick : Cancellable = DefaultCancellable.obj var antDischargingTick : Cancellable = DefaultCancellable.obj - var jammeredSoundTimer : Cancellable = DefaultCancellable.obj - var jammeredStatusTimer : Cancellable = DefaultCancellable.obj /** @@ -178,12 +178,13 @@ class WorldSessionActor extends Actor with MDCContextAware { import scala.language.implicitConversions implicit def boolToInt(b : Boolean) : Int = if(b) 1 else 0 + def JammableObject = player + override def postStop() : Unit = { //TODO normally, player avatar persists a minute or so after disconnect; we are subject to the SessionReaper clientKeepAlive.cancel reviveTimer.cancel respawnTimer.cancel - PlayerActionsToCancel() chatService ! Service.Leave() continent.AvatarEvents ! Service.Leave() continent.LocalEvents ! Service.Leave() @@ -191,6 +192,7 @@ class WorldSessionActor extends Actor with MDCContextAware { galaxyService ! Service.Leave() LivePlayerList.Remove(sessionId) if(player != null && player.HasGUID) { + PlayerActionsToCancel() squadService ! Service.Leave(Some(player.CharId.toString)) val player_guid = player.GUID //handle orphaned deployables @@ -320,7 +322,7 @@ class WorldSessionActor extends Actor with MDCContextAware { context.stop(self) } - def Started : Receive = { + def Started : Receive = jammableBehavior.orElse { case ServiceManager.LookupResult("chat", endpoint) => chatService = endpoint log.info("ID: " + sessionId + " Got chat service " + endpoint) @@ -1174,12 +1176,6 @@ class WorldSessionActor extends Actor with MDCContextAware { case _ => ; } - case ClearJammeredSound() => - CancelJammeredSound() - - case ClearJammeredStatus() => - CancelJammeredStatus() - case default => log.warn(s"Invalid packet class received: $default from $sender") } @@ -1323,30 +1319,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } } if(target.isAlive && cause.projectile.profile.JammerProjectile) { - val radius = cause.projectile.profile.DamageRadius - JammingUnit.FindJammerDuration(cause.projectile.profile, target) match { - case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius => - //implants - DeactivateImplants() - //jammered sound - sendResponse(PlanetsideAttributeMessage(player.GUID, 54, 1)) - continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 54, 1)) - import scala.concurrent.ExecutionContext.Implicits.global - jammeredSoundTimer.cancel - jammeredSoundTimer = context.system.scheduler.scheduleOnce(30 seconds, self, ClearJammeredSound()) - //jammered status - skipStaminaRegenForTurns = 5 - jammeredEquipment = (jammeredEquipment ++ player.Holsters() - .map { _.Equipment } - .collect { - case Some(item) if item.Size != EquipmentSize.Melee => - sendResponse(PlanetsideAttributeMessage(item.GUID, 27, 1)) - item.GUID - }).distinct - jammeredStatusTimer.cancel - jammeredStatusTimer = context.system.scheduler.scheduleOnce(dur milliseconds, self, ClearJammeredStatus()) - case _ => ; - } + self ! JammableUnit.Jammered(cause) } } @@ -3425,6 +3398,7 @@ class WorldSessionActor extends Actor with MDCContextAware { player.Slot(39).Equipment = SimpleItem(remote_electronics_kit) player.Locker.Inventory += 0 -> SimpleItem(remote_electronics_kit) player.Inventory.Items.foreach { _.obj.Faction = faction } + player.Actor = self //TODO end temp player character auto-loading self ! ListAccountCharacters import scala.concurrent.ExecutionContext.Implicits.global @@ -7801,8 +7775,8 @@ class WorldSessionActor extends Actor with MDCContextAware { * This is not a complete list but, for the purpose of enforcement, some pointers will be documented here. */ def PlayerActionsToCancel() : Unit = { - CancelJammeredSound() - CancelJammeredStatus() + CancelJammeredSound(player) + CancelJammeredStatus(player) progressBarUpdate.cancel progressBarValue = None lastTerminalOrderFulfillment = true @@ -10242,16 +10216,55 @@ class WorldSessionActor extends Actor with MDCContextAware { } } - def CancelJammeredSound() : Unit = { - jammeredSoundTimer.cancel - sendResponse(PlanetsideAttributeMessage(player.GUID, 54, 0)) - continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 54, 0)) + def TryJammerEffectActivate(target : Any, cause : ResolvedProjectile) : Unit = target match { + case obj : Player => + val radius = cause.projectile.profile.DamageRadius + JammingUnit.FindJammerDuration(cause.projectile.profile, obj) match { + case Some(dur) if Vector3.DistanceSquared(cause.hit_pos, cause.target.Position) < radius * radius => + DeactivateImplants() + skipStaminaRegenForTurns = 5 + StartJammeredSound(obj) + StartJammeredStatus(obj, dur) + case _ => ; + } + case _ => ; } - def CancelJammeredStatus() : Unit = { - jammeredStatusTimer.cancel - jammeredEquipment.foreach { id => sendResponse(PlanetsideAttributeMessage(id, 27, 0)) } - jammeredEquipment = Nil + override def StartJammeredSound(target : Any, dur : Int) : Unit = target match { + case obj : Player => + sendResponse(PlanetsideAttributeMessage(obj.GUID, 27, 1)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(obj.GUID, 27, 1)) + super.StartJammeredSound(obj, dur) + case _ => ; + } + + override def StartJammeredStatus(target : Any, dur : Int) : Unit = target match { + case obj : Player => + jammeredEquipment = (jammeredEquipment ++ obj.Holsters() + .map { _.Equipment } + .collect { + case Some(item) if item.Size != EquipmentSize.Melee => + sendResponse(PlanetsideAttributeMessage(item.GUID, 27, 1)) + item.GUID + }).distinct + super.StartJammeredStatus(obj, dur) + case _ => ; + } + + override def CancelJammeredSound(target : Any) : Unit = target match { + case obj : Player => + sendResponse(PlanetsideAttributeMessage(obj.GUID, 27, 0)) + continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(obj.GUID, 27, 0)) + super.CancelJammeredSound(obj) + case _ => ; + } + + override def CancelJammeredStatus(target : Any) : Unit = target match { + case obj : Player => + jammeredEquipment.foreach { id => sendResponse(PlanetsideAttributeMessage(id, 27, 0)) } + jammeredEquipment = Nil + super.CancelJammeredStatus(obj) + case _ => ; } def failWithError(error : String) = { @@ -10412,15 +10425,11 @@ object WorldSessionActor { protected final case class SquadUIElement(name : String, index : Int, zone : Int, health : Int, armor : Int, position : Vector3) - private final case class NtuCharging(tplayer: Player, - vehicle: Vehicle) + private final case class NtuCharging(tplayer: Player, vehicle: Vehicle) + private final case class NtuDischarging(tplayer: Player, vehicle: Vehicle, silo_guid: PlanetSideGUID) private final case class FinalizeDeployable(obj : PlanetSideGameObject with Deployable, tool : ConstructionItem, index : Int) private final case class LoadedRemoteProjectile(projectile_guid : PlanetSideGUID, projectile : Option[Projectile]) - - private final case class ClearJammeredSound() - - private final case class ClearJammeredStatus() }