From e1c5cd90a7075869afb6d59fb393eaa56097b399 Mon Sep 17 00:00:00 2001 From: "Jason_DiDonato@yahoo.com" Date: Wed, 14 Oct 2020 22:40:27 -0400 Subject: [PATCH] updated ntu -> power workflow by making event progress - the silo will report the ntu state to the generator and the generator will only report on the power state if it is not destroyed; if the generator is destroyed, that is where the messaging will end, until the generator comes back online; the events for these state change are somewhat arbitrary --- .../actors/session/SessionActor.scala | 25 +++++-- .../psforever/actors/zone/BuildingActor.scala | 71 +++++++++++++++++-- .../generator/GeneratorControl.scala | 48 ++++++++++--- .../ImplantTerminalMechControl.scala | 9 ++- .../repair/AmenityAutoRepair.scala | 17 ++++- .../serverobject/structures/Building.scala | 11 ++- .../terminals/TerminalControl.scala | 9 ++- .../serverobject/tube/SpawnTubeControl.scala | 6 ++ .../turret/FacilityTurretControl.scala | 11 ++- .../game/PlanetsideAttributeMessage.scala | 2 +- 10 files changed, 178 insertions(+), 31 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index ec3e800f..b2a31c00 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -3646,6 +3646,12 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con if (isMovingPlus) { CancelZoningProcessWithDescriptiveReason("cancel_motion") } + if (!player.Crouching && is_crouching) { + continent.Buildings.values.find { b => Vector3.Distance(player.Position, b.Position) <= b.Definition.SOIRadius} match { + case Some(b) => ; + case _ => ; + } + } player.Position = pos player.Velocity = vel player.Orientation = Vector3(player.Orientation.x, pitch, yaw) @@ -6554,13 +6560,20 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con */ def configZone(zone: Zone): Unit = { zone.Buildings.values.foreach(building => { - sendResponse(SetEmpireMessage(building.GUID, building.Faction)) - - // Synchronise capitol force dome state - if (building.IsCapitol && building.ForceDomeActive) { - sendResponse(GenericObjectActionMessage(building.GUID, 13)) + val guid = building.GUID + sendResponse(SetEmpireMessage(guid, building.Faction)) + // power + building.Generator match { + case Some(obj) if obj.Condition != PlanetSideGeneratorState.Normal => + sendResponse(PlanetsideAttributeMessage(guid, 48, 1)) + sendResponse(PlanetsideAttributeMessage(guid, 38, 0)) + case _ => ; } - // Synchronise amenities + // capitol force dome state + if (building.IsCapitol && building.ForceDomeActive) { + sendResponse(GenericObjectActionMessage(guid, 13)) + } + // amenities building.Amenities.collect { case obj if obj.Destroyed => configAmenityAsDestroyed(obj) case obj => configAmenityAsWorking(obj) diff --git a/src/main/scala/net/psforever/actors/zone/BuildingActor.scala b/src/main/scala/net/psforever/actors/zone/BuildingActor.scala index d34936d4..13201790 100644 --- a/src/main/scala/net/psforever/actors/zone/BuildingActor.scala +++ b/src/main/scala/net/psforever/actors/zone/BuildingActor.scala @@ -9,8 +9,10 @@ import net.psforever.objects.{CommonNtuContainer, NtuContainer} import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.generator.Generator import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate} +import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.zones.Zone import net.psforever.persistence +import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.types.PlanetSideEmpire import net.psforever.util.Database._ import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage} @@ -43,7 +45,11 @@ object BuildingActor { // Once they do, we won't need this anymore final case class MapUpdate() extends Command - final case class AmenityStateChange(obj: Amenity) extends Command + final case class AmenityStateChange(obj: Amenity, data: Option[Any]) extends Command + + object AmenityStateChange{ + def apply(obj: Amenity): AmenityStateChange = AmenityStateChange(obj, None) + } final case class Ntu(command: NtuCommand.Command) extends Command @@ -160,29 +166,50 @@ class BuildingActor( galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage())) Behaviors.same - case AmenityStateChange(obj: Generator) => + case AmenityStateChange(obj: Generator, data) => //TODO when parameter object is finally immutable, perform analysis on it to determine specific actions - val msg = if(obj.Destroyed) BuildingActor.PowerOff() else BuildingActor.PowerOn() - building.Amenities.foreach { _.Actor ! msg } + data match { + case Some("overloaded") => + powerLost() + val zone = building.Zone + val msg = AvatarAction.PlanetsideAttributeToAll(building.GUID, 46, 2) + building.PlayersInSOI.foreach { player => + zone.AvatarEvents ! AvatarServiceMessage(player.Name, msg) + } //??? + case Some("repaired") => + powerRestored() + val zone = building.Zone + building.PlayersInSOI.foreach { player => + val msg = AvatarAction.PlanetsideAttributeToAll(building.GUID, 46, 0) + zone.AvatarEvents ! AvatarServiceMessage(player.Name, msg) + } //reset ??? + case _ => ; + } //update the map galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage())) Behaviors.same - case AmenityStateChange(_) => + case AmenityStateChange(_, _) => //TODO when parameter object is finally immutable, perform analysis on it to determine specific actions //for now, just update the map galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage())) Behaviors.same + case PowerOff() => + powerLost() + Behaviors.same + + case PowerOn() => + powerRestored() + Behaviors.same + case msg @ NtuDepleted() => - log.trace(s"${building.Definition.Name} ${building.Name} ntu has been depleted") building.Amenities.foreach { amenity => amenity.Actor ! msg } Behaviors.same case msg @ SuppliedWithNtu() => - log.trace(s"ntu supply has been restored to ${building.Definition.Name} ${building.Name}") building.Amenities.foreach { amenity => amenity.Actor ! msg } @@ -193,6 +220,36 @@ class BuildingActor( } } + def powerLost(): Unit = { + val zone = building.Zone + val zoneId = zone.id + val events = zone.AvatarEvents + val guid = building.GUID + val powerMsg = BuildingActor.PowerOff() + building.Amenities.foreach { amenity => + amenity.Actor ! powerMsg + } + //amenities disabled; red warning lights + events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 48, 1)) + //disable spawn target on deployment map + events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 38, 0)) + } + + def powerRestored(): Unit = { + val zone = building.Zone + val zoneId = zone.id + val events = zone.AvatarEvents + val guid = building.GUID + val powerMsg = BuildingActor.PowerOn() + building.Amenities.foreach { amenity => + amenity.Actor ! powerMsg + } + //amenities enabled; normal lights + events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 48, 0)) + //enable spawn target on deployment map + events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 38, 1)) + } + def ntu(msg: NtuCommand.Command): Behavior[Command] = { import NtuCommand._ msg match { diff --git a/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala b/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala index 5a45f43f..23a99c67 100644 --- a/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala @@ -48,7 +48,7 @@ class GeneratorControl(gen: Generator) gen.Health = 0 super.DestructionAwareness(gen, gen.LastShot.get) gen.Condition = PlanetSideGeneratorState.Destroyed - GeneratorControl.UpdateOwner(gen) + GeneratorControl.UpdateOwner(gen, Some("destroyed")) //kaboom zone.AvatarEvents ! AvatarServiceMessage( zone.id, @@ -74,13 +74,27 @@ class GeneratorControl(gen: Generator) case GeneratorControl.UnderThreatAlarm() => if (!alarmCooldownPeriod) { alarmCooldownPeriod = true - GeneratorControl.BroadcastGeneratorEvent(gen, event = 15) + GeneratorControl.BroadcastGeneratorEvent(gen, GeneratorControl.Event.UnderAttack) context.system.scheduler.scheduleOnce(delay = 5 seconds, self, GeneratorControl.AlarmReset()) } case GeneratorControl.AlarmReset() => alarmCooldownPeriod = false + case BuildingActor.NtuDepleted() => + gen.Owner match { + case b: Building if !gen.Destroyed => + b.Actor ! BuildingActor.PowerOff() + case _ => ; + } + + case BuildingActor.SuppliedWithNtu() => + gen.Owner match { + case b: Building if !gen.Destroyed => + b.Actor ! BuildingActor.PowerOn() + case _ => ; + } + case _ => ; } @@ -108,7 +122,8 @@ class GeneratorControl(gen: Generator) target.Health = 1 //temporary imminentExplosion = true context.system.scheduler.scheduleOnce(10 seconds, self, GeneratorControl.GeneratorExplodes()) - GeneratorControl.BroadcastGeneratorEvent(gen, 16) + GeneratorControl.UpdateOwner(gen, Some("overloaded")) + GeneratorControl.BroadcastGeneratorEvent(gen, GeneratorControl.Event.Overloaded) } } @@ -123,8 +138,8 @@ class GeneratorControl(gen: Generator) override def Restoration(obj: Repairable.Target): Unit = { super.Restoration(obj) gen.Condition = PlanetSideGeneratorState.Normal - GeneratorControl.UpdateOwner(gen) - GeneratorControl.BroadcastGeneratorEvent(gen, 17) + GeneratorControl.UpdateOwner(gen, Some("repaired")) + GeneratorControl.BroadcastGeneratorEvent(gen, GeneratorControl.Event.Online) } } @@ -145,13 +160,23 @@ object GeneratorControl { */ private case class AlarmReset() + /** + * na + */ + object Event extends Enumeration { + val UnderAttack = Value(15) + val Critical = Value(0) + val Overloaded = Value(16) + val Online = Value(17) + } + /** * na * @param obj na */ - private def UpdateOwner(obj: Generator): Unit = { + private def UpdateOwner(obj: Generator, data: Option[Any] = None): Unit = { obj.Owner match { - case b: Building => b.Actor ! BuildingActor.AmenityStateChange(obj) + case b: Building => b.Actor ! BuildingActor.AmenityStateChange(obj, data) case _ => ; } } @@ -161,11 +186,14 @@ object GeneratorControl { * @param target the generator * @param event the action code for the event */ - private def BroadcastGeneratorEvent(target: Generator, event: Int): Unit = { + private def BroadcastGeneratorEvent(target: Generator, event: Event.Value): Unit = { target.Owner match { case b: Building => val events = target.Zone.AvatarEvents - val msg = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, target.Owner.GUID, event) + val msg = event match { + case Event.Critical => AvatarAction.PlanetsideAttributeToAll(b.GUID, 46, 1) //critical status warning + case _ => AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, b.GUID, event.id) + } b.PlayersInSOI.foreach { player => events ! AvatarServiceMessage(player.Name, msg) } @@ -185,7 +213,7 @@ object GeneratorControl { val max: Float = target.MaxHealth.toFloat if (target.Condition != PlanetSideGeneratorState.Critical && health / max < 0.51f) { //becoming critical target.Condition = PlanetSideGeneratorState.Critical - GeneratorControl.UpdateOwner(target) + GeneratorControl.UpdateOwner(target, Some("critical")) } //the generator is under attack target.Actor ! UnderThreatAlarm() diff --git a/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala b/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala index f1d2f136..4400a3e5 100644 --- a/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/implantmech/ImplantTerminalMechControl.scala @@ -107,7 +107,12 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech) newHealth } + override def tryAutoRepair() : Boolean = { + isPowered && super.tryAutoRepair() + } + def powerTurnOffCallback(): Unit = { + stopAutoRepair() //kick all occupants val guid = mech.GUID val zone = mech.Zone @@ -126,5 +131,7 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech) ) } - def powerTurnOnCallback(): Unit = { } + def powerTurnOnCallback(): Unit = { + tryAutoRepair() + } } diff --git a/src/main/scala/net/psforever/objects/serverobject/repair/AmenityAutoRepair.scala b/src/main/scala/net/psforever/objects/serverobject/repair/AmenityAutoRepair.scala index 22d45abe..64b925d6 100644 --- a/src/main/scala/net/psforever/objects/serverobject/repair/AmenityAutoRepair.scala +++ b/src/main/scala/net/psforever/objects/serverobject/repair/AmenityAutoRepair.scala @@ -129,10 +129,25 @@ trait AmenityAutoRepair /** * Attempt to start auto-repair operation * only if no operation is currently being processed. + * @see `actuallyTryAutoRepair` * @return `true`, if the auto-repair process started specifically due to this call; * `false`, if it was already started, or did not start */ - final def tryAutoRepair(): Boolean = { + def tryAutoRepair(): Boolean = { + actuallyTryAutoRepair() + } + + /** + * Attempt to start auto-repair operation + * only if no operation is currently being processed. + * In case that an override to the normals operations of `tryAutoRepair` is necessary, + * but the superclass can not be invoked, + * this method is the backup of those operations to initiate auto-repair. + * @see `tryAutoRepair` + * @return `true`, if the auto-repair process started specifically due to this call; + * `false`, if it was already started, or did not start + */ + final def actuallyTryAutoRepair(): Boolean = { val before = autoRepairTimer.isCancelled autoRepairStartFunc() !(before || autoRepairTimer.isCancelled) diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala b/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala index e1ba19fa..39ab6939 100644 --- a/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala +++ b/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala @@ -114,6 +114,13 @@ class Building( } } + def Generator: Option[Generator] = { + Amenities.find(_.isInstanceOf[Generator]) match { + case Some(obj: Generator) => Some(obj) + case _ => None + } + } + def CaptureTerminal: Option[CaptureTerminal] = { Amenities.find(_.isInstanceOf[CaptureTerminal]) match { case Some(term) => Some(term.asInstanceOf[CaptureTerminal]) @@ -187,8 +194,8 @@ class Building( (false, PlanetSideEmpire.NEUTRAL, 0L) } //if we have no generator, assume the state is "Normal" - val (generatorState, boostGeneratorPain) = Amenities.find(x => x.isInstanceOf[Generator]) match { - case Some(obj: Generator) => + val (generatorState, boostGeneratorPain) = Generator match { + case Some(obj) => (obj.Condition, false) // todo: poll pain field strength case _ => (PlanetSideGeneratorState.Normal, false) diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala index c0ef203f..fcfdba3c 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala @@ -89,7 +89,12 @@ class TerminalControl(term: Terminal) newHealth } + override def tryAutoRepair() : Boolean = { + isPowered && super.tryAutoRepair() + } + def powerTurnOffCallback() : Unit = { + stopAutoRepair() //clear hack state if (term.HackedBy.nonEmpty) { val zone = term.Zone @@ -97,7 +102,9 @@ class TerminalControl(term: Terminal) } } - def powerTurnOnCallback() : Unit = { } + def powerTurnOnCallback() : Unit = { + tryAutoRepair() + } override def toString: String = term.Definition.Name } diff --git a/src/main/scala/net/psforever/objects/serverobject/tube/SpawnTubeControl.scala b/src/main/scala/net/psforever/objects/serverobject/tube/SpawnTubeControl.scala index 63b65066..c7607bc1 100644 --- a/src/main/scala/net/psforever/objects/serverobject/tube/SpawnTubeControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/tube/SpawnTubeControl.scala @@ -71,8 +71,13 @@ class SpawnTubeControl(tube: SpawnTube) } } + override def tryAutoRepair() : Boolean = { + isPowered && super.tryAutoRepair() + } + def powerTurnOffCallback(): Unit = { tube.offline = false + stopAutoRepair() tube.Owner match { case b: Building => b.Actor ! BuildingActor.AmenityStateChange(tube) case _ => ; @@ -81,6 +86,7 @@ class SpawnTubeControl(tube: SpawnTube) def powerTurnOnCallback(): Unit = { tube.offline = true + tryAutoRepair() tube.Owner match { case b: Building => b.Actor ! BuildingActor.AmenityStateChange(tube) case _ => ; diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala index 9325475e..9734810b 100644 --- a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala @@ -58,11 +58,11 @@ class FacilityTurretControl(turret: FacilityTurret) .orElse(dismountBehavior) .orElse(takesDamage) .orElse(canBeRepairedByNanoDispenser) - .orElse(autoRepairBehavior) def poweredStateLogic: Receive = commonBehavior .orElse(mountBehavior) + .orElse(autoRepairBehavior) .orElse { case CommonMessages.Use(player, Some((item: Tool, upgradeValue: Int))) if player.Faction == turret.Faction && @@ -157,7 +157,12 @@ class FacilityTurretControl(turret: FacilityTurret) events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 0)) } + override def tryAutoRepair() : Boolean = { + isPowered && super.tryAutoRepair() + } + def powerTurnOffCallback(): Unit = { + stopAutoRepair() //kick all occupants val guid = turret.GUID val zone = turret.Zone @@ -176,5 +181,7 @@ class FacilityTurretControl(turret: FacilityTurret) ) } - def powerTurnOnCallback(): Unit = { } + def powerTurnOnCallback(): Unit = { + tryAutoRepair() + } } diff --git a/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala b/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala index a1539e79..d3a8044f 100644 --- a/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala +++ b/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala @@ -144,7 +144,7 @@ import scodec.codecs._ * `45 - NTU charge bar 0-10, 5 = 50% full. Seems to apply to both ANT and NTU Silo (possibly siphons?)`
* `46 - Sends "Generator damage is at a critical level!" message` * `47 - Sets base NTU level to CRITICAL. MUST use base MapId not base GUID`
- * `48 - Set to 1 to send base power loss message & turns on red warning lights throughout base. MUST use base MapId not base GUID`
+ * `48 - Set to 1 to send base power loss message & turns on red warning lights throughout base. MUST use base MapId not base GUID`?
* `49 - Vehicle texture effects state? (>0 turns on ANT panel glow or ntu silo panel glow + orbs) (bit?)`
* `52 - Vehicle particle effects? (>0 turns on orbs going towards ANT. Doesn't affect silo) (bit?)`
* `53 - LFS. Value is 1 to flag LFS`