Merge pull request #825 from Fate-JH/one-llu

Only One LLU
This commit is contained in:
Fate-JH 2021-05-19 19:19:34 -04:00 committed by GitHub
commit cead0e21c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 65 deletions

View file

@ -11,7 +11,19 @@ import net.psforever.types.Vector3
* It is used as a position reference for spawning the LLU in the correct location when the base is hacked * It is used as a position reference for spawning the LLU in the correct location when the base is hacked
* @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields * @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/ */
class CaptureFlagSocket(tDef: CaptureFlagSocketDefinition) extends Amenity { class CaptureFlagSocket(tDef: CaptureFlagSocketDefinition)
extends Amenity {
private var spawnedCaptureFlag: Option[CaptureFlag] = None
def captureFlag: Option[CaptureFlag] = spawnedCaptureFlag
def captureFlag_=(flag: CaptureFlag): Option[CaptureFlag] = captureFlag_=(Some(flag))
def captureFlag_=(flag: Option[CaptureFlag]): Option[CaptureFlag] = {
spawnedCaptureFlag = flag
captureFlag
}
def Definition : CaptureFlagSocketDefinition = tDef def Definition : CaptureFlagSocketDefinition = tDef
} }

View file

@ -129,7 +129,12 @@ class Building(
} }
def GetFlagSocket: Option[CaptureFlagSocket] = this.Amenities.find(_.Definition == GlobalDefinitions.llm_socket).asInstanceOf[Option[CaptureFlagSocket]] def GetFlagSocket: Option[CaptureFlagSocket] = this.Amenities.find(_.Definition == GlobalDefinitions.llm_socket).asInstanceOf[Option[CaptureFlagSocket]]
def GetFlag: Option[CaptureFlag] = this.Amenities.find(_.Definition == GlobalDefinitions.capture_flag).asInstanceOf[Option[CaptureFlag]] def GetFlag: Option[CaptureFlag] = {
GetFlagSocket match {
case Some(socket) => socket.captureFlag
case None => None
}
}
def HackableAmenities: List[Amenity with Hackable] = { def HackableAmenities: List[Amenity with Hackable] = {
Amenities.filter(x => x.isInstanceOf[Hackable]).map(x => x.asInstanceOf[Amenity with Hackable]) Amenities.filter(x => x.isInstanceOf[Hackable]).map(x => x.asInstanceOf[Amenity with Hackable])

View file

@ -102,6 +102,7 @@ class CaptureFlagManager(val taskResolver: ActorRef, zone: Zone) extends Actor{
) )
// Add the flag as an amenity and track it internally // Add the flag as an amenity and track it internally
socket.captureFlag = flag
TrackFlag(flag) TrackFlag(flag)
taskResolver ! CallBackForTask( taskResolver ! CallBackForTask(
@ -128,15 +129,19 @@ class CaptureFlagManager(val taskResolver: ActorRef, zone: Zone) extends Actor{
HandleFlagDespawn(flag) HandleFlagDespawn(flag)
case CaptureFlagManager.Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) => case CaptureFlagManager.Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) =>
val message = reason match { reason match {
case CaptureFlagLostReasonEnum.Resecured => case CaptureFlagLostReasonEnum.Resecured =>
CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building]) ChatBroadcast(
case CaptureFlagLostReasonEnum.TimedOut => flag.Zone,
CaptureFlagChatMessageStrings.CTF_Failed_TimedOut(flag.Owner.asInstanceOf[Building].Name, flag.Target) CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building])
)
case CaptureFlagLostReasonEnum.TimedOut =>
ChatBroadcast(
flag.Zone,
CaptureFlagChatMessageStrings.CTF_Failed_TimedOut(flag.Owner.asInstanceOf[Building].Name, flag.Target)
)
case CaptureFlagLostReasonEnum.Ended => ; /* no message */
} }
ChatBroadcast(flag.Zone, message)
HandleFlagDespawn(flag) HandleFlagDespawn(flag)
case CaptureFlagManager.PickupFlag(flag: CaptureFlag, player: Player) => case CaptureFlagManager.PickupFlag(flag: CaptureFlag, player: Player) =>
@ -173,14 +178,13 @@ class CaptureFlagManager(val taskResolver: ActorRef, zone: Zone) extends Actor{
} }
private def HandleFlagDespawn(flag: CaptureFlag): Unit = { private def HandleFlagDespawn(flag: CaptureFlag): Unit = {
// Remove the flag as an amenity
flag.Owner.asInstanceOf[Building].GetFlagSocket.get.captureFlag = None
UntrackFlag(flag)
// Unregister LLU from clients, // Unregister LLU from clients,
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.LluDespawned(PlanetSideGUID(-1), flag)) flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.LluDespawned(PlanetSideGUID(-1), flag))
// Then unregister it from the GUID pool // Then unregister it from the GUID pool
taskResolver ! TaskResolver.GiveTask(GUIDTask.UnregisterObjectTask(flag)(flag.Zone.GUID).task) taskResolver ! TaskResolver.GiveTask(GUIDTask.UnregisterObjectTask(flag)(flag.Zone.GUID).task)
// Remove the flag as an amenity
UntrackFlag(flag)
} }
private def ChatBroadcast(zone: Zone, message: String, fanfare: Boolean = true): Unit = { private def ChatBroadcast(zone: Zone, message: String, fanfare: Boolean = true): Unit = {
@ -271,6 +275,7 @@ object CaptureFlagChatMessageStrings {
case PlanetSideEmpire.TR => "TerranRepublic" case PlanetSideEmpire.TR => "TerranRepublic"
case PlanetSideEmpire.NC => "NewConglomerate" case PlanetSideEmpire.NC => "NewConglomerate"
case PlanetSideEmpire.VS => "VanuSovereigncy" // Yes, this is wrong. It is like that in packet captures. case PlanetSideEmpire.VS => "VanuSovereigncy" // Yes, this is wrong. It is like that in packet captures.
case _ => "TerranRepublic" //todo: BO message?
} }
} }
} }
@ -278,5 +283,5 @@ object CaptureFlagChatMessageStrings {
object CaptureFlagLostReasonEnum extends Enumeration { object CaptureFlagLostReasonEnum extends Enumeration {
type CaptureFlagLostReasonEnum = Value type CaptureFlagLostReasonEnum = Value
val Resecured, TimedOut = Value val Resecured, TimedOut, Ended = Value
} }

View file

@ -31,42 +31,36 @@ class HackCaptureActor(val taskResolver: ActorRef) extends Actor {
def receive: Receive = { def receive: Receive = {
case HackCaptureActor.StartCaptureTerminalHack(target, zone, unk1, unk2, startTime) => case HackCaptureActor.StartCaptureTerminalHack(target, zone, unk1, unk2, startTime) =>
log.trace(s"StartCaptureTerminalHack: ${target.GUID} is hacked.") log.trace(s"StartCaptureTerminalHack: ${target.GUID} is hacked.")
val duration = target.Definition match {
val duration = target.Definition match { case GlobalDefinitions.capture_terminal =>
case GlobalDefinitions.capture_terminal => // Base CC
// Base CC 15 minutes
15 minutes case GlobalDefinitions.secondary_capture =>
case GlobalDefinitions.secondary_capture => // Tower CC
// Tower CC 1 nanosecond
1 nanosecond case GlobalDefinitions.vanu_control_console =>
case GlobalDefinitions.vanu_control_console => // Cavern CC
// Cavern CC 10 minutes
10 minutes }
} target.HackedBy match {
case Some(hackInfo) =>
target.HackedBy match { target.HackedBy = hackInfo.Duration(duration.toNanos)
case Some(hackInfo) => case None =>
target.HackedBy = hackInfo.Duration(duration.toNanos) log.error(s"Initial $target hack information is missing")
case None => }
log.error(s"Initial $target hack information is missing") hackedObjects.find(_.target == target) match {
} case Some(_) =>
log.trace(
hackedObjects.find(_.target == target) match { s"StartCaptureTerminalHack: ${target.GUID} was already hacked - removing it from the hacked objects list before re-adding it."
case Some(_) => )
log.trace( hackedObjects = hackedObjects.filterNot(x => x.target == target)
s"StartCaptureTerminalHack: ${target.GUID} was already hacked - removing it from the hacked objects list before re-adding it." case _ => ;
) }
hackedObjects = hackedObjects.filterNot(x => x.target == target) hackedObjects = hackedObjects :+ HackCaptureActor.HackEntry(target, zone, unk1, unk2, duration, startTime)
case _ => ; // Restart the timer, in case this is the first object in the hacked objects list or the object was removed and re-added
} RestartTimer()
NotifyHackStateChange(target, isResecured = false)
hackedObjects = hackedObjects :+ HackCaptureActor.HackEntry(target, zone, unk1, unk2, duration, startTime) TrySpawnCaptureFlag(target)
// Restart the timer, in case this is the first object in the hacked objects list or the object was removed and re-added
RestartTimer()
NotifyHackStateChange(target, isResecured = false)
TrySpawnCaptureFlag(target)
case HackCaptureActor.ProcessCompleteHacks() => case HackCaptureActor.ProcessCompleteHacks() =>
log.trace("Processing complete hacks") log.trace("Processing complete hacks")
@ -134,27 +128,57 @@ class HackCaptureActor(val taskResolver: ActorRef) extends Actor {
case _ => ; case _ => ;
} }
private def TrySpawnCaptureFlag(terminal: CaptureTerminal): Unit = { private def TrySpawnCaptureFlag(terminal: CaptureTerminal): Boolean = {
// Handle LLUs if the base contains a LLU socket // Handle LLUs if the base contains a LLU socket
// If there are no neighbouring bases belonging to the hacking faction this will be handled as a regular timed hack (e.g. neutral base in enemy territory) // If there are no neighbouring bases belonging to the hacking faction this will be handled as a regular timed hack (e.g. neutral base in enemy territory)
val owner = terminal.Owner.asInstanceOf[Building] terminal.Owner match {
val hackingFaction = HackCaptureActor.GetHackingFaction(terminal).get case owner: Building if owner.IsCtfBase =>
val hackingFactionNeighbourBases = owner.Neighbours(hackingFaction) val socket = owner.GetFlagSocket.get
val flag = socket.captureFlag
hackingFactionNeighbourBases match { val owningFaction = owner.Faction
case Some(neighbours) => val hackingFaction = HackCaptureActor.GetHackingFaction(terminal).get
if(owner.IsCtfBase) { owner.Neighbours(hackingFaction) match {
// Find a random neighbouring base matching the hacking faction case Some(neighbours) =>
val targetBase = neighbours.toVector((new Random).nextInt(neighbours.size)) if (flag.isEmpty) {
log.info(s"An LLU is being spawned for facility ${owner.Name} by $hackingFaction")
// Request LLU is created by CaptureFlagActor via LocalService spawnCaptureFlag(neighbours, terminal, hackingFaction)
terminal.Zone.LocalEvents ! CaptureFlagManager.SpawnCaptureFlag(terminal, targetBase, hackingFaction) true
} else if (hackingFaction != flag.get.Faction) {
log.info(s"$hackingFaction is overriding the ongoing LLU hack of facility ${owner.Name} by ${flag.get.Faction}")
terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(flag.get, CaptureFlagLostReasonEnum.Ended)
NotifyHackStateChange(terminal, isResecured = false)
RestartTimer()
spawnCaptureFlag(neighbours, terminal, hackingFaction)
true
} else if (hackingFaction == owningFaction) {
log.error(s"Owning faction and hacking faction match for facility ${owner.Name}; should we be resecuring instead?")
false
} else {
log.warn(s"LLU hack of facility ${owner.Name} by $hackingFaction in progress - no change")
false
}
case None => ;
log.info(s"Couldn't find any neighbouring $hackingFaction facilities of ${owner.Name} for LLU hack")
false
} }
case None =>
log.info("Couldn't find any neighbouring bases for LLU hack.") case thing =>
log.error(s"Capture terminal has unexpected owner - $thing - that is not a facility")
false
} }
} }
private def spawnCaptureFlag(
neighbours: Set[Building],
terminal: CaptureTerminal,
hackingFaction: PlanetSideEmpire.Value
): Unit = {
// Find a random neighbouring base matching the hacking faction
val targetBase = neighbours.toVector((new Random).nextInt(neighbours.size))
// Request LLU is created by CaptureFlagActor via LocalService
terminal.Zone.LocalEvents ! CaptureFlagManager.SpawnCaptureFlag(terminal, targetBase, hackingFaction)
}
private def NotifyHackStateChange(terminal: CaptureTerminal, isResecured: Boolean): Unit = { private def NotifyHackStateChange(terminal: CaptureTerminal, isResecured: Boolean): Unit = {
val attribute_value = HackCaptureActor.GetHackUpdateAttributeValue(terminal, isResecured) val attribute_value = HackCaptureActor.GetHackUpdateAttributeValue(terminal, isResecured)