incorporating structural changes to hacking for future expansion

This commit is contained in:
Fate-JH 2024-07-26 10:02:22 -04:00
parent e5cde75e72
commit c6b3403e4d
5 changed files with 118 additions and 102 deletions

View file

@ -10,7 +10,8 @@ object CommonMessages {
final case class Unuse(player: Player, data: Option[Any] = None) 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 Hack(player: Player, obj: PlanetSideServerObject with Hackable, data: Option[Any] = None)
final case class ClearHack() 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 * The message that progresses some form of user-driven activity with a certain eventual outcome
* and potential feedback per cycle. * and potential feedback per cycle.

View file

@ -31,12 +31,12 @@ object GenericHackables {
turretUpgradeTime turretUpgradeTime
} }
/** /**
* na * na
* *
* @param player the player doing the hacking * @param player the player doing the hacking
* @param obj the object being hacked * @param obj the object being hacked
* @return the percentage amount of progress per tick * @return the percentage amount of progress per tick
*/ */
def GetHackSpeed(player: Player, obj: PlanetSideServerObject): Float = { def GetHackSpeed(player: Player, obj: PlanetSideServerObject): Float = {
val playerHackLevel = player.avatar.hackingSkillLevel() val playerHackLevel = player.avatar.hackingSkillLevel()
val timeToHack = obj match { val timeToHack = obj match {
@ -60,23 +60,23 @@ object GenericHackables {
} }
/** /**
* Evaluate the progress of the user applying a tool to modify some server object. * 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. * 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) * 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. * is also governed by this action per tick of progress.
* @see `HackMessage` * @see `HackMessage`
* @see `HackState` * @see `HackState`
* @param progressType 1 - remote electronics kit hack (various ...); * @param progressType 1 - remote electronics kit hack (various ...);
* 2 - nano dispenser (upgrade canister) turret upgrade * 2 - nano dispenser (upgrade canister) turret upgrade
* @param tplayer the player performing the action * @param tplayer the player performing the action
* @param target the object being affected * @param target the object being affected
* @param tool_guid the tool being used to affest the object * @param tool_guid the tool being used to affest the object
* @param progress the current progress value * @param progress the current progress value
* @return `true`, if the next cycle of progress should occur; * @return `true`, if the next cycle of progress should occur;
* `false`, otherwise * `false`, otherwise
*/ */
def HackingTickAction(progressType: Int, tplayer: Player, target: PlanetSideServerObject, tool_guid: PlanetSideGUID)( def HackingTickAction(progressType: Int, tplayer: Player, target: PlanetSideServerObject, tool_guid: PlanetSideGUID)(
progress: Float progress: Float
): Boolean = { ): Boolean = {
//hack state for progress bar visibility //hack state for progress bar visibility
val vis = if (progress <= 0L) { val vis = if (progress <= 0L) {
@ -108,37 +108,40 @@ object GenericHackables {
} }
/** /**
* The process of hacking an object is completed. * The process of hacking an object is completed.
* Pass the message onto the hackable object and onto the local events system. * Pass the message onto the hackable object and onto the local events system.
* @param target the `Hackable` object that has been hacked * @param target the `Hackable` object that has been hacked
* @param user the player that is performing this hacking task * @param user the player that is performing this hacking task
* @param unk na; * @param unk na;
* used by `HackMessage` as `unk5` * used by `HackMessage` as `unk5`
* @see `HackMessage` * @see `HackMessage`
*/ */
//TODO add params here depending on which params in HackMessage are important //TODO add params here depending on which params in HackMessage are important
def FinishHacking(target: PlanetSideServerObject with Hackable, user: Player, unk: Long)(): Unit = { def FinishHacking(target: PlanetSideServerObject with Hackable, user: Player, unk: Long)(): Unit = {
import akka.pattern.ask import akka.pattern.ask
import scala.concurrent.duration._ 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 // Wait for the target actor to set the HackedBy property, otherwise LocalAction.HackTemporarily will not complete properly
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
val tplayer = user val tplayer = user
ask(target.Actor, CommonMessages.Hack(tplayer, target))(1 second).mapTo[Boolean].onComplete { ask(target.Actor, CommonMessages.Hack(tplayer, target))(timeout = 2 second)
case Success(_) => .mapTo[CommonMessages.EntityHackState]
val zone = target.Zone .onComplete {
val zoneId = zone.id case Success(_) =>
val pguid = tplayer.GUID val zone = target.Zone
zone.LocalEvents ! LocalServiceMessage( val zoneId = zone.id
zoneId, val pguid = tplayer.GUID
LocalAction.TriggerSound(pguid, target.HackSound, tplayer.Position, 30, 0.49803925f) log.info(s"${user.Name} hacked a ${target.Definition.Name}")
) zone.LocalEvents ! LocalServiceMessage(
zone.LocalEvents ! LocalServiceMessage( zoneId,
zoneId, LocalAction.TriggerSound(pguid, target.HackSound, tplayer.Position, 30, 0.49803925f)
LocalAction )
.HackTemporarily(pguid, zone, target, unk, target.HackEffectDuration(user.avatar.hackingSkillLevel())) zone.LocalEvents ! LocalServiceMessage(
) zoneId,
case Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}") 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}")
}
} }
} }

View file

@ -1,32 +1,44 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.hackable 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 net.psforever.objects.serverobject.CommonMessages
import scala.annotation.unused
object HackableBehavior { object HackableBehavior {
/** /**
* The logic governing generic `Hackable` objects that use the `Hack` and `ClearHack` message. * 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. * This is a mix-in trait for combining with existing `Receive` logic.
* @see `Hackable` * @see `Hackable`
*/ */
trait GenericHackable { trait GenericHackable {
this: Actor => this: Actor =>
def HackableObject: Hackable def HackableObject: PlanetSideGameObject with Hackable
val clearHackBehavior: Receive = { val clearHackBehavior: Receive = {
case CommonMessages.ClearHack() => case CommonMessages.ClearHack() =>
val obj = HackableObject performClearHack(None, sender())
obj.HackedBy = None
} }
val hackableBehavior: Receive = clearHackBehavior val hackableBehavior: Receive = clearHackBehavior
.orElse { .orElse {
case CommonMessages.Hack(player, _, _) => case CommonMessages.Hack(player, _, _) =>
val obj = HackableObject performHack(player, None, sender())
obj.HackedBy = player }
sender() ! true
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)
} }
} }
} }

View file

@ -4,12 +4,12 @@ package net.psforever.objects.serverobject.terminals
import akka.actor.ActorRef import akka.actor.ActorRef
import net.psforever.objects.{GlobalDefinitions, SimpleItem} import net.psforever.objects.{GlobalDefinitions, SimpleItem}
import net.psforever.objects.serverobject.CommonMessages 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.Target
import net.psforever.objects.serverobject.damage.{Damageable, DamageableAmenity} 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.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.objects.vital.interaction.DamageResult
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.local.{LocalAction, LocalServiceMessage} 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 * @param term the `Terminal` object being governed
*/ */
class TerminalControl(term: Terminal) class TerminalControl(term: Terminal)
extends PoweredAmenityControl extends PoweredAmenityControl
with FactionAffinityBehavior.Check with FactionAffinityBehavior.Check
with HackableBehavior.GenericHackable with HackableBehavior.GenericHackable
with DamageableAmenity with DamageableAmenity
with RepairableAmenity with RepairableAmenity
with AmenityAutoRepair { with AmenityAutoRepair {
def FactionObject: FactionAffinity = term def FactionObject: Terminal = term
def HackableObject: Hackable = term def HackableObject: Terminal = term
def DamageableObject: Amenity = term def DamageableObject: Terminal = term
def RepairableObject: Amenity = term def RepairableObject: Terminal = term
def AutoRepairObject: Amenity = term def AutoRepairObject: Terminal = term
val commonBehavior: Receive = checkBehavior val commonBehavior: Receive = checkBehavior
.orElse(takesDamage) .orElse(takesDamage)
.orElse(canBeRepairedByNanoDispenser) .orElse(canBeRepairedByNanoDispenser)
.orElse(autoRepairBehavior) .orElse(autoRepairBehavior)
def poweredStateLogic : Receive = def poweredStateLogic: Receive =
commonBehavior commonBehavior
.orElse(hackableBehavior) .orElse(hackableBehavior)
.orElse { .orElse {

View file

@ -1,6 +1,5 @@
package net.psforever.objects.serverobject.terminals.capture package net.psforever.objects.serverobject.terminals.capture
import akka.util.Timeout
import net.psforever.objects.Player import net.psforever.objects.Player
import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.sourcing.PlayerSource import net.psforever.objects.sourcing.PlayerSource
@ -10,17 +9,16 @@ import scala.util.{Failure, Success}
object CaptureTerminals {import scala.concurrent.duration._ object CaptureTerminals {import scala.concurrent.duration._
private val log = org.log4s.getLogger("CaptureTerminals") private val log = org.log4s.getLogger("CaptureTerminals")
private implicit val timeout: Timeout = 1.second
/** /**
* The process of hacking an object is completed. * The process of hacking an object is completed.
* Pass the message onto the hackable object and onto the local events system. * Pass the message onto the hackable object and onto the local events system.
* @param target the `Hackable` object that has been hacked * @param target the `Hackable` object that has been hacked
* @param hackingPlayer The player that hacked the control console * @param hackingPlayer The player that hacked the control console
* @param unk na; * @param unk na;
* used by `HackMessage` as `unk5` * used by `HackMessage` as `unk5`
* @see `HackMessage` * @see `HackMessage`
*/ */
//TODO add params here depending on which params in HackMessage are important //TODO add params here depending on which params in HackMessage are important
def FinishHackingCaptureConsole(target: CaptureTerminal, hackingPlayer: Player, unk: Long)(): Unit = { def FinishHackingCaptureConsole(target: CaptureTerminal, hackingPlayer: Player, unk: Long)(): Unit = {
import akka.pattern.ask import akka.pattern.ask
@ -28,31 +26,33 @@ object CaptureTerminals {import scala.concurrent.duration._
log.info(s"${hackingPlayer.toString} hacked a ${target.Definition.Name}") log.info(s"${hackingPlayer.toString} hacked a ${target.Definition.Name}")
// Wait for the target actor to set the HackedBy property // Wait for the target actor to set the HackedBy property
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
ask(target.Actor, CommonMessages.Hack(hackingPlayer, target)).mapTo[Boolean].onComplete { ask(target.Actor, CommonMessages.Hack(hackingPlayer, target))(timeout = 2 second)
case Success(_) => .mapTo[CommonMessages.EntityHackState]
val zone = target.Zone .onComplete {
val zoneid = zone.id case Success(_) =>
val events = zone.LocalEvents val zone = target.Zone
val isResecured = hackingPlayer.Faction == target.Faction val zoneid = zone.id
events ! LocalServiceMessage( val events = zone.LocalEvents
zoneid, val isResecured = hackingPlayer.Faction == target.Faction
LocalAction.TriggerSound(hackingPlayer.GUID, target.HackSound, hackingPlayer.Position, 30, 0.49803925f)
)
if (isResecured) {
// Resecure the CC
events ! LocalServiceMessage( events ! LocalServiceMessage(
zoneid, zoneid,
LocalAction.ResecureCaptureTerminal(target, PlayerSource(hackingPlayer)) LocalAction.TriggerSound(hackingPlayer.GUID, target.HackSound, hackingPlayer.Position, 30, 0.49803925f)
) )
} else { if (isResecured) {
// Start the CC hack timer // Resecure the CC
events ! LocalServiceMessage( events ! LocalServiceMessage(
zoneid, zoneid,
LocalAction.StartCaptureTerminalHack(target) LocalAction.ResecureCaptureTerminal(target, PlayerSource(hackingPlayer))
) )
} } else {
case Failure(_) => // Start the CC hack timer
log.warn(s"Hack message failed on target guid: ${target.GUID}") events ! LocalServiceMessage(
} zoneid,
LocalAction.StartCaptureTerminalHack(target)
)
}
case Failure(_) =>
log.warn(s"Hack message failed on target guid: ${target.GUID}")
}
} }
} }