diff --git a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala index cedba0624..ab40f6222 100644 --- a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/normal/VehicleHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/VehicleHandlerLogic.scala index 5890402e8..55d01d2a1 100644 --- a/src/main/scala/net/psforever/actors/session/normal/VehicleHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/VehicleHandlerLogic.scala @@ -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) } } diff --git a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala index f263e6600..afbe13088 100644 --- a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala @@ -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}") diff --git a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractWithEnvironment.scala b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractWithEnvironment.scala index 9cd84dd75..3ccc489d1 100644 --- a/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractWithEnvironment.scala +++ b/src/main/scala/net/psforever/objects/serverobject/environment/interaction/InteractWithEnvironment.scala @@ -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))) diff --git a/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala b/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala index 3f0426eb3..df0d5f129 100644 --- a/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala +++ b/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala @@ -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 { diff --git a/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala b/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala index f616f8e1d..1a88b0e00 100644 --- a/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala +++ b/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala @@ -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 _ => () } diff --git a/src/test/scala/objects/ResourceSiloTest.scala b/src/test/scala/objects/ResourceSiloTest.scala index bdb67b97d..aa56739af 100644 --- a/src/test/scala/objects/ResourceSiloTest.scala +++ b/src/test/scala/objects/ResourceSiloTest.scala @@ -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 }