duplicate capture lost message eliminated; flag lost violently due to environment in general rather than just water interaction; flag lost violently due to warp gate envelope interaction; flag lost due to be dropped in an unsafe position

This commit is contained in:
Fate-JH 2024-09-02 12:33:17 -04:00
parent ab1933ea76
commit 17914548c5
7 changed files with 93 additions and 68 deletions

View file

@ -164,7 +164,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
}
//llu destruction check
if (player.Carrying.contains(SpecialCarry.CaptureFlag)) {
CaptureFlagManager.reasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, player)
CaptureFlagManager.ReasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, player)
}
//
val eagleEye: Boolean = ops.canSeeReallyFar

View file

@ -69,7 +69,7 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
continent
.GUID(player.VehicleSeated)
.collect { case vehicle: Vehicle =>
CaptureFlagManager.reasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, vehicle)
CaptureFlagManager.ReasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, vehicle)
}
}

View file

@ -220,12 +220,12 @@ class GeneralOperations(
)
}
}
if (!CaptureFlagManager.reasonToLoseFlagViolently(continent, Some(guid), player)) {
if (!CaptureFlagManager.ReasonToLoseFlagViolently(continent, Some(guid), player)) {
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
}
case Some((llu, Some(carrier: Player)))
if carrier.GUID == player.GUID &&
!CaptureFlagManager.reasonToLoseFlagViolently(continent, Some(guid), player) =>
!CaptureFlagManager.ReasonToLoseFlagViolently(continent, Some(guid), player) =>
continent.LocalEvents ! CaptureFlagManager.DropFlag(llu)
case Some((_, Some(carrier: Player))) =>
log.warn(s"${player.toString} tried to drop LLU, but it is currently held by ${carrier.toString}")

View file

@ -97,6 +97,8 @@ class InteractWithEnvironment()
.foreach(_.stopInteractingWith(obj, body, None))
}
}
def OngoingInteractions: Set[EnvironmentTrait] = interactWith.map(_.attribute)
}
object InteractWithEnvironment {
@ -183,12 +185,12 @@ case class OnStableEnvironment() extends InteractionBehavior {
): Set[PieceOfEnvironment] = {
if (allow) {
val interactions = obj.interaction().collectFirst { case inter: InteractWithEnvironment => inter.Interactions }
val env = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
env.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
if (env.nonEmpty) {
val bodies = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
bodies.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
if (bodies.nonEmpty) {
nextstep = AwaitOngoingInteraction(obj.Zone)
}
env
bodies
} else {
nextstep = BlockedFromInteracting()
Set()
@ -223,22 +225,22 @@ final case class AwaitOngoingInteraction(zone: Zone) extends InteractionBehavior
): Set[PieceOfEnvironment] = {
val interactions = obj.interaction().collectFirst { case inter: InteractWithEnvironment => inter.Interactions }
if (allow) {
val env = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
val bodies = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
val (in, out) = existing.partition(body => InteractWithEnvironment.checkSpecificEnvironmentInteraction(zone, body, obj).nonEmpty)
val inAttrs = env.map(_.attribute)
val inAttrs = bodies.map(_.attribute)
out
.filterNot(e => inAttrs.contains(e.attribute))
.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.stopInteractingWith(obj, body, None)))
env
bodies
.diff(in)
.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
if (env.isEmpty) {
if (bodies.isEmpty) {
val n = OnStableEnvironment()
val out = n.perform(obj, sector, Set(), allow)
nextstep = n.next
out
} else {
env
bodies
}
} else {
existing.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.stopInteractingWith(obj, body, None)))

View file

@ -5,7 +5,8 @@ import akka.actor.{Actor, ActorRef, Cancellable}
import net.psforever.login.WorldSession
import net.psforever.objects.{Default, PlanetSideGameObject, Player}
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects.serverobject.environment.interaction.common.Watery
import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait}
import net.psforever.objects.serverobject.environment.interaction.InteractWithEnvironment
import net.psforever.objects.serverobject.llu.CaptureFlag
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
@ -274,7 +275,7 @@ object CaptureFlagManager {
* @param flagGuid flag that may exist
* @param target evaluate this to determine if to continue with this loss
*/
def reasonToLoseFlagViolently(
def ReasonToLoseFlagViolently(
zone: Zone,
flagGuid: Option[PlanetSideGUID],
target: PlanetSideGameObject with InteractsWithZone
@ -283,23 +284,41 @@ object CaptureFlagManager {
.GUID(flagGuid)
.collect {
case flag: CaptureFlag
if Watery.wading(target) || {
val position = target.Position
zone
.blockMap
.sector(position, range = 10f)
.buildingList
.collectFirst {
case gate: WarpGate if Vector3.DistanceSquared(position, gate.Position) < math.pow(gate.Definition.SOIRadius, 2f) => gate
}
.nonEmpty
} =>
if LoseFlagViolentlyToEnvironment(target, Set(EnvironmentAttribute.Water, EnvironmentAttribute.Lava, EnvironmentAttribute.Death)) ||
LoseFlagViolentlyToWarpGateEnvelope(zone, target) =>
flag.Destroyed = true
zone.LocalEvents ! LocalServiceMessage("", LocalAction.LluLost(flag))
true
}
.getOrElse(false)
}
def LoseFlagViolentlyToEnvironment(
target: PlanetSideGameObject with InteractsWithZone,
deniedEnvironments: Set[EnvironmentTrait]
): Boolean = {
target
.interaction()
.collectFirst { case env: InteractWithEnvironment => env.OngoingInteractions }
.map(_.intersect(deniedEnvironments))
.getOrElse(Set())
.nonEmpty
}
def LoseFlagViolentlyToWarpGateEnvelope(
zone: Zone,
target: PlanetSideGameObject with InteractsWithZone
): Boolean = {
val position = target.Position
zone
.blockMap
.sector(position, range = 10f)
.buildingList
.collectFirst {
case gate: WarpGate if Vector3.DistanceSquared(position, gate.Position) < math.pow(gate.Definition.SOIRadius, 2f) => gate
}
.nonEmpty
}
}
object CaptureFlagChatMessageStrings {

View file

@ -145,17 +145,20 @@ class HackCaptureActor extends Actor {
}
case HackCaptureActor.FlagLost(flag) =>
val terminalOpt = flag.Owner.asInstanceOf[Building].CaptureTerminal
val owner = flag.Owner.asInstanceOf[Building]
val guid = owner.GUID
val terminalOpt = owner.CaptureTerminal
hackedObjects
.find(entry => terminalOpt.contains(entry.target))
.find(entry => guid == entry.target.Owner.GUID)
.collect { entry =>
val terminal = terminalOpt.get
hackedObjects = hackedObjects.filterNot(x => x == entry)
hackedObjects = hackedObjects.filterNot(x => x eq entry)
log.info(s"FlagLost: ${flag.Carrier.map(_.Name).getOrElse("")} the flag carrier screwed up the capture for ${flag.Target.Name} and the LLU has been lost")
terminal.Actor ! CommonMessages.ClearHack()
NotifyHackStateChange(terminal, isResecured = true)
// If there's hacked objects left in the list restart the timer with the shortest hack time left
RestartTimer()
entry
}
.orElse{
log.warn(s"FlagLost: flag data does not match to an entry in the hacked objects list")
@ -163,7 +166,6 @@ class HackCaptureActor extends Actor {
}
context.parent ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.FlagLost)
case _ => ()
}

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.Props
import akka.actor.{ActorRef, Props}
import akka.testkit.TestProbe
import base.{ActorTest, FreedContextActorTest}
import net.psforever.actors.zone.BuildingActor
@ -63,7 +63,7 @@ class ResourceSiloTest extends Specification {
PlanetSideGUID(0),
PlanetSideGUID(2),
0L,
false,
unk3 = false,
Vector3(0f, 0f, 0f),
Vector3(0f, 0f, 0f),
0,
@ -77,11 +77,11 @@ class ResourceSiloTest extends Specification {
}
class ResourceSiloControlStartupTest extends ActorTest {
val obj = ResourceSilo()
val obj: ResourceSilo = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
val buildingEvents = TestProbe("test-building-events")
val buildingEvents: TestProbe = TestProbe("test-building-events")
obj.Owner =
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
Actor = buildingEvents.ref
@ -97,11 +97,11 @@ class ResourceSiloControlStartupTest extends ActorTest {
}
class ResourceSiloControlStartupMessageNoneTest extends ActorTest {
val obj = ResourceSilo()
val obj: ResourceSilo = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
val buildingEvents = TestProbe("test-building-events")
val buildingEvents: TestProbe = TestProbe("test-building-events")
obj.Owner =
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
Actor = buildingEvents.ref
@ -123,11 +123,11 @@ class ResourceSiloControlStartupMessageNoneTest extends ActorTest {
}
class ResourceSiloControlStartupMessageSomeTest extends ActorTest {
val obj = ResourceSilo()
val obj: ResourceSilo = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
val buildingEvents = TestProbe("test-building-events")
val buildingEvents: TestProbe = TestProbe("test-building-events")
obj.Owner =
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
Actor = buildingEvents.ref
@ -154,19 +154,19 @@ class ResourceSiloControlUseTest extends FreedContextActorTest {
expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]()
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
val ant = Vehicle(GlobalDefinitions.ant)
val player: Player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
val ant: Vehicle = Vehicle(GlobalDefinitions.ant)
val silo = new ResourceSilo()
val catchall = new TestProbe(system).ref
val zone = new Zone("test", new ZoneMap("test-map"), 0) {
override def SetupNumberPools() = {}
val catchall: ActorRef = new TestProbe(system).ref
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
override def SetupNumberPools(): Unit = {}
GUID(guid)
override def AvatarEvents = catchall
override def LocalEvents = catchall
override def VehicleEvents = catchall
override def Activity = catchall
override def Vehicles = List(ant)
override def Buildings = { buildingMap.toMap }
override def AvatarEvents: ActorRef = catchall
override def LocalEvents: ActorRef = catchall
override def VehicleEvents: ActorRef = catchall
override def Activity: ActorRef = catchall
override def Vehicles: List[Vehicle] = List(ant)
override def Buildings: Map[Int, Building] = { buildingMap.toMap }
}
val building = new Building(
name = "integ-fac-test-building",
@ -186,7 +186,7 @@ class ResourceSiloControlUseTest extends FreedContextActorTest {
guid.register(silo, number = 5)
guid.register(building, number = 6)
val maxNtuCap = ant.Definition.MaxNtuCapacitor
val maxNtuCap: Float = ant.Definition.MaxNtuCapacitor
player.Spawn()
ant.NtuCapacitor = maxNtuCap
val probe = new TestProbe(system)
@ -205,14 +205,14 @@ class ResourceSiloControlUseTest extends FreedContextActorTest {
val reply = probe.receiveOne(3000 milliseconds)
reply match {
case TransferBehavior.Discharging(Ntu.Nanites) => ()
case _ => assert(false, "")
case _ => assert(ResourceSiloTest.fail, "")
}
}
}
}
class ResourceSiloControlNtuWarningTest extends ActorTest {
val obj = ResourceSilo()
val obj: ResourceSilo = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
@ -222,7 +222,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
}
obj.Owner.GUID = PlanetSideGUID(6)
val zoneEvents = TestProbe("zone-events")
val zoneEvents: TestProbe = TestProbe("zone-events")
zone.AvatarEvents = zoneEvents.ref
obj.Actor ! Service.Startup()
obj.Actor ! ResourceSilo.UpdateChargeLevel(-obj.NtuCapacitor)
@ -236,7 +236,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
val reply = zoneEvents.receiveOne(5000 milliseconds)
reply match {
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
case _ => assert(false, s"$reply is wrong")
case _ => assert(ResourceSiloTest.fail, s"$reply is wrong")
}
assert(!obj.LowNtuWarningOn)
}
@ -244,7 +244,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
}
class ResourceSiloControlUpdate1Test extends ActorTest {
val obj = ResourceSilo()
val obj: ResourceSilo = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
@ -252,8 +252,8 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
bldg.GUID = PlanetSideGUID(6)
obj.Owner = bldg
val zoneEvents = TestProbe("zone-events")
val buildingEvents = TestProbe("building-events")
val zoneEvents: TestProbe = TestProbe("zone-events")
val buildingEvents: TestProbe = TestProbe("building-events")
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
obj.Actor ! Service.Startup()
@ -275,12 +275,12 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
assert(obj.CapacitorDisplay == 3)
reply1.head match {
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 3)) => ;
case _ => assert(false, s"$reply1 is wrong")
case _ => assert(ResourceSiloTest.fail, s"$reply1 is wrong")
}
assert(reply2.isInstanceOf[BuildingActor.MapUpdate], s"$reply2 is wrong")
reply1(1) match {
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
case _ => assert(false, s"${reply1(1)} is wrong")
case _ => assert(ResourceSiloTest.fail, s"${reply1(1)} is wrong")
}
assert(!obj.LowNtuWarningOn)
}
@ -288,7 +288,7 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
}
class ResourceSiloControlUpdate2Test extends ActorTest {
val obj = ResourceSilo()
val obj: ResourceSilo = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
@ -296,8 +296,8 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
bldg.GUID = PlanetSideGUID(6)
obj.Owner = bldg
val zoneEvents = TestProbe("zone-events")
val buildingEvents = TestProbe("building-events")
val zoneEvents: TestProbe = TestProbe("zone-events")
val buildingEvents: TestProbe = TestProbe("building-events")
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
obj.Actor ! Service.Startup()
@ -319,12 +319,12 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
assert(obj.CapacitorDisplay == 2)
reply1.head match {
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 2)) => ;
case _ => assert(false, s"$reply1 is wrong")
case _ => assert(ResourceSiloTest.fail, s"$reply1 is wrong")
}
assert(reply2.isInstanceOf[BuildingActor.MapUpdate])
reply1(1) match {
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
case _ => assert(false, s"${reply1(1)} is wrong")
case _ => assert(ResourceSiloTest.fail, s"${reply1(1)} is wrong")
}
assert(!obj.LowNtuWarningOn)
}
@ -332,7 +332,7 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
}
class ResourceSiloControlNoUpdateTest extends ActorTest {
val obj = ResourceSilo()
val obj: ResourceSilo = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
@ -340,8 +340,8 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
bldg.GUID = PlanetSideGUID(6)
obj.Owner = bldg
val zoneEvents = TestProbe("zone-events")
val buildingEvents = TestProbe("building-events")
val zoneEvents: TestProbe = TestProbe("zone-events")
val buildingEvents: TestProbe = TestProbe("building-events")
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
obj.Actor ! Service.Startup()
@ -370,7 +370,9 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
}
object ResourceSiloTest {
val player = Player(
val player: Player = Player(
Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute).copy(stamina = 0)
)
val fail: Boolean = false
}