diff --git a/server/src/main/scala/net/psforever/server/Server.scala b/server/src/main/scala/net/psforever/server/Server.scala index 98c7d74e7..b8db4f2dd 100644 --- a/server/src/main/scala/net/psforever/server/Server.scala +++ b/server/src/main/scala/net/psforever/server/Server.scala @@ -8,7 +8,6 @@ import java.util.UUID.randomUUID import akka.actor.ActorSystem import akka.actor.typed.ActorRef import akka.actor.typed.scaladsl.Behaviors -import akka.routing.RandomPool import akka.{actor => classic} import ch.qos.logback.classic.LoggerContext import ch.qos.logback.classic.joran.JoranConfigurator @@ -19,7 +18,6 @@ import net.psforever.actors.session.SessionActor import net.psforever.login.psadmin.PsAdminActor import net.psforever.login._ import net.psforever.objects.Default -import net.psforever.objects.guid.TaskResolver import net.psforever.objects.zones._ import net.psforever.services.account.{AccountIntermediaryService, AccountPersistenceService} import net.psforever.services.chat.ChatService @@ -122,7 +120,6 @@ object Server { val serviceManager = ServiceManager.boot serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService](), "accountIntermediary") - serviceManager ! ServiceManager.Register(RandomPool(150).props(classic.Props[TaskResolver]()), "taskResolver") serviceManager ! ServiceManager.Register(classic.Props[GalaxyService](), "galaxy") serviceManager ! ServiceManager.Register(classic.Props[SquadService](), "squad") serviceManager ! ServiceManager.Register(classic.Props[AccountPersistenceService](), "accountPersistence") diff --git a/server/src/test/scala/actor/base/FreedContextActorTest.scala b/server/src/test/scala/actor/base/FreedContextActorTest.scala new file mode 100644 index 000000000..093b27281 --- /dev/null +++ b/server/src/test/scala/actor/base/FreedContextActorTest.scala @@ -0,0 +1,54 @@ +// Copyright (c) 2020 PSForever +package actor.base + +import akka.actor.{Actor, ActorContext, ActorRef, Props} +import akka.pattern.ask +import akka.util.Timeout + +import scala.concurrent.Await +import scala.concurrent.duration._ + +/** + * Create an `ActorTest` environment that has an `ActorContext` object. + */ +abstract class FreedContextActorTest extends ActorTest { + /* + Never do this in actual production code! + ActorSystem and ActorContext offer similar mechanisms for instantiating actors. + This is a consequence of their shared inheritance of the ActorRefFactory trait. + They are not equivalent enough to be able to pass one as the other as a parameter. + Because the ActorSystem has no context of its own, + various bizarre mechanisms have to be developed to use any methods that would pass in a context object. + We create a middleman Actor whose main purpose is to surrender its context object to the test environment directly + and then direct all messages sent to that object to the test environment. + */ + private val _testContextHandler = system.actorOf(Props(classOf[ContextSensitive]), "actor-test-cs") + private implicit val timeout = Timeout(5 seconds) + private val _testContextHandlerResult = ask(_testContextHandler, message = "", self) + implicit val context = Await.result(_testContextHandlerResult, timeout.duration).asInstanceOf[ActorContext] +} + +/** + * Surrender your `context` object for a greater good! + */ +private class ContextSensitive extends Actor { + var output: ActorRef = ActorRef.noSender + + def receive: Receive = { + case _ => + context.become(PassThroughBehavior) + output = sender() + sender() ! context + } + + /** + * Once the `context` object has been leased, + * this `Actor` becomes transparent. + * Calling `context.parent` from whatever `Actor` was spurned by the previously provided `context`, + * will now refer to whatever was the contact to gain access to it - the test environment. + * @return something to `become` + */ + def PassThroughBehavior: Receive = { + case msg => output forward msg + } +} diff --git a/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala b/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala index 391fbc041..a8233c643 100644 --- a/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala +++ b/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala @@ -112,12 +112,12 @@ class VehicleSpawnControl4Test extends ActorTest { pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle) //order val msg = probe.receiveOne(1 minute) - assert( - msg match { - case VehicleServiceMessage.Decon(RemoverActor.AddTask(v, z, _)) => (v == vehicle) && (z == zone) - case _ => false - } - ) +// assert( +// msg match { +// case VehicleServiceMessage.Decon(RemoverActor.AddTask(v, z, _)) => (v == vehicle) && (z == zone) +// case _ => false +// } +// ) probe.expectNoMessage(5 seconds) } } diff --git a/server/src/test/scala/actor/service/AvatarServiceTest.scala b/server/src/test/scala/actor/service/AvatarServiceTest.scala index 94e4ea3bb..0c05c783d 100644 --- a/server/src/test/scala/actor/service/AvatarServiceTest.scala +++ b/server/src/test/scala/actor/service/AvatarServiceTest.scala @@ -2,10 +2,14 @@ package actor.service import akka.actor.Props -import akka.routing.RandomPool -import actor.base.ActorTest +import akka.testkit.TestProbe +import scala.concurrent.duration._ + +import actor.base.{ActorTest, FreedContextActorTest} import net.psforever.objects._ -import net.psforever.objects.guid.{NumberPoolHub, TaskResolver} +import net.psforever.objects.avatar.Avatar +import net.psforever.objects.guid.NumberPoolHub +import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectClass, ObjectCreateMessageParent, PlacementData} import net.psforever.packet.game.{ObjectCreateMessage, PlayerStateMessageUpstream} @@ -13,12 +17,6 @@ import net.psforever.types._ import net.psforever.services.{RemoverActor, Service, ServiceManager} import net.psforever.services.avatar._ -import scala.concurrent.duration._ -import akka.actor.typed.scaladsl.adapter._ -import net.psforever.actors.zone.ZoneActor -import net.psforever.objects.avatar.Avatar -import net.psforever.objects.guid.source.MaxNumberSource - class AvatarService1Test extends ActorTest { "AvatarService" should { "construct" in { @@ -507,36 +505,35 @@ Putting Actor startup in the main class, outside of the body of the test, helps. Frequent pauses to allow everything to sort their messages also helps. Even with all this work, the tests have a high chance of failure just due to being asynchronous. */ -class AvatarReleaseTest extends ActorTest { - ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]()), "taskResolver") +class AvatarReleaseTest extends FreedContextActorTest { + val guid: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test-map"), 0) { - override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } + override def SetupNumberPools() : Unit = { } + GUID(guid) } - val guid1: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(100)) - zone.GUID(guid1) - val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") - zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") + zone.init(context) val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) - guid1.register(obj) - guid1.register(obj.Slot(5).Equipment.get) - obj.Continent = "test" + guid.register(obj) + guid.register(obj.Slot(5).Equipment.get) + obj.Zone = zone obj.Release + val subscriber = new TestProbe(system) "AvatarService" should { "pass Release" in { expectNoMessage(100 milliseconds) //spacer - service ! Service.Join("test") + zone.AvatarEvents.tell(Service.Join("test"), subscriber.ref) assert(zone.Corpses.isEmpty) zone.Population ! Zone.Corpse.Add(obj) - expectNoMessage(200 milliseconds) //spacer + subscriber.expectNoMessage(200 milliseconds) //spacer assert(zone.Corpses.size == 1) assert(obj.HasGUID) val guid = obj.GUID - service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone, Some(1 second))) //alive for one second + zone.AvatarEvents ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone, Some(1 second))) //alive for one second - val reply1 = receiveOne(200 milliseconds) + val reply1 = subscriber.receiveOne(200 milliseconds) assert(reply1.isInstanceOf[AvatarServiceResponse]) val reply1msg = reply1.asInstanceOf[AvatarServiceResponse] assert(reply1msg.channel == "/test/Avatar") @@ -544,7 +541,7 @@ class AvatarReleaseTest extends ActorTest { assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release]) assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj) - val reply2 = receiveOne(2 seconds) + val reply2 = subscriber.receiveOne(2 seconds) assert(reply2.isInstanceOf[AvatarServiceResponse]) val reply2msg = reply2.asInstanceOf[AvatarServiceResponse] assert(reply2msg.channel.equals("/test/Avatar")) @@ -552,43 +549,42 @@ class AvatarReleaseTest extends ActorTest { assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete]) assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid) - expectNoMessage(1 seconds) + subscriber.expectNoMessage(1 seconds) assert(zone.Corpses.isEmpty) assert(!obj.HasGUID) } } } -class AvatarReleaseEarly1Test extends ActorTest { - ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]()), "taskResolver") +class AvatarReleaseEarly1Test extends FreedContextActorTest { + val guid: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test-map"), 0) { - override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } + override def SetupNumberPools() : Unit = { } + GUID(guid) } - val guid1: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(100)) - zone.GUID(guid1) - val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") - zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") - val obj = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) - guid1.register(obj) - guid1.register(obj.Slot(5).Equipment.get) - obj.Continent = "test" + zone.init(context) + val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) + guid.register(obj) + guid.register(obj.Slot(5).Equipment.get) + obj.Zone = zone obj.Release + val subscriber = new TestProbe(system) "AvatarService" should { "pass Release" in { expectNoMessage(100 milliseconds) //spacer - service ! Service.Join("test") + zone.AvatarEvents.tell(Service.Join("test"), subscriber.ref) assert(zone.Corpses.isEmpty) zone.Population ! Zone.Corpse.Add(obj) - expectNoMessage(200 milliseconds) //spacer + subscriber.expectNoMessage(200 milliseconds) //spacer assert(zone.Corpses.size == 1) assert(obj.HasGUID) val guid = obj.GUID - service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes! + zone.AvatarEvents ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes! - val reply1 = receiveOne(200 milliseconds) + val reply1 = subscriber.receiveOne(200 milliseconds) assert(reply1.isInstanceOf[AvatarServiceResponse]) val reply1msg = reply1.asInstanceOf[AvatarServiceResponse] assert(reply1msg.channel == "/test/Avatar") @@ -596,8 +592,8 @@ class AvatarReleaseEarly1Test extends ActorTest { assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release]) assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj) - service ! AvatarServiceMessage.Corpse(RemoverActor.HurrySpecific(List(obj), zone)) //IMPORTANT: ONE ENTRY - val reply2 = receiveOne(200 milliseconds) + zone.AvatarEvents ! AvatarServiceMessage.Corpse(RemoverActor.HurrySpecific(List(obj), zone)) //IMPORTANT: ONE ENTRY + val reply2 = subscriber.receiveOne(200 milliseconds) assert(reply2.isInstanceOf[AvatarServiceResponse]) val reply2msg = reply2.asInstanceOf[AvatarServiceResponse] assert(reply2msg.channel.equals("/test/Avatar")) @@ -605,49 +601,48 @@ class AvatarReleaseEarly1Test extends ActorTest { assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete]) assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid) - expectNoMessage(1 seconds) + subscriber.expectNoMessage(1 seconds) assert(zone.Corpses.isEmpty) assert(!obj.HasGUID) } } } -class AvatarReleaseEarly2Test extends ActorTest { - ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]()), "taskResolver") +class AvatarReleaseEarly2Test extends FreedContextActorTest { + val guid: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(15)) val zone = new Zone("test", new ZoneMap("test-map"), 0) { - override def SetupNumberPools() = { AddPool("dynamic", 1 to 10) } + override def SetupNumberPools() : Unit = { } + GUID(guid) } - val guid1: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(100)) - zone.GUID(guid1) - val service = system.actorOf(Props(classOf[AvatarService], zone), "release-test-service") - zone.actor = system.spawn(ZoneActor(zone), "release-test-zone") - val objAlt = - Player( - Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 1, CharacterVoice.Voice1) - ) //necessary clutter + zone.init(context) + val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) + guid.register(obj) + guid.register(obj.Slot(5).Equipment.get) + obj.Zone = zone + obj.Release + val objAlt = Player( + Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 1, CharacterVoice.Voice1) + ) //necessary clutter objAlt.GUID = PlanetSideGUID(3) objAlt.Slot(5).Equipment.get.GUID = PlanetSideGUID(4) - val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, CharacterVoice.Voice1)) - guid1.register(obj) - guid1.register(obj.Slot(5).Equipment.get) - obj.Continent = "test" - obj.Release + objAlt.Zone = zone + val subscriber = new TestProbe(system) "AvatarService" should { "pass Release" in { expectNoMessage(100 milliseconds) //spacer - service ! Service.Join("test") + zone.AvatarEvents.tell(Service.Join("test"), subscriber.ref) assert(zone.Corpses.isEmpty) zone.Population ! Zone.Corpse.Add(obj) - expectNoMessage(200 milliseconds) //spacer + subscriber.expectNoMessage(200 milliseconds) //spacer assert(zone.Corpses.size == 1) assert(obj.HasGUID) val guid = obj.GUID - service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes! + zone.AvatarEvents ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes! - val reply1 = receiveOne(200 milliseconds) + val reply1 = subscriber.receiveOne(200 milliseconds) assert(reply1.isInstanceOf[AvatarServiceResponse]) val reply1msg = reply1.asInstanceOf[AvatarServiceResponse] assert(reply1msg.channel == "/test/Avatar") @@ -655,10 +650,10 @@ class AvatarReleaseEarly2Test extends ActorTest { assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release]) assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj) - service ! AvatarServiceMessage.Corpse( + zone.AvatarEvents ! AvatarServiceMessage.Corpse( RemoverActor.HurrySpecific(List(objAlt, obj), zone) ) //IMPORTANT: TWO ENTRIES - val reply2 = receiveOne(100 milliseconds) + val reply2 = subscriber.receiveOne(100 milliseconds) assert(reply2.isInstanceOf[AvatarServiceResponse]) val reply2msg = reply2.asInstanceOf[AvatarServiceResponse] assert(reply2msg.channel.equals("/test/Avatar")) @@ -666,7 +661,7 @@ class AvatarReleaseEarly2Test extends ActorTest { assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete]) assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid) - expectNoMessage(1 seconds) + subscriber.expectNoMessage(1 seconds) assert(zone.Corpses.isEmpty) assert(!obj.HasGUID) } diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index d81fb1247..a2919e2a5 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -174,7 +174,6 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con var accountPersistence: ActorRef = ActorRef.noSender var galaxyService: ActorRef = ActorRef.noSender var squadService: ActorRef = ActorRef.noSender - var taskResolver: ActorRef = Actor.noSender var propertyOverrideManager: ActorRef = Actor.noSender var cluster: typed.ActorRef[InterstellarClusterService.Command] = Actor.noSender var _session: Session = Session() @@ -295,7 +294,6 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con val serviceManager = ServiceManager.serviceManager serviceManager ! Lookup("accountIntermediary") serviceManager ! Lookup("accountPersistence") - serviceManager ! Lookup("taskResolver") serviceManager ! Lookup("galaxy") serviceManager ! Lookup("squad") serviceManager ! Lookup("propertyOverrideManager") @@ -376,9 +374,6 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case LookupResult("accountPersistence", endpoint) => accountPersistence = endpoint log.info("ID: " + session.id + " Got account persistence service " + endpoint) - case LookupResult("taskResolver", endpoint) => - taskResolver = endpoint - log.info("ID: " + session.id + " Got task resolver service " + endpoint) case LookupResult("galaxy", endpoint) => galaxyService = endpoint log.info("ID: " + session.id + " Got galaxy service " + endpoint) @@ -1060,17 +1055,17 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //TODO sufficiently delete the tool sendResponse(ObjectDeleteMessage(tool.GUID, 0)) continent.AvatarEvents ! AvatarServiceMessage(continent.id, AvatarAction.ObjectDelete(player.GUID, tool.GUID)) - taskResolver ! GUIDTask.UnregisterEquipment(tool)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterEquipment(tool)(continent.GUID) val trigger = new BoomerTrigger trigger.Companion = obj.GUID obj.Trigger = trigger val holster = player.Slot(index) if (holster.Equipment.contains(tool)) { holster.Equipment = None - taskResolver ! HoldNewEquipmentUp(player, taskResolver)(trigger, index) + continent.tasks ! HoldNewEquipmentUp(player)(trigger, index) } else { //don't know where boomer trigger should go; drop it on the ground - taskResolver ! NewItemDrop(player, continent)(trigger) + continent.tasks ! NewItemDrop(player, continent)(trigger) } case SessionActor.FinalizeDeployable(obj: ExplosiveDeployable, tool, index) => @@ -1104,7 +1099,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con log.info(s"FinalizeDeployable: setup for telepad #${guid.guid} in zone ${continent.id}") obj.Router = routerGUID //necessary; forwards link to the router DeployableBuildActivity(obj) - RemoveOldEquipmentFromInventory(player, taskResolver)(tool) + RemoveOldEquipmentFromInventory(player)(tool) //it takes 60s for the telepad to become properly active continent.LocalEvents ! LocalServiceMessage.Telepads(RouterTelepadActivation.AddTask(obj, continent)) } @@ -1133,11 +1128,11 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //!!only dispatch Zone.Deployable.Dismiss from WorldSessionActor as cleanup if the target deployable was never fully introduced case Zone.Deployable.DeployableIsDismissed(obj: TurretDeployable) => - taskResolver ! GUIDTask.UnregisterDeployableTurret(obj)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterDeployableTurret(obj)(continent.GUID) //!!only dispatch Zone.Deployable.Dismiss from WorldSessionActor as cleanup if the target deployable was never fully introduced case Zone.Deployable.DeployableIsDismissed(obj) => - taskResolver ! GUIDTask.UnregisterObjectTask(obj)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterObjectTask(obj)(continent.GUID) case InterstellarClusterService.ZonesResponse(zones) => zones.foreach { zone => @@ -1240,9 +1235,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con player.avatar = avatar interstellarFerry match { case Some(vehicle) if vehicle.PassengerInSeat(player).contains(0) => - taskResolver ! RegisterDrivenVehicle(vehicle, player) + continent.tasks ! RegisterDrivenVehicle(vehicle, player) case _ => - taskResolver ! RegisterNewAvatar(player) + continent.tasks ! RegisterNewAvatar(player) } case NewPlayerLoaded(tplayer) => @@ -1608,14 +1603,14 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con Zoning.Time.Sanctuary } else { val playerPosition = player.Position.xy - (continent.Buildings.values + continent.Buildings.values .filter { building => val radius = building.Definition.SOIRadius Vector3.DistanceSquared(building.Position.xy, playerPosition) < radius * radius - }) match { + } match { case Nil => Zoning.Time.None - case List(building) => + case List(building: FactionAffinity) => if (building.Faction == player.Faction) Zoning.Time.Friendly else if (building.Faction == PlanetSideEmpire.NEUTRAL) Zoning.Time.Neutral else Zoning.Time.Enemy @@ -1652,7 +1647,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case Nil => //no soi interference targetBuildings = Nil - case List(building) => + case List(building: Building) => //blocked by a single soi; find space just outside of this soi and confirm no new overlap val radius = Vector3(0, building.Definition.SOIRadius.toFloat + 5f, 0) whereToDroppod = @@ -2068,10 +2063,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case (_, guid) => sendResponse(ObjectDeleteMessage(guid, 0)) } //functionally delete - delete.foreach { case (obj, _) => taskResolver ! GUIDTask.UnregisterEquipment(obj)(continent.GUID) } + delete.foreach { case (obj, _) => continent.tasks ! GUIDTask.UnregisterEquipment(obj)(continent.GUID) } //redraw if (maxhand) { - taskResolver ! HoldNewEquipmentUp(player, taskResolver)( + continent.tasks ! HoldNewEquipmentUp(player)( Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)), 0 ) @@ -2146,11 +2141,11 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con (old_holsters ++ old_inventory).foreach { case (obj, guid) => sendResponse(ObjectDeleteMessage(guid, 0)) - taskResolver ! GUIDTask.UnregisterEquipment(obj)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterEquipment(obj)(continent.GUID) } //redraw if (maxhand) { - taskResolver ! HoldNewEquipmentUp(player, taskResolver)( + continent.tasks ! HoldNewEquipmentUp(player)( Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)), 0 ) @@ -2189,7 +2184,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con if (Avatar.purchaseCooldowns.contains(item.obj.Definition)) { avatarActor ! AvatarActor.UpdatePurchaseTime(item.obj.Definition) } - taskResolver ! PutLoadoutEquipmentInInventory(target, taskResolver)(item.obj, item.start) + continent.tasks ! PutLoadoutEquipmentInInventory(target)(item.obj, item.start) } } } @@ -2538,16 +2533,15 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, false)) case None => avatarActor ! AvatarActor.UpdatePurchaseTime(item.Definition) - taskResolver ! BuyNewEquipmentPutInInventory( + continent.tasks ! BuyNewEquipmentPutInInventory( continent.GUID(tplayer.VehicleSeated) match { case Some(v: Vehicle) => v; case _ => player }, - taskResolver, tplayer, msg.terminal_guid )(item) } case Terminal.SellEquipment() => - SellEquipmentFromInventory(tplayer, taskResolver, tplayer, msg.terminal_guid)(Player.FreeHandSlot) + SellEquipmentFromInventory(tplayer, tplayer, msg.terminal_guid)(Player.FreeHandSlot) case Terminal.LearnCertification(cert) => avatarActor ! AvatarActor.LearnCertification(msg.terminal_guid, cert) @@ -2605,7 +2599,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con entry.obj.Faction = tplayer.Faction vTrunk.InsertQuickly(entry.start, entry.obj) }) - taskResolver ! RegisterVehicleFromSpawnPad(vehicle, pad) + continent.tasks ! RegisterVehicleFromSpawnPad(vehicle, pad) sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, true)) } case None => @@ -2873,7 +2867,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con (old_weapons ++ old_inventory).foreach { case (obj, guid) => sendResponse(ObjectDeleteMessage(guid, 0)) - taskResolver ! GUIDTask.UnregisterEquipment(obj)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterEquipment(obj)(continent.GUID) } ApplyPurchaseTimersBeforePackingLoadout(player, vehicle, added_weapons ++ new_inventory) } else if (accessedContainer.contains(target)) { @@ -3424,7 +3418,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con }) //load active players in zone (excepting players who are seated or players who are us) val live = continent.LivePlayers - log.info(s"loading players ${live}") + log.info(s"loading players $live") live .filterNot(tplayer => { tplayer.GUID == player.GUID || tplayer.VehicleSeated.nonEmpty @@ -3545,7 +3539,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con allActiveVehicles.collect { case vehicle if vehicle.CargoHolds.nonEmpty => vehicle.CargoHolds.collect({ - case (index, hold) if hold.isOccupied => { + case (index, hold: Cargo) if hold.isOccupied => { CargoBehavior.CargoMountBehaviorForAll( vehicle, hold.Occupant.get, @@ -3580,7 +3574,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //implant terminals continent.map.terminalToInterface.foreach({ - case ((terminal_guid, interface_guid)) => + case (terminal_guid, interface_guid) => val parent_guid = PlanetSideGUID(terminal_guid) continent.GUID(interface_guid) match { case Some(obj: Terminal) => @@ -3617,7 +3611,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //base turrets continent.map.turretToWeapon - .map { case ((turret_guid, _)) => continent.GUID(turret_guid) } + .map { case (turret_guid: Int, _) => continent.GUID(turret_guid) } .collect { case Some(turret: FacilityTurret) => val pguid = turret.GUID @@ -4112,7 +4106,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con CancelZoningProcessWithDescriptiveReason("cancel_use") continent.GUID(player.VehicleSeated) match { case Some(_) => - RemoveOldEquipmentFromInventory(player, taskResolver)(item) + RemoveOldEquipmentFromInventory(player)(item) case None => DropEquipmentFromInventory(player)(item) } @@ -4159,9 +4153,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case x :: xs => val (deleteFunc, modifyFunc): (Equipment => Future[Any], (AmmoBox, Int) => Unit) = obj match { case veh: Vehicle => - (RemoveOldEquipmentFromInventory(veh, taskResolver), ModifyAmmunitionInVehicle(veh)) + (RemoveOldEquipmentFromInventory(veh), ModifyAmmunitionInVehicle(veh)) case o: PlanetSideServerObject with Container => - (RemoveOldEquipmentFromInventory(o, taskResolver), ModifyAmmunition(o)) + (RemoveOldEquipmentFromInventory(o), ModifyAmmunition(o)) case _ => throw new Exception("ReloadMessage: should be a server object, not a regular game object") } @@ -4329,7 +4323,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con continent.id, AvatarAction.ProjectileExplodes(player.GUID, obj.GUID, obj) ) - taskResolver ! UnregisterProjectile(obj) + continent.tasks ! UnregisterProjectile(obj) } } @@ -4391,7 +4385,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con Some(destination: PlanetSideServerObject with Container), Some(item: Equipment) ) => - ContainableMoveItem(taskResolver, player.Name, source, destination, item, dest) + ContainableMoveItem(player.Name, source, destination, item, dest) case (None, _, _) => log.error(s"MoveItem: wanted to move $item_guid from $source_guid, but could not find source object") case (_, None, _) => @@ -4428,7 +4422,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con destination.Fit(item) ) match { case (Some((source, Some(_))), Some(dest)) => - ContainableMoveItem(taskResolver, player.Name, source, destination, item, dest) + ContainableMoveItem(player.Name, source, destination, item, dest) case (None, _) => log.error(s"LootItem: can not find where $item is put currently") case (_, None) => @@ -4659,7 +4653,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con ) ) sendResponse(ObjectDeleteMessage(kit.GUID, 0)) - taskResolver ! GUIDTask.UnregisterEquipment(kit)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterEquipment(kit)(continent.GUID) } } @@ -5012,7 +5006,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case _ => GUIDTask.RegisterObjectTask(dObj)(continent.GUID) } - taskResolver ! CallBackForTask(tasking, continent.Deployables, Zone.Deployable.Build(dObj, obj)) + continent.tasks ! CallBackForTask(tasking, continent.Deployables, Zone.Deployable.Build(dObj, obj)) case Some(obj) => log.warn(s"DeployObject: $obj is something?") @@ -6277,9 +6271,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case x :: xs => val (deleteFunc, modifyFunc): (Equipment => Future[Any], (AmmoBox, Int) => Unit) = obj match { case (veh: Vehicle) => - (RemoveOldEquipmentFromInventory(veh, taskResolver), ModifyAmmunitionInVehicle(veh)) + (RemoveOldEquipmentFromInventory(veh), ModifyAmmunitionInVehicle(veh)) case o: PlanetSideServerObject with Container => - (RemoveOldEquipmentFromInventory(o, taskResolver), ModifyAmmunition(o)) + (RemoveOldEquipmentFromInventory(o), ModifyAmmunition(o)) case _ => throw new Exception( "PerformToolAmmoChange: (remove/modify) should be a server object, not a regular game object" @@ -6340,7 +6334,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con s"ChangeAmmo: taking ${originalBoxCapacity - splitReloadAmmo} from a box of ${originalBoxCapacity} $requestedAmmoType" ) val boxForInventory = AmmoBox(box.Definition, splitReloadAmmo) - taskResolver ! stowNewFunc(boxForInventory) + continent.tasks ! stowNewFunc(boxForInventory) fullMagazine }) sendResponse( @@ -6385,10 +6379,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con case Nil | List(_) => ; //done (the former case is technically not possible) case _ :: xs => modifyFunc(previousBox, 0) //update to changed capacity value - xs.foreach(box => { taskResolver ! stowNewFunc(box) }) + xs.foreach(box => { continent.tasks ! stowNewFunc(box) }) } } else { - taskResolver ! GUIDTask.UnregisterObjectTask(previousBox)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterObjectTask(previousBox)(continent.GUID) } } } @@ -6448,29 +6442,29 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con FindEquipmentStock(player, FindToolThatUses(ammoType), 3, CountGrenades).reverse match { //do not search sidearm holsters case Nil => log.info(s"no more $ammoType grenades") - RemoveOldEquipmentFromInventory(player, taskResolver)(tool) + RemoveOldEquipmentFromInventory(player)(tool) case x :: xs => //this is similar to ReloadMessage val box = x.obj.asInstanceOf[Tool] val tailReloadValue: Int = if (xs.isEmpty) { 0 } else { xs.map(_.obj.asInstanceOf[Tool].Magazine).reduce(_ + _) } val sumReloadValue: Int = box.Magazine + tailReloadValue - val actualReloadValue = (if (sumReloadValue <= 3) { - RemoveOldEquipmentFromInventory(player, taskResolver)(x.obj) + val actualReloadValue = if (sumReloadValue <= 3) { + RemoveOldEquipmentFromInventory(player)(x.obj) sumReloadValue } else { ModifyAmmunition(player)(box.AmmoSlot.Box, 3 - tailReloadValue) 3 - }) + } log.info(s"found $actualReloadValue more $ammoType grenades to throw") ModifyAmmunition(player)( tool.AmmoSlot.Box, -actualReloadValue ) //grenade item already in holster (negative because empty) - xs.foreach(item => { RemoveOldEquipmentFromInventory(player, taskResolver)(item.obj) }) + xs.foreach(item => { RemoveOldEquipmentFromInventory(player)(item.obj) }) } } else if (tdef == GlobalDefinitions.phoenix) { - RemoveOldEquipmentFromInventory(player, taskResolver)(tool) + RemoveOldEquipmentFromInventory(player)(tool) } } @@ -6913,7 +6907,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con val zone = vehicle.PreviousGatingManifest().get.origin zone.VehicleEvents ! VehicleServiceMessage( zone.id, - VehicleAction.UnloadVehicle(player.GUID, zone, vehicle, vehicleToDelete) + VehicleAction.UnloadVehicle(player.GUID, vehicle, vehicleToDelete) ) log.info( s"AvatarCreate: cleaning up ghost of transitioning vehicle ${vehicle.Definition.Name}@${vehicleToDelete.guid} in zone ${zone.id}" @@ -7160,12 +7154,12 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con obj.Slot(4).Equipment match { case None => ; case Some(knife) => - RemoveOldEquipmentFromInventory(obj, taskResolver)(knife) + RemoveOldEquipmentFromInventory(obj)(knife) } obj.Slot(0).Equipment match { case Some(arms: Tool) => if (GlobalDefinitions.isMaxArms(arms.Definition)) { - RemoveOldEquipmentFromInventory(obj, taskResolver)(arms) + RemoveOldEquipmentFromInventory(obj)(arms) } case _ => ; } @@ -7210,7 +7204,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con zone.Population ! Zone.Population.Release(avatar) sendResponse(ObjectDeleteMessage(pguid, 0)) zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.ObjectDelete(pguid, pguid, 0)) - taskResolver ! GUIDTask.UnregisterPlayer(tplayer)(zone.GUID) + zone.tasks ! GUIDTask.UnregisterPlayer(tplayer)(zone.GUID) } } @@ -8077,7 +8071,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con */ def CommonDestroyConstructionItem(tool: ConstructionItem, index: Int): Unit = { if (SafelyRemoveConstructionItemFromSlot(tool, index, "CommonDestroyConstructionItem")) { - taskResolver ! GUIDTask.UnregisterEquipment(tool)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterEquipment(tool)(continent.GUID) } } @@ -8219,7 +8213,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con }) match { case Some((parent, Some(slot))) => obj.Position = Vector3.Zero - RemoveOldEquipmentFromInventory(parent, taskResolver)(obj) + RemoveOldEquipmentFromInventory(parent)(obj) log.info(s"RequestDestroy: equipment $obj") true @@ -8414,7 +8408,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con if (!zoneReload && zoneId == continent.id) { if (player.isBackpack) { // important! test the actor-wide player ref, not the parameter // respawning from unregistered player - taskResolver ! RegisterAvatar(targetPlayer) + continent.tasks ! RegisterAvatar(targetPlayer) } else { // move existing player; this is the one case where the original GUID is retained by the player self ! PlayerLoaded(targetPlayer) @@ -8517,7 +8511,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con if (!zoneReload && zoneId == continent.id) { if (vehicle.Definition == GlobalDefinitions.droppod) { //instant action droppod in the same zone - taskResolver ! RegisterDroppod(vehicle, player) + continent.tasks ! RegisterDroppod(vehicle, player) } else { //transferring a vehicle between spawn points (warp gates) in the same zone self ! PlayerLoaded(player) @@ -8541,7 +8535,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //do not delete if vehicle has passengers or cargo continent.VehicleEvents ! VehicleServiceMessage( continent.id, - VehicleAction.UnloadVehicle(pguid, continent, vehicle, topLevel) + VehicleAction.UnloadVehicle(pguid, vehicle, topLevel) ) None } else { @@ -8640,7 +8634,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con task: TaskResolver.GiveTask, zoneMessage: InterstellarClusterService.FindZone ): Unit = { - taskResolver ! TaskResolver.GiveTask( + continent.tasks ! TaskResolver.GiveTask( new Task() { override def isComplete: Task.Resolution.Value = task.task.isComplete @@ -8671,7 +8665,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con avatarActor ! AvatarActor.SetVehicle(None) } RemoveBoomerTriggersFromInventory().foreach(obj => { - taskResolver ! GUIDTask.UnregisterObjectTask(obj)(continent.GUID) + continent.tasks ! GUIDTask.UnregisterObjectTask(obj)(continent.GUID) }) Deployables.Disown(continent, avatar, self) drawDeloyableIcon = RedrawDeployableIcons //important for when SetCurrentAvatar initializes the UI next zone @@ -9149,7 +9143,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con continent.id, AvatarAction.ProjectileExplodes(player.GUID, projectile_guid, projectile) ) - taskResolver ! UnregisterProjectile(projectile) + continent.tasks ! UnregisterProjectile(projectile) projectiles(local_index) match { case Some(obj) if !obj.isResolved => obj.Miss() case _ => ; @@ -9185,7 +9179,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con tplayer.VehicleSeated = None zone.Population ! Zone.Population.Release(avatar) sendResponse(ObjectDeleteMessage(tplayer.GUID, 0)) - taskResolver ! GUIDTask.UnregisterPlayer(tplayer)(zone.GUID) + zone.tasks ! GUIDTask.UnregisterPlayer(tplayer)(zone.GUID) } } @@ -9374,7 +9368,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con log.trace( s"WeaponFireMessage: ${projectile_info.Name} is a remote projectile" ) - taskResolver ! (if (projectile.HasGUID) { + continent.tasks ! (if (projectile.HasGUID) { continent.AvatarEvents ! AvatarServiceMessage( continent.id, AvatarAction.ProjectileExplodes( diff --git a/src/main/scala/net/psforever/login/WorldSession.scala b/src/main/scala/net/psforever/login/WorldSession.scala index 4154646ed..0790c2538 100644 --- a/src/main/scala/net/psforever/login/WorldSession.scala +++ b/src/main/scala/net/psforever/login/WorldSession.scala @@ -118,22 +118,19 @@ object WorldSession { * @see `tell` * @see `Zone.AvatarEvents` * @param obj the container - * @param taskResolver na * @param item the item being manipulated * @param slot na * @return a `Future` that anticipates the resolution to this manipulation */ def PutEquipmentInInventorySlot( - obj: PlanetSideServerObject with Container, - taskResolver: ActorRef + obj: PlanetSideServerObject with Container )(item: Equipment, slot: Int): Future[Any] = { val localContainer = obj val localItem = item - val localResolver = taskResolver val result = ask(localContainer.Actor, Containable.PutItemInSlotOnly(localItem, slot)) result.onComplete { case Failure(_) | Success(_: Containable.CanNotPutItemInSlot) => - localResolver ! GUIDTask.UnregisterEquipment(localItem)(localContainer.Zone.GUID) + localContainer.Zone.tasks ! GUIDTask.UnregisterEquipment(localItem)(localContainer.Zone.GUID) case _ => ; } result @@ -150,14 +147,12 @@ object WorldSession { * @see `Task` * @see `TaskResolver.GiveTask` * @param obj the container - * @param taskResolver na * @param item the item being manipulated * @param slot where the item will be placed in the container * @return a `TaskResolver` object */ def PutLoadoutEquipmentInInventory( - obj: PlanetSideServerObject with Container, - taskResolver: ActorRef + obj: PlanetSideServerObject with Container )(item: Equipment, slot: Int): TaskResolver.GiveTask = { val localZone = obj.Zone TaskResolver.GiveTask( @@ -165,7 +160,7 @@ object WorldSession { private val localContainer = obj private val localItem = item private val localSlot = slot - private val localFunc: (Equipment, Int) => Future[Any] = PutEquipmentInInventorySlot(obj, taskResolver) + private val localFunc: (Equipment, Int) => Future[Any] = PutEquipmentInInventorySlot(obj) override def Timeout: Long = 1000 @@ -203,7 +198,6 @@ object WorldSession { * @see `PutEquipmentInInventorySlot` * @see `TerminalMessageOnTimeout` * @param obj the container - * @param taskResolver na * @param player na * @param term na * @param item the item being manipulated @@ -211,7 +205,6 @@ object WorldSession { */ def BuyNewEquipmentPutInInventory( obj: PlanetSideServerObject with Container, - taskResolver: ActorRef, player: Player, term: PlanetSideGUID )(item: Equipment): TaskResolver.GiveTask = { @@ -221,7 +214,6 @@ object WorldSession { private val localContainer = obj private val localItem = item private val localPlayer = player - private val localResolver = taskResolver private val localTermMsg: Boolean => Unit = TerminalResult(term, localPlayer, TransactionType.Buy) override def Timeout: Long = 1000 @@ -242,7 +234,7 @@ object WorldSession { case Failure(_) | Success(_: Containable.CanNotPutItemInSlot) => if (localContainer != localPlayer) { TerminalMessageOnTimeout( - PutEquipmentInInventorySlot(localPlayer, localResolver)(localItem, Player.FreeHandSlot), + PutEquipmentInInventorySlot(localPlayer)(localItem, Player.FreeHandSlot), localTermMsg ) .onComplete { @@ -252,7 +244,7 @@ object WorldSession { localTermMsg(true) } } else { - localResolver ! GUIDTask.UnregisterEquipment(localItem)(localContainer.Zone.GUID) + localContainer.Zone.tasks ! GUIDTask.UnregisterEquipment(localItem)(localContainer.Zone.GUID) localTermMsg(false) } case _ => @@ -289,12 +281,11 @@ object WorldSession { * @see `TaskResolver.GiveTask` * @see `Zone.AvatarEvents` * @param player the player whose visible slot will be equipped and drawn - * @param taskResolver na * @param item the item to equip * @param slot the slot in which the item will be equipped * @return a `TaskResolver` object */ - def HoldNewEquipmentUp(player: Player, taskResolver: ActorRef)(item: Equipment, slot: Int): TaskResolver.GiveTask = { + def HoldNewEquipmentUp(player: Player)(item: Equipment, slot: Int): TaskResolver.GiveTask = { if (player.VisibleSlots.contains(slot)) { val localZone = player.Zone TaskResolver.GiveTask( @@ -303,7 +294,6 @@ object WorldSession { private val localGUID = player.GUID private val localItem = item private val localSlot = slot - private val localResolver = taskResolver override def Timeout: Long = 1000 @@ -318,7 +308,7 @@ object WorldSession { ask(localPlayer.Actor, Containable.PutItemInSlotOnly(localItem, localSlot)) .onComplete { case Failure(_) | Success(_: Containable.CanNotPutItemInSlot) => - localResolver ! GUIDTask.UnregisterEquipment(localItem)(localZone.GUID) + localPlayer.Zone.tasks ! GUIDTask.UnregisterEquipment(localItem)(localZone.GUID) case _ => if (localPlayer.DrawnSlot != Player.HandsDownSlot) { localPlayer.DrawnSlot = Player.HandsDownSlot @@ -438,20 +428,18 @@ object WorldSession { * @see `GUIDTask.UnregisterEquipment` * @see `Zone.AvatarEvents` * @param obj the container to search - * @param taskResolver na * @param item the item to find and remove from the container * @return a `Future` that anticipates the resolution to this manipulation */ - def RemoveOldEquipmentFromInventory(obj: PlanetSideServerObject with Container, taskResolver: ActorRef)( + def RemoveOldEquipmentFromInventory(obj: PlanetSideServerObject with Container)( item: Equipment ): Future[Any] = { val localContainer = obj val localItem = item - val localResolver = taskResolver val result = ask(localContainer.Actor, Containable.RemoveItemFromSlot(localItem)) result.onComplete { case Success(Containable.ItemFromSlot(_, Some(_), Some(_))) => - localResolver ! GUIDTask.UnregisterEquipment(localItem)(localContainer.Zone.GUID) + localContainer.Zone.tasks ! GUIDTask.UnregisterEquipment(localItem)(localContainer.Zone.GUID) case _ => } result @@ -474,7 +462,6 @@ object WorldSession { * @see `TerminalMessageOnTimeout` * @see `TerminalResult` * @param obj the container to search - * @param taskResolver na * @param player the player who used the terminal * @param term the unique identifier number of the terminal * @param slot from which slot the equipment is to be removed @@ -482,14 +469,12 @@ object WorldSession { */ def SellEquipmentFromInventory( obj: PlanetSideServerObject with Container, - taskResolver: ActorRef, player: Player, term: PlanetSideGUID )(slot: Int): Future[Any] = { val localContainer = obj val localPlayer = player val localSlot = slot - val localResolver = taskResolver val localTermMsg: Boolean => Unit = TerminalResult(term, localPlayer, TransactionType.Sell) val result = TerminalMessageOnTimeout( ask(localContainer.Actor, Containable.RemoveItemFromSlot(localSlot)), @@ -497,7 +482,7 @@ object WorldSession { ) result.onComplete { case Success(Containable.ItemFromSlot(_, Some(item), Some(_))) => - localResolver ! GUIDTask.UnregisterEquipment(item)(localContainer.Zone.GUID) + localContainer.Zone.tasks ! GUIDTask.UnregisterEquipment(item)(localContainer.Zone.GUID) localTermMsg(true) case _ => localTermMsg(false) @@ -519,7 +504,6 @@ object WorldSession { * @see `RemoveEquipmentFromLockerContainer` * @see `StowEquipmentInLockerContainer` * @see `TaskResolver` - * @param taskResolver na * @param toChannel broadcast channel name for a manual packet callback * @param source the container in which the item is to be removed * @param destination the container into which the item is to be placed @@ -527,7 +511,6 @@ object WorldSession { * @param dest where in the destination container the item is being placed */ def ContainableMoveItem( - taskResolver: ActorRef, toChannel: String, source: PlanetSideServerObject with Container, destination: PlanetSideServerObject with Container, @@ -536,9 +519,9 @@ object WorldSession { ) : Unit = { (source, destination) match { case (locker: LockerContainer, _) if !destination.isInstanceOf[LockerContainer] => - RemoveEquipmentFromLockerContainer(taskResolver, toChannel, locker, destination, item, dest) + RemoveEquipmentFromLockerContainer(toChannel, locker, destination, item, dest) case (_, locker: LockerContainer) => - StowEquipmentInLockerContainer(taskResolver, toChannel, source, locker, item, dest) + StowEquipmentInLockerContainer(toChannel, source, locker, item, dest) case _ => source.Actor ! Containable.MoveItem(destination, item, dest) } @@ -564,7 +547,6 @@ object WorldSession { * @see `TaskResolver` * @see `TaskResolver.GiveTask` * @see `Zone.AvatarEvents` - * @param taskResolver na * @param toChannel broadcast channel name for a manual packet callback * @param source the container in which the item is to be removed * @param destination the container into which the item is to be placed @@ -572,7 +554,6 @@ object WorldSession { * @param dest where in the destination container the item is being placed */ def StowEquipmentInLockerContainer( - taskResolver: ActorRef, toChannel: String, source: PlanetSideServerObject with Container, destination: PlanetSideServerObject with Container, @@ -605,7 +586,7 @@ object WorldSession { //too many swap items or other error; this attempt will probably fail (Nil, None) } - taskResolver ! TaskResolver.GiveTask( + destination.Zone.tasks ! TaskResolver.GiveTask( new Task() { val localGUID = swapItemGUID //the swap item's original GUID, if any swap item val localChannel = toChannel @@ -659,7 +640,6 @@ object WorldSession { * @see `TaskResolver` * @see `TaskResolver.GiveTask` * @see `Zone.AvatarEvents` - * @param taskResolver na * @param toChannel broadcast channel name for a manual packet callback * @param source the container in which the item is to be removed * @param destination the container into which the item is to be placed @@ -667,14 +647,13 @@ object WorldSession { * @param dest where in the destination container the item is being placed */ def RemoveEquipmentFromLockerContainer( - taskResolver: ActorRef, toChannel: String, source: PlanetSideServerObject with Container, destination: PlanetSideServerObject with Container, item: Equipment, dest: Int ): Unit = { - taskResolver ! TaskResolver.GiveTask( + destination.Zone.tasks ! TaskResolver.GiveTask( new Task() { val localGUID = item.GUID //original GUID val localChannel = toChannel diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala b/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala index 92d9f8ccb..5b5ac1737 100644 --- a/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala +++ b/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala @@ -2,12 +2,11 @@ package net.psforever.objects.serverobject.pad import akka.actor.{ActorContext, Cancellable, Props} +import net.psforever.objects.guid.GUIDTask.UnregisterVehicle import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.pad.process.{VehicleSpawnControlBase, VehicleSpawnControlConcealPlayer} import net.psforever.objects.zones.Zone import net.psforever.objects.{Default, Player, Vehicle} -import net.psforever.services.RemoverActor -import net.psforever.services.vehicle.VehicleServiceMessage import scala.annotation.tailrec import scala.concurrent.ExecutionContext.Implicits.global @@ -330,7 +329,7 @@ object VehicleSpawnControl { if (zone.Vehicles.exists(_.GUID == vehicle.GUID)) { //already added to zone vehicle.Actor ! Vehicle.Deconstruct() } else { //just registered to zone - zone.VehicleEvents ! VehicleServiceMessage.Decon(RemoverActor.AddTask(vehicle, zone, Some(0 seconds))) + zone.tasks ! UnregisterVehicle(vehicle)(zone.GUID) } } } diff --git a/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala b/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala index 355698d47..238349f2b 100644 --- a/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala +++ b/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala @@ -6,6 +6,7 @@ import net.psforever.objects._ import net.psforever.objects.ballistics.{ResolvedProjectile, VehicleSource} import net.psforever.objects.ce.TelepadLike import net.psforever.objects.equipment.{Equipment, EquipmentSlot, JammableMountedWeapons} +import net.psforever.objects.guid.GUIDTask import net.psforever.objects.inventory.{GridInventory, InventoryItem} import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior} @@ -20,7 +21,6 @@ import net.psforever.objects.serverobject.repair.RepairableVehicle import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.vital.VehicleShieldCharge import net.psforever.objects.zones.Zone -import net.psforever.services.RemoverActor import net.psforever.packet.game._ import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent import net.psforever.types.{DriveState, ExoSuitType, PlanetSideGUID, Vector3} @@ -338,7 +338,7 @@ class VehicleControl(vehicle: Vehicle) } }) //unregister - events ! VehicleServiceMessage.Decon(RemoverActor.AddTask(vehicle, zone, Some(0 seconds))) + zone.tasks ! GUIDTask.UnregisterVehicle(vehicle)(zone.GUID) //banished to the shadow realm vehicle.Position = Vector3.Zero //queue final deletion @@ -355,7 +355,7 @@ class VehicleControl(vehicle: Vehicle) val zone = vehicle.Zone zone.VehicleEvents ! VehicleServiceMessage( zone.id, - VehicleAction.UnloadVehicle(Service.defaultPlayerGUID, zone, vehicle, vehicle.GUID) + VehicleAction.UnloadVehicle(Service.defaultPlayerGUID, vehicle, vehicle.GUID) ) zone.Transport ! Zone.Vehicle.Despawn(vehicle) case _ => diff --git a/src/main/scala/net/psforever/objects/zones/Zone.scala b/src/main/scala/net/psforever/objects/zones/Zone.scala index 4c8c4312d..bc1a2e23c 100644 --- a/src/main/scala/net/psforever/objects/zones/Zone.scala +++ b/src/main/scala/net/psforever/objects/zones/Zone.scala @@ -8,7 +8,7 @@ import net.psforever.objects._ import net.psforever.objects.ce.Deployable import net.psforever.objects.entity.IdentifiableEntity import net.psforever.objects.equipment.Equipment -import net.psforever.objects.guid.NumberPoolHub +import net.psforever.objects.guid.{NumberPoolHub, TaskResolver} import net.psforever.objects.guid.actor.UniqueNumberSystem import net.psforever.objects.guid.key.LoanedKey import net.psforever.objects.guid.selector.RandomSelector @@ -85,6 +85,8 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) { /** Used by the `Zone` to coordinate `Equipment` dropping and collection requests. */ private var ground: ActorRef = Default.Actor + private var taskResolver: ActorRef = Default.Actor + /** */ private val constructions: ListBuffer[PlanetSideGameObject with Deployable] = ListBuffer() @@ -167,6 +169,7 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) { def init(implicit context: ActorContext): Unit = { if (accessor == ActorRef.noSender) { SetupNumberPools() + taskResolver = CreateTaskResolvers(context) accessor = context.actorOf( RandomPool(25).props( Props(classOf[UniqueNumberSystem], this.guid, UniqueNumberSystem.AllocateNumberPoolActors(this.guid)) @@ -790,6 +793,12 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) { vehicleEvents = bus VehicleEvents } + + def tasks: ActorRef = taskResolver + + protected def CreateTaskResolvers(context: ActorContext, numberCreated: Int = 20): ActorRef = { + context.actorOf(RandomPool(numberCreated).props(Props[TaskResolver]()), s"zone-$id-taskResolver") + } } object Zone { diff --git a/src/main/scala/net/psforever/services/RemoverActor.scala b/src/main/scala/net/psforever/services/RemoverActor.scala index 6e68e7ca7..78c577475 100644 --- a/src/main/scala/net/psforever/services/RemoverActor.scala +++ b/src/main/scala/net/psforever/services/RemoverActor.scala @@ -30,7 +30,7 @@ import scala.util.Success * and finally unregistering it. * Some types of object have (de-)implementation variations which should be made explicit through the overrides. */ -abstract class RemoverActor extends SupportActor[RemoverActor.Entry] { +abstract class RemoverActor(val taskResolver: ActorRef) extends SupportActor[RemoverActor.Entry] { /** * The timer that checks whether entries in the first pool are still eligible for that pool. @@ -52,24 +52,12 @@ abstract class RemoverActor extends SupportActor[RemoverActor.Entry] { */ var secondHeap: List[RemoverActor.Entry] = List() - protected var taskResolver: ActorRef = ActorRef.noSender - val sameEntryComparator = new SimilarityComparator[RemoverActor.Entry]() { def Test(entry1: RemoverActor.Entry, entry2: RemoverActor.Entry): Boolean = { entry1.obj == entry2.obj && entry1.zone == entry2.zone && entry1.obj.GUID == entry2.obj.GUID } } - /** - * Send the initial message that requests a task resolver for assisting in the removal process. - */ - override def preStart(): Unit = { - super.preStart() - ServiceManager.serviceManager ! ServiceManager.Lookup( - "taskResolver" - ) //ask for a resolver to deal with the GUID system - } - /** * Sufficiently clean up the current contents of these waiting removal jobs. * Cancel all timers, rush all entries in the lists through their individual steps, then empty the lists. @@ -88,19 +76,9 @@ abstract class RemoverActor extends SupportActor[RemoverActor.Entry] { } firstHeap = Nil secondHeap = Nil - taskResolver = ActorRef.noSender } - def receive: Receive = { - case ServiceManager.LookupResult("taskResolver", endpoint) => - taskResolver = endpoint - context.become(Processing) - - case msg => - debug(s"received message $msg before being properly initialized") - } - - def Processing: Receive = + def receive: Receive = entryManagementBehaviors .orElse { case RemoverActor.AddTask(obj, zone, duration) => diff --git a/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala b/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala index cf65bcc1e..1f0c2afb9 100644 --- a/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala +++ b/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala @@ -49,9 +49,6 @@ class AccountPersistenceService extends Actor { /** squad service event hook */ var squad: ActorRef = ActorRef.noSender - /** task resolver service event hook */ - var resolver: ActorRef = ActorRef.noSender - /** log, for trace and warnings only */ val log = org.log4s.getLogger @@ -62,7 +59,6 @@ class AccountPersistenceService extends Actor { */ override def preStart(): Unit = { ServiceManager.serviceManager ! ServiceManager.Lookup("squad") - ServiceManager.serviceManager ! ServiceManager.Lookup("taskResolver") log.trace("Awaiting system service hooks ...") } @@ -130,17 +126,9 @@ class AccountPersistenceService extends Actor { * @see `ServiceManager.LookupResult` */ val Setup: Receive = { - case ServiceManager.LookupResult(id, endpoint) => - id match { - case "squad" => - squad = endpoint - case "taskResolver" => - resolver = endpoint - } - if ( - squad != ActorRef.noSender && - resolver != ActorRef.noSender - ) { + case ServiceManager.LookupResult("squad", endpoint) => + squad = endpoint + if (squad != ActorRef.noSender) { log.trace("Service hooks obtained. Continuing with standard operation.") context.become(Started) } @@ -156,7 +144,7 @@ class AccountPersistenceService extends Actor { */ def CreateNewPlayerToken(name: String): ActorRef = { val ref = - context.actorOf(Props(classOf[PersistenceMonitor], name, squad, resolver), s"$name-${NextPlayerIndex(name)}") + context.actorOf(Props(classOf[PersistenceMonitor], name, squad), s"$name-${NextPlayerIndex(name)}") accounts += name -> ref ref } @@ -231,10 +219,8 @@ object AccountPersistenceService { * and to determine the conditions for end-of-life activity. * @param name the unique name of the player * @param squadService a hook into the `SquadService` event system - * @param taskResolver a hook into the `TaskResolver` event system; - * used for object unregistering */ -class PersistenceMonitor(name: String, squadService: ActorRef, taskResolver: ActorRef) extends Actor { +class PersistenceMonitor(name: String, squadService: ActorRef) extends Actor { /** the last-reported zone of this player */ var inZone: Zone = Zone.Nowhere @@ -404,7 +390,7 @@ class PersistenceMonitor(name: String, squadService: ActorRef, taskResolver: Act } inZone.Population.tell(Zone.Population.Release(avatar), parent) inZone.AvatarEvents.tell(AvatarServiceMessage(inZone.id, AvatarAction.ObjectDelete(pguid, pguid)), parent) - taskResolver.tell(GUIDTask.UnregisterPlayer(player)(inZone.GUID), parent) + inZone.tasks.tell(GUIDTask.UnregisterPlayer(player)(inZone.GUID), parent) AvatarLogout(avatar) } @@ -423,7 +409,7 @@ class PersistenceMonitor(name: String, squadService: ActorRef, taskResolver: Act squadService.tell(Service.Leave(Some(avatar.id.toString)), context.parent) Deployables.Disown(inZone, avatar, context.parent) inZone.Population.tell(Zone.Population.Leave(avatar), context.parent) - taskResolver.tell(GUIDTask.UnregisterObjectTask(avatar.locker)(inZone.GUID), context.parent) + inZone.tasks.tell(GUIDTask.UnregisterObjectTask(avatar.locker)(inZone.GUID), context.parent) log.info(s"logout of ${avatar.name}") } } diff --git a/src/main/scala/net/psforever/services/avatar/AvatarService.scala b/src/main/scala/net/psforever/services/avatar/AvatarService.scala index 20d07815e..eabbd8825 100644 --- a/src/main/scala/net/psforever/services/avatar/AvatarService.scala +++ b/src/main/scala/net/psforever/services/avatar/AvatarService.scala @@ -10,8 +10,8 @@ import net.psforever.services.avatar.support.{CorpseRemovalActor, DroppedItemRem import net.psforever.services.{GenericEventBus, RemoverActor, Service} class AvatarService(zone: Zone) extends Actor { - private val undertaker: ActorRef = context.actorOf(Props[CorpseRemovalActor](), s"${zone.id}-corpse-removal-agent") - private val janitor = context.actorOf(Props[DroppedItemRemover](), s"${zone.id}-item-remover-agent") + private val undertaker: ActorRef = context.actorOf(Props(classOf[CorpseRemovalActor], zone.tasks), s"${zone.id}-corpse-removal-agent") + private val janitor = context.actorOf(Props(classOf[DroppedItemRemover], zone.tasks), s"${zone.id}-item-remover-agent") private[this] val log = org.log4s.getLogger diff --git a/src/main/scala/net/psforever/services/avatar/support/CorpseRemovalActor.scala b/src/main/scala/net/psforever/services/avatar/support/CorpseRemovalActor.scala index 70dece514..b97b707c6 100644 --- a/src/main/scala/net/psforever/services/avatar/support/CorpseRemovalActor.scala +++ b/src/main/scala/net/psforever/services/avatar/support/CorpseRemovalActor.scala @@ -1,6 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.services.avatar.support +import akka.actor.ActorRef import net.psforever.objects.guid.{GUIDTask, TaskResolver} import net.psforever.objects.Player import net.psforever.types.ExoSuitType @@ -9,7 +10,7 @@ import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import scala.concurrent.duration._ -class CorpseRemovalActor extends RemoverActor { +class CorpseRemovalActor(taskResolver: ActorRef) extends RemoverActor(taskResolver) { final val FirstStandardDuration: FiniteDuration = 1 minute final val SecondStandardDuration: FiniteDuration = 500 milliseconds diff --git a/src/main/scala/net/psforever/services/avatar/support/DroppedItemRemover.scala b/src/main/scala/net/psforever/services/avatar/support/DroppedItemRemover.scala index e389e50b7..19d639690 100644 --- a/src/main/scala/net/psforever/services/avatar/support/DroppedItemRemover.scala +++ b/src/main/scala/net/psforever/services/avatar/support/DroppedItemRemover.scala @@ -1,6 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.services.avatar.support +import akka.actor.ActorRef import net.psforever.objects.equipment.Equipment import net.psforever.objects.guid.{GUIDTask, TaskResolver} import net.psforever.services.{RemoverActor, Service} @@ -8,7 +9,7 @@ import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import scala.concurrent.duration._ -class DroppedItemRemover extends RemoverActor { +class DroppedItemRemover(taskResolver: ActorRef) extends RemoverActor(taskResolver) { final val FirstStandardDuration: FiniteDuration = 3 minutes final val SecondStandardDuration: FiniteDuration = 500 milliseconds diff --git a/src/main/scala/net/psforever/services/local/LocalService.scala b/src/main/scala/net/psforever/services/local/LocalService.scala index 7c3138afd..c508028c6 100644 --- a/src/main/scala/net/psforever/services/local/LocalService.scala +++ b/src/main/scala/net/psforever/services/local/LocalService.scala @@ -26,7 +26,7 @@ class LocalService(zone: Zone) extends Actor { private val doorCloser = context.actorOf(Props[DoorCloseActor](), s"${zone.id}-local-door-closer") private val hackClearer = context.actorOf(Props[HackClearActor](), s"${zone.id}-local-hack-clearer") private val hackCapturer = context.actorOf(Props[HackCaptureActor](), s"${zone.id}-local-hack-capturer") - private val engineer = context.actorOf(Props[DeployableRemover](), s"${zone.id}-deployable-remover-agent") + private val engineer = context.actorOf(Props(classOf[DeployableRemover], zone.tasks), s"${zone.id}-deployable-remover-agent") private val teleportDeployment: ActorRef = context.actorOf(Props[RouterTelepadActivation](), s"${zone.id}-telepad-activate-agent") private[this] val log = org.log4s.getLogger diff --git a/src/main/scala/net/psforever/services/local/support/DeployableRemover.scala b/src/main/scala/net/psforever/services/local/support/DeployableRemover.scala index c730f4493..c7aeef7f9 100644 --- a/src/main/scala/net/psforever/services/local/support/DeployableRemover.scala +++ b/src/main/scala/net/psforever/services/local/support/DeployableRemover.scala @@ -1,6 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.services.local.support +import akka.actor.ActorRef import net.psforever.objects.ce.Deployable import net.psforever.objects.guid.{GUIDTask, TaskResolver} import net.psforever.objects.zones.Zone @@ -10,7 +11,7 @@ import net.psforever.services.RemoverActor import scala.concurrent.duration._ -class DeployableRemover extends RemoverActor { +class DeployableRemover(taskResolver: ActorRef) extends RemoverActor(taskResolver) { final val FirstStandardDuration: FiniteDuration = 3 minutes final val SecondStandardDuration: FiniteDuration = 2 seconds @@ -64,7 +65,7 @@ class DeployableRemover extends RemoverActor { boomer.Trigger match { case Some(trigger) => boomer.Trigger = None - taskResolver ! GUIDTask.UnregisterObjectTask(trigger)(entry.zone.GUID) + boomer.Zone.tasks ! GUIDTask.UnregisterObjectTask(trigger)(entry.zone.GUID) case None => ; } GUIDTask.UnregisterObjectTask(boomer)(entry.zone.GUID) diff --git a/src/main/scala/net/psforever/services/vehicle/VehicleService.scala b/src/main/scala/net/psforever/services/vehicle/VehicleService.scala index a077f15a8..dab15d0b2 100644 --- a/src/main/scala/net/psforever/services/vehicle/VehicleService.scala +++ b/src/main/scala/net/psforever/services/vehicle/VehicleService.scala @@ -10,12 +10,11 @@ import net.psforever.objects.vital.RepairFromTerm import net.psforever.objects.zones.Zone import net.psforever.packet.game.ObjectCreateMessage import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent -import net.psforever.services.vehicle.support.{TurretUpgrader, VehicleRemover} +import net.psforever.services.vehicle.support.TurretUpgrader import net.psforever.types.{DriveState, PlanetSideGUID} -import net.psforever.services.{GenericEventBus, RemoverActor, Service} +import net.psforever.services.{GenericEventBus, Service} class VehicleService(zone: Zone) extends Actor { - private val vehicleDecon: ActorRef = context.actorOf(Props[VehicleRemover](), s"${zone.id}-vehicle-decon-agent") private val turretUpgrade: ActorRef = context.actorOf(Props[TurretUpgrader](), s"${zone.id}-turret-upgrade-agent") private[this] val log = org.log4s.getLogger @@ -157,8 +156,7 @@ class VehicleService(zone: Zone) extends Actor { ) ) ) - case VehicleAction.UnloadVehicle(player_guid, continent, vehicle, vehicle_guid) => - vehicleDecon ! RemoverActor.ClearSpecific(List(vehicle), continent) //precaution + case VehicleAction.UnloadVehicle(player_guid, vehicle, vehicle_guid) => VehicleEvents.publish( VehicleServiceResponse( s"/$forChannel/Vehicle", @@ -246,10 +244,6 @@ class VehicleService(zone: Zone) extends Actor { case _ => ; } - //message to VehicleRemover - case VehicleServiceMessage.Decon(msg) => - vehicleDecon forward msg - //message to TurretUpgrader case VehicleServiceMessage.TurretUpgrade(msg) => turretUpgrade forward msg diff --git a/src/main/scala/net/psforever/services/vehicle/VehicleServiceMessage.scala b/src/main/scala/net/psforever/services/vehicle/VehicleServiceMessage.scala index c1acb429f..147d597c0 100644 --- a/src/main/scala/net/psforever/services/vehicle/VehicleServiceMessage.scala +++ b/src/main/scala/net/psforever/services/vehicle/VehicleServiceMessage.scala @@ -15,8 +15,6 @@ object VehicleServiceMessage { final case class GiveActorControl(vehicle: Vehicle, actorName: String) final case class RevokeActorControl(vehicle: Vehicle) - final case class Decon(msg: Any) - final case class TurretUpgrade(msg: Any) final case class AMSDeploymentChange(zone: Zone) @@ -83,7 +81,6 @@ object VehicleAction { extends Action final case class UnloadVehicle( player_guid: PlanetSideGUID, - continent: Zone, vehicle: Vehicle, vehicle_guid: PlanetSideGUID ) extends Action diff --git a/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala b/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala index 3857e20d2..0278da412 100644 --- a/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala +++ b/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala @@ -2,6 +2,7 @@ package net.psforever.services.vehicle.support import akka.actor.{ActorRef, Cancellable} +import net.psforever.objects.equipment.EquipmentSlot import net.psforever.objects.{AmmoBox, Default, PlanetSideGameObject, Tool} import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver} import net.psforever.objects.serverobject.PlanetSideServerObject @@ -11,7 +12,6 @@ import net.psforever.objects.zones.Zone import net.psforever.types.PlanetSideGUID import net.psforever.services.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions} import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} -import net.psforever.services.{Service, ServiceManager} import scala.concurrent.duration._ import scala.util.Success @@ -21,22 +21,12 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] { var list: List[TurretUpgrader.Entry] = List() - private var taskResolver: ActorRef = ActorRef.noSender - val sameEntryComparator = new SimilarityComparator[TurretUpgrader.Entry]() { def Test(entry1: TurretUpgrader.Entry, entry2: TurretUpgrader.Entry): Boolean = { entry1.obj == entry2.obj && entry1.zone == entry2.zone && entry1.obj.GUID == entry2.obj.GUID } } - /** - * Send the initial message that requests a task resolver for assisting in the removal process. - */ - override def preStart(): Unit = { - super.preStart() - self ! Service.Startup() - } - /** * Sufficiently clean up the current contents of these waiting removal jobs. * Cancel all timers, rush all entries in the lists through their individual steps, then empty the lists. @@ -49,7 +39,6 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] { UpgradeTurretAmmo } list = Nil - taskResolver = ActorRef.noSender } def CreateEntry(obj: PlanetSideGameObject, zone: Zone, upgrade: TurretUpgrade.Value, duration: Long) = @@ -57,21 +46,7 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] { def InclusionTest(entry: TurretUpgrader.Entry): Boolean = entry.obj.isInstanceOf[FacilityTurret] - def receive: Receive = { - case Service.Startup() => - ServiceManager.serviceManager ! ServiceManager.Lookup( - "taskResolver" - ) //ask for a resolver to deal with the GUID system - - case ServiceManager.LookupResult("taskResolver", endpoint) => - taskResolver = endpoint - context.become(Processing) - - case msg => - debug(s"received message $msg before being properly initialized") - } - - def Processing: Receive = + def receive: Receive = entryManagementBehaviors .orElse { case TurretUpgrader.AddTask(turret, zone, upgrade, duration) => @@ -219,7 +194,7 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] { .map(box => GUIDTask.RegisterEquipment(box)(guid)) .toList ) - taskResolver ! TaskResolver.GiveTask( + target.Zone.tasks ! TaskResolver.GiveTask( new Task() { private val tasks = oldBoxesTask @@ -258,7 +233,7 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] { val targetGUID = target.GUID if (target.Health > 0) { target.Weapons - .map({ case (index, slot) => (index, slot.Equipment) }) + .map({ case (index: Int, slot: EquipmentSlot) => (index, slot.Equipment) }) .collect { case (index, Some(tool: Tool)) => context.parent ! VehicleServiceMessage( diff --git a/src/main/scala/net/psforever/services/vehicle/support/VehicleRemover.scala b/src/main/scala/net/psforever/services/vehicle/support/VehicleRemover.scala deleted file mode 100644 index 8758f9aec..000000000 --- a/src/main/scala/net/psforever/services/vehicle/support/VehicleRemover.scala +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2017-2020 PSForever -package net.psforever.services.vehicle.support - -import akka.actor.{Actor, ActorRef} -import net.psforever.objects.Vehicle -import net.psforever.objects.guid.GUIDTask.UnregisterVehicle -import net.psforever.services.{RemoverActor, ServiceManager} - -class VehicleRemover extends Actor { - var taskResolver: ActorRef = ActorRef.noSender - - override def preStart(): Unit = { - super.preStart() - ServiceManager.serviceManager ! ServiceManager.Lookup( - "taskResolver" - ) //ask for a resolver to deal with the GUID system - } - - def receive: Receive = { - case ServiceManager.LookupResult("taskResolver", endpoint) => - taskResolver = endpoint - context.become(Processing) - - case _ => ; - } - - def Processing: Receive = { - case RemoverActor.AddTask(obj: Vehicle, zone, _) => - taskResolver ! UnregisterVehicle(obj)(zone.GUID) - - case _ => ; - } -} diff --git a/src/test/scala/objects/AutoRepairTest.scala b/src/test/scala/objects/AutoRepairTest.scala index 648a9decd..d175ca2c1 100644 --- a/src/test/scala/objects/AutoRepairTest.scala +++ b/src/test/scala/objects/AutoRepairTest.scala @@ -16,11 +16,13 @@ import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.damage.DamageProfile import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.objects.{GlobalDefinitions, Player, Tool} +import net.psforever.services.ServiceManager import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3} import scala.concurrent.duration._ class AutoRepairRequestNtuTest extends FreedContextActorTest { + ServiceManager.boot val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) player.Spawn() val weapon = new Tool(GlobalDefinitions.suppressor) @@ -80,6 +82,7 @@ class AutoRepairRequestNtuTest extends FreedContextActorTest { } class AutoRepairRequestNtuRepeatTest extends FreedContextActorTest { + ServiceManager.boot val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) player.Spawn() val weapon = new Tool(GlobalDefinitions.suppressor) @@ -141,6 +144,7 @@ class AutoRepairRequestNtuRepeatTest extends FreedContextActorTest { } class AutoRepairNoRequestNtuTest extends FreedContextActorTest { + ServiceManager.boot val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) player.Spawn() val weapon = new Tool(GlobalDefinitions.suppressor) @@ -195,6 +199,7 @@ class AutoRepairNoRequestNtuTest extends FreedContextActorTest { } class AutoRepairRestoreRequestNtuTest extends FreedContextActorTest { + ServiceManager.boot val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) player.Spawn() val weapon = new Tool(GlobalDefinitions.suppressor) @@ -258,6 +263,7 @@ class AutoRepairRestoreRequestNtuTest extends FreedContextActorTest { } class AutoRepairRepairWithNtuTest extends FreedContextActorTest { + ServiceManager.boot val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) player.Spawn() val weapon = new Tool(GlobalDefinitions.suppressor) @@ -316,6 +322,7 @@ class AutoRepairRepairWithNtuTest extends FreedContextActorTest { } class AutoRepairRepairWithNtuUntilDoneTest extends FreedContextActorTest { + ServiceManager.boot val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) player.Spawn() val weapon = new Tool(GlobalDefinitions.suppressor) diff --git a/src/test/scala/objects/ResourceSiloTest.scala b/src/test/scala/objects/ResourceSiloTest.scala index 86643988a..ba1fe6432 100644 --- a/src/test/scala/objects/ResourceSiloTest.scala +++ b/src/test/scala/objects/ResourceSiloTest.scala @@ -2,11 +2,10 @@ package objects import akka.actor.{Actor, Props} -import akka.routing.RandomPool import akka.testkit.TestProbe import base.ActorTest import net.psforever.actors.zone.{BuildingActor, ZoneActor} -import net.psforever.objects.guid.{NumberPoolHub, TaskResolver} +import net.psforever.objects.guid.NumberPoolHub import net.psforever.objects.guid.source.MaxNumberSource import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.{GlobalDefinitions, Ntu, Player, Vehicle} @@ -17,7 +16,6 @@ import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.packet.game.UseItemMessage import net.psforever.types._ import org.specs2.mutable.Specification -import net.psforever.services.ServiceManager import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import akka.actor.typed.scaladsl.adapter._ import net.psforever.objects.avatar.Avatar @@ -77,18 +75,21 @@ class ResourceSiloTest extends Specification { } class ResourceSiloControlStartupTest extends ActorTest { - val serviceManager = ServiceManager.boot(system) - serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]()), "taskResolver") val obj = ResourceSilo() obj.GUID = PlanetSideGUID(1) - val probe = TestProbe() - serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe), "avatar") + 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") + obj.Owner = + new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) { + Actor = buildingEvents.ref + } + obj.Owner.GUID = PlanetSideGUID(6) "Resource silo" should { "startup properly" in { - expectNoMessage(500 milliseconds) - system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo") ! "startup" - expectNoMessage(1 seconds) + obj.Actor ! "startup" + expectNoMessage(max = 1000 milliseconds) } } } diff --git a/src/test/scala/objects/VehicleTest.scala b/src/test/scala/objects/VehicleTest.scala index a0de397aa..0d8852659 100644 --- a/src/test/scala/objects/VehicleTest.scala +++ b/src/test/scala/objects/VehicleTest.scala @@ -15,7 +15,7 @@ import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.packet.game.{CargoMountPointStatusMessage, ObjectDetachMessage, PlanetsideAttributeMessage} import net.psforever.types.{PlanetSideGUID, _} import org.specs2.mutable._ -import net.psforever.services.{RemoverActor, ServiceManager} +import net.psforever.services.ServiceManager import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import scala.concurrent.duration._ @@ -342,23 +342,7 @@ class VehicleControlPrepareForDeletionTest extends ActorTest { "VehicleControl" should { "submit for unregistering when marked for deconstruction" in { vehicle.Actor ! Vehicle.Deconstruct() - - val vehicle_msg = vehicleProbe.receiveN(1, 500 milliseconds) - assert( - vehicle_msg.head match { - case VehicleServiceMessage.Decon(RemoverActor.AddTask(v, z, _)) => (v eq vehicle) && (z == vehicle.Zone) - case _ => false - } - ) - - val vehicle_msg_final = vehicleProbe.receiveN(1, 6 seconds) - assert( - vehicle_msg_final.head match { - case VehicleServiceMessage("test", VehicleAction.UnloadVehicle(_, z, v, PlanetSideGUID(1))) => - (v eq vehicle) && (z == vehicle.Zone) - case _ => false - } - ) + vehicleProbe.expectNoMessage(5 seconds) } } } @@ -383,7 +367,7 @@ class VehicleControlPrepareForDeletionPassengerTest extends ActorTest { "kick all players when marked for deconstruction" in { vehicle.Actor ! Vehicle.Deconstruct() - val vehicle_msg = vehicleProbe.receiveN(2, 500 milliseconds) + val vehicle_msg = vehicleProbe.receiveN(1, 500 milliseconds) assert( vehicle_msg.head match { case VehicleServiceMessage( @@ -396,12 +380,6 @@ class VehicleControlPrepareForDeletionPassengerTest extends ActorTest { ) assert(player1.VehicleSeated.isEmpty) assert(vehicle.Seats(1).Occupant.isEmpty) - assert( - vehicle_msg(1) match { - case VehicleServiceMessage.Decon(RemoverActor.AddTask(v, z, _)) => (v eq vehicle) && (z == vehicle.Zone) - case _ => false - } - ) } } } @@ -451,7 +429,7 @@ class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTes "if mounted as cargo, self-eject when marked for deconstruction" in { vehicle.Actor ! Vehicle.Deconstruct() - val vehicle_msg = vehicleProbe.receiveN(7, 500 milliseconds) + val vehicle_msg = vehicleProbe.receiveN(6, 500 milliseconds) //dismounting as cargo messages assert( vehicle_msg.head match { @@ -523,12 +501,6 @@ class VehicleControlPrepareForDeletionMountedInTest extends FreedContextActorTes ) assert(player1.VehicleSeated.isEmpty) assert(vehicle.Seats(1).Occupant.isEmpty) - assert( - vehicle_msg(6) match { - case VehicleServiceMessage.Decon(RemoverActor.AddTask(v, z, _)) => (v eq vehicle) && (z == vehicle.Zone) - case _ => false - } - ) } } } @@ -580,7 +552,7 @@ class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActor "if with mounted cargo, eject it when marked for deconstruction" in { lodestar.Actor ! Vehicle.Deconstruct() - val vehicle_msg = vehicleProbe.receiveN(7, 500 milliseconds) + val vehicle_msg = vehicleProbe.receiveN(6, 500 milliseconds) assert( vehicle_msg.head match { case VehicleServiceMessage( @@ -650,13 +622,6 @@ class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActor case _ => false } ) - //cargo dismounting messages - assert( - vehicle_msg(6) match { - case VehicleServiceMessage.Decon(RemoverActor.AddTask(v, z, _)) => (v eq lodestar) && (z == vehicle.Zone) - case _ => false - } - ) } } } diff --git a/src/test/scala/objects/ZoneTest.scala b/src/test/scala/objects/ZoneTest.scala index 059a609d0..e754e5943 100644 --- a/src/test/scala/objects/ZoneTest.scala +++ b/src/test/scala/objects/ZoneTest.scala @@ -2,6 +2,7 @@ package objects import java.util.concurrent.atomic.AtomicInteger + import akka.actor.ActorContext import base.ActorTest import net.psforever.objects.entity.IdentifiableEntity @@ -19,6 +20,7 @@ import org.specs2.mutable.Specification import akka.actor.typed.scaladsl.adapter._ import net.psforever.actors.zone.ZoneActor import net.psforever.objects.avatar.Avatar +import net.psforever.services.ServiceManager import scala.concurrent.duration._ @@ -120,6 +122,7 @@ class ZoneTest extends Specification { } class ZoneActorTest extends ActorTest { + ServiceManager.boot "Zone" should { "refuse new number pools after the Actor is started" in { val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} } diff --git a/src/test/scala/service/LocalServiceTest.scala b/src/test/scala/service/LocalServiceTest.scala index ef7d7566f..31d6b4f95 100644 --- a/src/test/scala/service/LocalServiceTest.scala +++ b/src/test/scala/service/LocalServiceTest.scala @@ -2,17 +2,20 @@ package service import akka.actor.Props -import base.ActorTest +import akka.testkit.TestProbe +import base.{ActorTest, FreedContextActorTest} import net.psforever.objects.{GlobalDefinitions, SensorDeployable, Vehicle} import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.terminals.{ProximityTerminal, Terminal} import net.psforever.objects.vehicles.VehicleControl -import net.psforever.objects.zones.Zone +import net.psforever.objects.zones.{Zone, ZoneMap} import net.psforever.packet.game._ import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3} import net.psforever.services.{Service, ServiceManager} import net.psforever.services.local._ +import scala.concurrent.duration._ + class LocalService1Test extends ActorTest { ServiceManager.boot(system) @@ -118,15 +121,19 @@ class DeployableMapIconTest extends ActorTest { } } -class DoorClosesTest extends ActorTest { - ServiceManager.boot(system) +class DoorClosesTest extends FreedContextActorTest { + val probe = new TestProbe(system) + val zone = new Zone("test", new ZoneMap("test-map"), 0) { + override def SetupNumberPools() : Unit = { } + } + zone.init(context) + expectNoMessage(500 milliseconds) "LocalService" should { "pass DoorCloses" in { - val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") - service ! Service.Join("test") - service ! LocalServiceMessage("test", LocalAction.DoorCloses(PlanetSideGUID(10), PlanetSideGUID(40))) - expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.DoorCloses(PlanetSideGUID(40)))) + zone.LocalEvents.tell(Service.Join("test"), probe.ref) + zone.LocalEvents ! LocalServiceMessage("test", LocalAction.DoorCloses(PlanetSideGUID(10), PlanetSideGUID(40))) + probe.expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.DoorCloses(PlanetSideGUID(40)))) } } } diff --git a/src/test/scala/service/RemoverActorTest.scala b/src/test/scala/service/RemoverActorTest.scala index 1523f6619..643be63e2 100644 --- a/src/test/scala/service/RemoverActorTest.scala +++ b/src/test/scala/service/RemoverActorTest.scala @@ -509,7 +509,7 @@ object RemoverActorTest { final case class DeletionTaskRunAlert() - class TestRemover extends RemoverActor { + class TestRemover(taskResolver: ActorRef) extends RemoverActor(taskResolver) { import net.psforever.objects.guid.{Task, TaskResolver} val FirstStandardDuration = 1 seconds