mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-20 02:54:46 +00:00
ward against spawning multiple LLU's during normal/wrested base capture
This commit is contained in:
parent
2a5c50c9ec
commit
afb1f4b279
|
|
@ -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
|
||||
* @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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,12 @@ class Building(
|
|||
}
|
||||
|
||||
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] = {
|
||||
Amenities.filter(x => x.isInstanceOf[Hackable]).map(x => x.asInstanceOf[Amenity with Hackable])
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ class CaptureFlagManager(val taskResolver: ActorRef, zone: Zone) extends Actor{
|
|||
)
|
||||
|
||||
// Add the flag as an amenity and track it internally
|
||||
socket.captureFlag = flag
|
||||
TrackFlag(flag)
|
||||
|
||||
taskResolver ! CallBackForTask(
|
||||
|
|
@ -128,15 +129,19 @@ class CaptureFlagManager(val taskResolver: ActorRef, zone: Zone) extends Actor{
|
|||
HandleFlagDespawn(flag)
|
||||
|
||||
case CaptureFlagManager.Lost(flag: CaptureFlag, reason: CaptureFlagLostReasonEnum) =>
|
||||
val message = reason match {
|
||||
reason match {
|
||||
case CaptureFlagLostReasonEnum.Resecured =>
|
||||
CaptureFlagChatMessageStrings.CTF_Failed_SourceResecured(flag.Owner.asInstanceOf[Building])
|
||||
case CaptureFlagLostReasonEnum.TimedOut =>
|
||||
CaptureFlagChatMessageStrings.CTF_Failed_TimedOut(flag.Owner.asInstanceOf[Building].Name, flag.Target)
|
||||
ChatBroadcast(
|
||||
flag.Zone,
|
||||
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)
|
||||
|
||||
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 = {
|
||||
// Remove the flag as an amenity
|
||||
flag.Owner.asInstanceOf[Building].GetFlagSocket.get.captureFlag = None
|
||||
UntrackFlag(flag)
|
||||
// Unregister LLU from clients,
|
||||
flag.Zone.LocalEvents ! LocalServiceMessage(flag.Zone.id, LocalAction.LluDespawned(PlanetSideGUID(-1), flag))
|
||||
|
||||
// Then unregister it from the GUID pool
|
||||
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 = {
|
||||
|
|
@ -271,6 +275,7 @@ object CaptureFlagChatMessageStrings {
|
|||
case PlanetSideEmpire.TR => "TerranRepublic"
|
||||
case PlanetSideEmpire.NC => "NewConglomerate"
|
||||
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 {
|
||||
type CaptureFlagLostReasonEnum = Value
|
||||
|
||||
val Resecured, TimedOut = Value
|
||||
val Resecured, TimedOut, Ended = Value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,42 +31,36 @@ class HackCaptureActor(val taskResolver: ActorRef) extends Actor {
|
|||
def receive: Receive = {
|
||||
case HackCaptureActor.StartCaptureTerminalHack(target, zone, unk1, unk2, startTime) =>
|
||||
log.trace(s"StartCaptureTerminalHack: ${target.GUID} is hacked.")
|
||||
|
||||
val duration = target.Definition match {
|
||||
case GlobalDefinitions.capture_terminal =>
|
||||
// Base CC
|
||||
15 minutes
|
||||
case GlobalDefinitions.secondary_capture =>
|
||||
// Tower CC
|
||||
1 nanosecond
|
||||
case GlobalDefinitions.vanu_control_console =>
|
||||
// Cavern CC
|
||||
10 minutes
|
||||
}
|
||||
|
||||
target.HackedBy match {
|
||||
case Some(hackInfo) =>
|
||||
target.HackedBy = hackInfo.Duration(duration.toNanos)
|
||||
case None =>
|
||||
log.error(s"Initial $target hack information is missing")
|
||||
}
|
||||
|
||||
hackedObjects.find(_.target == target) match {
|
||||
case Some(_) =>
|
||||
log.trace(
|
||||
s"StartCaptureTerminalHack: ${target.GUID} was already hacked - removing it from the hacked objects list before re-adding it."
|
||||
)
|
||||
hackedObjects = hackedObjects.filterNot(x => x.target == target)
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
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
|
||||
RestartTimer()
|
||||
|
||||
NotifyHackStateChange(target, isResecured = false)
|
||||
TrySpawnCaptureFlag(target)
|
||||
val duration = target.Definition match {
|
||||
case GlobalDefinitions.capture_terminal =>
|
||||
// Base CC
|
||||
15 minutes
|
||||
case GlobalDefinitions.secondary_capture =>
|
||||
// Tower CC
|
||||
1 nanosecond
|
||||
case GlobalDefinitions.vanu_control_console =>
|
||||
// Cavern CC
|
||||
10 minutes
|
||||
}
|
||||
target.HackedBy match {
|
||||
case Some(hackInfo) =>
|
||||
target.HackedBy = hackInfo.Duration(duration.toNanos)
|
||||
case None =>
|
||||
log.error(s"Initial $target hack information is missing")
|
||||
}
|
||||
hackedObjects.find(_.target == target) match {
|
||||
case Some(_) =>
|
||||
log.trace(
|
||||
s"StartCaptureTerminalHack: ${target.GUID} was already hacked - removing it from the hacked objects list before re-adding it."
|
||||
)
|
||||
hackedObjects = hackedObjects.filterNot(x => x.target == target)
|
||||
case _ => ;
|
||||
}
|
||||
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
|
||||
RestartTimer()
|
||||
NotifyHackStateChange(target, isResecured = false)
|
||||
TrySpawnCaptureFlag(target)
|
||||
|
||||
case HackCaptureActor.ProcessCompleteHacks() =>
|
||||
log.trace("Processing complete hacks")
|
||||
|
|
@ -134,27 +128,57 @@ class HackCaptureActor(val taskResolver: ActorRef) extends Actor {
|
|||
case _ => ;
|
||||
}
|
||||
|
||||
private def TrySpawnCaptureFlag(terminal: CaptureTerminal): Unit = {
|
||||
private def TrySpawnCaptureFlag(terminal: CaptureTerminal): Boolean = {
|
||||
// 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)
|
||||
val owner = terminal.Owner.asInstanceOf[Building]
|
||||
val hackingFaction = HackCaptureActor.GetHackingFaction(terminal).get
|
||||
val hackingFactionNeighbourBases = owner.Neighbours(hackingFaction)
|
||||
|
||||
hackingFactionNeighbourBases match {
|
||||
case Some(neighbours) =>
|
||||
if(owner.IsCtfBase) {
|
||||
// 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)
|
||||
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
|
||||
owner.Neighbours(hackingFaction) match {
|
||||
case Some(neighbours) =>
|
||||
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 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 = {
|
||||
val attribute_value = HackCaptureActor.GetHackUpdateAttributeValue(terminal, isResecured)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue