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 =>
ChatBroadcast(
flag.Zone,
CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building]) CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building])
)
case CaptureFlagLostReasonEnum.TimedOut => case CaptureFlagLostReasonEnum.TimedOut =>
ChatBroadcast(
flag.Zone,
CaptureFlagChatMessageStrings.CTF_Failed_TimedOut(flag.Owner.asInstanceOf[Building].Name, flag.Target) 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,7 +31,6 @@ 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
@ -43,14 +42,12 @@ class HackCaptureActor(val taskResolver: ActorRef) extends Actor {
// Cavern CC // Cavern CC
10 minutes 10 minutes
} }
target.HackedBy match { target.HackedBy match {
case Some(hackInfo) => case Some(hackInfo) =>
target.HackedBy = hackInfo.Duration(duration.toNanos) target.HackedBy = hackInfo.Duration(duration.toNanos)
case None => case None =>
log.error(s"Initial $target hack information is missing") log.error(s"Initial $target hack information is missing")
} }
hackedObjects.find(_.target == target) match { hackedObjects.find(_.target == target) match {
case Some(_) => case Some(_) =>
log.trace( log.trace(
@ -59,12 +56,9 @@ class HackCaptureActor(val taskResolver: ActorRef) extends Actor {
hackedObjects = hackedObjects.filterNot(x => x.target == target) hackedObjects = hackedObjects.filterNot(x => x.target == target)
case _ => ; case _ => ;
} }
hackedObjects = hackedObjects :+ HackCaptureActor.HackEntry(target, zone, unk1, unk2, duration, startTime) hackedObjects = hackedObjects :+ HackCaptureActor.HackEntry(target, zone, unk1, unk2, duration, startTime)
// Restart the timer, in case this is the first object in the hacked objects list or the object was removed and re-added // Restart the timer, in case this is the first object in the hacked objects list or the object was removed and re-added
RestartTimer() RestartTimer()
NotifyHackStateChange(target, isResecured = false) NotifyHackStateChange(target, isResecured = false)
TrySpawnCaptureFlag(target) TrySpawnCaptureFlag(target)
@ -134,26 +128,56 @@ 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 {
case owner: Building if owner.IsCtfBase =>
val socket = owner.GetFlagSocket.get
val flag = socket.captureFlag
val owningFaction = owner.Faction
val hackingFaction = HackCaptureActor.GetHackingFaction(terminal).get val hackingFaction = HackCaptureActor.GetHackingFaction(terminal).get
val hackingFactionNeighbourBases = owner.Neighbours(hackingFaction) owner.Neighbours(hackingFaction) match {
hackingFactionNeighbourBases match {
case Some(neighbours) => case Some(neighbours) =>
if(owner.IsCtfBase) { if (flag.isEmpty) {
log.info(s"An LLU is being spawned for facility ${owner.Name} by $hackingFaction")
spawnCaptureFlag(neighbours, terminal, 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 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 // Find a random neighbouring base matching the hacking faction
val targetBase = neighbours.toVector((new Random).nextInt(neighbours.size)) val targetBase = neighbours.toVector((new Random).nextInt(neighbours.size))
// Request LLU is created by CaptureFlagActor via LocalService // Request LLU is created by CaptureFlagActor via LocalService
terminal.Zone.LocalEvents ! CaptureFlagManager.SpawnCaptureFlag(terminal, targetBase, hackingFaction) terminal.Zone.LocalEvents ! CaptureFlagManager.SpawnCaptureFlag(terminal, targetBase, hackingFaction)
} }
case None =>
log.info("Couldn't find any neighbouring bases for LLU hack.")
}
}
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)