diff --git a/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala b/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala index 7f19cf8d2..ef1d4679b 100644 --- a/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala +++ b/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala @@ -10,7 +10,8 @@ object CommonMessages { final case class Unuse(player: Player, data: Option[Any] = None) final case class Hack(player: Player, obj: PlanetSideServerObject with Hackable, data: Option[Any] = None) final case class ClearHack() - + final case class EntityHackState(obj: PlanetSideGameObject with Hackable, hackState: Boolean) + /** * The message that progresses some form of user-driven activity with a certain eventual outcome * and potential feedback per cycle. diff --git a/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala b/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala index ed83e5ce0..a88b1907e 100644 --- a/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala +++ b/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala @@ -31,12 +31,12 @@ object GenericHackables { turretUpgradeTime } /** - * na - * - * @param player the player doing the hacking - * @param obj the object being hacked - * @return the percentage amount of progress per tick - */ + * na + * + * @param player the player doing the hacking + * @param obj the object being hacked + * @return the percentage amount of progress per tick + */ def GetHackSpeed(player: Player, obj: PlanetSideServerObject): Float = { val playerHackLevel = player.avatar.hackingSkillLevel() val timeToHack = obj match { @@ -60,23 +60,23 @@ object GenericHackables { } /** - * Evaluate the progress of the user applying a tool to modify some server object. - * This action is using the remote electronics kit to convert an enemy unit into an allied unit, primarily. - * The act of transforming allied units of one kind into allied units of another kind (facility turret upgrades) - * is also governed by this action per tick of progress. - * @see `HackMessage` - * @see `HackState` - * @param progressType 1 - remote electronics kit hack (various ...); - * 2 - nano dispenser (upgrade canister) turret upgrade - * @param tplayer the player performing the action - * @param target the object being affected - * @param tool_guid the tool being used to affest the object - * @param progress the current progress value - * @return `true`, if the next cycle of progress should occur; - * `false`, otherwise - */ + * Evaluate the progress of the user applying a tool to modify some server object. + * This action is using the remote electronics kit to convert an enemy unit into an allied unit, primarily. + * The act of transforming allied units of one kind into allied units of another kind (facility turret upgrades) + * is also governed by this action per tick of progress. + * @see `HackMessage` + * @see `HackState` + * @param progressType 1 - remote electronics kit hack (various ...); + * 2 - nano dispenser (upgrade canister) turret upgrade + * @param tplayer the player performing the action + * @param target the object being affected + * @param tool_guid the tool being used to affest the object + * @param progress the current progress value + * @return `true`, if the next cycle of progress should occur; + * `false`, otherwise + */ def HackingTickAction(progressType: Int, tplayer: Player, target: PlanetSideServerObject, tool_guid: PlanetSideGUID)( - progress: Float + progress: Float ): Boolean = { //hack state for progress bar visibility val vis = if (progress <= 0L) { @@ -108,37 +108,40 @@ object GenericHackables { } /** - * The process of hacking an object is completed. - * Pass the message onto the hackable object and onto the local events system. - * @param target the `Hackable` object that has been hacked - * @param user the player that is performing this hacking task - * @param unk na; - * used by `HackMessage` as `unk5` - * @see `HackMessage` - */ + * The process of hacking an object is completed. + * Pass the message onto the hackable object and onto the local events system. + * @param target the `Hackable` object that has been hacked + * @param user the player that is performing this hacking task + * @param unk na; + * used by `HackMessage` as `unk5` + * @see `HackMessage` + */ //TODO add params here depending on which params in HackMessage are important def FinishHacking(target: PlanetSideServerObject with Hackable, user: Player, unk: Long)(): Unit = { import akka.pattern.ask import scala.concurrent.duration._ - log.info(s"${user.Name} hacked a ${target.Definition.Name}") // Wait for the target actor to set the HackedBy property, otherwise LocalAction.HackTemporarily will not complete properly import scala.concurrent.ExecutionContext.Implicits.global val tplayer = user - ask(target.Actor, CommonMessages.Hack(tplayer, target))(1 second).mapTo[Boolean].onComplete { - case Success(_) => - val zone = target.Zone - val zoneId = zone.id - val pguid = tplayer.GUID - zone.LocalEvents ! LocalServiceMessage( - zoneId, - LocalAction.TriggerSound(pguid, target.HackSound, tplayer.Position, 30, 0.49803925f) - ) - zone.LocalEvents ! LocalServiceMessage( - zoneId, - LocalAction - .HackTemporarily(pguid, zone, target, unk, target.HackEffectDuration(user.avatar.hackingSkillLevel())) - ) - case Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}") - } + ask(target.Actor, CommonMessages.Hack(tplayer, target))(timeout = 2 second) + .mapTo[CommonMessages.EntityHackState] + .onComplete { + case Success(_) => + val zone = target.Zone + val zoneId = zone.id + val pguid = tplayer.GUID + log.info(s"${user.Name} hacked a ${target.Definition.Name}") + zone.LocalEvents ! LocalServiceMessage( + zoneId, + LocalAction.TriggerSound(pguid, target.HackSound, tplayer.Position, 30, 0.49803925f) + ) + zone.LocalEvents ! LocalServiceMessage( + zoneId, + LocalAction + .HackTemporarily(pguid, zone, target, unk, target.HackEffectDuration(user.avatar.hackingSkillLevel())) + ) + case Failure(_) => + log.warn(s"Hack message failed on target: ${target.Definition.Name}@${target.GUID.guid}") + } } } diff --git a/src/main/scala/net/psforever/objects/serverobject/hackable/HackableBehavior.scala b/src/main/scala/net/psforever/objects/serverobject/hackable/HackableBehavior.scala index cd333ece0..d3d1243e1 100644 --- a/src/main/scala/net/psforever/objects/serverobject/hackable/HackableBehavior.scala +++ b/src/main/scala/net/psforever/objects/serverobject/hackable/HackableBehavior.scala @@ -1,32 +1,44 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.hackable -import akka.actor.Actor +import akka.actor.{Actor, ActorRef} +import net.psforever.objects.{PlanetSideGameObject, Player} import net.psforever.objects.serverobject.CommonMessages +import scala.annotation.unused + object HackableBehavior { /** - * The logic governing generic `Hackable` objects that use the `Hack` and `ClearHack` message. - * This is a mix-in trait for combining with existing `Receive` logic. - * @see `Hackable` - */ + * The logic governing generic `Hackable` objects that use the `Hack` and `ClearHack` message. + * This is a mix-in trait for combining with existing `Receive` logic. + * @see `Hackable` + */ trait GenericHackable { this: Actor => - def HackableObject: Hackable + def HackableObject: PlanetSideGameObject with Hackable val clearHackBehavior: Receive = { case CommonMessages.ClearHack() => - val obj = HackableObject - obj.HackedBy = None + performClearHack(None, sender()) } val hackableBehavior: Receive = clearHackBehavior .orElse { case CommonMessages.Hack(player, _, _) => - val obj = HackableObject - obj.HackedBy = player - sender() ! true + performHack(player, None, sender()) + } + + def performHack(player: Player, @unused data: Option[Any], replyTo: ActorRef): Unit = { + val obj = HackableObject + obj.HackedBy = player + replyTo ! CommonMessages.EntityHackState(obj, hackState = true) + } + + def performClearHack(@unused data: Option[Any], replyTo: ActorRef): Unit = { + val obj = HackableObject + obj.HackedBy = None + replyTo ! CommonMessages.EntityHackState(obj, hackState = 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 6cab6095c..46f596aa8 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala @@ -4,12 +4,12 @@ package net.psforever.objects.serverobject.terminals import akka.actor.ActorRef import net.psforever.objects.{GlobalDefinitions, SimpleItem} import net.psforever.objects.serverobject.CommonMessages -import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} +import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior import net.psforever.objects.serverobject.damage.Damageable.Target import net.psforever.objects.serverobject.damage.{Damageable, DamageableAmenity} -import net.psforever.objects.serverobject.hackable.{GenericHackables, Hackable, HackableBehavior} +import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior} import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity} -import net.psforever.objects.serverobject.structures.{Amenity, Building, PoweredAmenityControl} +import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl} import net.psforever.objects.vital.interaction.DamageResult import net.psforever.services.Service import net.psforever.services.local.{LocalAction, LocalServiceMessage} @@ -19,24 +19,24 @@ import net.psforever.services.local.{LocalAction, LocalServiceMessage} * @param term the `Terminal` object being governed */ class TerminalControl(term: Terminal) - extends PoweredAmenityControl + extends PoweredAmenityControl with FactionAffinityBehavior.Check with HackableBehavior.GenericHackable with DamageableAmenity with RepairableAmenity with AmenityAutoRepair { - def FactionObject: FactionAffinity = term - def HackableObject: Hackable = term - def DamageableObject: Amenity = term - def RepairableObject: Amenity = term - def AutoRepairObject: Amenity = term + def FactionObject: Terminal = term + def HackableObject: Terminal = term + def DamageableObject: Terminal = term + def RepairableObject: Terminal = term + def AutoRepairObject: Terminal = term val commonBehavior: Receive = checkBehavior .orElse(takesDamage) .orElse(canBeRepairedByNanoDispenser) .orElse(autoRepairBehavior) - def poweredStateLogic : Receive = + def poweredStateLogic: Receive = commonBehavior .orElse(hackableBehavior) .orElse { diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala index 0ed0f7161..7144d4803 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala @@ -1,6 +1,5 @@ package net.psforever.objects.serverobject.terminals.capture -import akka.util.Timeout import net.psforever.objects.Player import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.sourcing.PlayerSource @@ -10,17 +9,16 @@ import scala.util.{Failure, Success} object CaptureTerminals {import scala.concurrent.duration._ private val log = org.log4s.getLogger("CaptureTerminals") - private implicit val timeout: Timeout = 1.second /** - * The process of hacking an object is completed. - * Pass the message onto the hackable object and onto the local events system. - * @param target the `Hackable` object that has been hacked - * @param hackingPlayer The player that hacked the control console - * @param unk na; - * used by `HackMessage` as `unk5` - * @see `HackMessage` - */ + * The process of hacking an object is completed. + * Pass the message onto the hackable object and onto the local events system. + * @param target the `Hackable` object that has been hacked + * @param hackingPlayer The player that hacked the control console + * @param unk na; + * used by `HackMessage` as `unk5` + * @see `HackMessage` + */ //TODO add params here depending on which params in HackMessage are important def FinishHackingCaptureConsole(target: CaptureTerminal, hackingPlayer: Player, unk: Long)(): Unit = { import akka.pattern.ask @@ -28,31 +26,33 @@ object CaptureTerminals {import scala.concurrent.duration._ log.info(s"${hackingPlayer.toString} hacked a ${target.Definition.Name}") // Wait for the target actor to set the HackedBy property import scala.concurrent.ExecutionContext.Implicits.global - ask(target.Actor, CommonMessages.Hack(hackingPlayer, target)).mapTo[Boolean].onComplete { - case Success(_) => - val zone = target.Zone - val zoneid = zone.id - val events = zone.LocalEvents - val isResecured = hackingPlayer.Faction == target.Faction - events ! LocalServiceMessage( - zoneid, - LocalAction.TriggerSound(hackingPlayer.GUID, target.HackSound, hackingPlayer.Position, 30, 0.49803925f) - ) - if (isResecured) { - // Resecure the CC + ask(target.Actor, CommonMessages.Hack(hackingPlayer, target))(timeout = 2 second) + .mapTo[CommonMessages.EntityHackState] + .onComplete { + case Success(_) => + val zone = target.Zone + val zoneid = zone.id + val events = zone.LocalEvents + val isResecured = hackingPlayer.Faction == target.Faction events ! LocalServiceMessage( zoneid, - LocalAction.ResecureCaptureTerminal(target, PlayerSource(hackingPlayer)) + LocalAction.TriggerSound(hackingPlayer.GUID, target.HackSound, hackingPlayer.Position, 30, 0.49803925f) ) - } else { - // Start the CC hack timer - events ! LocalServiceMessage( - zoneid, - LocalAction.StartCaptureTerminalHack(target) - ) - } - case Failure(_) => - log.warn(s"Hack message failed on target guid: ${target.GUID}") - } + if (isResecured) { + // Resecure the CC + events ! LocalServiceMessage( + zoneid, + LocalAction.ResecureCaptureTerminal(target, PlayerSource(hackingPlayer)) + ) + } else { + // Start the CC hack timer + events ! LocalServiceMessage( + zoneid, + LocalAction.StartCaptureTerminalHack(target) + ) + } + case Failure(_) => + log.warn(s"Hack message failed on target guid: ${target.GUID}") + } } }