diff --git a/.codecov.yml b/.codecov.yml
index 26736d869..37159d819 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -9,6 +9,9 @@ coverage:
threshold: 0.25%
ignore:
+ - "src/main/java"
+ - "src/main/resources"
+ - "src/main/scala/akka"
- "src/main/scala/net/psforever/objects/ObjectType.scala"
- "src/main/scala/net/psforever/objects/avatar/Avatars.scala"
- "src/main/scala/net/psforever/objects/ballistics/DamageResolution.scala"
@@ -18,7 +21,12 @@ ignore:
- "src/main/scala/net/psforever/objects/equipment/EquipmentSize.scala"
- "src/main/scala/net/psforever/objects/equipment/Kits.scala"
- "src/main/scala/net/psforever/objects/equipment/SItem.scala"
+ - "src/main/scala/net/psforever/objects/global"
- "src/main/scala/net/psforever/objects/guid/AvailabilityPolicy.scala"
+ - "src/main/scala/net/psforever/objects/loadouts/EquipmentLoadout.scala"
+ - "src/main/scala/net/psforever/objects/loadouts/InfantryLoadout.scala"
+ - "src/main/scala/net/psforever/objects/loadouts/SquadLoadout.scala"
+ - "src/main/scala/net/psforever/objects/loadouts/VehicleLoadout.scala"
- "src/main/scala/net/psforever/objects/serverobject/pad/AutoDriveControls.scala"
- "src/main/scala/net/psforever/objects/serverobject/structures/StructureType.scala"
- "src/main/scala/net/psforever/objects/serverobject/shuttle/ShuttleAmenity.scala"
@@ -56,24 +64,34 @@ ignore:
- "src/main/scala/net/psforever/packet/ControlPacketOpcode.scala"
- "src/main/scala/net/psforever/packet/CryptoPacketOpcode.scala"
- "src/main/scala/net/psforever/packet/GamePacketOpcode.scala"
- - "src/main/scala/net/psforever/types/Angular.scala"
- - "src/main/scala/net/psforever/types/CertificationType.scala"
- - "src/main/scala/net/psforever/types/ChatMessageType.scala"
- - "src/main/scala/net/psforever/types/DriveState.scala"
- - "src/main/scala/net/psforever/types/EmoteType.scala"
- - "src/main/scala/net/psforever/types/ExoSuitType.scala"
- - "src/main/scala/net/psforever/types/GrenadeState.scala"
- - "src/main/scala/net/psforever/types/ImplantType.scala"
- - "src/main/scala/net/psforever/types/MeritCommendation.scala"
- - "src/main/scala/net/psforever/types/PlanetSideEmpire.scala"
- - "src/main/scala/net/psforever/types/TransactionType.scala"
+ - "src/main/scala/net/psforever/packet/ResetSequenceOpcode.scala"
+ - "src/main/scala/net/psforever/persistence"
+ - "src/main/scala/net/psforever/services/account/IPAddress.scala"
+ - "src/main/scala/net/psforever/services/account/ReceiveAccountData.scala"
+ - "src/main/scala/net/psforever/services/account/ReceiveIPAddress.scala"
+ - "src/main/scala/net/psforever/services/account/RetrieveAccountData.scala"
+ - "src/main/scala/net/psforever/services/account/RetrieveIPAddress.scala"
+ - "src/main/scala/net/psforever/services/account/StoreAccountData.scala"
+ - "src/main/scala/net/psforever/services/account/StoreIPAddress.scala"
- "src/main/scala/net/psforever/services/avatar/AvatarAction.scala"
- - "src/main/scala/net/psforever/services/avatar/AvatarResponse.scala"
- - "src/main/scala/net/psforever/services/galaxy/GalaxyAction.scala"
- - "src/main/scala/net/psforever/services/galaxy/GalaxyResponse.scala"
+ - "src/main/scala/net/psforever/services/avatar/AvatarService.scala"
+ - "src/main/scala/net/psforever/services/base/bus"
+ - "src/main/scala/net/psforever/services/base/envelope"
+ - "src/main/scala/net/psforever/services/chat/ChatChannel.scala"
+ - "src/main/scala/net/psforever/services/galaxy/GalaxyAction"
+ - "src/main/scala/net/psforever/services/galaxy/GalaxyService"
- "src/main/scala/net/psforever/services/hart/HartEvent.scala"
- "src/main/scala/net/psforever/services/hart/HartTimerActions.scala"
- - "src/main/scala/net/psforever/services/local/LocalAction.scala"
- - "src/main/scala/net/psforever/services/local/LocalResponse.scala"
- - "src/main/scala/net/psforever/services/vehicle/VehicleAction.scala"
- - "src/main/scala/net/psforever/services/vehicle/VehicleResponse.scala"
+ - "src/main/scala/net/psforever/services/local/LocalAction"
+ - "src/main/scala/net/psforever/services/local/LocalService"
+ - "src/main/scala/net/psforever/services/teamwork/SquadServiceMessage.scala"
+ - "src/main/scala/net/psforever/services/teamwork/SquadServiceResponse.scala"
+ - "src/main/scala/net/psforever/services/vehicle/VehicleAction"
+ - "src/main/scala/net/psforever/services/vehicle/VehicleService"
+ - "src/main/scala/net/psforever/services/Service.scala"
+ - "src/main/scala/net/psforever/types"
+ - "src/main/scala/net/psforever/util"
+ - "src/main/scala/net/psforever/zones"
+ - "src/main/scala/net/psforever/IFinalizable.scala"
+ - "src/main/scala/scodec"
+ - "src/test"
diff --git a/server/src/main/scala/net/psforever/server/Server.scala b/server/src/main/scala/net/psforever/server/Server.scala
index 2ec30a503..686e39953 100644
--- a/server/src/main/scala/net/psforever/server/Server.scala
+++ b/server/src/main/scala/net/psforever/server/Server.scala
@@ -101,7 +101,7 @@ object Server {
val zones = Zones.zones :+ Zone.Nowhere
val serviceManager = ServiceManager.boot
serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService](), "accountIntermediary")
- serviceManager ! ServiceManager.Register(classic.Props[GalaxyService](), "galaxy")
+ serviceManager ! ServiceManager.Register(GalaxyService(), "galaxy")
serviceManager ! ServiceManager.Register(classic.Props[SquadService](), "squad")
serviceManager ! ServiceManager.Register(classic.Props[AccountPersistenceService](), "accountPersistence")
serviceManager ! ServiceManager.Register(classic.Props[PropertyOverrideManager](), "propertyOverrideManager")
diff --git a/server/src/test/scala/actor/objects/AutoRepairIntegrationTest.scala b/server/src/test/scala/actor/objects/AutoRepairIntegrationTest.scala
index 7742079e0..b1b939c67 100644
--- a/server/src/test/scala/actor/objects/AutoRepairIntegrationTest.scala
+++ b/server/src/test/scala/actor/objects/AutoRepairIntegrationTest.scala
@@ -32,7 +32,7 @@ import scala.concurrent.duration._
class AutoRepairFacilityIntegrationTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
- ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
+ ServiceManager.boot(system) ! ServiceManager.Register(GalaxyService(), "galaxy")
expectNoMessage(1000 milliseconds)
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
val avatarProbe = new TestProbe(system)
@@ -105,7 +105,7 @@ class AutoRepairFacilityIntegrationTest extends FreedContextActorTest {
class AutoRepairFacilityIntegrationGiveNtuTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
- ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
+ ServiceManager.boot(system) ! ServiceManager.Register(GalaxyService(), "galaxy")
expectNoMessage(1000 milliseconds)
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
val avatarProbe = new TestProbe(system)
@@ -160,7 +160,7 @@ class AutoRepairFacilityIntegrationGiveNtuTest extends FreedContextActorTest {
class AutoRepairFacilityIntegrationAntGiveNtuTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
- ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
+ ServiceManager.boot(system) ! ServiceManager.Register(GalaxyService(), "galaxy")
expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]()
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
@@ -251,7 +251,7 @@ class AutoRepairFacilityIntegrationAntGiveNtuTest extends FreedContextActorTest
class AutoRepairFacilityIntegrationTerminalDestroyedTerminalAntTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
- ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
+ ServiceManager.boot(system) ! ServiceManager.Register(GalaxyService(), "galaxy")
expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]()
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
@@ -353,7 +353,7 @@ class AutoRepairFacilityIntegrationTerminalDestroyedTerminalAntTest extends Free
class AutoRepairFacilityIntegrationTerminalIncompleteRepairTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
- ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
+ ServiceManager.boot(system) ! ServiceManager.Register(GalaxyService(), "galaxy")
expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]()
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
@@ -469,7 +469,7 @@ class AutoRepairFacilityIntegrationTerminalIncompleteRepairTest extends FreedCon
class AutoRepairTowerIntegrationTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
- ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
+ ServiceManager.boot(system) ! ServiceManager.Register(GalaxyService(), "galaxy")
expectNoMessage(1000 milliseconds)
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
val avatarProbe = new TestProbe(system)
diff --git a/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala b/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala
index 6ca49eca0..e847d5036 100644
--- a/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala
+++ b/server/src/test/scala/actor/objects/VehicleSpawnPadTest.scala
@@ -9,11 +9,12 @@ import net.psforever.objects.serverobject.structures.StructureType
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
import net.psforever.objects.zones.Zone
import net.psforever.types.{PlanetSideGUID, _}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.vehicle.VehicleAction
import akka.actor.typed.scaladsl.adapter._
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.serverobject.terminals.Terminal
+import net.psforever.services.base.envelope.GenericMessageEnvelope
import scala.concurrent.duration._
@@ -37,7 +38,7 @@ class VehicleSpawnControl2Test extends ActorTest {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
- probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
+ probe.expectMsgClass(1 minute, classOf[GenericMessageEnvelope])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
vehicle.Seats(0).mount(player)
@@ -69,11 +70,11 @@ class VehicleSpawnControl3Test extends ActorTest {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player2, vehicle, terminal) //second order (vehicle shared)
assert(probe.receiveOne(1 seconds) match {
- case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Queue, _) => true
- case _ => false
+ case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, _) => true
+ case _ => false
})
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
- probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
+ probe.expectMsgClass(1 minute, classOf[GenericMessageEnvelope])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
vehicle.Seats(0).mount(player)
@@ -82,11 +83,11 @@ class VehicleSpawnControl3Test extends ActorTest {
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideStart])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
assert(probe.receiveOne(1 minute) match {
- case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
+ case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false
})
assert(probe.receiveOne(1 minute) match {
- case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
+ case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false
})
@@ -110,14 +111,6 @@ class VehicleSpawnControl4Test extends ActorTest {
player.Continent = "problem" //problem
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
-
- val msg = probe.receiveOne(1 minute)
-// assert(
-// msg match {
-// case VehicleServiceMessage.Decon(RemoverActor.AddTask(v, z, _)) => (v == vehicle) && (z == zone)
-// case _ => false
-// }
-// )
probe.expectNoMessage(5 seconds)
}
}
@@ -133,18 +126,18 @@ class VehicleSpawnControl5Test extends ActorTest() {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
- probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
+ probe.expectMsgClass(1 minute, classOf[GenericMessageEnvelope])
vehicle.Health = 0 //problem
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match {
- case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true
- case _ => false
+ case GenericMessageEnvelope(_, _, VehicleAction.LoadVehicle(_, _, _, _)) => true
+ case _ => false
})
assert(probe.receiveOne(1 minute) match {
- case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
- case _ => false
+ case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
+ case _ => false
})
}
}
@@ -160,18 +153,18 @@ class VehicleSpawnControl6Test extends ActorTest() {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
- probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
+ probe.expectMsgClass(1 minute, classOf[GenericMessageEnvelope])
player.Die
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match {
- case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true
- case _ => false
+ case GenericMessageEnvelope(_, _, VehicleAction.LoadVehicle(_, _, _, _)) => true
+ case _ => false
})
assert(probe.receiveOne(1 minute) match {
- case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
- case _ => false
+ case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
+ case _ => false
})
}
}
@@ -188,18 +181,18 @@ class VehicleSpawnControl7Test extends ActorTest {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
- probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage])
+ probe.expectMsgClass(1 minute, classOf[GenericMessageEnvelope])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match {
- case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true
- case _ => false
+ case GenericMessageEnvelope(_, _, VehicleAction.LoadVehicle(_, _, _, _)) => true
+ case _ => false
})
assert(probe.receiveOne(1 minute) match {
- case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true
- case _ => false
+ case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
+ case _ => false
})
}
}
diff --git a/server/src/test/scala/actor/service/AvatarServiceTest.scala b/server/src/test/scala/actor/service/AvatarServiceTest.scala
deleted file mode 100644
index 6e0eab30d..000000000
--- a/server/src/test/scala/actor/service/AvatarServiceTest.scala
+++ /dev/null
@@ -1,651 +0,0 @@
-// Copyright (c) 2017 PSForever
-package actor.service
-
-import akka.actor.Props
-import akka.testkit.TestProbe
-import scala.concurrent.duration._
-
-import actor.base.{ActorTest, FreedContextActorTest}
-import net.psforever.objects._
-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}
-import net.psforever.types._
-import net.psforever.services.{RemoverActor, Service, ServiceManager}
-import net.psforever.services.avatar._
-
-class AvatarService1Test extends ActorTest {
- "AvatarService" should {
- "construct" in {
- ServiceManager.boot(system)
- system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- assert(true)
- }
- }
-}
-
-class AvatarService2Test extends ActorTest {
- "AvatarService" should {
- "subscribe" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- assert(true)
- }
- }
-}
-
-class AvatarService3Test extends ActorTest {
- "AvatarService" should {
- ServiceManager.boot(system)
- "subscribe to a specific channel" in {
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! Service.Leave()
- assert(true)
- }
- }
-}
-
-class AvatarService4Test extends ActorTest {
- "AvatarService" should {
- "subscribe" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! Service.LeaveAll()
- assert(true)
- }
- }
-}
-
-class AvatarService5Test extends ActorTest {
- "AvatarService" should {
- "pass an unhandled message" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! "hello"
- expectNoMessage()
- }
- }
-}
-
-class ArmorChangedTest extends ActorTest {
- "AvatarService" should {
- "pass ArmorChanged" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.ArmorChanged(PlanetSideGUID(10), ExoSuitType.Reinforced, 0))
- expectMsg(
- AvatarServiceResponse(
- "/test/Avatar",
- PlanetSideGUID(10),
- AvatarResponse.ArmorChanged(ExoSuitType.Reinforced, 0)
- )
- )
- }
- }
-}
-
-class ConcealPlayerTest extends ActorTest {
- "AvatarService" should {
- "pass ConcealPlayer" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.ConcealPlayer(PlanetSideGUID(10)))
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ConcealPlayer()))
- }
- }
-}
-
-class EquipmentInHandTest extends ActorTest {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service")
- val toolDef = GlobalDefinitions.beamer
- val tool = Tool(toolDef)
- tool.GUID = PlanetSideGUID(40)
- tool.AmmoSlots.head.Box.GUID = PlanetSideGUID(41)
- val pkt = ObjectCreateMessage(
- toolDef.ObjectId,
- tool.GUID,
- ObjectCreateMessageParent(PlanetSideGUID(11), 2),
- toolDef.Packet.ConstructorData(tool).get
- )
-
- "AvatarService" should {
- "pass EquipmentInHand" in {
- service ! Service.Join("test")
- service ! AvatarServiceMessage(
- "test",
- AvatarAction.EquipmentInHand(PlanetSideGUID(10), PlanetSideGUID(11), 2, tool)
- )
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentInHand(pkt)))
- }
- }
-}
-
-class DroptItemTest extends ActorTest {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), "release-test-service")
- val toolDef = GlobalDefinitions.beamer
- val tool = Tool(toolDef)
- tool.Position = Vector3(1, 2, 3)
- tool.Orientation = Vector3(4, 5, 6)
- tool.GUID = PlanetSideGUID(40)
- tool.AmmoSlots.head.Box.GUID = PlanetSideGUID(41)
- val pkt = ObjectCreateMessage(
- toolDef.ObjectId,
- tool.GUID,
- DroppedItemData(
- PlacementData(tool.Position, tool.Orientation),
- toolDef.Packet.ConstructorData(tool).get
- )
- )
-
- "AvatarService" should {
- "pass DropItem" in {
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.DropItem(PlanetSideGUID(10), tool))
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.DropItem(pkt)))
- }
- }
-}
-
-class LoadPlayerTest extends ActorTest {
- val obj = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.VS, CharacterSex.Female, 1, CharacterVoice.Voice1))
- obj.GUID = PlanetSideGUID(10)
- obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(11)
- val c1data = obj.Definition.Packet.DetailedConstructorData(obj).get
- val pkt1 = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(10), c1data)
- val parent = ObjectCreateMessageParent(PlanetSideGUID(12), 0)
- obj.VehicleSeated = PlanetSideGUID(12)
- val c2data = obj.Definition.Packet.DetailedConstructorData(obj).get
- val pkt2 = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(10), parent, c2data)
-
- "AvatarService" should {
- "pass LoadPlayer" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- //no parent data
- service ! AvatarServiceMessage(
- "test",
- AvatarAction.LoadPlayer(PlanetSideGUID(20), ObjectClass.avatar, PlanetSideGUID(10), c1data, None)
- )
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(20), AvatarResponse.LoadPlayer(pkt1)))
- //parent data
- service ! AvatarServiceMessage(
- "test",
- AvatarAction.LoadPlayer(PlanetSideGUID(20), ObjectClass.avatar, PlanetSideGUID(10), c2data, Some(parent))
- )
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(20), AvatarResponse.LoadPlayer(pkt2)))
- }
- }
-}
-
-class ObjectDeleteTest extends ActorTest {
- "AvatarService" should {
- "pass ObjectDelete" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11)))
- expectMsg(
- AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 0))
- )
-
- service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11), 55))
- expectMsg(
- AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 55))
- )
- }
- }
-}
-
-class ObjectHeldTest extends ActorTest {
- "AvatarService" should {
- "pass ObjectHeld" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.ObjectHeld(PlanetSideGUID(10), 1, 2))
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectHeld(1, 2)))
- }
- }
-}
-
-class PutDownFDUTest extends ActorTest {
- "AvatarService" should {
- "pass PutDownFDU" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.PutDownFDU(PlanetSideGUID(10)))
- expectMsg(
- AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PutDownFDU(PlanetSideGUID(10)))
- )
- }
- }
-}
-
-class PlanetsideAttributeTest extends ActorTest {
- "AvatarService" should {
- "pass PlanetsideAttribute" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.PlanetsideAttribute(PlanetSideGUID(10), 5, 1200L))
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlanetsideAttribute(5, 1200L)))
- }
- }
-}
-
-class PlayerStateTest extends ActorTest {
- val msg = PlayerStateMessageUpstream(
- PlanetSideGUID(75),
- Vector3(3694.1094f, 2735.4531f, 90.84375f),
- Some(Vector3(4.375f, 2.59375f, 0.0f)),
- 61.875f,
- 351.5625f,
- 0.0f,
- 136,
- 0,
- false,
- false,
- false,
- false,
- 112,
- 0
- )
-
- "AvatarService" should {
- "pass PlayerState" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage(
- "test",
- AvatarAction.PlayerState(
- PlanetSideGUID(10),
- Vector3(3694.1094f, 2735.4531f, 90.84375f),
- Some(Vector3(4.375f, 2.59375f, 0.0f)),
- 61.875f,
- 351.5625f,
- 0.0f,
- 136,
- false,
- false,
- false,
- false,
- false,
- false
- )
- )
- expectMsg(
- AvatarServiceResponse(
- "/test/Avatar",
- PlanetSideGUID(10),
- AvatarResponse.PlayerState(
- Vector3(3694.1094f, 2735.4531f, 90.84375f),
- Some(Vector3(4.375f, 2.59375f, 0.0f)),
- 61.875f,
- 351.5625f,
- 0.0f,
- 136,
- false,
- false,
- false,
- false,
- false,
- false
- )
- )
- )
- }
- }
-}
-
-class PickupItemTest extends ActorTest {
- val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterSex.Female, 1, CharacterVoice.Voice1))
- val tool = Tool(GlobalDefinitions.beamer)
- tool.GUID = PlanetSideGUID(40)
-
- "pass PickUpItem" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.PickupItem(PlanetSideGUID(10), tool))
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(tool.GUID, 0)))
- }
-}
-
-class ReloadTest extends ActorTest {
- "AvatarService" should {
- "pass Reload" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.Reload(PlanetSideGUID(10), PlanetSideGUID(40)))
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.Reload(PlanetSideGUID(40))))
- }
- }
-}
-
-class ChangeAmmoTest extends ActorTest {
- val ammoDef = GlobalDefinitions.energy_cell
- val ammoBox = AmmoBox(ammoDef)
-
- "AvatarService" should {
- "pass ChangeAmmo" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage(
- "test",
- AvatarAction.ChangeAmmo(
- PlanetSideGUID(10),
- PlanetSideGUID(40),
- 0,
- PlanetSideGUID(40),
- ammoDef.ObjectId,
- PlanetSideGUID(41),
- ammoDef.Packet.ConstructorData(ammoBox).get
- )
- )
- expectMsg(
- AvatarServiceResponse(
- "/test/Avatar",
- PlanetSideGUID(10),
- AvatarResponse.ChangeAmmo(
- PlanetSideGUID(40),
- 0,
- PlanetSideGUID(40),
- ammoDef.ObjectId,
- PlanetSideGUID(41),
- ammoDef.Packet.ConstructorData(ammoBox).get
- )
- )
- )
- }
- }
-}
-
-class ChangeFireModeTest extends ActorTest {
- val ammoDef = GlobalDefinitions.energy_cell
- val ammoBox = AmmoBox(ammoDef)
-
- "AvatarService" should {
- "pass ChangeFireMode" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.ChangeFireMode(PlanetSideGUID(10), PlanetSideGUID(40), 0))
- expectMsg(
- AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireMode(PlanetSideGUID(40), 0))
- )
- }
- }
-}
-
-class ChangeFireStateStartTest extends ActorTest {
- "AvatarService" should {
- "pass ChangeFireState_Start" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Start(PlanetSideGUID(10), PlanetSideGUID(40)))
- expectMsg(
- AvatarServiceResponse(
- "/test/Avatar",
- PlanetSideGUID(10),
- AvatarResponse.ChangeFireState_Start(PlanetSideGUID(40))
- )
- )
- }
- }
-}
-
-class ChangeFireStateStopTest extends ActorTest {
- "AvatarService" should {
- "pass ChangeFireState_Stop" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Stop(PlanetSideGUID(10), PlanetSideGUID(40)))
- expectMsg(
- AvatarServiceResponse(
- "/test/Avatar",
- PlanetSideGUID(10),
- AvatarResponse.ChangeFireState_Stop(PlanetSideGUID(40))
- )
- )
- }
- }
-}
-
-class WeaponDryFireTest extends ActorTest {
- "AvatarService" should {
- "pass WeaponDryFire" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.WeaponDryFire(PlanetSideGUID(10), PlanetSideGUID(40)))
- expectMsg(
- AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.WeaponDryFire(PlanetSideGUID(40)))
- )
- }
- }
-}
-
-class AvatarStowEquipmentTest extends ActorTest {
- val tool = Tool(GlobalDefinitions.beamer)
-
- "AvatarService" should {
- "pass StowEquipment" in {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[AvatarService], Zone.Nowhere), AvatarServiceTest.TestName)
- service ! Service.Join("test")
- service ! AvatarServiceMessage(
- "test",
- AvatarAction.StowEquipment(PlanetSideGUID(10), PlanetSideGUID(11), 2, tool)
- )
- expectMsg(
- AvatarServiceResponse(
- "/test/Avatar",
- PlanetSideGUID(10),
- AvatarResponse.StowEquipment(PlanetSideGUID(11), 2, tool)
- )
- )
- }
- }
-}
-
-/*
-Preparation for these three Release tests is involved.
-The ServiceManager must be set up correctly.
-The Zone needs to be set up and initialized properly with a ZoneActor.
-The ZoneActor builds the GUID Actor and the ZonePopulationActor.
-
-ALL of these Actors will talk to each other.
-The lines of communication can short circuit if the next Actor does not have the correct information.
-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 FreedContextActorTest {
- val guid: NumberPoolHub = new NumberPoolHub(new MaxNumberSource(15))
- val zone = new Zone("test", new ZoneMap("test-map"), 0) {
- override def SetupNumberPools() : Unit = { }
- GUID(guid)
- }
- zone.init(context)
- val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterSex.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
-
- zone.AvatarEvents.tell(Service.Join("test"), subscriber.ref)
- assert(zone.Corpses.isEmpty)
- zone.Population ! Zone.Corpse.Add(obj)
- subscriber.expectNoMessage(200 milliseconds) //spacer
-
- assert(zone.Corpses.size == 1)
- assert(obj.HasGUID)
- val guid = obj.GUID
- zone.AvatarEvents ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone, Some(1 second))) //alive for one second
-
- val reply1 = subscriber.receiveOne(200 milliseconds)
- assert(reply1.isInstanceOf[AvatarServiceResponse])
- val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
- assert(reply1msg.channel == "/test/Avatar")
- assert(reply1msg.avatar_guid == guid)
- assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
- assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
-
- val reply2 = subscriber.receiveOne(2 seconds)
- assert(reply2.isInstanceOf[AvatarServiceResponse])
- val reply2msg = reply2.asInstanceOf[AvatarServiceResponse]
- assert(reply2msg.channel.equals("/test/Avatar"))
- assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
- assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
- assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
-
- subscriber.expectNoMessage(1 seconds)
- assert(zone.Corpses.isEmpty)
- assert(!obj.HasGUID)
- }
- }
-}
-
-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() : Unit = { }
- GUID(guid)
- }
- zone.init(context)
- val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterSex.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
-
- zone.AvatarEvents.tell(Service.Join("test"), subscriber.ref)
- assert(zone.Corpses.isEmpty)
- zone.Population ! Zone.Corpse.Add(obj)
- subscriber.expectNoMessage(200 milliseconds) //spacer
-
- assert(zone.Corpses.size == 1)
- assert(obj.HasGUID)
- val guid = obj.GUID
- zone.AvatarEvents ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes!
-
- val reply1 = subscriber.receiveOne(200 milliseconds)
- assert(reply1.isInstanceOf[AvatarServiceResponse])
- val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
- assert(reply1msg.channel == "/test/Avatar")
- assert(reply1msg.avatar_guid == guid)
- assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
- assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
-
- 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"))
- assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
- assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
- assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
-
- subscriber.expectNoMessage(1 seconds)
- assert(zone.Corpses.isEmpty)
- assert(!obj.HasGUID)
- }
- }
-}
-
-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() : Unit = { }
- GUID(guid)
- }
- zone.init(context)
- val obj = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterSex.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, CharacterSex.Male, 1, CharacterVoice.Voice1)
- ) //necessary clutter
- objAlt.GUID = PlanetSideGUID(3)
- objAlt.Slot(5).Equipment.get.GUID = PlanetSideGUID(4)
- objAlt.Zone = zone
- val subscriber = new TestProbe(system)
-
- "AvatarService" should {
- "pass Release" in {
- expectNoMessage(100 milliseconds) //spacer
-
- zone.AvatarEvents.tell(Service.Join("test"), subscriber.ref)
- assert(zone.Corpses.isEmpty)
- zone.Population ! Zone.Corpse.Add(obj)
- subscriber.expectNoMessage(200 milliseconds) //spacer
-
- assert(zone.Corpses.size == 1)
- assert(obj.HasGUID)
- val guid = obj.GUID
- zone.AvatarEvents ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes!
-
- val reply1 = subscriber.receiveOne(200 milliseconds)
- assert(reply1.isInstanceOf[AvatarServiceResponse])
- val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
- assert(reply1msg.channel == "/test/Avatar")
- assert(reply1msg.avatar_guid == guid)
- assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
- assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
-
- zone.AvatarEvents ! AvatarServiceMessage.Corpse(
- RemoverActor.HurrySpecific(List(objAlt, obj), zone)
- ) //IMPORTANT: TWO ENTRIES
- val reply2 = subscriber.receiveOne(100 milliseconds)
- assert(reply2.isInstanceOf[AvatarServiceResponse])
- val reply2msg = reply2.asInstanceOf[AvatarServiceResponse]
- assert(reply2msg.channel.equals("/test/Avatar"))
- assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
- assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
- assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
-
- subscriber.expectNoMessage(1 seconds)
- assert(zone.Corpses.isEmpty)
- assert(!obj.HasGUID)
- }
- }
-}
-
-object AvatarServiceTest {
- import java.util.concurrent.atomic.AtomicInteger
- private val number = new AtomicInteger(1)
-
- def TestName: String = {
- s"service${number.getAndIncrement()}"
- }
-}
diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf
index 86ac54b7f..765c800fe 100644
--- a/src/main/resources/application.conf
+++ b/src/main/resources/application.conf
@@ -575,6 +575,17 @@ network {
# before it is dropped. Can be used as a watchdog for hung server sessions.
outbound-grace-time = 1 minute
}
+
+ event-caching {
+ # The minimum amount of time a cached message has to wait before being dispatched. (ms)
+ # Ideal circumstances are when message traffic is light.
+ flush-cache-delay = 15
+ # The absolute maximum amount of time a cached message has to wait before being dispatched. (ms)
+ flush-cache-max-delay = 50
+ # The numeric difference between light traffic and heavy traffic.
+ # In this case, the event system's traffic density and the message caching delay are numerically synonymous.
+ message-traffic-threshold = 12
+ }
}
development {
diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala
index 2b72d42ff..87c59aa42 100644
--- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala
+++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala
@@ -12,7 +12,8 @@ import net.psforever.objects.avatar.ModePermissions
import net.psforever.objects.avatar.scoring.{Assist, Death, EquipmentStat, KDAStat, Kill, Life, ScoreCard, SupportActivity}
import net.psforever.objects.sourcing.{TurretSource, VehicleSource}
import net.psforever.packet.game.ImplantAction
-import net.psforever.services.avatar.AvatarServiceResponse
+import net.psforever.services.avatar.AvatarStamp
+import net.psforever.services.base.envelope.GenericResponseEnvelope
import net.psforever.types.{ChatMessageType, StatisticalCategory, StatisticalElement}
import net.psforever.zones.Zones
import org.joda.time.{LocalDateTime, Seconds}
@@ -49,8 +50,9 @@ import net.psforever.objects.vital.{DamagingActivity, HealFromImplant, HealingAc
import net.psforever.packet.game.objectcreate.{BasicCharacterData, ObjectClass, RibbonBars}
import net.psforever.packet.game.{Friend => GameFriend, _}
import net.psforever.persistence
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{SendResponse, PlanetsideAttribute}
+import net.psforever.services.avatar.AvatarAction
import net.psforever.types.{
CharacterSex,
CharacterVoice,
@@ -585,9 +587,10 @@ object AvatarActor {
def displayLookingForSquad(session: Session, state: Int): Unit = {
val player = session.player
- session.zone.AvatarEvents ! AvatarServiceMessage(
+ session.zone.AvatarEvents ! MessageEnvelope(
player.Faction.toString,
- AvatarAction.PlanetsideAttribute(player.GUID, 53, state)
+ player.GUID,
+ PlanetsideAttribute(player.GUID, 53, state)
)
}
@@ -1383,9 +1386,10 @@ class AvatarActor(
case SetLookingForSquad(lfs) =>
avatarCopy(avatar.copy(lookingForSquad = lfs))
sessionActor ! SessionActor.SendResponse(PlanetsideAttributeMessage(session.get.player.GUID, 53, 0))
- session.get.zone.AvatarEvents ! AvatarServiceMessage(
+ session.get.zone.AvatarEvents ! MessageEnvelope(
avatar.faction.toString,
- AvatarAction.PlanetsideAttribute(session.get.player.GUID, 53, if (lfs) 1 else 0)
+ session.get.player.GUID,
+ PlanetsideAttribute(session.get.player.GUID, 53, if (lfs) 1 else 0)
)
Behaviors.same
@@ -1794,9 +1798,9 @@ class AvatarActor(
)
val player = session.get.player
val zone = player.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, DisplayedAwardMessage(player.GUID, ribbon, bar))
+ SendResponse(DisplayedAwardMessage(player.GUID, ribbon, bar))
)
Behaviors.same
@@ -2073,9 +2077,9 @@ class AvatarActor(
case Success(_) =>
val zone = session.get.zone
avatarCopy(avatar.copy(decoration = avatar.decoration.copy(cosmetics = Some(cosmetics))))
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttributeToAll(
+ PlanetsideAttribute(
session.get.player.GUID,
106,
Cosmetic.valuesToAttributeValue(cosmetics)
@@ -3000,13 +3004,13 @@ class AvatarActor(
val next = BattleRank.withExperience(newBep).value
val br24 = BattleRank.BR24.value
sessionActor ! SessionActor.SendResponse(BattleExperienceMessage(pguid, newBep, localModifier))
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(pguid, 17, newBep))
+ events ! MessageEnvelope(zoneId, PlanetsideAttribute(pguid, 17, newBep))
if (current < br24 && next >= br24 || current >= br24 && next < br24) {
setCosmetics(Set()).onComplete { _ =>
val evts = events
val name = player.Name
val guid = pguid
- evts ! AvatarServiceMessage(name, AvatarAction.PlanetsideAttributeToAll(guid, 106, 1)) //set to no helmet
+ evts ! MessageEnvelope(name, PlanetsideAttribute(guid, 106, 1)) //set to no helmet
}
}
// when the level is reduced, take away any implants over the implant slot limit
@@ -3051,10 +3055,7 @@ class AvatarActor(
val sess = session.get
val zone = sess.zone
avatar = avatar.copy(cep = cep)
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.PlanetsideAttributeToAll(sess.player.GUID, 18, cep)
- )
+ zone.AvatarEvents ! MessageEnvelope(zone.id, PlanetsideAttribute(sess.player.GUID, 18, cep))
case Failure(exception) =>
log.error(exception)("db failure")
}
@@ -3152,7 +3153,7 @@ class AvatarActor(
if (exp > 0L) {
setBep(exp, msg)
zone.actor ! ZoneActor.RewardOurSupporters(playerSource, historyTranscript, killStat, exp)
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
player.Name, AvatarAction.ShareKillExperienceWithSquad(player, exp))
}
}
@@ -3163,12 +3164,9 @@ class AvatarActor(
val _session = session.get
val zone = _session.zone
val player = _session.player
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
player.Name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- AvatarStatisticsMessage(DeathStatistic(ScoreCard.deathCount(avatar.scorecard)))
- )
+ SendResponse(AvatarStatisticsMessage(DeathStatistic(ScoreCard.deathCount(avatar.scorecard))))
)
}
@@ -3494,8 +3492,8 @@ class AvatarActor(
value: Int
): Unit = {
import akka.actor.typed.scaladsl.adapter.TypedActorRefOps
- import net.psforever.services.avatar.{AvatarResponse => RESP}
- sessionActor.toClassic ! AvatarServiceResponse("", guid, RESP.AvatarImplant(action, index, value))
+ val resp = AvatarAction.AvatarImplant(action, index, value)
+ sessionActor.toClassic ! GenericResponseEnvelope(AvatarStamp, "", guid, resp)
}
private def buyImplantAction(
@@ -3654,9 +3652,9 @@ class AvatarActor(
// Start client-side initialization timer, visible on the character screen
// Progress accumulates according to the client's knowledge of the implant initialization time
// What is normally a 60s timer that is set to 120s on the server will still visually update as if 60s
- session.get.zone.AvatarEvents ! AvatarServiceMessage(
+ session.get.zone.AvatarEvents ! MessageEnvelope(
avatar.name,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, actionProgress))
+ SendResponse(ActionProgressMessage(slot + 6, actionProgress))
)
implant.copy(initialized = false, active = false, timer = futureDelay)
} else {
@@ -3703,9 +3701,9 @@ class AvatarActor(
def stopImplantInitializationTimer(implant: Implant, slot: Int): Implant = {
cancelImplantInitializedTimer(slot)
//can not formally stop the initialization time on the character information window; set it to 100 to make it look blank
- session.get.zone.AvatarEvents ! AvatarServiceMessage(
+ session.get.zone.AvatarEvents ! MessageEnvelope(
avatar.name,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 100))
+ SendResponse(ActionProgressMessage(slot + 6, 100))
)
implant.copy(initialized = false, active = false, timer = 0L)
}
@@ -3773,9 +3771,10 @@ class AvatarActor(
private def deactivateImplant(implant: Implant, slot: Int): Implant = {
cancelImplantInitializedTimer(slot)
// Deactivation sound / effect
- session.get.zone.AvatarEvents ! AvatarServiceMessage(
+ session.get.zone.AvatarEvents ! MessageEnvelope(
session.get.zone.id,
- AvatarAction.PlanetsideAttribute(session.get.player.GUID, 28, implant.definition.implantType.value * 2)
+ session.get.player.GUID,
+ PlanetsideAttribute(session.get.player.GUID, 28, implant.definition.implantType.value * 2)
)
sendAvatarImplantMessageToSelf(session.get.player.GUID, ImplantAction.Activation, slot, value = 0)
implant.copy(active = false)
@@ -3852,10 +3851,7 @@ class AvatarActor(
val newHealth = player.Health = originalHealth + 1
val events = zone.AvatarEvents
player.LogActivity(HealFromImplant(implant.definition.implantType, 1))
- events ! AvatarServiceMessage(
- zone.id,
- AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth)
- )
+ events ! MessageEnvelope(zone.id, PlanetsideAttribute(guid, 0, newHealth))
false
} else {
!aliveAndWounded
@@ -3867,9 +3863,10 @@ class AvatarActor(
// Activation sound / effect
val sess = session.get
val zone = sess.zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttribute(
+ sess.player.GUID,
+ PlanetsideAttribute(
sess.player.GUID,
28,
implant.definition.implantType.value * 2 + 1
@@ -3892,9 +3889,9 @@ class AvatarActor(
case (implantOpt @ Some(implant), slot) =>
//update ongoing progress
val actionProgress = calculateImplantTimerStats(implant, AvatarActor.initializationTime(implant))._3
- session.get.zone.AvatarEvents ! AvatarServiceMessage(
+ session.get.zone.AvatarEvents ! MessageEnvelope(
avatar.name,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, actionProgress))
+ SendResponse(ActionProgressMessage(slot + 6, actionProgress))
)
implantOpt
case (None, _) =>
diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala
index aaec38df4..29bee0368 100644
--- a/src/main/scala/net/psforever/actors/session/SessionActor.scala
+++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala
@@ -3,7 +3,7 @@ package net.psforever.actors.session
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware, typed}
import net.psforever.actors.session.normal.NormalMode
-import net.psforever.actors.session.support.ZoningOperations
+import net.psforever.actors.session.support.{CommonHandlerFunctions, CommonHandlerLogic, ZoningOperations}
import net.psforever.objects.TurretDeployable
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.containable.Containable
@@ -18,12 +18,13 @@ import net.psforever.services.CavernRotationService
import net.psforever.services.CavernRotationService.SendCavernRotationUpdates
import net.psforever.services.ServiceManager.LookupResult
import net.psforever.services.account.{PlayerToken, ReceiveAccountData}
-import net.psforever.services.avatar.AvatarServiceResponse
+import net.psforever.services.avatar.AvatarStamp
+import net.psforever.services.base.envelope.{GenericResponseEnvelope, Undelivered}
import net.psforever.services.chat.ChatService
-import net.psforever.services.galaxy.GalaxyServiceResponse
-import net.psforever.services.local.LocalServiceResponse
+import net.psforever.services.galaxy.GalaxyStamp
+import net.psforever.services.local.LocalStamp
import net.psforever.services.teamwork.SquadServiceResponse
-import net.psforever.services.vehicle.VehicleServiceResponse
+import net.psforever.services.vehicle.VehicleStamp
import org.joda.time.LocalDateTime
import org.log4s.MDC
@@ -94,6 +95,26 @@ object SessionActor {
private final case object PokeClient extends Command
final case class SetMode(mode: PlayerMode) extends Command
+
+ /**
+ * Determine if a response handler would process a given reply message, ignoring its guards.
+ * Treat handlers already ignoring their guards as "determined (will not pass)".
+ * @see `CommonHandlerFunctions.IgnoreFilter_=`
+ * @param reply message
+ * @param handler message handler
+ * @return `true`, if the response handler will process the response;
+ * `false`, if the handler is skipped or if it would not process
+ */
+ private def HandlerAcceptingMessageTest(reply: Any)(handler: CommonHandlerFunctions): Boolean = {
+ if (handler.IgnoreFilter) {
+ false
+ } else {
+ handler.IgnoreFilter = true
+ val result = handler.isDefinedAt(reply)
+ handler.IgnoreFilter = false
+ result
+ }
+ }
}
class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], connectionId: String, sessionId: Long)
@@ -106,6 +127,9 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
private[this] val data = new SessionData(middlewareActor, context)
private[this] var mode: PlayerMode = NormalMode
private[this] var logic: ModeLogic = _
+ private[this] var listOfHandlers: Seq[CommonHandlerFunctions] = List.empty
+
+ private val commonHandlerLogic: CommonHandlerLogic = new CommonHandlerLogic(data, context)
override def postStop(): Unit = {
clientKeepAlive.cancel()
@@ -119,7 +143,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
buffer.addOne(msg)
case _ if data.whenAllEventBusesLoaded() =>
context.become(inTheGame)
- logic = mode.setup(data)
+ changeModeSetup(mode)
buffer.foreach { self.tell(_, self) } //we forget the original sender, shouldn't be doing callbacks at this point
buffer.clear()
case _ => ()
@@ -160,37 +184,39 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
if (mode != newMode) {
logic.switchFrom(data.session)
mode = newMode
- logic = newMode.setup(data)
+ changeModeSetup(newMode)
}
logic.switchTo(data.session)
}
+ private def changeModeSetup(newMode: PlayerMode): Unit = {
+ logic = newMode.setup(data)
+ listOfHandlers = List(
+ logic.avatarResponse,
+ logic.local,
+ logic.vehicleResponse,
+ logic.galaxy,
+ commonHandlerLogic
+ )
+ }
+
private def parse(sender: ActorRef): Receive = {
/* really common messages (very frequently, every life) */
case packet: PlanetSideGamePacket =>
handleGamePkt(packet)
- case AvatarServiceResponse(toChannel, guid, reply) =>
- logic.avatarResponse.handle(toChannel, guid, reply)
+ case SquadServiceResponse(_, excluded, reply) =>
+ logic.squad.handle(reply, excluded)
- case GalaxyServiceResponse(_, reply) =>
- logic.galaxy.handle(reply)
-
- case LocalServiceResponse(toChannel, guid, reply) =>
- logic.local.handle(toChannel, guid, reply)
+ case envelope: GenericResponseEnvelope =>
+ handleGenericResponseEnvelope(envelope)
case Mountable.MountMessages(tplayer, reply) =>
logic.mountResponse.handle(tplayer, reply)
- case SquadServiceResponse(_, excluded, response) =>
- logic.squad.handle(response, excluded)
-
case Terminal.TerminalMessage(tplayer, msg, order) =>
logic.terminals.handle(tplayer, msg, order)
- case VehicleServiceResponse(toChannel, guid, reply) =>
- logic.vehicleResponse.handle(toChannel, guid, reply)
-
case ChatService.MessageResponse(fromSession, message, _) =>
logic.chat.handleIncomingMessage(message, fromSession)
@@ -369,6 +395,52 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
logic.general.handleReceiveDefaultMessage(default, sender)
}
+ private def handleGenericResponseEnvelope(envelope: GenericResponseEnvelope): Unit = {
+ //try use the stamp to match the specific handler
+ envelope.stamp match {
+ case Undelivered =>
+ val GenericResponseEnvelope(_, _, reply) = envelope
+ log.error(s"received a message's response that was not processed by an event system - $reply")
+ case AvatarStamp =>
+ handleEnvelopeWithResponseHandler(logic.avatarResponse, envelope)
+ case LocalStamp =>
+ handleEnvelopeWithResponseHandler(logic.local, envelope)
+ case VehicleStamp =>
+ handleEnvelopeWithResponseHandler(logic.vehicleResponse, envelope)
+ case GalaxyStamp =>
+ handleEnvelopeWithResponseHandler(logic.galaxy, envelope)
+ case unknownStamp =>
+ log.error(s"received a message from an unknown event system - reply: $envelope, stamp: $unknownStamp")
+ }
+ //println(s"event-system-rtt: ${System.currentTimeMillis() - envelope.time} ms")
+ }
+
+ private def handleEnvelopeWithResponseHandler(
+ responseHandler: CommonHandlerFunctions,
+ envelope: GenericResponseEnvelope
+ ): Unit = {
+ val GenericResponseEnvelope(toChannel, guid, reply) = envelope
+ //try the expected handler with the input response
+ if (!responseHandler.handle(toChannel, guid, reply)) {
+ //test the expected handler again, ignoring guard booleans; if it would have been handled, stop with this
+ responseHandler.IgnoreFilter = true
+ if (!responseHandler.isDefinedAt(reply)) {
+ //find every handler that might accept the input response, ignoring guard booleans only for the search
+ //try each discovered handler against the input response until one works
+ val test: CommonHandlerFunctions => Boolean = SessionActor.HandlerAcceptingMessageTest(reply)
+ listOfHandlers.filter(test) match {
+ case Nil =>
+ log.error(s"received completely unhandled response message - $reply for ${envelope.stamp}:$toChannel")
+ case first :: Nil =>
+ first.tryToHandle(reply)
+ case first :: others =>
+ first.tryToHandle(reply) || others.exists(_.tryToHandle(reply))
+ }
+ }
+ responseHandler.IgnoreFilter = false
+ }
+ }
+
private def handleGamePkt: PlanetSideGamePacket => Unit = {
case packet: ConnectToWorldRequestMessage =>
logic.general.handleConnectToWorldRequest(packet)
diff --git a/src/main/scala/net/psforever/actors/session/csr/AvatarHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/csr/AvatarHandlerLogic.scala
index 764a6c89e..f1750d6c8 100644
--- a/src/main/scala/net/psforever/actors/session/csr/AvatarHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/csr/AvatarHandlerLogic.scala
@@ -1,6 +1,7 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.csr
+import akka.actor.Actor.Receive
import akka.actor.{ActorContext, typed}
import net.psforever.actors.session.SessionActor
import net.psforever.actors.session.normal.NormalMode
@@ -12,7 +13,9 @@ import net.psforever.objects.serverobject.containable.ContainableBehavior
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.vital.RevivingActivity
import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction}
-import net.psforever.services.avatar.AvatarServiceResponse
+import net.psforever.services.avatar.{AvatarAction, AvatarStamp}
+import net.psforever.services.base.envelope.GenericResponseEnvelope
+import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, ReloadTool, WeaponDryFire}
import net.psforever.types.ImplantType
//
@@ -25,9 +28,7 @@ import net.psforever.objects.inventory.InventoryItem
import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
import net.psforever.objects.zones.Zoning
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
-import net.psforever.packet.game.{ArmorChangedMessage, ChangeAmmoMessage, ChangeFireModeMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, DestroyMessage, DrowningTarget, GenericActionMessage, GenericObjectActionMessage, HitHint, ItemTransactionResultMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectHeldMessage, OxygenStateMessage, PlanetsideAttributeMessage, PlayerStateMessage, ProjectileStateMessage, ReloadMessage, SetEmpireMessage, UseItemMessage, WeaponDryFireMessage}
-import net.psforever.services.avatar.AvatarResponse
-import net.psforever.services.Service
+import net.psforever.packet.game.{ArmorChangedMessage, ChangeAmmoMessage, ChangeFireModeMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, DestroyMessage, DrowningTarget, GenericActionMessage, GenericObjectActionMessage, ItemTransactionResultMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectHeldMessage, OxygenStateMessage, PlanetsideAttributeMessage, PlayerStateMessage, ProjectileStateMessage, ReloadMessage, UseItemMessage, WeaponDryFireMessage}
import net.psforever.types.{ChatMessageType, PlanetSideGUID, TransactionType, Vector3}
import net.psforever.util.Config
@@ -42,547 +43,496 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
private val avatarActor: typed.ActorRef[AvatarActor.Command] = ops.avatarActor
- /**
- * na
- * @param toChannel na
- * @param guid na
- * @param reply na
- */
- def handle(toChannel: String, guid: PlanetSideGUID, reply: AvatarResponse.Response): Unit = {
- val resolvedPlayerGuid = if (player != null && player.HasGUID) {
- player.GUID
- } else {
- Service.defaultPlayerGUID
- }
- val isNotSameTarget = resolvedPlayerGuid != guid
- val isSameTarget = !isNotSameTarget
- reply match {
- /* special messages */
- case AvatarResponse.TeardownConnection() if player.spectator =>
- context.self ! SessionActor.SetMode(CustomerServiceRepresentativeMode)
- context.self.forward(AvatarServiceResponse(toChannel, guid, reply))
+ def receive: Receive = {
+ /* special messages */
+ case AvatarAction.TeardownConnection
+ if TestFilter(() => { player.spectator }) =>
+ context.self ! SessionActor.SetMode(CustomerServiceRepresentativeMode)
+ context.self.forward(GenericResponseEnvelope(AvatarStamp, "", FilterGuid, AvatarAction.TeardownConnection))
- case AvatarResponse.TeardownConnection() =>
- context.self ! SessionActor.SetMode(NormalMode)
- context.self.forward(AvatarServiceResponse(toChannel, guid, reply))
+ case AvatarAction.TeardownConnection =>
+ context.self ! SessionActor.SetMode(NormalMode)
+ context.self.forward(GenericResponseEnvelope(AvatarStamp, "", FilterGuid, AvatarAction.TeardownConnection))
- /* really common messages (very frequently, every life) */
- case pstate @ AvatarResponse.PlayerState(
- pos,
- vel,
- yaw,
- pitch,
- yawUpper,
- _,
- isCrouching,
- isJumping,
- jumpThrust,
- isCloaking,
- isNotRendered,
- canSeeReallyFar
- ) if isNotSameTarget =>
- val pstateToSave = pstate.copy(timestamp = 0)
- val (lastMsg, lastTime, lastPosition, wasVisible, wasShooting) = ops.lastSeenStreamMessage.get(guid.guid) match {
- case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, shooting, time)) => (Some(msg), time, msg.pos, visible, shooting)
- case _ => (None, 0L, Vector3.Zero, false, None)
- }
- val drawConfig = Config.app.game.playerDraw //m
- val maxRange = drawConfig.rangeMax * drawConfig.rangeMax //sq.m
- val ourPosition = player.Position //xyz
- val currentDistance = Vector3.DistanceSquared(ourPosition, pos) //sq.m
- val inDrawableRange = currentDistance <= maxRange
- val now = System.currentTimeMillis() //ms
- if (
- sessionLogic.zoning.zoningStatus != Zoning.Status.Deconstructing &&
- !isNotRendered && inDrawableRange
+ /* really common messages (very frequently, every life) */
+ case pstate @ AvatarAction.PlayerState(
+ pos,
+ vel,
+ yaw,
+ pitch,
+ yawUpper,
+ _,
+ isCrouching,
+ isJumping,
+ jumpThrust,
+ isCloaking,
+ isNotRendered,
+ canSeeReallyFar
+ ) if TestFilter(NotSameTargetTest) =>
+ val pstateToSave = pstate.copy(timestamp = 0)
+ val (lastMsg, lastTime, lastPosition, wasVisible, wasShooting) = ops.lastSeenStreamMessage.get(FilterGuid.guid) match {
+ case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, shooting, time)) => (Some(msg), time, msg.pos, visible, shooting)
+ case _ => (None, 0L, Vector3.Zero, false, None)
+ }
+ val drawConfig = Config.app.game.playerDraw //m
+ val maxRange = drawConfig.rangeMax * drawConfig.rangeMax //sq.m
+ val ourPosition = player.Position //xyz
+ val currentDistance = Vector3.DistanceSquared(ourPosition, pos) //sq.m
+ val inDrawableRange = currentDistance <= maxRange
+ val now = System.currentTimeMillis() //ms
+ if (
+ sessionLogic.zoning.zoningStatus != Zoning.Status.Deconstructing &&
+ !isNotRendered && inDrawableRange
+ ) {
+ //conditions where visibility is assured
+ val durationSince = now - lastTime //ms
+ lazy val previouslyInDrawableRange = Vector3.DistanceSquared(ourPosition, lastPosition) <= maxRange
+ lazy val targetDelay = {
+ val populationOver = math.max(
+ 0,
+ sessionLogic.localSector.livePlayerList.size - drawConfig.populationThreshold
+ )
+ val distanceAdjustment = math.pow(populationOver / drawConfig.populationStep * drawConfig.rangeStep, 2) //sq.m
+ val adjustedDistance = currentDistance + distanceAdjustment //sq.m
+ drawConfig.ranges.lastIndexWhere { dist => adjustedDistance > dist * dist } match {
+ case -1 => 1
+ case index => drawConfig.delays(index)
+ }
+ } //ms
+ if (!wasVisible ||
+ !previouslyInDrawableRange ||
+ durationSince > drawConfig.delayMax ||
+ (!lastMsg.contains(pstateToSave) &&
+ (canSeeReallyFar ||
+ currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
+ sessionLogic.general.canSeeReallyFar ||
+ durationSince > targetDelay
+ )
+ )
) {
- //conditions where visibility is assured
- val durationSince = now - lastTime //ms
- lazy val previouslyInDrawableRange = Vector3.DistanceSquared(ourPosition, lastPosition) <= maxRange
- lazy val targetDelay = {
- val populationOver = math.max(
- 0,
- sessionLogic.localSector.livePlayerList.size - drawConfig.populationThreshold
+ //must draw
+ sendResponse(
+ PlayerStateMessage(
+ FilterGuid,
+ pos,
+ vel,
+ yaw,
+ pitch,
+ yawUpper,
+ timestamp = 0, //is this okay?
+ isCrouching,
+ isJumping,
+ jumpThrust,
+ isCloaking
)
- val distanceAdjustment = math.pow(populationOver / drawConfig.populationStep * drawConfig.rangeStep, 2) //sq.m
- val adjustedDistance = currentDistance + distanceAdjustment //sq.m
- drawConfig.ranges.lastIndexWhere { dist => adjustedDistance > dist * dist } match {
- case -1 => 1
- case index => drawConfig.delays(index)
- }
- } //ms
- if (!wasVisible ||
- !previouslyInDrawableRange ||
- durationSince > drawConfig.delayMax ||
- (!lastMsg.contains(pstateToSave) &&
- (canSeeReallyFar ||
- currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
- sessionLogic.general.canSeeReallyFar ||
- durationSince > targetDelay
- )
- )
- ) {
- //must draw
- sendResponse(
- PlayerStateMessage(
- guid,
- pos,
- vel,
- yaw,
- pitch,
- yawUpper,
- timestamp = 0, //is this okay?
- isCrouching,
- isJumping,
- jumpThrust,
- isCloaking
- )
- )
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, now))
- } else {
- //is visible, but skip reinforcement
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, lastTime))
- }
+ )
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, now))
} else {
- //conditions where the target is not currently visible
- if (wasVisible) {
- //the target was JUST PREVIOUSLY visible; one last draw to move target beyond a renderable distance
- val lat = (1 + ops.hidingPlayerRandomizer.nextInt(continent.map.scale.height.toInt)).toFloat
- sendResponse(
- PlayerStateMessage(
- guid,
- Vector3(1f, lat, 1f),
- vel=None,
- facingYaw=0f,
- facingPitch=0f,
- facingYawUpper=0f,
- timestamp=0, //is this okay?
- is_cloaked = isCloaking
- )
+ //is visible, but skip reinforcement
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, lastTime))
+ }
+ } else {
+ //conditions where the target is not currently visible
+ if (wasVisible) {
+ //the target was JUST PREVIOUSLY visible; one last draw to move target beyond a renderable distance
+ val lat = (1 + ops.hidingPlayerRandomizer.nextInt(continent.map.scale.height.toInt)).toFloat
+ sendResponse(
+ PlayerStateMessage(
+ FilterGuid,
+ Vector3(1f, lat, 1f),
+ vel=None,
+ facingYaw=0f,
+ facingPitch=0f,
+ facingYawUpper=0f,
+ timestamp=0, //is this okay?
+ is_cloaked = isCloaking
)
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, now))
- } else {
- //skip drawing altogether
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, lastTime))
- }
+ )
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, now))
+ } else {
+ //skip drawing altogether
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, lastTime))
+ }
+ }
+
+ case AvatarAction.AvatarImplant(ImplantAction.Add, implant_slot, value)
+ if TestFilter(() => { value == ImplantType.SecondWind.value }) =>
+ sendResponse(AvatarImplantMessage(ResolvedGuid, ImplantAction.Add, implant_slot, 7))
+ //second wind does not normally load its icon into the shortcut hotbar
+ avatar
+ .shortcuts
+ .zipWithIndex
+ .find { case (s, _) => s.isEmpty}
+ .foreach { case (_, index) =>
+ sendResponse(CreateShortcutMessage(ResolvedGuid, index + 1, Some(ImplantType.SecondWind.shortcut)))
}
- case AvatarResponse.AvatarImplant(ImplantAction.Add, implant_slot, value)
- if value == ImplantType.SecondWind.value =>
- sendResponse(AvatarImplantMessage(resolvedPlayerGuid, ImplantAction.Add, implant_slot, 7))
- //second wind does not normally load its icon into the shortcut hotbar
- avatar
- .shortcuts
- .zipWithIndex
- .find { case (s, _) => s.isEmpty}
- .foreach { case (_, index) =>
- sendResponse(CreateShortcutMessage(resolvedPlayerGuid, index + 1, Some(ImplantType.SecondWind.shortcut)))
- }
-
- case AvatarResponse.AvatarImplant(ImplantAction.Remove, implant_slot, value)
- if value == ImplantType.SecondWind.value =>
- sendResponse(AvatarImplantMessage(resolvedPlayerGuid, ImplantAction.Remove, implant_slot, value))
- //second wind does not normally unload its icon from the shortcut hotbar
- val shortcut = {
- val imp = ImplantType.SecondWind.shortcut
- net.psforever.objects.avatar.Shortcut(imp.code, imp.tile) //case class
- }
- avatar
- .shortcuts
- .zipWithIndex
- .find { case (s, _) => s.contains(shortcut) }
- .foreach { case (_, index) =>
- sendResponse(CreateShortcutMessage(resolvedPlayerGuid, index + 1, None))
- }
-
- case AvatarResponse.AvatarImplant(action, implant_slot, value) =>
- sendResponse(AvatarImplantMessage(resolvedPlayerGuid, action, implant_slot, value))
-
- case AvatarResponse.ObjectHeld(slot, _)
- if isSameTarget && player.VisibleSlots.contains(slot) =>
- sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
- //Stop using proximity terminals if player unholsters a weapon
- continent.GUID(sessionLogic.terminals.usingMedicalTerminal).collect {
- case term: Terminal with ProximityUnit => sessionLogic.terminals.StopUsingProximityUnit(term)
- }
- if (sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing) {
- sessionLogic.zoning.spawn.stopDeconstructing()
+ case AvatarAction.AvatarImplant(ImplantAction.Remove, implant_slot, value)
+ if TestFilter(() => { value == ImplantType.SecondWind.value }) =>
+ sendResponse(AvatarImplantMessage(ResolvedGuid, ImplantAction.Remove, implant_slot, value))
+ //second wind does not normally unload its icon from the shortcut hotbar
+ val shortcut = {
+ val imp = ImplantType.SecondWind.shortcut
+ net.psforever.objects.avatar.Shortcut(imp.code, imp.tile) //case class
+ }
+ avatar
+ .shortcuts
+ .zipWithIndex
+ .find { case (s, _) => s.contains(shortcut) }
+ .foreach { case (_, index) =>
+ sendResponse(CreateShortcutMessage(ResolvedGuid, index + 1, None))
}
- case AvatarResponse.ObjectHeld(slot, _)
- if isSameTarget && slot > -1 =>
- sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
+ case AvatarAction.AvatarImplant(action, implant_slot, value) =>
+ sendResponse(AvatarImplantMessage(ResolvedGuid, action, implant_slot, value))
- case AvatarResponse.ObjectHeld(_, _)
- if isSameTarget => ()
+ case AvatarAction.ObjectHeld(slot, _)
+ if TestFilter(() => { SameTarget && player.VisibleSlots.contains(slot) }) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, slot, unk1=true))
+ //Stop using proximity terminals if player unholsters a weapon
+ continent.GUID(sessionLogic.terminals.usingMedicalTerminal).collect {
+ case term: Terminal with ProximityUnit => sessionLogic.terminals.StopUsingProximityUnit(term)
+ }
+ if (sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing) {
+ sessionLogic.zoning.spawn.stopDeconstructing()
+ }
- case AvatarResponse.ObjectHeld(_, previousSlot) =>
- sendResponse(ObjectHeldMessage(guid, previousSlot, unk1=false))
+ case AvatarAction.ObjectHeld(slot, _)
+ if TestFilter(() => {SameTarget && slot > -1 }) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, slot, unk1=true))
- case AvatarResponse.ChangeFireState_Start(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- sendResponse(ChangeFireStateMessage_Start(weaponGuid))
- val entry = ops.lastSeenStreamMessage(guid.guid)
- ops.lastSeenStreamMessage.put(guid.guid, entry.copy(shooting = Some(weaponGuid)))
+ case AvatarAction.ObjectHeld(_, _)
+ if TestFilter(SameTargetTest) => ()
- case AvatarResponse.ChangeFireState_Start(weaponGuid)
- if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Start(weaponGuid))
+ case AvatarAction.ObjectHeld(_, previousSlot) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, previousSlot, unk1=false))
- case AvatarResponse.ChangeFireState_Stop(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { msg => msg.visible || msg.shooting.nonEmpty } =>
- sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
- val entry = ops.lastSeenStreamMessage(guid.guid)
- ops.lastSeenStreamMessage.put(guid.guid, entry.copy(shooting = None))
+ case ChangeFireState_Start(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible } }) =>
+ sendResponse(ChangeFireStateMessage_Start(weaponGuid))
+ val entry = ops.lastSeenStreamMessage(FilterGuid.guid)
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, entry.copy(shooting = Some(weaponGuid)))
- case AvatarResponse.ChangeFireState_Stop(weaponGuid)
- if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
+ case ChangeFireState_Stop(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { msg => msg.visible || msg.shooting.nonEmpty } }) =>
+ sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
+ val entry = ops.lastSeenStreamMessage(FilterGuid.guid)
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, entry.copy(shooting = None))
- case AvatarResponse.LoadPlayer(pkt) if isNotSameTarget =>
- sendResponse(pkt)
+ case AvatarAction.LoadCreatedPlayer(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
- case AvatarResponse.EquipmentInHand(pkt) if isNotSameTarget =>
- sendResponse(pkt)
+ case AvatarAction.EquipmentCreatedInHand(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
- case AvatarResponse.PlanetsideAttribute(attributeType, attributeValue) if isNotSameTarget =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
+ case AvatarAction.Destroy(victim, killer, weapon, pos) =>
+ // guid = victim // killer = killer
+ sendResponse(DestroyMessage(victim, killer, weapon, pos))
- case AvatarResponse.PlanetsideAttributeToAll(attributeType, attributeValue) =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
+ case AvatarAction.DestroyDisplay(killer, victim, method, unk) =>
+ sendResponse(ops.destroyDisplayMessage(killer, victim, method, unk))
- case AvatarResponse.PlanetsideAttributeSelf(attributeType, attributeValue) if isSameTarget =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
+ case AvatarAction.TerminalOrderResult(terminalGuid, action, result)
+ if TestFilter(() => { result && (action == TransactionType.Buy || action == TransactionType.Loadout) }) =>
+ sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
+ sessionLogic.terminals.lastTerminalOrderFulfillment = true
+ AvatarActor.savePlayerData(player)
- case AvatarResponse.GenericObjectAction(objectGuid, actionCode) if isNotSameTarget =>
- sendResponse(GenericObjectActionMessage(objectGuid, actionCode))
+ case AvatarAction.TerminalOrderResult(terminalGuid, action, result) =>
+ sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
+ sessionLogic.terminals.lastTerminalOrderFulfillment = true
- case AvatarResponse.HitHint(sourceGuid) if player.isAlive =>
- sendResponse(HitHint(sourceGuid, guid))
- sessionLogic.zoning.CancelZoningProcess()
-
- case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
- // guid = victim // killer = killer
- sendResponse(DestroyMessage(victim, killer, weapon, pos))
-
- case AvatarResponse.DestroyDisplay(killer, victim, method, unk) =>
- sendResponse(ops.destroyDisplayMessage(killer, victim, method, unk))
-
- case AvatarResponse.TerminalOrderResult(terminalGuid, action, result)
- if result && (action == TransactionType.Buy || action == TransactionType.Loadout) =>
- sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
- sessionLogic.terminals.lastTerminalOrderFulfillment = true
- AvatarActor.savePlayerData(player)
-
- case AvatarResponse.TerminalOrderResult(terminalGuid, action, result) =>
- sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
- sessionLogic.terminals.lastTerminalOrderFulfillment = true
-
- case AvatarResponse.ChangeExosuit(
- target,
- armor,
- exosuit,
- subtype,
- _,
- maxhand,
- oldHolsters,
- holsters,
- oldInventory,
- inventory,
- drop,
- delete
- ) if resolvedPlayerGuid == target =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to this player
- //cleanup
- sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=false))
- (oldHolsters ++ oldInventory ++ delete).foreach {
- case (_, dguid) => sendResponse(ObjectDeleteMessage(dguid, unk1=0))
- }
- //functionally delete
- delete.foreach { case (obj, _) => TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj)) }
- //redraw
- if (maxhand) {
- TaskWorkflow.execute(HoldNewEquipmentUp(player)(
- Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)),
- 0
- ))
- }
- //draw free hand
- player.FreeHand.Equipment.foreach { obj =>
+ case AvatarAction.ChangeExosuit(
+ target,
+ armor,
+ exosuit,
+ subtype,
+ _,
+ maxhand,
+ oldHolsters,
+ holsters,
+ oldInventory,
+ inventory,
+ drop,
+ delete
+ ) if TestFilter(() => {ResolvedGuid == target }) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to this player
+ //cleanup
+ sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=false))
+ (oldHolsters ++ oldInventory ++ delete).foreach {
+ case (_, dguid) => sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+ }
+ //functionally delete
+ delete.foreach { case (obj, _) => TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj)) }
+ //redraw
+ if (maxhand) {
+ TaskWorkflow.execute(HoldNewEquipmentUp(player)(
+ Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)),
+ 0
+ ))
+ }
+ //draw free hand
+ player.FreeHand.Equipment.foreach { obj =>
+ val definition = obj.Definition
+ sendResponse(
+ ObjectCreateDetailedMessage(
+ definition.ObjectId,
+ obj.GUID,
+ ObjectCreateMessageParent(target, Player.FreeHandSlot),
+ definition.Packet.DetailedConstructorData(obj).get
+ )
+ )
+ }
+ //draw holsters and inventory
+ (holsters ++ inventory).foreach {
+ case InventoryItem(obj, index) =>
val definition = obj.Definition
sendResponse(
ObjectCreateDetailedMessage(
definition.ObjectId,
obj.GUID,
- ObjectCreateMessageParent(target, Player.FreeHandSlot),
+ ObjectCreateMessageParent(target, index),
definition.Packet.DetailedConstructorData(obj).get
)
)
- }
- //draw holsters and inventory
- (holsters ++ inventory).foreach {
- case InventoryItem(obj, index) =>
- val definition = obj.Definition
- sendResponse(
- ObjectCreateDetailedMessage(
- definition.ObjectId,
- obj.GUID,
- ObjectCreateMessageParent(target, index),
- definition.Packet.DetailedConstructorData(obj).get
- )
+ }
+ DropLeftovers(player)(drop)
+
+ case AvatarAction.ChangeExosuit(target, armor, exosuit, subtype, slot, _, oldHolsters, holsters, _, _, drop, delete) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to some other player
+ sendResponse(ObjectHeldMessage(target, slot, unk1 = false))
+ //cleanup
+ val dropPred = ContainableBehavior.DropPredicate(player)
+ val deleteFromDrop = drop.filterNot(dropPred)
+ (oldHolsters ++ delete ++ deleteFromDrop.map(f =>(f.obj, f.GUID)))
+ .distinctBy(_._2)
+ .foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
+ //draw holsters
+ holsters.foreach {
+ case InventoryItem(obj, index) =>
+ val definition = obj.Definition
+ sendResponse(
+ ObjectCreateMessage(
+ definition.ObjectId,
+ obj.GUID,
+ ObjectCreateMessageParent(target, index),
+ definition.Packet.ConstructorData(obj).get
)
- }
- DropLeftovers(player)(drop)
-
- case AvatarResponse.ChangeExosuit(target, armor, exosuit, subtype, slot, _, oldHolsters, holsters, _, _, drop, delete) =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to some other player
- sendResponse(ObjectHeldMessage(target, slot, unk1 = false))
- //cleanup
- val dropPred = ContainableBehavior.DropPredicate(player)
- val deleteFromDrop = drop.filterNot(dropPred)
- (oldHolsters ++ delete ++ deleteFromDrop.map(f =>(f.obj, f.GUID)))
- .distinctBy(_._2)
- .foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
- //draw holsters
- holsters.foreach {
- case InventoryItem(obj, index) =>
- val definition = obj.Definition
- sendResponse(
- ObjectCreateMessage(
- definition.ObjectId,
- obj.GUID,
- ObjectCreateMessageParent(target, index),
- definition.Packet.ConstructorData(obj).get
- )
- )
- }
-
- case AvatarResponse.ChangeLoadout(
- target,
- armor,
- exosuit,
- subtype,
- _,
- maxhand,
- oldHolsters,
- holsters,
- oldInventory,
- inventory,
- drops
- ) if resolvedPlayerGuid == target =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to this player
- sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=true))
- //cleanup
- (oldHolsters ++ oldInventory).foreach {
- case (obj, objGuid) =>
- sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
- TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
- }
- drops.foreach(item => sendResponse(ObjectDeleteMessage(item.obj.GUID, unk1=0)))
- //redraw
- if (maxhand) {
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=7, player.Capacitor.toLong))
- TaskWorkflow.execute(HoldNewEquipmentUp(player)(
- Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)),
- slot = 0
- ))
- }
- (holsters ++ inventory).foreach { case InventoryItem(item, slot) =>
- TaskWorkflow.execute(PutLoadoutEquipmentInInventory(player)(item, slot))
- }
- DropLeftovers(player)(drops)
-
- case AvatarResponse.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
- //redraw handled by callbacks
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to some other player
- sendResponse(ObjectHeldMessage(target, slot, unk1=false))
- //cleanup
- oldHolsters.foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
-
- case AvatarResponse.UseKit(kguid, kObjId) =>
- sendResponse(
- UseItemMessage(
- resolvedPlayerGuid,
- kguid,
- resolvedPlayerGuid,
- unk2 = 4294967295L,
- unk3 = false,
- unk4 = Vector3.Zero,
- unk5 = Vector3.Zero,
- unk6 = 126,
- unk7 = 0, //sequence time?
- unk8 = 137,
- kObjId
)
- )
- sendResponse(ObjectDeleteMessage(kguid, unk1=0))
+ }
- case AvatarResponse.KitNotUsed(_, "") =>
- sessionLogic.general.kitToBeUsed = None
-
- case AvatarResponse.KitNotUsed(_, msg) =>
- sessionLogic.general.kitToBeUsed = None
- sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
-
- case AvatarResponse.SendResponse(msg) =>
- sendResponse(msg)
-
- case AvatarResponse.SendResponseTargeted(targetGuid, msg) if resolvedPlayerGuid == targetGuid =>
- sendResponse(msg)
-
- /* common messages (maybe once every respawn) */
- case AvatarResponse.Reload(itemGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
-
- case AvatarResponse.Killed(_, mount) =>
- //pure logic
- sessionLogic.shooting.shotsWhileDead = 0
- sessionLogic.zoning.CancelZoningProcess()
- sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
- sessionLogic.zoning.zoningStatus = Zoning.Status.None
- continent.GUID(mount).collect {
- case obj: Vehicle if obj.Destroyed =>
- ops.killedWhileMounted(obj, resolvedPlayerGuid)
- sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
- sessionLogic.general.unaccessContainer(obj)
-
- case obj: Vehicle =>
- ops.killedWhileMounted(obj, resolvedPlayerGuid)
- sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
-
- case obj: PlanetSideGameObject with Mountable with Container if obj.Destroyed =>
- ops.killedWhileMounted(obj, resolvedPlayerGuid)
- sessionLogic.general.unaccessContainer(obj)
-
- case obj: PlanetSideGameObject with Mountable with Container =>
- ops.killedWhileMounted(obj, resolvedPlayerGuid)
-
- case obj: PlanetSideGameObject with Mountable =>
- ops.killedWhileMounted(obj, resolvedPlayerGuid)
- }
- //player state changes
- sessionLogic.general.dropSpecialSlotItem()
- sessionLogic.general.toggleMaxSpecialState(enable = false)
- player.FreeHand.Equipment.foreach(DropEquipmentFromInventory(player)(_))
- AvatarActor.updateToolDischargeFor(avatar)
- AvatarActor.savePlayerLocation(player)
- ops.revive()
- avatarActor ! AvatarActor.InitializeImplants
- //render
- CustomerServiceRepresentativeMode.renderPlayer(sessionLogic, continent, player)
-
- case AvatarResponse.Release(tplayer) if isNotSameTarget =>
- sessionLogic.zoning.spawn.DepictPlayerAsCorpse(tplayer)
-
- case AvatarResponse.Revive(revivalTargetGuid)
- if resolvedPlayerGuid == revivalTargetGuid =>
- ops.revive()
- player.Actor ! Player.Revive
- player.History
- .findLast { _.isInstanceOf[RevivingActivity] }
- .map {
- case activity: RevivingActivity
- if System.currentTimeMillis() - activity.time < 5000L =>
- val reviveMessage = s"@YouHaveBeenMessage^revived~^${activity.user.unique.name}~"
- sendResponse(ChatMsg(ChatMessageType.UNK_227, reviveMessage))
- None
- }
-
- /* uncommon messages (utility, or once in a while) */
- case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- ops.changeAmmoProcedures(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
- sendResponse(ChangeAmmoMessage(weapon_guid, 1))
-
- case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
- if isNotSameTarget =>
- ops.changeAmmoProcedures(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
-
- case AvatarResponse.ChangeFireMode(itemGuid, mode) if isNotSameTarget =>
- sendResponse(ChangeFireModeMessage(itemGuid, mode))
-
- case AvatarResponse.ConcealPlayer() =>
- sendResponse(GenericObjectActionMessage(guid, code=9))
-
- case AvatarResponse.EnvironmentalDamage(_, _, _) =>
- //TODO damage marker?
- sessionLogic.zoning.CancelZoningProcess()
-
- case AvatarResponse.DropItem(pkt) if isNotSameTarget =>
- sendResponse(pkt)
-
- case AvatarResponse.ObjectDelete(itemGuid, unk) if isNotSameTarget =>
- sendResponse(ObjectDeleteMessage(itemGuid, unk))
-
- /* rare messages */
- case AvatarResponse.SetEmpire(objectGuid, faction) if isNotSameTarget =>
- sendResponse(SetEmpireMessage(objectGuid, faction))
-
- case AvatarResponse.DropSpecialItem() =>
- sessionLogic.general.dropSpecialSlotItem()
-
- case AvatarResponse.OxygenState(player, vehicle) =>
- sendResponse(OxygenStateMessage(
- DrowningTarget(player.guid, player.progress, player.state),
- vehicle.flatMap { vinfo => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) }
+ case AvatarAction.ChangeLoadout(
+ target,
+ armor,
+ exosuit,
+ subtype,
+ _,
+ maxhand,
+ oldHolsters,
+ holsters,
+ oldInventory,
+ inventory,
+ drops
+ ) if TestFilter(() => { ResolvedGuid == target }) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to this player
+ sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=true))
+ //cleanup
+ (oldHolsters ++ oldInventory).foreach {
+ case (obj, objGuid) =>
+ sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
+ TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
+ }
+ drops.foreach(item => sendResponse(ObjectDeleteMessage(item.obj.GUID, unk1=0)))
+ //redraw
+ if (maxhand) {
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=7, player.Capacitor.toLong))
+ TaskWorkflow.execute(HoldNewEquipmentUp(player)(
+ Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)),
+ slot = 0
))
+ }
+ (holsters ++ inventory).foreach { case InventoryItem(item, slot) =>
+ TaskWorkflow.execute(PutLoadoutEquipmentInInventory(player)(item, slot))
+ }
+ DropLeftovers(player)(drops)
- case AvatarResponse.LoadProjectile(pkt) if isNotSameTarget =>
- sendResponse(pkt)
+ case AvatarAction.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
+ //redraw handled by callbacks
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to some other player
+ sendResponse(ObjectHeldMessage(target, slot, unk1=false))
+ //cleanup
+ oldHolsters.foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
- case AvatarResponse.ProjectileState(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid) if isNotSameTarget =>
- sendResponse(ProjectileStateMessage(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid))
-
- case AvatarResponse.ProjectileExplodes(projectileGuid, projectile) =>
- sendResponse(
- ProjectileStateMessage(
- projectileGuid,
- projectile.Position,
- shot_vel = Vector3.Zero,
- projectile.Orientation,
- sequence_num=0,
- end=true,
- hit_target_guid=PlanetSideGUID(0)
- )
+ case AvatarAction.UseKit(kguid, kObjId) =>
+ sendResponse(
+ UseItemMessage(
+ ResolvedGuid,
+ kguid,
+ ResolvedGuid,
+ unk2 = 4294967295L,
+ unk3 = false,
+ unk4 = Vector3.Zero,
+ unk5 = Vector3.Zero,
+ unk6 = 126,
+ unk7 = 0, //sequence time?
+ unk8 = 137,
+ kObjId
)
- sendResponse(ObjectDeleteMessage(projectileGuid, unk1=2))
+ )
+ sendResponse(ObjectDeleteMessage(kguid, unk1=0))
- case AvatarResponse.ProjectileAutoLockAwareness(mode) =>
- sendResponse(GenericActionMessage(mode))
+ case AvatarAction.KitNotUsed(_, "") =>
+ sessionLogic.general.kitToBeUsed = None
- case AvatarResponse.PutDownFDU(target) if isNotSameTarget =>
- sendResponse(GenericObjectActionMessage(target, code=53))
+ case AvatarAction.KitNotUsed(_, msg) =>
+ sessionLogic.general.kitToBeUsed = None
+ sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
- case AvatarResponse.StowEquipment(target, slot, item) if isNotSameTarget =>
- val definition = item.Definition
- sendResponse(
- ObjectCreateDetailedMessage(
- definition.ObjectId,
- item.GUID,
- ObjectCreateMessageParent(target, slot),
- definition.Packet.DetailedConstructorData(item).get
- )
- )
- case AvatarResponse.WeaponDryFire(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- continent.GUID(weaponGuid).collect {
- case tool: Tool if tool.Magazine == 0 =>
- // check that the magazine is still empty before sending WeaponDryFireMessage
- // if it has been reloaded since then, other clients will not see it firing
- sendResponse(WeaponDryFireMessage(weaponGuid))
+ /* common messages (maybe once every respawn) */
+ case ReloadTool(itemGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible } }) =>
+ sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
+
+ case AvatarAction.Killed(_, mount) =>
+ //pure logic
+ sessionLogic.shooting.shotsWhileDead = 0
+ sessionLogic.zoning.CancelZoningProcess()
+ sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
+ sessionLogic.zoning.zoningStatus = Zoning.Status.None
+ continent.GUID(mount).collect {
+ case obj: Vehicle if obj.Destroyed =>
+ ops.killedWhileMounted(obj, ResolvedGuid)
+ sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
+ sessionLogic.general.unaccessContainer(obj)
+
+ case obj: Vehicle =>
+ ops.killedWhileMounted(obj, ResolvedGuid)
+ sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
+
+ case obj: PlanetSideGameObject with Mountable with Container if obj.Destroyed =>
+ ops.killedWhileMounted(obj, ResolvedGuid)
+ sessionLogic.general.unaccessContainer(obj)
+
+ case obj: PlanetSideGameObject with Mountable with Container =>
+ ops.killedWhileMounted(obj, ResolvedGuid)
+
+ case obj: PlanetSideGameObject with Mountable =>
+ ops.killedWhileMounted(obj, ResolvedGuid)
+ }
+ //player state changes
+ sessionLogic.general.dropSpecialSlotItem()
+ sessionLogic.general.toggleMaxSpecialState(enable = false)
+ player.FreeHand.Equipment.foreach(DropEquipmentFromInventory(player)(_))
+ AvatarActor.updateToolDischargeFor(avatar)
+ AvatarActor.savePlayerLocation(player)
+ ops.revive()
+ avatarActor ! AvatarActor.InitializeImplants
+ //render
+ CustomerServiceRepresentativeMode.renderPlayer(sessionLogic, continent, player)
+
+ case AvatarAction.ReleasePlayer(tplayer)
+ if TestFilter(NotSameTargetTest) =>
+ sessionLogic.zoning.spawn.DepictPlayerAsCorpse(tplayer)
+
+ case AvatarAction.Revive(revivalTargetGuid)
+ if TestFilter(() => { ResolvedGuid == revivalTargetGuid }) =>
+ ops.revive()
+ player.Actor ! Player.Revive
+ player.History
+ .findLast { _.isInstanceOf[RevivingActivity] }
+ .map {
+ case activity: RevivingActivity
+ if System.currentTimeMillis() - activity.time < 5000L =>
+ val reviveMessage = s"@YouHaveBeenMessage^revived~^${activity.user.unique.name}~"
+ sendResponse(ChatMsg(ChatMessageType.UNK_227, reviveMessage))
+ None
}
- case _ => ()
- }
+ /* uncommon messages (utility, or once in a while) */
+ case ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
+ if TestFilter(NotSameTargetTest) =>
+ ops.changeAmmoProcedure(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
+ sendResponse(ChangeAmmoMessage(weapon_guid, 1))
+
+ case AvatarAction.ChangeFireMode(itemGuid, mode)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ChangeFireModeMessage(itemGuid, mode))
+
+ case AvatarAction.EnvironmentalDamage(_, _, _) =>
+ //TODO damage marker?
+ sessionLogic.zoning.CancelZoningProcess()
+
+ case AvatarAction.DropCreatedItem(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ /* rare messages */
+ case AvatarAction.DropSpecialItem() =>
+ sessionLogic.general.dropSpecialSlotItem()
+
+ case AvatarAction.OxygenState(player, vehicle) =>
+ sendResponse(OxygenStateMessage(
+ DrowningTarget(player.guid, player.progress, player.state),
+ vehicle.flatMap { vinfo => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) }
+ ))
+
+ case AvatarAction.LoadCreatedProjectile(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ case AvatarAction.ProjectileState(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ProjectileStateMessage(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid))
+
+ case AvatarAction.ProjectileExplodes(projectileGuid, projectile) =>
+ sendResponse(
+ ProjectileStateMessage(
+ projectileGuid,
+ projectile.Position,
+ shot_vel = Vector3.Zero,
+ projectile.Orientation,
+ sequence_num=0,
+ end=true,
+ hit_target_guid=PlanetSideGUID(0)
+ )
+ )
+ sendResponse(ObjectDeleteMessage(projectileGuid, unk1=2))
+
+ case AvatarAction.ProjectileAutoLockAwareness(mode) =>
+ sendResponse(GenericActionMessage(mode))
+
+ case AvatarAction.PutDownFDU(target)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(GenericObjectActionMessage(target, code=53))
+
+ case AvatarAction.StowEquipment(target, slot, item)
+ if TestFilter(NotSameTargetTest) =>
+ val definition = item.Definition
+ sendResponse(
+ ObjectCreateDetailedMessage(
+ definition.ObjectId,
+ item.GUID,
+ ObjectCreateMessageParent(target, slot),
+ definition.Packet.DetailedConstructorData(item).get
+ )
+ )
+
+ case WeaponDryFire(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible } }) =>
+ continent.GUID(weaponGuid).collect {
+ case tool: Tool if tool.Magazine == 0 =>
+ sendResponse(WeaponDryFireMessage(weaponGuid))
+ }
}
}
diff --git a/src/main/scala/net/psforever/actors/session/csr/ChatLogic.scala b/src/main/scala/net/psforever/actors/session/csr/ChatLogic.scala
index 3d5d4c45b..13053039c 100644
--- a/src/main/scala/net/psforever/actors/session/csr/ChatLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/csr/ChatLogic.scala
@@ -16,7 +16,9 @@ import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ChatMsg, SetChatFilterMessage}
import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{ObjectDelete, SetEmpire}
import net.psforever.services.chat.{ChatChannel, DefaultChannel, SpectatorChannel, SquadChannel}
import net.psforever.types.ChatMessageType.{CMT_TOGGLESPECTATORMODE, CMT_TOGGLE_GM}
import net.psforever.types.{ChatMessageType, PlanetSideEmpire}
@@ -312,17 +314,20 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
val events = continent.AvatarEvents
seeSpectatorsIn = Some(continent)
events ! Service.Join(s"spectator")
- continent
- .AllPlayers
- .filter(_.spectator)
- .foreach { spectator =>
- val guid = spectator.GUID
- val definition = spectator.Definition
- events ! AvatarServiceMessage(
- channel,
- AvatarAction.LoadPlayer(guid, definition.ObjectId, guid, definition.Packet.ConstructorData(spectator).get, None)
- )
- }
+ events ! BundledEnvelope(
+ continent
+ .AllPlayers
+ .filter(_.spectator)
+ .map { spectator =>
+ val guid = spectator.GUID
+ val definition = spectator.Definition
+ MessageEnvelope(
+ channel,
+ guid,
+ AvatarAction.LoadPlayer(definition.ObjectId, guid, definition.Packet.ConstructorData(spectator).get, None)
+ )
+ }
+ )
true
}
@@ -330,17 +335,16 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
val channel = player.Name
val events = continent.AvatarEvents
seeSpectatorsIn = None
- events ! Service.Leave(Some("spectator"))
- continent
- .AllPlayers
- .filter(_.spectator)
- .foreach { spectator =>
- val guid = spectator.GUID
- events ! AvatarServiceMessage(
- channel,
- AvatarAction.ObjectDelete(guid, guid)
- )
- }
+ events ! Service.Leave("spectator")
+ events ! BundledEnvelope(
+ continent
+ .AllPlayers
+ .filter(_.spectator)
+ .map { spectator =>
+ val guid = spectator.GUID
+ MessageEnvelope(channel, guid, ObjectDelete(guid))
+ }
+ )
true
}
@@ -392,9 +396,9 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
true
case o: Deployable =>
o.Faction = foundFaction
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.SetEmpire(Service.defaultPlayerGUID, o.GUID, foundFaction)
+ SetEmpire(o.GUID, foundFaction)
)
true
case o: Building =>
@@ -405,9 +409,9 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
true
case o: PlanetSideGameObject with FactionAffinity =>
o.Faction = foundFaction
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.SetEmpire(Service.defaultPlayerGUID, o.GUID, foundFaction)
+ SetEmpire(o.GUID, foundFaction)
)
true
}
@@ -512,7 +516,7 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
.foreach {
case (_, false, _) => ()
case (faction, true, _) =>
- //events ! AvatarServiceMessage(s"$faction", reloadZoneMsg)
+ //events ! MessageEnvelope(s"$faction", reloadZoneMsg)
}
}
}
diff --git a/src/main/scala/net/psforever/actors/session/csr/CustomerServiceRepresentativeMode.scala b/src/main/scala/net/psforever/actors/session/csr/CustomerServiceRepresentativeMode.scala
index 0e454f71b..0ab1782fc 100644
--- a/src/main/scala/net/psforever/actors/session/csr/CustomerServiceRepresentativeMode.scala
+++ b/src/main/scala/net/psforever/actors/session/csr/CustomerServiceRepresentativeMode.scala
@@ -10,9 +10,10 @@ import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ChatMsg, ObjectCreateDetailedMessage, PlanetsideAttributeMessage}
import net.psforever.packet.game.objectcreate.RibbonBars
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.chat.{CustomerServiceChannel, SpectatorChannel}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.{ChatMessageType, MeritCommendation, PlanetSideGUID}
class CustomerServiceRepresentativeMode(data: SessionData) extends ModeLogic {
@@ -120,6 +121,10 @@ class CustomerServiceRepresentativeMode(data: SessionData) extends ModeLogic {
.GUID(player.VehicleSeated)
.collect { case obj: PlanetSideGameObject with Vitality =>
CustomerServiceRepresentativeMode.topOffHealth(data, obj)
+ obj
+ }
+ .getOrElse {
+ data.updateBlockMap(player, player.Position)
}
data.squad.updateSquad()
} else {
@@ -144,13 +149,16 @@ case object CustomerServiceRepresentativeMode extends PlayerMode {
packet.DetailedConstructorData(player).get
))
data.zoning.spawn.HandleSetCurrentAvatar(player)
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.LoadPlayer(
+ zone.AvatarEvents ! MessageEnvelope(
+ zone.id,
pguid,
- objectClass,
- pguid,
- packet.ConstructorData(player).get,
- None
- ))
+ AvatarAction.LoadPlayer(
+ objectClass,
+ pguid,
+ packet.ConstructorData(player).get,
+ None
+ )
+ )
}
def topOffHealth(data: SessionData, obj: PlanetSideGameObject with Vitality): Unit = {
@@ -174,14 +182,14 @@ case object CustomerServiceRepresentativeMode extends PlayerMode {
player.Health = maxHealthOfPlayer.toInt
player.LogActivity(player.ClearHistory().head)
data.sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOfPlayer))
- data.continent.AvatarEvents ! AvatarServiceMessage(zoneid, AvatarAction.PlanetsideAttribute(guid, 0, maxHealthOfPlayer))
+ data.continent.AvatarEvents ! MessageEnvelope(zoneid, PlanetsideAttribute(guid, 0, maxHealthOfPlayer))
}
//below half armor, full armor
val maxArmor = player.MaxArmor.toLong
if (player.Armor < maxArmor) {
player.Armor = maxArmor.toInt
data.sendResponse(PlanetsideAttributeMessage(guid, 4, maxArmor))
- data.continent.AvatarEvents ! AvatarServiceMessage(zoneid, AvatarAction.PlanetsideAttribute(guid, 4, maxArmor))
+ data.continent.AvatarEvents ! MessageEnvelope(zoneid, PlanetsideAttribute(guid, 4, maxArmor))
}
}
@@ -194,9 +202,9 @@ case object CustomerServiceRepresentativeMode extends PlayerMode {
val guid = vehicle.GUID
vehicle.Shields = maxShieldsOfVehicle.toInt
data.sendResponse(PlanetsideAttributeMessage(guid, shieldsUi, maxShieldsOfVehicle))
- data.continent.VehicleEvents ! VehicleServiceMessage(
+ data.continent.VehicleEvents ! MessageEnvelope(
data.continent.id,
- VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), guid, shieldsUi, maxShieldsOfVehicle)
+ PlanetsideAttribute(guid, shieldsUi, maxShieldsOfVehicle)
)
}
}
@@ -208,9 +216,9 @@ case object CustomerServiceRepresentativeMode extends PlayerMode {
if (obj.Health < maxHealthOf) {
obj.Health = maxHealthOf.toInt
data.sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOf))
- data.continent.VehicleEvents ! VehicleServiceMessage(
+ data.continent.VehicleEvents ! MessageEnvelope(
data.continent.id,
- VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), guid, 0, maxHealthOf)
+ PlanetsideAttribute(guid, 0, maxHealthOf)
)
}
}
diff --git a/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala
index 4f168065b..b795a07b4 100644
--- a/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/csr/GeneralLogic.scala
@@ -33,9 +33,11 @@ import net.psforever.objects.zones.{ZoneProjectile, Zoning}
import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.OutfitEventAction.{Initial, OutfitInfo, OutfitRankNames, Unk1}
import net.psforever.packet.game.{ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitEvent, OutfitMemberEvent, OutfitMembershipRequest, OutfitMembershipResponse, OutfitRequest, OutfitRequestAction, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage}
-import net.psforever.services.RemoverActor
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.avatar.support.CorpseEnvelope
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
+import net.psforever.services.base.support.RemoverActor
import net.psforever.types.{CapacitorStateType, ChatMessageType, Cosmetic, ExoSuitType, PlanetSideEmpire, PlanetSideGUID, Vector3}
import scala.concurrent.duration._
@@ -132,10 +134,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
val eagleEye: Boolean = ops.canSeeReallyFar
val isNotVisible: Boolean = sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
(player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime)
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
channel,
+ avatarGuid,
AvatarAction.PlayerState(
- avatarGuid,
player.Position,
player.Velocity,
yaw,
@@ -163,15 +165,8 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
}
def handleEmote(pkt: EmoteMsg): Unit = {
- val EmoteMsg(avatarGuid, emote) = pkt
- val pZone = player.Zone
- sendResponse(EmoteMsg(avatarGuid, emote))
- pZone.blockMap.sector(player).livePlayerList.collect { case t if t.GUID != player.GUID =>
- pZone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendResponse(EmoteMsg(avatarGuid, emote)))
- }
- pZone.AllPlayers.collect { case t if t.GUID != player.GUID && !t.allowInteraction =>
- pZone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendResponse(EmoteMsg(avatarGuid, emote)))
- }
+ sendResponse(pkt)
+ ops.handleEmote(pkt)
}
def handleDropItem(pkt: DropItemMessage): Unit = {
@@ -239,7 +234,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case Some(obj: Player) if obj.isBackpack =>
obj.Position = Vector3.Zero
- continent.AvatarEvents ! AvatarServiceMessage.Corpse(RemoverActor.ClearSpecific(List(obj), continent))
+ continent.AvatarEvents ! CorpseEnvelope(RemoverActor.ClearSpecific(List(obj), continent))
case Some(obj: Player) =>
sessionLogic.general.suicide(obj)
@@ -439,9 +434,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
ops.dropSpecialSlotItem()
case GenericAction.MaxAnchorsExtend_RCV =>
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.PlanetsideAttribute(player.GUID, 19, 1)
+ player.GUID,
+ PlanetsideAttribute(player.GUID, 19, 1)
)
definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
@@ -459,9 +455,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
}
case GenericAction.MaxAnchorsRelease_RCV =>
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.PlanetsideAttribute(player.GUID, 19, 0)
+ player.GUID,
+ PlanetsideAttribute(player.GUID, 19, 0)
)
definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
diff --git a/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala
index 1965825ab..e7a3b4494 100644
--- a/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/csr/MountHandlerLogic.scala
@@ -7,7 +7,6 @@ import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject, Player, Vehicle, Vehicles}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.environment.interaction.ResetAllEnvironmentInteractions
-import net.psforever.objects.serverobject.hackable.GenericHackables
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.structures.WarpGate
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
@@ -15,9 +14,9 @@ import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
import net.psforever.objects.vehicles.AccessPermissionGroup
import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{ChatMsg, DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlanetsideAttributeMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{SendResponse, SetEmpire}
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3}
object MountHandlerLogic {
@@ -160,7 +159,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
if obj.Definition == GlobalDefinitions.vanu_sentry_turret =>
sessionLogic.zoning.CancelZoningProcess()
- obj.Zone.LocalEvents ! LocalServiceMessage(obj.Zone.id, LocalAction.SetEmpire(obj.GUID, player.Faction))
+ obj.Zone.LocalEvents ! MessageEnvelope(obj.Zone.id, SetEmpire(obj.GUID, player.Faction))
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
ops.updateWeaponAtSeatPosition(obj, seatNumber)
ops.MountingAction(tplayer, obj, seatNumber)
@@ -199,9 +198,9 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
val (pos, zang) = Vehicles.dismountShuttle(obj, mountPoint)
tplayer.Position = pos
sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true))
- continent.LocalEvents ! LocalServiceMessage(
+ continent.LocalEvents ! MessageEnvelope(
continent.id,
- LocalAction.SendResponse(ObjectDetachMessage(sguid, pguid, pos, roll=0, pitch=0, zang))
+ SendResponse(ObjectDetachMessage(sguid, pguid, pos, roll=0, pitch=0, zang))
)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
@@ -213,25 +212,21 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountAction(tplayer, obj, seatNum)
continent.actor ! ZoneActor.RemoveFromBlockMap(player) //character doesn't need it
//DismountAction(...) uses vehicle service, so use that service to coordinate the remainder of the messages
- events ! VehicleServiceMessage(
- player.Name,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, PlayerStasisMessage(pguid)) //the stasis message
- )
//when the player dismounts, they will be positioned where the shuttle was when it disappeared in the sky
//the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone
//having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
- events ! VehicleServiceMessage(
- player.Name,
- VehicleAction.SendResponse(
- Service.defaultPlayerGUID,
- PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)) //cower in the shuttle bay
+ events ! BundledEnvelope(
+ MessageEnvelope(player.Name,
+ SendResponse(Seq(
+ PlayerStasisMessage(pguid),
+ PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
+ ))
+ ),
+ MessageEnvelope(continent.id, pguid,
+ SendResponse(GenericObjectActionMessage(pguid, code=9)) /* conceal the player */
)
)
- events ! VehicleServiceMessage(
- continent.id,
- VehicleAction.SendResponse(pguid, GenericObjectActionMessage(pguid, code=9)) //conceal the player
- )
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
@@ -256,9 +251,10 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountVehicleAction(tplayer, obj, seatNum)
case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.KickPassenger(tplayer.GUID, seat_num, unk2=true, obj.GUID)
+ tplayer.GUID,
+ VehicleAction.KickPassenger(seat_num, unk2=true, obj.GUID)
)
case Mountable.CanDismount(obj: PlanetSideGameObject with PlanetSideGameObject with Mountable with FactionAffinity with InGameHistory, seatNum, _) =>
diff --git a/src/main/scala/net/psforever/actors/session/csr/SpectateAsCustomerServiceRepresentativeMode.scala b/src/main/scala/net/psforever/actors/session/csr/SpectateAsCustomerServiceRepresentativeMode.scala
index 592fbedd5..9e6510812 100644
--- a/src/main/scala/net/psforever/actors/session/csr/SpectateAsCustomerServiceRepresentativeMode.scala
+++ b/src/main/scala/net/psforever/actors/session/csr/SpectateAsCustomerServiceRepresentativeMode.scala
@@ -7,7 +7,9 @@ import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.{Player, Session, Vehicle}
import net.psforever.objects.zones.Zone
import net.psforever.packet.PlanetSidePacket
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.ObjectDelete
import net.psforever.services.chat.SpectatorChannel
import net.psforever.services.teamwork.{SquadAction, SquadServiceMessage}
import net.psforever.types.{ChatMessageType, SquadRequestType}
@@ -45,7 +47,7 @@ class SpectatorCSRModeLogic(data: SessionData) extends ModeLogic {
//
player.spectator = true
data.chat.JoinChannel(SpectatorChannel)
- continent.AvatarEvents ! AvatarServiceMessage(continent.id, AvatarAction.ObjectDelete(pguid, pguid))
+ continent.AvatarEvents ! MessageEnvelope(continent.id, pguid, ObjectDelete(pguid))
sendResponse(ChatMsg(ChatMessageType.CMT_TOGGLESPECTATORMODE, "on"))
sendResponse(ChatMsg(ChatMessageType.UNK_225, "CSR SPECTATOR MODE ON"))
}
@@ -59,9 +61,10 @@ class SpectatorCSRModeLogic(data: SessionData) extends ModeLogic {
//
player.spectator = false
data.chat.LeaveChannel(SpectatorChannel)
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.LoadPlayer(pguid, avatarId, pguid, player.Definition.Packet.ConstructorData(player).get, None)
+ pguid,
+ AvatarAction.LoadPlayer(avatarId, pguid, player.Definition.Packet.ConstructorData(player).get, None)
)
sendResponse(ChatMsg(ChatMessageType.CMT_TOGGLESPECTATORMODE, "off"))
}
diff --git a/src/main/scala/net/psforever/actors/session/csr/VehicleLogic.scala b/src/main/scala/net/psforever/actors/session/csr/VehicleLogic.scala
index 6870f3c12..f49f3ad01 100644
--- a/src/main/scala/net/psforever/actors/session/csr/VehicleLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/csr/VehicleLogic.scala
@@ -12,7 +12,9 @@ import net.psforever.objects.vehicles.control.BfrFlight
import net.psforever.objects.zones.Zone
import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game.{ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.CachedEnvelope
+import net.psforever.services.vehicle.VehicleAction
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{DriveState, Vector3}
object VehicleLogic {
@@ -76,10 +78,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Position = position
obj.Orientation = angle
//
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
+ player.GUID,
VehicleAction.VehicleState(
- player.GUID,
vehicle_guid,
unk1,
position,
@@ -92,7 +94,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
is_decelerating,
obj.Cloaked
)
- )
+ ) //todo CachedMessage
sessionLogic.squad.updateSquad()
case (None, _) =>
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone")
@@ -164,26 +166,11 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Position = position
obj.Orientation = angle
obj.DeploymentState = if (is_crouched || !notMountedState) DriveState.Kneeling else DriveState.Mobile
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.FrameVehicleState(
- player.GUID,
- vehicle_guid,
- unk1,
- position,
- angle,
- velocity,
- unk2,
- unk3,
- unk4,
- is_crouched,
- is_airborne,
- ascending_flight,
- flight_time,
- unk9,
- unkA
- )
- )
+ player.GUID,
+ VehicleAction.FrameVehicleState(vehicle_guid, unk1, position, angle, velocity, unk2, unk3, unk4, is_crouched, is_airborne, ascending_flight, flight_time, unk9, unkA)
+ ) //todo CachedMessage
sessionLogic.squad.updateSquad()
case (None, _) =>
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone")
@@ -234,10 +221,11 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
val angle = Vector3(0f, pitch, yaw)
tool.Orientation = angle
player.Orientation = angle
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.ChildObjectState(player.GUID, object_guid, pitch, yaw)
- )
+ player.GUID,
+ VehicleAction.ChildObjectState(object_guid, pitch, yaw)
+ ) //todo CachedMessage
}
//TODO status condition of "playing getting out of vehicle to allow for late packets without warning
if (player.death_by == -1) {
@@ -256,22 +244,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Velocity = vel
sessionLogic.updateBlockMap(obj, pos)
obj.zoneInteractions()
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! CachedEnvelope(
continent.id,
- VehicleAction.VehicleState(
- player.GUID,
- vehicle_guid,
- unk1,
- pos,
- ang,
- obj.Velocity,
- obj.Flying,
- 0,
- 0,
- 15,
- unk5 = false,
- obj.Cloaked
- )
+ player.GUID,
+ VehicleAction.VehicleState(vehicle_guid, unk1, pos, ang, obj.Velocity, obj.Flying, 0, 0, 15, unk5 = false, obj.Cloaked)
)
}
}
@@ -328,9 +304,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
if (obj.DeploymentState != DriveState.Mobile) {
obj.DeploymentState = DriveState.Mobile
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero))
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.DeployRequest(player.GUID, obj.GUID, DriveState.Mobile, 0, unk2=false, Vector3.Zero)
+ player.GUID,
+ VehicleAction.DeployRequest(obj.GUID, DriveState.Mobile, 0, unk2=false, Vector3.Zero)
)
}
}
diff --git a/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala
index 586391cf8..4c5a324a1 100644
--- a/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala
@@ -1,6 +1,7 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.normal
+import akka.actor.Actor.Receive
import akka.actor.{ActorContext, typed}
import net.psforever.actors.session.support.AvatarHandlerFunctions
import net.psforever.actors.zone.ZoneActor
@@ -12,7 +13,9 @@ import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.vital.RevivingActivity
import net.psforever.objects.vital.interaction.Adversarial
import net.psforever.packet.game.{AvatarImplantMessage, CreateShortcutMessage, ImplantAction, PlanetsideStringAttributeMessage}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, ObjectDelete, PlanetsideAttribute, ReloadTool, WeaponDryFire}
import net.psforever.types.ImplantType
import scala.concurrent.duration._
@@ -28,9 +31,7 @@ import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
import net.psforever.objects.vital.etc.ExplodingEntityReason
import net.psforever.objects.zones.Zoning
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
-import net.psforever.packet.game.{ArmorChangedMessage, AvatarDeadStateMessage, ChangeAmmoMessage, ChangeFireModeMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, DeadState, DestroyMessage, DrowningTarget, GenericActionMessage, GenericObjectActionMessage, HitHint, ItemTransactionResultMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectHeldMessage, OxygenStateMessage, PlanetsideAttributeMessage, PlayerStateMessage, ProjectileStateMessage, ReloadMessage, SetEmpireMessage, UseItemMessage, WeaponDryFireMessage}
-import net.psforever.services.avatar.AvatarResponse
-import net.psforever.services.Service
+import net.psforever.packet.game.{ArmorChangedMessage, AvatarDeadStateMessage, ChangeAmmoMessage, ChangeFireModeMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, DeadState, DestroyMessage, DrowningTarget, GenericActionMessage, GenericObjectActionMessage, ItemTransactionResultMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectHeldMessage, OxygenStateMessage, PlanetsideAttributeMessage, PlayerStateMessage, ProjectileStateMessage, ReloadMessage, UseItemMessage, WeaponDryFireMessage}
import net.psforever.types.{ChatMessageType, PlanetSideGUID, TransactionType, Vector3}
import net.psforever.util.Config
@@ -45,661 +46,609 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
private val avatarActor: typed.ActorRef[AvatarActor.Command] = ops.avatarActor
- /**
- * na
- * @param toChannel na
- * @param guid na
- * @param reply na
- */
- def handle(toChannel: String, guid: PlanetSideGUID, reply: AvatarResponse.Response): Unit = {
- val resolvedPlayerGuid = if (player != null && player.HasGUID) {
- player.GUID
- } else {
- Service.defaultPlayerGUID
- }
- val isNotSameTarget = resolvedPlayerGuid != guid
- val isSameTarget = !isNotSameTarget
- reply match {
- /* special messages */
- case AvatarResponse.TeardownConnection() =>
- log.trace(s"ending ${player.Name}'s old session by event system request (relog)")
- context.stop(context.self)
+ def receive: Receive = {
+ /* special messages */
+ case AvatarAction.TeardownConnection =>
+ log.trace(s"ending ${player.Name}'s old session by event system request (relog)")
+ context.stop(context.self)
- /* really common messages (very frequently, every life) */
- case pstate @ AvatarResponse.PlayerState(
- pos,
- vel,
- yaw,
- pitch,
- yawUpper,
- _,
- isCrouching,
- isJumping,
- jumpThrust,
- isCloaking,
- isNotRendered,
- canSeeReallyFar
- ) if isNotSameTarget =>
- val pstateToSave = pstate.copy(timestamp = 0)
- val (lastMsg, lastTime, lastPosition, wasVisible, wasShooting) = ops.lastSeenStreamMessage.get(guid.guid) match {
- case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, shooting, time)) => (Some(msg), time, msg.pos, visible, shooting)
- case _ => (None, 0L, Vector3.Zero, false, None)
- }
- val drawConfig = Config.app.game.playerDraw //m
- val maxRange = drawConfig.rangeMax * drawConfig.rangeMax //sq.m
- val ourPosition = player.Position //xyz
- val currentDistance = Vector3.DistanceSquared(ourPosition, pos) //sq.m
- val inDrawableRange = currentDistance <= maxRange
- val now = System.currentTimeMillis() //ms
- if (
- sessionLogic.zoning.zoningStatus != Zoning.Status.Deconstructing &&
- !isNotRendered && inDrawableRange
+ /* really common messages (very frequently, every life) */
+ case pstate @ AvatarAction.PlayerState(
+ pos,
+ vel,
+ yaw,
+ pitch,
+ yawUpper,
+ _,
+ isCrouching,
+ isJumping,
+ jumpThrust,
+ isCloaking,
+ isNotRendered,
+ canSeeReallyFar
+ ) if TestFilter(NotSameTargetTest) =>
+ val pstateToSave = pstate.copy(timestamp = 0)
+ val (lastMsg, lastTime, lastPosition, wasVisible, wasShooting) = ops.lastSeenStreamMessage.get(FilterGuid.guid) match {
+ case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, shooting, time)) => (Some(msg), time, msg.pos, visible, shooting)
+ case _ => (None, 0L, Vector3.Zero, false, None)
+ }
+ val drawConfig = Config.app.game.playerDraw //m
+ val maxRange = drawConfig.rangeMax * drawConfig.rangeMax //sq.m
+ val ourPosition = player.Position //xyz
+ val currentDistance = Vector3.DistanceSquared(ourPosition, pos) //sq.m
+ val inDrawableRange = currentDistance <= maxRange
+ val now = System.currentTimeMillis() //ms
+ if (
+ sessionLogic.zoning.zoningStatus != Zoning.Status.Deconstructing &&
+ !isNotRendered && inDrawableRange
+ ) {
+ //conditions where visibility is assured
+ val durationSince = now - lastTime //ms
+ lazy val previouslyInDrawableRange = Vector3.DistanceSquared(ourPosition, lastPosition) <= maxRange
+ lazy val targetDelay = {
+ val populationOver = math.max(
+ 0,
+ sessionLogic.localSector.livePlayerList.size - drawConfig.populationThreshold
+ )
+ val distanceAdjustment = math.pow(populationOver / drawConfig.populationStep * drawConfig.rangeStep, 2) //sq.m
+ val adjustedDistance = currentDistance + distanceAdjustment //sq.m
+ drawConfig.ranges.lastIndexWhere { dist => adjustedDistance > dist * dist } match {
+ case -1 => 1
+ case index => drawConfig.delays(index)
+ }
+ } //ms
+ if (!wasVisible ||
+ !previouslyInDrawableRange ||
+ durationSince > drawConfig.delayMax ||
+ (!lastMsg.contains(pstateToSave) &&
+ (canSeeReallyFar ||
+ currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
+ sessionLogic.general.canSeeReallyFar ||
+ durationSince > targetDelay
+ )
+ )
) {
- //conditions where visibility is assured
- val durationSince = now - lastTime //ms
- lazy val previouslyInDrawableRange = Vector3.DistanceSquared(ourPosition, lastPosition) <= maxRange
- lazy val targetDelay = {
- val populationOver = math.max(
- 0,
- sessionLogic.localSector.livePlayerList.size - drawConfig.populationThreshold
+ //must draw
+ sendResponse(
+ PlayerStateMessage(
+ FilterGuid,
+ pos,
+ vel,
+ yaw,
+ pitch,
+ yawUpper,
+ timestamp = 0, //is this okay?
+ isCrouching,
+ isJumping,
+ jumpThrust,
+ isCloaking
)
- val distanceAdjustment = math.pow(populationOver / drawConfig.populationStep * drawConfig.rangeStep, 2) //sq.m
- val adjustedDistance = currentDistance + distanceAdjustment //sq.m
- drawConfig.ranges.lastIndexWhere { dist => adjustedDistance > dist * dist } match {
- case -1 => 1
- case index => drawConfig.delays(index)
- }
- } //ms
- if (!wasVisible ||
- !previouslyInDrawableRange ||
- durationSince > drawConfig.delayMax ||
- (!lastMsg.contains(pstateToSave) &&
- (canSeeReallyFar ||
- currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
- sessionLogic.general.canSeeReallyFar ||
- durationSince > targetDelay
- )
- )
- ) {
- //must draw
- sendResponse(
- PlayerStateMessage(
- guid,
- pos,
- vel,
- yaw,
- pitch,
- yawUpper,
- timestamp = 0, //is this okay?
- isCrouching,
- isJumping,
- jumpThrust,
- isCloaking
- )
- )
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, now))
- } else {
- //is visible, but skip reinforcement
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, lastTime))
- }
+ )
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, now))
} else {
- //conditions where the target is not currently visible
- if (wasVisible) {
- //the target was JUST PREVIOUSLY visible; one last draw to move target beyond a renderable distance
- val lat = (1 + ops.hidingPlayerRandomizer.nextInt(continent.map.scale.height.toInt)).toFloat
- sendResponse(
- PlayerStateMessage(
- guid,
- Vector3(1f, lat, 1f),
- vel=None,
- facingYaw=0f,
- facingPitch=0f,
- facingYawUpper=0f,
- timestamp=0, //is this okay?
- is_cloaked = isCloaking
- )
+ //is visible, but skip reinforcement
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, lastTime))
+ }
+ } else {
+ //conditions where the target is not currently visible
+ if (wasVisible) {
+ //the target was JUST PREVIOUSLY visible; one last draw to move target beyond a renderable distance
+ val lat = (1 + ops.hidingPlayerRandomizer.nextInt(continent.map.scale.height.toInt)).toFloat
+ sendResponse(
+ PlayerStateMessage(
+ FilterGuid,
+ Vector3(1f, lat, 1f),
+ vel=None,
+ facingYaw=0f,
+ facingPitch=0f,
+ facingYawUpper=0f,
+ timestamp=0, //is this okay?
+ is_cloaked = isCloaking
)
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, now))
- } else {
- //skip drawing altogether
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, lastTime))
+ )
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, now))
+ } else {
+ //skip drawing altogether
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, lastTime))
+ }
+ }
+
+ case AvatarAction.AvatarImplant(ImplantAction.Add, implant_slot, value)
+ if TestFilter(() => { value == ImplantType.SecondWind.value }) =>
+ sendResponse(AvatarImplantMessage(ResolvedGuid, ImplantAction.Add, implant_slot, 7))
+ //second wind does not normally load its icon into the shortcut hotbar
+ avatar
+ .shortcuts
+ .zipWithIndex
+ .find { case (s, _) => s.isEmpty}
+ .foreach { case (_, index) =>
+ sendResponse(CreateShortcutMessage(ResolvedGuid, index + 1, Some(ImplantType.SecondWind.shortcut)))
+ }
+
+ case AvatarAction.AvatarImplant(ImplantAction.Remove, implant_slot, value)
+ if TestFilter(() => { value == ImplantType.SecondWind.value }) =>
+ sendResponse(AvatarImplantMessage(ResolvedGuid, ImplantAction.Remove, implant_slot, value))
+ //second wind does not normally unload its icon from the shortcut hotbar
+ val shortcut = {
+ val imp = ImplantType.SecondWind.shortcut
+ net.psforever.objects.avatar.Shortcut(imp.code, imp.tile) //case class
+ }
+ avatar
+ .shortcuts
+ .zipWithIndex
+ .find { case (s, _) => s.contains(shortcut) }
+ .foreach { case (_, index) =>
+ sendResponse(CreateShortcutMessage(ResolvedGuid, index + 1, None))
+ }
+
+ case AvatarAction.AvatarImplant(action, implant_slot, value) =>
+ sendResponse(AvatarImplantMessage(ResolvedGuid, action, implant_slot, value))
+
+ case AvatarAction.ObjectHeld(slot, _)
+ if TestFilter(() => { SameTarget && player.VisibleSlots.contains(slot) }) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, slot, unk1=true))
+ //Stop using proximity terminals if player unholsters a weapon
+ continent.GUID(sessionLogic.terminals.usingMedicalTerminal).collect {
+ case term: Terminal with ProximityUnit => sessionLogic.terminals.StopUsingProximityUnit(term)
+ }
+ if (sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing) {
+ sessionLogic.zoning.spawn.stopDeconstructing()
+ }
+
+ case AvatarAction.ObjectHeld(slot, _)
+ if TestFilter(() => { SameTarget && slot > -1 }) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, slot, unk1=true))
+
+ case AvatarAction.ObjectHeld(_, _)
+ if TestFilter(SameTargetTest) => ()
+
+ case AvatarAction.ObjectHeld(_, previousSlot) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, previousSlot, unk1=false))
+
+ case ChangeFireState_Start(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible } }) =>
+ sendResponse(ChangeFireStateMessage_Start(weaponGuid))
+ val entry = ops.lastSeenStreamMessage(FilterGuid.guid)
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, entry.copy(shooting = Some(weaponGuid)))
+
+ case ChangeFireState_Stop(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { msg => msg.visible || msg.shooting.nonEmpty } }) =>
+ sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
+ val entry = ops.lastSeenStreamMessage(FilterGuid.guid)
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, entry.copy(shooting = None))
+
+ case AvatarAction.LoadCreatedPlayer(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ case AvatarAction.EquipmentCreatedInHand(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ case AvatarAction.PlanetsideStringAttribute(attributeType, attributeValue) =>
+ sendResponse(PlanetsideStringAttributeMessage(FilterGuid, attributeType, attributeValue))
+
+ case AvatarAction.Destroy(victim, killer, weapon, pos) =>
+ // guid = victim // killer = killer
+ sendResponse(DestroyMessage(victim, killer, weapon, pos))
+
+ case AvatarAction.DestroyDisplay(killer, victim, method, unk) =>
+ sendResponse(ops.destroyDisplayMessage(killer, victim, method, unk))
+
+ case AvatarAction.TerminalOrderResult(terminalGuid, action, result)
+ if result && (action == TransactionType.Buy || action == TransactionType.Loadout) =>
+ sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
+ sessionLogic.terminals.lastTerminalOrderFulfillment = true
+ AvatarActor.savePlayerData(player)
+ sessionLogic.general.renewCharSavedTimer(
+ Config.app.game.savedMsg.interruptedByAction.fixed,
+ Config.app.game.savedMsg.interruptedByAction.variable
+ )
+
+ case AvatarAction.TerminalOrderResult(terminalGuid, action, result) =>
+ sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
+ sessionLogic.terminals.lastTerminalOrderFulfillment = true
+
+ case AvatarAction.ChangeExosuit(
+ target,
+ armor,
+ exosuit,
+ subtype,
+ _,
+ maxhand,
+ oldHolsters,
+ holsters,
+ oldInventory,
+ inventory,
+ drop,
+ delete
+ ) if TestFilter(() => { ResolvedGuid == target }) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to this player
+ //cleanup
+ sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=false))
+ (oldHolsters ++ oldInventory ++ delete).foreach {
+ case (_, dguid) => sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+ }
+ //functionally delete
+ if (delete.size > 1 || delete.nonEmpty && !delete.exists {
+ case (e: Tool, _) => GlobalDefinitions.isMaxArms(e.Definition)
+ case _ => false
+ }) {
+ /*
+ if going x -> max, you will have enough space in max inventory for any displaced holster equipment
+ for max -> max, don't care about the max weapon arm being deleted (allow for 1)
+ for any other x -> x, any deleted equipment will raise this comment
+ */
+ sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ItemsDeconstructed"))
+ }
+ delete.foreach { case (obj, _) => TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj)) }
+ //redraw
+ if (maxhand) {
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=7, player.Capacitor.toLong))
+ val maxArmDefinition = GlobalDefinitions.MAXArms(subtype, player.Faction)
+ TaskWorkflow.execute(HoldNewEquipmentUp(player)(Tool(maxArmDefinition), slot = 0))
+ player.avatar.purchaseCooldown(maxArmDefinition)
+ .collect(a => a)
+ .getOrElse {
+ avatarActor ! AvatarActor.UpdatePurchaseTime(maxArmDefinition)
+ None
}
- }
-
- case AvatarResponse.AvatarImplant(ImplantAction.Add, implant_slot, value)
- if value == ImplantType.SecondWind.value =>
- sendResponse(AvatarImplantMessage(resolvedPlayerGuid, ImplantAction.Add, implant_slot, 7))
- //second wind does not normally load its icon into the shortcut hotbar
- avatar
- .shortcuts
- .zipWithIndex
- .find { case (s, _) => s.isEmpty}
- .foreach { case (_, index) =>
- sendResponse(CreateShortcutMessage(resolvedPlayerGuid, index + 1, Some(ImplantType.SecondWind.shortcut)))
- }
-
- case AvatarResponse.AvatarImplant(ImplantAction.Remove, implant_slot, value)
- if value == ImplantType.SecondWind.value =>
- sendResponse(AvatarImplantMessage(resolvedPlayerGuid, ImplantAction.Remove, implant_slot, value))
- //second wind does not normally unload its icon from the shortcut hotbar
- val shortcut = {
- val imp = ImplantType.SecondWind.shortcut
- net.psforever.objects.avatar.Shortcut(imp.code, imp.tile) //case class
- }
- avatar
- .shortcuts
- .zipWithIndex
- .find { case (s, _) => s.contains(shortcut) }
- .foreach { case (_, index) =>
- sendResponse(CreateShortcutMessage(resolvedPlayerGuid, index + 1, None))
- }
-
- case AvatarResponse.AvatarImplant(action, implant_slot, value) =>
- sendResponse(AvatarImplantMessage(resolvedPlayerGuid, action, implant_slot, value))
-
- case AvatarResponse.ObjectHeld(slot, _)
- if isSameTarget && player.VisibleSlots.contains(slot) =>
- sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
- //Stop using proximity terminals if player unholsters a weapon
- continent.GUID(sessionLogic.terminals.usingMedicalTerminal).collect {
- case term: Terminal with ProximityUnit => sessionLogic.terminals.StopUsingProximityUnit(term)
- }
- if (sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing) {
- sessionLogic.zoning.spawn.stopDeconstructing()
- }
-
- case AvatarResponse.ObjectHeld(slot, _)
- if isSameTarget && slot > -1 =>
- sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
-
- case AvatarResponse.ObjectHeld(_, _)
- if isSameTarget => ()
-
- case AvatarResponse.ObjectHeld(_, previousSlot) =>
- sendResponse(ObjectHeldMessage(guid, previousSlot, unk1=false))
-
- case AvatarResponse.ChangeFireState_Start(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- sendResponse(ChangeFireStateMessage_Start(weaponGuid))
- val entry = ops.lastSeenStreamMessage(guid.guid)
- ops.lastSeenStreamMessage.put(guid.guid, entry.copy(shooting = Some(weaponGuid)))
-
- case AvatarResponse.ChangeFireState_Start(weaponGuid)
- if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Start(weaponGuid))
-
- case AvatarResponse.ChangeFireState_Stop(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { msg => msg.visible || msg.shooting.nonEmpty } =>
- sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
- val entry = ops.lastSeenStreamMessage(guid.guid)
- ops.lastSeenStreamMessage.put(guid.guid, entry.copy(shooting = None))
-
- case AvatarResponse.ChangeFireState_Stop(weaponGuid)
- if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
-
- case AvatarResponse.LoadPlayer(pkt) if isNotSameTarget =>
- sendResponse(pkt)
-
- case AvatarResponse.EquipmentInHand(pkt) if isNotSameTarget =>
- sendResponse(pkt)
-
- case AvatarResponse.PlanetsideAttribute(attributeType, attributeValue) if isNotSameTarget =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
-
- case AvatarResponse.PlanetsideAttributeToAll(attributeType, attributeValue) =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
-
- case AvatarResponse.PlanetsideAttributeSelf(attributeType, attributeValue) if isSameTarget =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
-
- case AvatarResponse.PlanetsideStringAttribute(attributeType, attributeValue) =>
- sendResponse(PlanetsideStringAttributeMessage(guid, attributeType, attributeValue))
-
- case AvatarResponse.GenericObjectAction(objectGuid, actionCode) if isNotSameTarget =>
- sendResponse(GenericObjectActionMessage(objectGuid, actionCode))
-
- case AvatarResponse.HitHint(sourceGuid) if player.isAlive =>
- sendResponse(HitHint(sourceGuid, guid))
- sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
-
- case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
- // guid = victim // killer = killer
- sendResponse(DestroyMessage(victim, killer, weapon, pos))
-
- case AvatarResponse.DestroyDisplay(killer, victim, method, unk) =>
- sendResponse(ops.destroyDisplayMessage(killer, victim, method, unk))
-
- case AvatarResponse.TerminalOrderResult(terminalGuid, action, result)
- if result && (action == TransactionType.Buy || action == TransactionType.Loadout) =>
- sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
- sessionLogic.terminals.lastTerminalOrderFulfillment = true
- AvatarActor.savePlayerData(player)
- sessionLogic.general.renewCharSavedTimer(
- Config.app.game.savedMsg.interruptedByAction.fixed,
- Config.app.game.savedMsg.interruptedByAction.variable
+ }
+ //draw free hand
+ player.FreeHand.Equipment.foreach { obj =>
+ val definition = obj.Definition
+ sendResponse(
+ ObjectCreateDetailedMessage(
+ definition.ObjectId,
+ obj.GUID,
+ ObjectCreateMessageParent(target, Player.FreeHandSlot),
+ definition.Packet.DetailedConstructorData(obj).get
+ )
)
-
- case AvatarResponse.TerminalOrderResult(terminalGuid, action, result) =>
- sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
- sessionLogic.terminals.lastTerminalOrderFulfillment = true
-
- case AvatarResponse.ChangeExosuit(
- target,
- armor,
- exosuit,
- subtype,
- _,
- maxhand,
- oldHolsters,
- holsters,
- oldInventory,
- inventory,
- drop,
- delete
- ) if resolvedPlayerGuid == target =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to this player
- //cleanup
- sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=false))
- (oldHolsters ++ oldInventory ++ delete).foreach {
- case (_, dguid) => sendResponse(ObjectDeleteMessage(dguid, unk1=0))
- }
- //functionally delete
- if (delete.size > 1 || delete.nonEmpty && !delete.exists {
- case (e: Tool, _) => GlobalDefinitions.isMaxArms(e.Definition)
- case _ => false
- }) {
- /*
- if going x -> max, you will have enough space in max inventory for any displaced holster equipment
- for max -> max, don't care about the max weapon arm being deleted (allow for 1)
- for any other x -> x, any deleted equipment will raise this comment
- */
- sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ItemsDeconstructed"))
- }
- delete.foreach { case (obj, _) => TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj)) }
- //redraw
- if (maxhand) {
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=7, player.Capacitor.toLong))
- val maxArmDefinition = GlobalDefinitions.MAXArms(subtype, player.Faction)
- TaskWorkflow.execute(HoldNewEquipmentUp(player)(Tool(maxArmDefinition), slot = 0))
- player.avatar.purchaseCooldown(maxArmDefinition)
- .collect(a => a)
- .getOrElse {
- avatarActor ! AvatarActor.UpdatePurchaseTime(maxArmDefinition)
- None
- }
- }
- //draw free hand
- player.FreeHand.Equipment.foreach { obj =>
+ }
+ //draw holsters and inventory
+ (holsters ++ inventory).foreach {
+ case InventoryItem(obj, index) =>
val definition = obj.Definition
sendResponse(
ObjectCreateDetailedMessage(
definition.ObjectId,
obj.GUID,
- ObjectCreateMessageParent(target, Player.FreeHandSlot),
+ ObjectCreateMessageParent(target, index),
definition.Packet.DetailedConstructorData(obj).get
)
)
- }
- //draw holsters and inventory
- (holsters ++ inventory).foreach {
- case InventoryItem(obj, index) =>
- val definition = obj.Definition
- sendResponse(
- ObjectCreateDetailedMessage(
- definition.ObjectId,
- obj.GUID,
- ObjectCreateMessageParent(target, index),
- definition.Packet.DetailedConstructorData(obj).get
- )
+ }
+ DropLeftovers(player)(drop)
+ //deactivate non-passive implants
+ avatarActor ! AvatarActor.DeactivateActiveImplants
+
+ case AvatarAction.ChangeExosuit(target, armor, exosuit, subtype, slot, _, oldHolsters, holsters, _, _, drop, delete) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to some other player
+ sendResponse(ObjectHeldMessage(target, slot, unk1 = false))
+ //cleanup
+ val dropPred = ContainableBehavior.DropPredicate(player)
+ val deleteFromDrop = drop.filterNot(dropPred)
+ (oldHolsters ++ delete ++ deleteFromDrop.map(f =>(f.obj, f.GUID)))
+ .distinctBy(_._2)
+ .foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
+ //draw holsters
+ holsters.foreach {
+ case InventoryItem(obj, index) =>
+ val definition = obj.Definition
+ sendResponse(
+ ObjectCreateMessage(
+ definition.ObjectId,
+ obj.GUID,
+ ObjectCreateMessageParent(target, index),
+ definition.Packet.ConstructorData(obj).get
)
- }
- DropLeftovers(player)(drop)
- //deactivate non-passive implants
- avatarActor ! AvatarActor.DeactivateActiveImplants
-
- case AvatarResponse.ChangeExosuit(target, armor, exosuit, subtype, slot, _, oldHolsters, holsters, _, _, drop, delete) =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to some other player
- sendResponse(ObjectHeldMessage(target, slot, unk1 = false))
- //cleanup
- val dropPred = ContainableBehavior.DropPredicate(player)
- val deleteFromDrop = drop.filterNot(dropPred)
- (oldHolsters ++ delete ++ deleteFromDrop.map(f =>(f.obj, f.GUID)))
- .distinctBy(_._2)
- .foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
- //draw holsters
- holsters.foreach {
- case InventoryItem(obj, index) =>
- val definition = obj.Definition
- sendResponse(
- ObjectCreateMessage(
- definition.ObjectId,
- obj.GUID,
- ObjectCreateMessageParent(target, index),
- definition.Packet.ConstructorData(obj).get
- )
- )
- }
-
- case AvatarResponse.ChangeLoadout(
- target,
- armor,
- exosuit,
- subtype,
- _,
- maxhand,
- oldHolsters,
- holsters,
- oldInventory,
- inventory,
- drops
- ) if resolvedPlayerGuid == target =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to this player
- sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=true))
- //cleanup
- (oldHolsters ++ oldInventory).foreach {
- case (obj, objGuid) =>
- sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
- TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
- }
- drops.foreach(item => sendResponse(ObjectDeleteMessage(item.obj.GUID, unk1=0)))
- //redraw
- if (maxhand) {
- val maxArmWeapon = GlobalDefinitions.MAXArms(subtype, player.Faction)
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=7, player.Capacitor.toLong))
- TaskWorkflow.execute(HoldNewEquipmentUp(player)(Tool(maxArmWeapon), slot = 0))
- player.avatar.purchaseCooldown(maxArmWeapon)
- if (!oldHolsters.exists { case (e, _) => e.Definition == maxArmWeapon } &&
- player.avatar.purchaseCooldown(maxArmWeapon).isEmpty) {
- avatarActor ! AvatarActor.UpdatePurchaseTime(maxArmWeapon) //switching for first time causes cooldown
- }
- }
- sessionLogic.general.applyPurchaseTimersBeforePackingLoadout(player, player, holsters ++ inventory)
- DropLeftovers(player)(drops)
- //deactivate non-passive implants
- avatarActor ! AvatarActor.DeactivateActiveImplants
-
- case AvatarResponse.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
- //redraw handled by callbacks
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to some other player
- sendResponse(ObjectHeldMessage(target, slot, unk1=false))
- //cleanup
- oldHolsters.foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
-
- case AvatarResponse.UseKit(kguid, kObjId) =>
- sendResponse(
- UseItemMessage(
- resolvedPlayerGuid,
- kguid,
- resolvedPlayerGuid,
- unk2 = 4294967295L,
- unk3 = false,
- unk4 = Vector3.Zero,
- unk5 = Vector3.Zero,
- unk6 = 126,
- unk7 = 0, //sequence time?
- unk8 = 137,
- kObjId
)
+ }
+
+ case AvatarAction.ChangeLoadout(
+ target,
+ armor,
+ exosuit,
+ subtype,
+ _,
+ maxhand,
+ oldHolsters,
+ holsters,
+ oldInventory,
+ inventory,
+ drops
+ ) if TestFilter(() => { ResolvedGuid == target }) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to this player
+ sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=true))
+ //cleanup
+ (oldHolsters ++ oldInventory).foreach {
+ case (obj, objGuid) =>
+ sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
+ TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
+ }
+ drops.foreach(item => sendResponse(ObjectDeleteMessage(item.obj.GUID, unk1=0)))
+ //redraw
+ if (maxhand) {
+ val maxArmWeapon = GlobalDefinitions.MAXArms(subtype, player.Faction)
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=7, player.Capacitor.toLong))
+ TaskWorkflow.execute(HoldNewEquipmentUp(player)(Tool(maxArmWeapon), slot = 0))
+ player.avatar.purchaseCooldown(maxArmWeapon)
+ if (!oldHolsters.exists { case (e, _) => e.Definition == maxArmWeapon } &&
+ player.avatar.purchaseCooldown(maxArmWeapon).isEmpty) {
+ avatarActor ! AvatarActor.UpdatePurchaseTime(maxArmWeapon) //switching for first time causes cooldown
+ }
+ }
+ sessionLogic.general.applyPurchaseTimersBeforePackingLoadout(player, player, holsters ++ inventory)
+ DropLeftovers(player)(drops)
+ //deactivate non-passive implants
+ avatarActor ! AvatarActor.DeactivateActiveImplants
+
+ case AvatarAction.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
+ //redraw handled by callbacks
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to some other player
+ sendResponse(ObjectHeldMessage(target, slot, unk1=false))
+ //cleanup
+ oldHolsters.foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
+
+ case AvatarAction.UseKit(kguid, kObjId) =>
+ sendResponse(
+ UseItemMessage(
+ ResolvedGuid,
+ kguid,
+ ResolvedGuid,
+ unk2 = 4294967295L,
+ unk3 = false,
+ unk4 = Vector3.Zero,
+ unk5 = Vector3.Zero,
+ unk6 = 126,
+ unk7 = 0, //sequence time?
+ unk8 = 137,
+ kObjId
)
- sendResponse(ObjectDeleteMessage(kguid, unk1=0))
+ )
+ sendResponse(ObjectDeleteMessage(kguid, unk1=0))
- case AvatarResponse.KitNotUsed(_, "") =>
- sessionLogic.general.kitToBeUsed = None
+ case AvatarAction.KitNotUsed(_, "") =>
+ sessionLogic.general.kitToBeUsed = None
- case AvatarResponse.KitNotUsed(_, msg) =>
- sessionLogic.general.kitToBeUsed = None
- sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
+ case AvatarAction.KitNotUsed(_, msg) =>
+ sessionLogic.general.kitToBeUsed = None
+ sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
- case AvatarResponse.UpdateKillsDeathsAssists(_, kda) =>
- avatarActor ! AvatarActor.UpdateKillsDeathsAssists(kda)
+ case AvatarAction.UpdateKillsDeathsAssists(_, kda) =>
+ avatarActor ! AvatarActor.UpdateKillsDeathsAssists(kda)
- case AvatarResponse.AwardBep(charId, bep, expType) =>
- //if the target player, always award (some) BEP
- if (charId == player.CharId) {
- avatarActor ! AvatarActor.AwardBep(bep, expType)
- }
+ case AvatarAction.AwardBep(charId, bep, expType) =>
+ //if the target player, always award (some) BEP
+ if (charId == player.CharId) {
+ avatarActor ! AvatarActor.AwardBep(bep, expType)
+ }
- case AvatarResponse.AwardCep(charId, cep) =>
- //if the target player, always award (some) CEP
- if (charId == player.CharId) {
- avatarActor ! AvatarActor.AwardCep(cep)
- }
+ case AvatarAction.AwardCep(charId, cep) =>
+ //if the target player, always award (some) CEP
+ if (charId == player.CharId) {
+ avatarActor ! AvatarActor.AwardCep(cep)
+ }
- case AvatarResponse.FacilityCaptureRewards(buildingId, zoneNumber, cep) =>
- ops.facilityCaptureRewards(buildingId, zoneNumber, cep)
+ case AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, cep) =>
+ ops.facilityCaptureRewards(buildingId, zoneNumber, cep)
- case AvatarResponse.ShareKillExperienceWithSquad(killer, exp) =>
- ops.shareKillExperienceWithSquad(killer, exp)
+ case AvatarAction.ShareKillExperienceWithSquad(killer, exp) =>
+ ops.shareKillExperienceWithSquad(killer, exp)
- case AvatarResponse.ShareAntExperienceWithSquad(owner, exp, vehicle) =>
- ops.shareAntExperienceWithSquad(owner, exp, vehicle)
+ case AvatarAction.ShareAntExperienceWithSquad(owner, exp, vehicle) =>
+ ops.shareAntExperienceWithSquad(owner, exp, vehicle)
- case AvatarResponse.RemoveFromOutfitChat(outfit_id) =>
- ops.removeFromOutfitChat(outfit_id)
+ case AvatarAction.RemoveFromOutfitChat(outfit_id) =>
+ ops.removeFromOutfitChat(outfit_id)
- case AvatarResponse.SendResponse(msg) =>
- sendResponse(msg)
+ /* common messages (maybe once every respawn) */
+ case ReloadTool(itemGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible } }) =>
+ sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
- case AvatarResponse.SendResponseTargeted(targetGuid, msg) if resolvedPlayerGuid == targetGuid =>
- sendResponse(msg)
-
- /* common messages (maybe once every respawn) */
- case AvatarResponse.Reload(itemGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
-
- case AvatarResponse.Killed(cause, mount) =>
- //log and chat messages
- //destroy display
- val zoneChannel = continent.id
- val events = continent.AvatarEvents
- val pentry = PlayerSource(player)
- cause
- .adversarial
- .collect { case out @ Adversarial(attacker, _, _) if attacker != PlayerSource.Nobody => out }
- .orElse {
- player.LastDamage.collect {
- case attack if System.currentTimeMillis() - attack.interaction.hitTime < (10 seconds).toMillis =>
- attack
- .adversarial
- .collect { case out @ Adversarial(attacker, _, _) if attacker != PlayerSource.Nobody => out }
- }.flatten
- } match {
- case Some(adversarial) =>
- events ! AvatarServiceMessage(
- zoneChannel,
- AvatarAction.DestroyDisplay(adversarial.attacker, pentry, adversarial.implement)
- )
- case _ =>
- events ! AvatarServiceMessage(zoneChannel, AvatarAction.DestroyDisplay(pentry, pentry, 0))
- }
- //events chat and log
- val excuse = player.LastDamage.flatMap { damage =>
- val interaction = damage.interaction
- val reason = interaction.cause
- val adversarial = interaction.adversarial.map { _.attacker }
- reason match {
- case r: ExplodingEntityReason if r.entity.isInstanceOf[VehicleSpawnPad] =>
- //also, @SVCP_Killed_TooCloseToPadOnCreate^n~ or "... within n meters of pad ..."
- sendResponse(ChatMsg(ChatMessageType.UNK_227, "@SVCP_Killed_OnPadOnCreate"))
- case _ => ()
- }
- adversarial.map {_.Name }.orElse { Some(s"a ${reason.getClass.getSimpleName}") }
- }.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
- log.info(s"${player.Name} has died, killed by $excuse")
- if (sessionLogic.shooting.shotsWhileDead > 0) {
- log.warn(
- s"SHOTS_WHILE_DEAD: client of ${avatar.name} fired ${sessionLogic.shooting.shotsWhileDead} rounds while character was dead on server"
+ case AvatarAction.Killed(cause, mount) =>
+ //log and chat messages
+ //destroy display
+ val zoneChannel = continent.id
+ val events = continent.AvatarEvents
+ val pentry = PlayerSource(player)
+ cause
+ .adversarial
+ .collect { case out @ Adversarial(attacker, _, _) if attacker != PlayerSource.Nobody => out }
+ .orElse {
+ player.LastDamage.collect {
+ case attack if System.currentTimeMillis() - attack.interaction.hitTime < (10 seconds).toMillis =>
+ attack
+ .adversarial
+ .collect { case out @ Adversarial(attacker, _, _) if attacker != PlayerSource.Nobody => out }
+ }.flatten
+ } match {
+ case Some(adversarial) =>
+ events ! MessageEnvelope(
+ zoneChannel,
+ AvatarAction.DestroyDisplay(adversarial.attacker, pentry, adversarial.implement)
)
- sessionLogic.shooting.shotsWhileDead = 0
+ case _ =>
+ events ! MessageEnvelope(zoneChannel, AvatarAction.DestroyDisplay(pentry, pentry, 0))
+ }
+ //events chat and log
+ val excuse = player.LastDamage.flatMap { damage =>
+ val interaction = damage.interaction
+ val reason = interaction.cause
+ val adversarial = interaction.adversarial.map { _.attacker }
+ reason match {
+ case r: ExplodingEntityReason if r.entity.isInstanceOf[VehicleSpawnPad] =>
+ //also, @SVCP_Killed_TooCloseToPadOnCreate^n~ or "... within n meters of pad ..."
+ sendResponse(ChatMsg(ChatMessageType.UNK_227, "@SVCP_Killed_OnPadOnCreate"))
+ case _ => ()
}
- //TODO other methods of death?
- sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason(msg = "cancel")
- sessionLogic.general.renewCharSavedTimer(fixedLen = 1800L, varLen = 0L)
- continent.actor ! ZoneActor.RewardThisDeath(player)
-
- //player state changes
- sessionLogic.zoning.spawn.avatarActive = false
- AvatarActor.updateToolDischargeFor(avatar)
- player.FreeHand.Equipment.foreach { item =>
- DropEquipmentFromInventory(player)(item)
- }
- sessionLogic.general.dropSpecialSlotItem()
- sessionLogic.general.toggleMaxSpecialState(enable = false)
- sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
- sessionLogic.zoning.zoningStatus = Zoning.Status.None
- sessionLogic.zoning.spawn.deadState = DeadState.Dead
- continent.GUID(mount).collect {
- case obj: Vehicle =>
- killedWhileMounted(obj, resolvedPlayerGuid)
- sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
- sessionLogic.general.unaccessContainer(obj)
-
- case obj: PlanetSideGameObject with Mountable with Container =>
- killedWhileMounted(obj, resolvedPlayerGuid)
- sessionLogic.general.unaccessContainer(obj)
-
- case obj: PlanetSideGameObject with Mountable =>
- killedWhileMounted(obj, resolvedPlayerGuid)
- }
- sessionLogic.actionsToCancel()
- sessionLogic.terminals.CancelAllProximityUnits()
- AvatarActor.savePlayerLocation(player)
- sessionLogic.zoning.spawn.ShiftPosition = Some(player.Position)
-
- //respawn
- val respawnTimer = 300000 //milliseconds
- sendResponse(AvatarDeadStateMessage(DeadState.Dead, respawnTimer, respawnTimer, player.Position, player.Faction, unk5=true))
- sessionLogic.zoning.spawn.reviveTimer.cancel()
- sessionLogic.zoning.spawn.reviveTimer = Default.Cancellable
- if (player.death_by == 0) {
- sessionLogic.zoning.spawn.randomRespawn(300.seconds)
- } else {
- sessionLogic.zoning.spawn.HandleReleaseAvatar(player, continent)
- }
-
- case AvatarResponse.Release(tplayer) if isNotSameTarget =>
- sessionLogic.zoning.spawn.DepictPlayerAsCorpse(tplayer)
-
- case AvatarResponse.Revive(revivalTargetGuid)
- if resolvedPlayerGuid == revivalTargetGuid =>
- log.info(s"No time for rest, ${player.Name}. Back on your feet!")
- ops.revive()
- player.Actor ! Player.Revive
- player.History
- .findLast { _.isInstanceOf[RevivingActivity] }
- .map {
- case activity: RevivingActivity
- if System.currentTimeMillis() - activity.time < 5000L =>
- val reviveMessage = s"@YouHaveBeenMessage^revived~^${activity.user.unique.name}~"
- sendResponse(ChatMsg(ChatMessageType.UNK_227, reviveMessage))
- None
- }
-
- /* uncommon messages (utility, or once in a while) */
- case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- ops.changeAmmoProcedures(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
- sendResponse(ChangeAmmoMessage(weapon_guid, 1))
-
- case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
- if isNotSameTarget =>
- ops.changeAmmoProcedures(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
-
- case AvatarResponse.ChangeFireMode(itemGuid, mode) if isNotSameTarget =>
- sendResponse(ChangeFireModeMessage(itemGuid, mode))
-
- case AvatarResponse.ConcealPlayer() =>
- sendResponse(GenericObjectActionMessage(guid, code=9))
-
- case AvatarResponse.EnvironmentalDamage(_, _, _) =>
- //TODO damage marker?
- sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
-
- case AvatarResponse.DropItem(pkt) if isNotSameTarget =>
- sendResponse(pkt)
-
- case AvatarResponse.ObjectDelete(itemGuid, unk) if isNotSameTarget =>
- sendResponse(ObjectDeleteMessage(itemGuid, unk))
-
- /* rare messages */
- case AvatarResponse.SetEmpire(objectGuid, faction) if isNotSameTarget =>
- sendResponse(SetEmpireMessage(objectGuid, faction))
-
- case AvatarResponse.DropSpecialItem() =>
- sessionLogic.general.dropSpecialSlotItem()
-
- case AvatarResponse.OxygenState(player, vehicle) =>
- sendResponse(OxygenStateMessage(
- DrowningTarget(player.guid, player.progress, player.state),
- vehicle.flatMap { vinfo => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) }
- ))
-
- case AvatarResponse.LoadProjectile(pkt) if isNotSameTarget =>
- sendResponse(pkt)
-
- case AvatarResponse.ProjectileState(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid) if isNotSameTarget =>
- sendResponse(ProjectileStateMessage(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid))
-
- case AvatarResponse.ProjectileExplodes(projectileGuid, projectile) =>
- sendResponse(
- ProjectileStateMessage(
- projectileGuid,
- projectile.Position,
- shot_vel = Vector3.Zero,
- projectile.Orientation,
- sequence_num=0,
- end=true,
- hit_target_guid=PlanetSideGUID(0)
- )
+ adversarial.map {_.Name }.orElse { Some(s"a ${reason.getClass.getSimpleName}") }
+ }.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
+ log.info(s"${player.Name} has died, killed by $excuse")
+ if (sessionLogic.shooting.shotsWhileDead > 0) {
+ log.warn(
+ s"SHOTS_WHILE_DEAD: client of ${avatar.name} fired ${sessionLogic.shooting.shotsWhileDead} rounds while character was dead on server"
)
- sendResponse(ObjectDeleteMessage(projectileGuid, unk1=2))
+ sessionLogic.shooting.shotsWhileDead = 0
+ }
+ //TODO other methods of death?
+ sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason(msg = "cancel")
+ sessionLogic.general.renewCharSavedTimer(fixedLen = 1800L, varLen = 0L)
+ continent.actor ! ZoneActor.RewardThisDeath(player)
- case AvatarResponse.ProjectileAutoLockAwareness(mode) =>
- sendResponse(GenericActionMessage(mode))
+ //player state changes
+ sessionLogic.zoning.spawn.avatarActive = false
+ AvatarActor.updateToolDischargeFor(avatar)
+ player.FreeHand.Equipment.foreach { item =>
+ DropEquipmentFromInventory(player)(item)
+ }
+ sessionLogic.general.dropSpecialSlotItem()
+ sessionLogic.general.toggleMaxSpecialState(enable = false)
+ sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
+ sessionLogic.zoning.zoningStatus = Zoning.Status.None
+ sessionLogic.zoning.spawn.deadState = DeadState.Dead
+ continent.GUID(mount).collect {
+ case obj: Vehicle =>
+ killedWhileMounted(obj, ResolvedGuid)
+ sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
+ sessionLogic.general.unaccessContainer(obj)
- case AvatarResponse.PutDownFDU(target) if isNotSameTarget =>
- sendResponse(GenericObjectActionMessage(target, code=53))
+ case obj: PlanetSideGameObject with Mountable with Container =>
+ killedWhileMounted(obj, ResolvedGuid)
+ sessionLogic.general.unaccessContainer(obj)
- case AvatarResponse.StowEquipment(target, slot, item) if isNotSameTarget =>
- val definition = item.Definition
- sendResponse(
- ObjectCreateDetailedMessage(
- definition.ObjectId,
- item.GUID,
- ObjectCreateMessageParent(target, slot),
- definition.Packet.DetailedConstructorData(item).get
- )
- )
+ case obj: PlanetSideGameObject with Mountable =>
+ killedWhileMounted(obj, ResolvedGuid)
+ }
+ sessionLogic.actionsToCancel()
+ sessionLogic.terminals.CancelAllProximityUnits()
+ AvatarActor.savePlayerLocation(player)
+ sessionLogic.zoning.spawn.ShiftPosition = Some(player.Position)
- case AvatarResponse.WeaponDryFire(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- continent.GUID(weaponGuid).collect {
- case tool: Tool if tool.Magazine == 0 =>
- // check that the magazine is still empty before sending WeaponDryFireMessage
- // if it has been reloaded since then, other clients will not see it firing
- sendResponse(WeaponDryFireMessage(weaponGuid))
+ //respawn
+ val respawnTimer = 300000 //milliseconds
+ sendResponse(AvatarDeadStateMessage(DeadState.Dead, respawnTimer, respawnTimer, player.Position, player.Faction, unk5=true))
+ sessionLogic.zoning.spawn.reviveTimer.cancel()
+ sessionLogic.zoning.spawn.reviveTimer = Default.Cancellable
+ if (player.death_by == 0) {
+ sessionLogic.zoning.spawn.randomRespawn(300.seconds)
+ } else {
+ sessionLogic.zoning.spawn.HandleReleaseAvatar(player, continent)
+ }
+
+ case AvatarAction.ReleasePlayer(tplayer)
+ if TestFilter(NotSameTargetTest) =>
+ sessionLogic.zoning.spawn.DepictPlayerAsCorpse(tplayer)
+
+ case AvatarAction.Revive(revivalTargetGuid)
+ if TestFilter(() => { ResolvedGuid == revivalTargetGuid }) =>
+ log.info(s"No time for rest, ${player.Name}. Back on your feet!")
+ ops.revive()
+ player.Actor ! Player.Revive
+ player.History
+ .findLast { _.isInstanceOf[RevivingActivity] }
+ .map {
+ case activity: RevivingActivity
+ if System.currentTimeMillis() - activity.time < 5000L =>
+ val reviveMessage = s"@YouHaveBeenMessage^revived~^${activity.user.unique.name}~"
+ sendResponse(ChatMsg(ChatMessageType.UNK_227, reviveMessage))
+ None
}
- case _ => ()
- }
+ /* uncommon messages (utility, or once in a while) */
+ case ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
+ if TestFilter(NotSameTargetTest) =>
+ ops.changeAmmoProcedure(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
+ sendResponse(ChangeAmmoMessage(weapon_guid, 1))
+
+ case AvatarAction.ChangeFireMode(itemGuid, mode)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ChangeFireModeMessage(itemGuid, mode))
+
+ case AvatarAction.EnvironmentalDamage(_, _, _) =>
+ //TODO damage marker?
+ sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
+
+ case AvatarAction.DropCreatedItem(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ /* rare messages */
+ case AvatarAction.DropSpecialItem() =>
+ sessionLogic.general.dropSpecialSlotItem()
+
+ case AvatarAction.OxygenState(player, vehicle) =>
+ sendResponse(OxygenStateMessage(
+ DrowningTarget(player.guid, player.progress, player.state),
+ vehicle.flatMap { vinfo => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) }
+ ))
+
+ case AvatarAction.LoadCreatedProjectile(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ case AvatarAction.ProjectileState(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ProjectileStateMessage(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid))
+
+ case AvatarAction.ProjectileExplodes(projectileGuid, projectile) =>
+ sendResponse(
+ ProjectileStateMessage(
+ projectileGuid,
+ projectile.Position,
+ shot_vel = Vector3.Zero,
+ projectile.Orientation,
+ sequence_num=0,
+ end=true,
+ hit_target_guid=PlanetSideGUID(0)
+ )
+ )
+ sendResponse(ObjectDeleteMessage(projectileGuid, unk1=2))
+
+ case AvatarAction.ProjectileAutoLockAwareness(mode) =>
+ sendResponse(GenericActionMessage(mode))
+
+ case AvatarAction.PutDownFDU(target)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(GenericObjectActionMessage(target, code=53))
+
+ case AvatarAction.StowEquipment(target, slot, item)
+ if TestFilter(NotSameTargetTest) =>
+ val definition = item.Definition
+ sendResponse(
+ ObjectCreateDetailedMessage(
+ definition.ObjectId,
+ item.GUID,
+ ObjectCreateMessageParent(target, slot),
+ definition.Packet.DetailedConstructorData(item).get
+ )
+ )
+
+ case WeaponDryFire(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible } }) =>
+ continent.GUID(weaponGuid).collect {
+ case tool: Tool if tool.Magazine == 0 =>
+ sendResponse(WeaponDryFireMessage(weaponGuid))
+ }
}
def killedWhileMounted(obj: PlanetSideGameObject with Mountable, playerGuid: PlanetSideGUID): Unit = {
- val events = continent.AvatarEvents
ops.killedWhileMounted(obj, playerGuid)
- //make player invisible on client
- events ! AvatarServiceMessage(player.Name, AvatarAction.PlanetsideAttributeToAll(playerGuid, 29, 1))
- //only the dead player should "see" their own body, so that the death camera has something to focus on
- events ! AvatarServiceMessage(continent.id, AvatarAction.ObjectDelete(playerGuid, playerGuid))
+ continent.AvatarEvents ! BundledEnvelope(
+ /* make player invisible on client */
+ MessageEnvelope(player.Name, PlanetsideAttribute(playerGuid, 29, 1)),
+ /* only the dead player should "see" their own body, so that the death camera has something to focus on */
+ MessageEnvelope(continent.id, playerGuid, ObjectDelete(playerGuid))
+ )
}
}
diff --git a/src/main/scala/net/psforever/actors/session/normal/GalaxyHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/GalaxyHandlerLogic.scala
index fe2d4b873..5bc18cbf9 100644
--- a/src/main/scala/net/psforever/actors/session/normal/GalaxyHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/normal/GalaxyHandlerLogic.scala
@@ -1,11 +1,13 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.normal
+import akka.actor.Actor.Receive
import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.AvatarActor
-import net.psforever.actors.session.support.{GalaxyHandlerFunctions, SessionGalaxyHandlers, SessionData}
+import net.psforever.actors.session.support.{GalaxyHandlerFunctions, SessionData, SessionGalaxyHandlers}
import net.psforever.packet.game.{BroadcastWarpgateUpdateMessage, FriendsResponse, HotSpotUpdateMessage, ZoneInfoMessage, ZonePopulationUpdateMessage, HotSpotInfo => PacketHotSpotInfo}
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.galaxy.GalaxyAction
import net.psforever.types.{MemberAction, PlanetSideEmpire}
object GalaxyHandlerLogic {
@@ -26,68 +28,62 @@ class GalaxyHandlerLogic(val ops: SessionGalaxyHandlers, implicit val context: A
def handleUpdateIgnoredPlayers(pkt: FriendsResponse): Unit = {
sendResponse(pkt)
pkt.friends.foreach { f =>
- galaxyService ! GalaxyServiceMessage(GalaxyAction.LogStatusChange(f.name))
+ galaxyService ! MessageEnvelope("", GalaxyAction.LogStatusChange(f.name))
}
}
/* response handlers */
- def handle(reply: GalaxyResponse.Response): Unit = {
- reply match {
- case GalaxyResponse.HotSpotUpdate(zone_index, priority, hot_spot_info) =>
- sendResponse(
- HotSpotUpdateMessage(
- zone_index,
- priority,
- hot_spot_info.map { spot => PacketHotSpotInfo(spot.DisplayLocation.x, spot.DisplayLocation.y, 40) }
- )
+ def receive: Receive = {
+ case GalaxyAction.HotSpotUpdate(zone_index, priority, hot_spot_info) =>
+ sendResponse(
+ HotSpotUpdateMessage(
+ zone_index,
+ priority,
+ hot_spot_info.map { spot => PacketHotSpotInfo(spot.DisplayLocation.x, spot.DisplayLocation.y, 40) }
)
+ )
- case GalaxyResponse.MapUpdate(msg) =>
- sendResponse(msg)
- import net.psforever.actors.zone.ZoneActor
- import net.psforever.zones.Zones
- Zones.zones.find(_.Number == msg.continent_id) match {
- case Some(zone) =>
- zone.actor ! ZoneActor.BuildingInfoState(msg)
- case None =>
- }
+ case GalaxyAction.MapUpdate(msg) =>
+ sendResponse(msg)
+ import net.psforever.actors.zone.ZoneActor
+ import net.psforever.zones.Zones
+ Zones.zones.find(_.Number == msg.continent_id) match {
+ case Some(zone) =>
+ zone.actor ! ZoneActor.BuildingInfoState(msg)
+ case None =>
+ }
- case GalaxyResponse.UpdateBroadcastPrivileges(zoneId, gateMapId, fromFactions, toFactions) =>
- val faction = player.Faction
- val from = fromFactions.contains(faction)
- val to = toFactions.contains(faction)
- if (from && !to) {
- sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, PlanetSideEmpire.NEUTRAL))
- } else if (!from && to) {
- sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, faction))
- }
+ case GalaxyAction.UpdateBroadcastPrivileges(zoneId, gateMapId, fromFactions, toFactions) =>
+ val faction = player.Faction
+ val from = fromFactions.contains(faction)
+ val to = toFactions.contains(faction)
+ if (from && !to) {
+ sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, PlanetSideEmpire.NEUTRAL))
+ } else if (!from && to) {
+ sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, faction))
+ }
- case GalaxyResponse.FlagMapUpdate(msg) =>
- sendResponse(msg)
+ case GalaxyAction.FlagMapUpdate(msg) =>
+ sendResponse(msg)
- case GalaxyResponse.TransferPassenger(temp_channel, vehicle, _, manifest) =>
- sessionLogic.zoning.handleTransferPassenger(temp_channel, vehicle, manifest)
+ case GalaxyAction.TransferPassenger(_, temp_channel, vehicle, _, manifest) =>
+ sessionLogic.zoning.handleTransferPassenger(temp_channel, vehicle, manifest)
- case GalaxyResponse.LockedZoneUpdate(zone, time) =>
- sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
+ case GalaxyAction.LockedZoneUpdate(zone, time) =>
+ sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
- case GalaxyResponse.UnlockedZoneUpdate(zone) =>
- sendResponse(ZoneInfoMessage(zone.Number, empire_status=true, lock_time=0L))
- val popBO = 0
- val pop = zone.LivePlayers.distinctBy(_.CharId)
- val popTR = pop.count(_.Faction == PlanetSideEmpire.TR)
- val popNC = pop.count(_.Faction == PlanetSideEmpire.NC)
- val popVS = pop.count(_.Faction == PlanetSideEmpire.VS)
- sendResponse(ZonePopulationUpdateMessage(zone.Number, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
+ case GalaxyAction.UnlockedZoneUpdate(zone) =>
+ sendResponse(ZoneInfoMessage(zone.Number, empire_status=true, lock_time=0L))
+ val popBO = 0
+ val pop = zone.LivePlayers.distinctBy(_.CharId)
+ val popTR = pop.count(_.Faction == PlanetSideEmpire.TR)
+ val popNC = pop.count(_.Faction == PlanetSideEmpire.NC)
+ val popVS = pop.count(_.Faction == PlanetSideEmpire.VS)
+ sendResponse(ZonePopulationUpdateMessage(zone.Number, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
- case GalaxyResponse.LogStatusChange(name) if avatar.people.friend.exists(_.name.equals(name)) =>
- avatarActor ! AvatarActor.MemberListRequest(MemberAction.UpdateFriend, name)
-
- case GalaxyResponse.SendResponse(msg) =>
- sendResponse(msg)
-
- case _ => ()
- }
+ case GalaxyAction.LogStatusChange(name)
+ if TestFilter(() => avatar.people.friend.exists(_.name.equals(name))) =>
+ avatarActor ! AvatarActor.MemberListRequest(MemberAction.UpdateFriend, name)
}
}
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 df8a88363..076df89ac 100644
--- a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala
@@ -42,8 +42,9 @@ import net.psforever.objects.zones.{ZoneProjectile, Zoning}
import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.{ActionCancelMessage, ActionResultMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestAction, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitMembershipRequest, OutfitMembershipRequestAction, OutfitMembershipResponse, OutfitRequest, OutfitRequestAction, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage}
import net.psforever.services.account.{AccountPersistenceService, RetrieveAccountData}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.local.support.CaptureFlagManager
import net.psforever.types.{CapacitorStateType, ChatMessageType, Cosmetic, ExoSuitType, ImplantType, PlanetSideEmpire, PlanetSideGUID, Vector3}
import net.psforever.util.Config
@@ -179,10 +180,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case _ =>
false
})
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
+ avatarGuid,
AvatarAction.PlayerState(
- avatarGuid,
player.Position,
player.Velocity,
yaw,
@@ -196,7 +197,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
isNotVisible,
eagleEye
)
- )
+ ) //todo CachedMessage
sessionLogic.squad.updateSquad()
if (player.death_by == -1) {
sessionLogic.kickedByAdministration()
@@ -213,15 +214,8 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
}
def handleEmote(pkt: EmoteMsg): Unit = {
- val EmoteMsg(avatarGuid, emote) = pkt
- val pZone = player.Zone
- sendResponse(EmoteMsg(avatarGuid, emote))
- pZone.blockMap.sector(player).livePlayerList.collect { case t if t.GUID != player.GUID =>
- pZone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendResponse(EmoteMsg(avatarGuid, emote)))
- }
- pZone.AllPlayers.collect { case t if t.GUID != player.GUID && !t.allowInteraction =>
- pZone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendResponse(EmoteMsg(avatarGuid, emote)))
- }
+ sendResponse(pkt)
+ ops.handleEmote(pkt)
}
def handleDropItem(pkt: DropItemMessage): Unit = {
@@ -525,9 +519,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case GenericAction.MaxAnchorsExtend_RCV =>
log.info(s"${player.Name} has anchored ${player.Sex.pronounObject}self to the ground")
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.PlanetsideAttribute(player.GUID, 19, 1)
+ player.GUID,
+ PlanetsideAttribute(player.GUID, 19, 1)
)
definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
@@ -546,9 +541,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case GenericAction.MaxAnchorsRelease_RCV =>
log.info(s"${player.Name} has released the anchors")
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.PlanetsideAttribute(player.GUID, 19, 0)
+ player.GUID,
+ PlanetsideAttribute(player.GUID, 19, 0)
)
definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
diff --git a/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala
index 2f12efd95..003a60b08 100644
--- a/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala
@@ -1,17 +1,19 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.normal
+import akka.actor.Actor.Receive
import akka.actor.ActorContext
import net.psforever.actors.session.support.SpawnOperations.ActivityQueuedTask
import net.psforever.actors.session.support.{LocalHandlerFunctions, SessionData, SessionLocalHandlers, SpawnOperations}
import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.vehicles.MountableWeapons
-import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable}
-import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, HackState1, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage}
+import net.psforever.objects.{BoomerDeployable, Default, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable}
+import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, HackState1, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage}
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.services.{InterstellarClusterService, Service}
-import net.psforever.services.local.LocalResponse
-import net.psforever.types.{ChatMessageType, PlanetSideGUID, SpawnGroup}
+import net.psforever.services.local.LocalAction
+import net.psforever.types.{ChatMessageType, SpawnGroup}
object LocalHandlerLogic {
def apply(ops: SessionLocalHandlers): LocalHandlerLogic = {
@@ -34,244 +36,218 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act
/* response handlers */
- /**
- * na
- * @param toChannel na
- * @param guid na
- * @param reply na
- */
- def handle(toChannel: String, guid: PlanetSideGUID, reply: LocalResponse.Response): Unit = {
- val resolvedPlayerGuid = if (player.HasGUID) {
- player.GUID
- } else {
- Service.defaultPlayerGUID
- }
- val isNotSameTarget = resolvedPlayerGuid != guid
- reply match {
- case LocalResponse.DeployableMapIcon(behavior, deployInfo) if isNotSameTarget =>
- sendResponse(DeployableObjectsInfoMessage(behavior, deployInfo))
-
- case LocalResponse.DeployableUIFor(item) =>
- sessionLogic.general.updateDeployableUIElements(avatar.deployables.UpdateUIElement(item))
-
- case LocalResponse.Detonate(dguid, _: BoomerDeployable) =>
- sendResponse(TriggerEffectMessage(dguid, "detonate_boomer"))
- sendResponse(PlanetsideAttributeMessage(dguid, attribute_type=29, attribute_value=1))
- sendResponse(ObjectDeleteMessage(dguid, unk1=0))
-
- case LocalResponse.Detonate(dguid, _: ExplosiveDeployable) =>
- sendResponse(GenericObjectActionMessage(dguid, code=19))
- sendResponse(PlanetsideAttributeMessage(dguid, attribute_type=29, attribute_value=1))
- sendResponse(ObjectDeleteMessage(dguid, unk1=0))
-
- case LocalResponse.Detonate(_, obj) =>
- log.warn(s"LocalResponse.Detonate: ${obj.Definition.Name} not configured to explode correctly")
-
- case LocalResponse.DoorOpens(doorGuid) if isNotSameTarget =>
- val pos = player.Position.xy
- val range = ops.doorLoadRange()
- val foundDoor = continent
- .blockMap
- .sector(pos, range)
- .amenityList
- .collect { case door: Door => door }
- .find(_.GUID == doorGuid)
- val doorExistsInRange: Boolean = foundDoor.nonEmpty
- if (doorExistsInRange) {
- sendResponse(GenericObjectStateMsg(doorGuid, state=16))
- }
-
- case LocalResponse.DoorCloses(doorGuid) => //door closes for everyone
- sendResponse(GenericObjectStateMsg(doorGuid, state=17))
-
- case LocalResponse.EliminateDeployable(obj: TurretDeployable, dguid, _, _) if obj.Destroyed =>
- sendResponse(ObjectDeleteMessage(dguid, unk1=0))
-
- case LocalResponse.EliminateDeployable(obj: TurretDeployable, dguid, pos, _) =>
- obj.Destroyed = true
- ops.DeconstructDeployable(
- obj,
- dguid,
- pos,
- obj.Orientation,
- deletionType= if (obj.MountPoints.isEmpty) { 2 } else { 1 }
- )
-
- case LocalResponse.EliminateDeployable(obj: ExplosiveDeployable, dguid, _, _)
- if obj.Destroyed || obj.Jammed || obj.Health == 0 =>
- sendResponse(ObjectDeleteMessage(dguid, unk1=0))
-
- case LocalResponse.EliminateDeployable(obj: ExplosiveDeployable, dguid, pos, effect) =>
- obj.Destroyed = true
- ops.DeconstructDeployable(obj, dguid, pos, obj.Orientation, effect)
-
- case LocalResponse.EliminateDeployable(obj: TelepadDeployable, dguid, _, _) if obj.Active && obj.Destroyed =>
- //if active, deactivate
- obj.Active = false
- ops.deactivateTelpadDeployableMessages(dguid)
- //standard deployable elimination behavior
- sendResponse(ObjectDeleteMessage(dguid, unk1=0))
-
- case LocalResponse.EliminateDeployable(obj: TelepadDeployable, dguid, pos, _) if obj.Active =>
- //if active, deactivate
- obj.Active = false
- ops.deactivateTelpadDeployableMessages(dguid)
- //standard deployable elimination behavior
- obj.Destroyed = true
- ops.DeconstructDeployable(obj, dguid, pos, obj.Orientation, deletionType=2)
-
- case LocalResponse.EliminateDeployable(obj: TelepadDeployable, dguid, _, _) if obj.Destroyed =>
- //standard deployable elimination behavior
- sendResponse(ObjectDeleteMessage(dguid, unk1=0))
-
- case LocalResponse.EliminateDeployable(obj: TelepadDeployable, dguid, pos, _) =>
- //standard deployable elimination behavior
- obj.Destroyed = true
- ops.DeconstructDeployable(obj, dguid, pos, obj.Orientation, deletionType=2)
-
- case LocalResponse.EliminateDeployable(obj, dguid, _, _) if obj.Destroyed =>
- sendResponse(ObjectDeleteMessage(dguid, unk1=0))
-
- case LocalResponse.EliminateDeployable(obj, dguid, pos, effect) =>
- obj.Destroyed = true
- ops.DeconstructDeployable(obj, dguid, pos, obj.Orientation, effect)
-
- case LocalResponse.SendHackMessageHackCleared(targetGuid, unk1, unk2) =>
- sendResponse(HackMessage(HackState1.Unk0, targetGuid, guid, progress=0, unk1.toFloat, HackState.HackCleared, unk2))
-
- case LocalResponse.HackObject(targetGuid, unk1, unk2) =>
- sessionLogic.general.hackObject(targetGuid, unk1, unk2)
-
- case LocalResponse.PlanetsideAttribute(targetGuid, attributeType, attributeValue) =>
- sessionLogic.general.sendPlanetsideAttributeMessage(targetGuid, attributeType, attributeValue)
-
- case LocalResponse.GenericObjectAction(targetGuid, actionNumber) =>
- sendResponse(GenericObjectActionMessage(targetGuid, actionNumber))
-
- case LocalResponse.GenericActionMessage(actionNumber) =>
- sendResponse(GenericActionMessage(actionNumber))
-
- case LocalResponse.ChatMessage(msg) =>
- sendResponse(msg)
-
- case LocalResponse.SendPacket(packet) =>
- sendResponse(packet)
-
- case LocalResponse.LluSpawned(llu) =>
- // Create LLU on client
- sendResponse(ObjectCreateMessage(
- llu.Definition.ObjectId,
- llu.GUID,
- llu.Definition.Packet.ConstructorData(llu).get
- ))
- sendResponse(TriggerSoundMessage(TriggeredSound.LLUMaterialize, llu.Position, unk=20, volume=0.8000001f))
-
- case LocalResponse.LluDespawned(lluGuid, position) =>
- sendResponse(TriggerSoundMessage(TriggeredSound.LLUDeconstruct, position, unk=20, volume=0.8000001f))
- sendResponse(ObjectDeleteMessage(lluGuid, unk1=0))
- // If the player was holding the LLU, remove it from their tracked special item slot
- sessionLogic.general.specialItemSlotGuid.collect { case guid if guid == lluGuid =>
- sessionLogic.general.specialItemSlotGuid = None
- player.Carrying = None
- }
-
- case LocalResponse.ObjectDelete(objectGuid, unk) if isNotSameTarget =>
- sendResponse(ObjectDeleteMessage(objectGuid, unk))
-
- case LocalResponse.ProximityTerminalEffect(object_guid, true) =>
- sendResponse(ProximityTerminalUseMessage(Service.defaultPlayerGUID, object_guid, unk=true))
-
- case LocalResponse.ProximityTerminalEffect(objectGuid, false) =>
- sendResponse(ProximityTerminalUseMessage(Service.defaultPlayerGUID, objectGuid, unk=false))
- sessionLogic.terminals.ForgetAllProximityTerminals(objectGuid)
-
- case LocalResponse.RouterTelepadMessage(msg) =>
- sendResponse(ChatMsg(ChatMessageType.UNK_229, wideContents=false, recipient="", msg, note=None))
-
- case LocalResponse.RouterTelepadTransport(passengerGuid, srcGuid, destGuid) =>
- sessionLogic.general.useRouterTelepadEffect(passengerGuid, srcGuid, destGuid)
-
- case LocalResponse.SendResponse(msg) =>
- msg match {
- case m: GenericObjectActionMessage =>
- // delay building virus alert if player is dead/respawning
- if ((m.code == 58 || m.code == 60 || m.code == 61) && !sessionLogic.zoning.spawn.startEnqueueSquadMessages) {
- sessionLogic.zoning.spawn.enqueueNewActivity(ActivityQueuedTask(
- SpawnOperations.delaySendGenericObjectActionMessage(msg), 1))
- }
- else sendResponse(msg)
- case _ =>
- sendResponse(msg)
- }
-
- case LocalResponse.SetEmpire(objectGuid, empire) =>
- sendResponse(SetEmpireMessage(objectGuid, empire))
-
- case LocalResponse.ShuttleEvent(ev) =>
- val msg = OrbitalShuttleTimeMsg(
- ev.u1,
- ev.u2,
- ev.t1,
- ev.t2,
- ev.t3,
- pairs=ev.pairs.map { case ((a, b), c) => PadAndShuttlePair(a, b, c) }
- )
- sendResponse(msg)
-
- case LocalResponse.ShuttleDock(pguid, sguid, slot) =>
- sendResponse(ObjectAttachMessage(pguid, sguid, slot))
-
- case LocalResponse.ShuttleUndock(pguid, sguid, pos, orient) =>
- sendResponse(ObjectDetachMessage(pguid, sguid, pos, orient))
-
- case LocalResponse.ShuttleState(sguid, pos, orient, state) =>
- sendResponse(VehicleStateMessage(sguid, unk1=0, pos, orient, vel=None, Some(state), unk3=0, unk4=0, wheel_direction=15, is_decelerating=false, is_cloaked=false))
-
- case LocalResponse.ToggleTeleportSystem(router, systemPlan) =>
- sessionLogic.general.toggleTeleportSystem(router, systemPlan)
-
- case LocalResponse.TriggerEffect(targetGuid, effect, effectInfo, triggerLocation) =>
- sendResponse(TriggerEffectMessage(targetGuid, effect, effectInfo, triggerLocation))
-
- case LocalResponse.TriggerSound(sound, pos, unk, volume) =>
- sendResponse(TriggerSoundMessage(sound, pos, unk, volume))
-
- case LocalResponse.UpdateForceDomeStatus(buildingGuid, true) =>
- sendResponse(GenericObjectActionMessage(buildingGuid, 11))
-
- case LocalResponse.UpdateForceDomeStatus(buildingGuid, false) =>
- sendResponse(GenericObjectActionMessage(buildingGuid, 12))
-
- case LocalResponse.RechargeVehicleWeapon(vehicleGuid, weaponGuid) if resolvedPlayerGuid == guid =>
- continent.GUID(vehicleGuid)
- .collect { case vehicle: MountableWeapons => (vehicle, vehicle.PassengerInSeat(player)) }
- .collect { case (vehicle, Some(seat_num)) => vehicle.WeaponControlledFromSeat(seat_num) }
- .getOrElse(Set.empty)
- .collect { case weapon: Tool if weapon.GUID == weaponGuid =>
- sendResponse(InventoryStateMessage(weapon.AmmoSlot.Box.GUID, weapon.GUID, weapon.Magazine))
- }
-
- case LocalResponse.ForceZoneChange(zone) =>
- //todo we might be able to piggyback this for squad recalls later
- if(session.zone eq zone) {
- sessionLogic.zoning.zoneReload = true
- zone.AvatarEvents ! Service.Leave()
- zone.LocalEvents ! Service.Leave()
- zone.VehicleEvents ! Service.Leave()
- zone.AvatarEvents ! Service.Join(player.Name) //must manually restore this subscriptions
- sessionLogic.zoning.spawn.handleNewPlayerLoaded(player) //will restart subscriptions and dispatch a LoadMapMessage
- } else {
- import akka.actor.typed.scaladsl.adapter._
- sessionLogic.cluster ! InterstellarClusterService.GetRandomSpawnPoint(
- zone.Number,
- player.Faction,
- Seq(SpawnGroup.Facility, SpawnGroup.Tower, SpawnGroup.AMS),
- context.self
+ def receive: Receive = {
+ case SendResponse(msgs) =>
+ msgs.foreach {
+ case msg @ (m: GenericObjectActionMessage)
+ if (m.code == 58 || m.code == 60 || m.code == 61) && !sessionLogic.zoning.spawn.startEnqueueSquadMessages =>
+ // delay building virus alert if player is dead/respawning
+ sessionLogic.zoning.spawn.enqueueNewActivity(ActivityQueuedTask(
+ SpawnOperations.delaySendGenericObjectActionMessage(msg), 1)
)
+ case msg =>
+ sendResponse(msg)
+ }
+
+ case LocalAction.DeployableMapIcon(behavior, deployInfo)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(DeployableObjectsInfoMessage(behavior, deployInfo))
+
+ case LocalAction.DeployableUIFor(item) =>
+ sessionLogic.general.updateDeployableUIElements(avatar.deployables.UpdateUIElement(item))
+
+ case LocalAction.Detonate(dguid, _: BoomerDeployable) =>
+ sendResponse(TriggerEffectMessage(dguid, "detonate_boomer"))
+ sendResponse(PlanetsideAttributeMessage(dguid, attribute_type=29, attribute_value=1))
+ sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+
+ case LocalAction.Detonate(dguid, _: ExplosiveDeployable) =>
+ sendResponse(GenericObjectActionMessage(dguid, code=19))
+ sendResponse(PlanetsideAttributeMessage(dguid, attribute_type=29, attribute_value=1))
+ sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+
+ case LocalAction.Detonate(_, obj) =>
+ log.warn(s"LocalAction.Detonate: ${obj.Definition.Name} not configured to explode correctly")
+
+ case LocalAction.DoorOpens(_, door)
+ if TestFilter(NotSameTargetTest) =>
+ val doorGuid = door.GUID
+ val pos = player.Position.xy
+ val range = ops.doorLoadRange()
+ val foundDoor = continent
+ .blockMap
+ .sector(pos, range)
+ .amenityList
+ .collect { case door: Door => door }
+ .find(_.GUID == doorGuid)
+ val doorExistsInRange: Boolean = foundDoor.nonEmpty
+ if (doorExistsInRange) {
+ sendResponse(GenericObjectStateMsg(doorGuid, state=16))
+ }
+
+ case LocalAction.DoorCloses(doorGuid) => //door closes for everyone
+ sendResponse(GenericObjectStateMsg(doorGuid, state=17))
+
+ case LocalAction.EliminateDeployable(obj: TurretDeployable, dguid, _, _)
+ if TestFilter(() => obj.Destroyed) =>
+ sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+
+ case LocalAction.EliminateDeployable(obj: TurretDeployable, dguid, pos, _) =>
+ obj.Destroyed = true
+ ops.DeconstructDeployable(
+ obj,
+ dguid,
+ pos,
+ obj.Orientation,
+ deletionType= if (obj.MountPoints.isEmpty) { 2 } else { 1 }
+ )
+
+ case LocalAction.EliminateDeployable(obj: ExplosiveDeployable, dguid, _, _)
+ if TestFilter(() => { obj.Destroyed || obj.Jammed || obj.Health == 0 }) =>
+ sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+
+ case LocalAction.EliminateDeployable(obj: ExplosiveDeployable, dguid, pos, effect) =>
+ obj.Destroyed = true
+ ops.DeconstructDeployable(obj, dguid, pos, obj.Orientation, effect)
+
+ case LocalAction.EliminateDeployable(obj: TelepadDeployable, dguid, _, _)
+ if TestFilter(() => { obj.Active && obj.Destroyed }) =>
+ //if active, deactivate
+ obj.Active = false
+ ops.deactivateTelpadDeployableMessages(dguid)
+ //standard deployable elimination behavior
+ sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+
+ case LocalAction.EliminateDeployable(obj: TelepadDeployable, dguid, pos, _)
+ if TestFilter(() => obj.Active) =>
+ //if active, deactivate
+ obj.Active = false
+ ops.deactivateTelpadDeployableMessages(dguid)
+ //standard deployable elimination behavior
+ obj.Destroyed = true
+ ops.DeconstructDeployable(obj, dguid, pos, obj.Orientation, deletionType=2)
+
+ case LocalAction.EliminateDeployable(obj: TelepadDeployable, dguid, _, _)
+ if TestFilter(() => obj.Destroyed) =>
+ //standard deployable elimination behavior
+ sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+
+ case LocalAction.EliminateDeployable(obj: TelepadDeployable, dguid, pos, _) =>
+ //standard deployable elimination behavior
+ obj.Destroyed = true
+ ops.DeconstructDeployable(obj, dguid, pos, obj.Orientation, deletionType=2)
+
+ case LocalAction.EliminateDeployable(obj, dguid, _, _)
+ if TestFilter(() => obj.Destroyed) =>
+ sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+
+ case LocalAction.EliminateDeployable(obj, dguid, pos, effect) =>
+ obj.Destroyed = true
+ ops.DeconstructDeployable(obj, dguid, pos, obj.Orientation, effect)
+
+ case LocalAction.HackClear(targetGuid, unk1, unk2) =>
+ sendResponse(HackMessage(HackState1.Unk0, targetGuid, FilterGuid, progress=0, unk1.toFloat, HackState.HackCleared, unk2))
+
+ case LocalAction.HackObject(targetGuid, unk1, unk2) =>
+ sessionLogic.general.hackObject(targetGuid, unk1, unk2)
+
+ case LocalAction.GenericActionMessage(actionNumber) =>
+ sendResponse(GenericActionMessage(actionNumber))
+
+ case LocalAction.LluSpawned(llu) =>
+ // Create LLU on client
+ sendResponse(ObjectCreateMessage(
+ llu.Definition.ObjectId,
+ llu.GUID,
+ llu.Definition.Packet.ConstructorData(llu).get
+ ))
+ sendResponse(TriggerSoundMessage(TriggeredSound.LLUMaterialize, llu.Position, unk=20, volume=0.8000001f))
+
+ case LocalAction.LluDespawned(lluGuid, position) =>
+ sendResponse(TriggerSoundMessage(TriggeredSound.LLUDeconstruct, position, unk=20, volume=0.8000001f))
+ sendResponse(ObjectDeleteMessage(lluGuid, unk1=0))
+ // If the player was holding the LLU, remove it from their tracked special item slot
+ sessionLogic.general.specialItemSlotGuid.collect { case guid if guid == lluGuid =>
+ sessionLogic.general.specialItemSlotGuid = None
+ player.Carrying = None
+ }
+
+ case LocalAction.ProximityTerminalEffect(object_guid, true) =>
+ sendResponse(ProximityTerminalUseMessage(Default.GUID0, object_guid, unk=true))
+
+ case LocalAction.ProximityTerminalEffect(objectGuid, false) =>
+ sendResponse(ProximityTerminalUseMessage(Default.GUID0, objectGuid, unk=false))
+ sessionLogic.terminals.ForgetAllProximityTerminals(objectGuid)
+
+ case LocalAction.RouterTelepadMessage(msg) =>
+ sendResponse(ChatMsg(ChatMessageType.UNK_229, wideContents=false, recipient="", msg, note=None))
+
+ case LocalAction.RouterTelepadTransport(passengerGuid, srcGuid, destGuid) =>
+ sessionLogic.general.useRouterTelepadEffect(passengerGuid, srcGuid, destGuid)
+
+ case LocalAction.ShuttleEvent(ev) =>
+ val msg = OrbitalShuttleTimeMsg(
+ ev.u1,
+ ev.u2,
+ ev.t1,
+ ev.t2,
+ ev.t3,
+ pairs=ev.pairs.map { case ((a, b), c) => PadAndShuttlePair(a, b, c) }
+ )
+ sendResponse(msg)
+
+ case LocalAction.ShuttleDock(pguid, sguid, slot) =>
+ sendResponse(ObjectAttachMessage(pguid, sguid, slot))
+
+ case LocalAction.ShuttleUndock(pguid, sguid, pos, orient) =>
+ sendResponse(ObjectDetachMessage(pguid, sguid, pos, orient))
+
+ case LocalAction.ShuttleState(sguid, pos, orient, state) =>
+ sendResponse(VehicleStateMessage(sguid, unk1=0, pos, orient, vel=None, Some(state), unk3=0, unk4=0, wheel_direction=15, is_decelerating=false, is_cloaked=false))
+
+ case LocalAction.ToggleTeleportSystem(router, systemPlan) =>
+ sessionLogic.general.toggleTeleportSystem(router, systemPlan)
+
+ case LocalAction.TriggerEffectAtLocation(targetGuid, effect, effectInfo, triggerLocation) =>
+ sendResponse(TriggerEffectMessage(targetGuid, effect, effectInfo, triggerLocation))
+
+ case LocalAction.TriggerSound(sound, pos, unk, volume) =>
+ sendResponse(TriggerSoundMessage(sound, pos, unk, volume))
+
+ case LocalAction.UpdateForceDomeStatus(buildingGuid, true) =>
+ sendResponse(GenericObjectActionMessage(buildingGuid, 11))
+
+ case LocalAction.UpdateForceDomeStatus(buildingGuid, false) =>
+ sendResponse(GenericObjectActionMessage(buildingGuid, 12))
+
+ case LocalAction.RechargeVehicleWeapon(vehicleGuid, weaponGuid)
+ if TestFilter(SameTargetTest) =>
+ continent.GUID(vehicleGuid)
+ .collect { case vehicle: MountableWeapons => (vehicle, vehicle.PassengerInSeat(player)) }
+ .collect { case (vehicle, Some(seat_num)) => vehicle.WeaponControlledFromSeat(seat_num) }
+ .getOrElse(Set.empty)
+ .collect { case weapon: Tool if weapon.GUID == weaponGuid =>
+ sendResponse(InventoryStateMessage(weapon.AmmoSlot.Box.GUID, weapon.GUID, weapon.Magazine))
}
- case _ => ()
- }
+ case LocalAction.ForceZoneChange(zone) =>
+ //todo we might be able to piggyback this for squad recalls later
+ if(session.zone eq zone) {
+ sessionLogic.zoning.zoneReload = true
+ zone.AvatarEvents ! Service.LeaveAll
+ zone.LocalEvents ! Service.LeaveAll
+ zone.VehicleEvents ! Service.LeaveAll
+ zone.AvatarEvents ! Service.Join(player.Name) //must manually restore this subscriptions
+ sessionLogic.zoning.spawn.handleNewPlayerLoaded(player) //will restart subscriptions and dispatch a LoadMapMessage
+ } else {
+ import akka.actor.typed.scaladsl.adapter._
+ sessionLogic.cluster ! InterstellarClusterService.GetRandomSpawnPoint(
+ zone.Number,
+ player.Faction,
+ Seq(SpawnGroup.Facility, SpawnGroup.Tower, SpawnGroup.AMS),
+ context.self
+ )
+ }
}
/* support functions */
diff --git a/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala
index ae8399757..aa0f86714 100644
--- a/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala
@@ -16,9 +16,9 @@ import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
import net.psforever.objects.vehicles.AccessPermissionGroup
import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{ChatMsg, DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlanetsideAttributeMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{SendResponse, SetEmpire}
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3}
object MountHandlerLogic {
@@ -191,7 +191,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
if obj.Definition == GlobalDefinitions.vanu_sentry_turret =>
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
- obj.Zone.LocalEvents ! LocalServiceMessage(obj.Zone.id, LocalAction.SetEmpire(obj.GUID, player.Faction))
+ obj.Zone.LocalEvents ! MessageEnvelope(obj.Zone.id, SetEmpire(obj.GUID, player.Faction))
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
ops.updateWeaponAtSeatPosition(obj, seatNumber)
ops.MountingAction(tplayer, obj, seatNumber)
@@ -234,9 +234,9 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
val (pos, zang) = Vehicles.dismountShuttle(obj, mountPoint)
tplayer.Position = pos
sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true))
- continent.LocalEvents ! LocalServiceMessage(
+ continent.LocalEvents ! MessageEnvelope(
continent.id,
- LocalAction.SendResponse(ObjectDetachMessage(sguid, pguid, pos, roll=0, pitch=0, zang))
+ SendResponse(ObjectDetachMessage(sguid, pguid, pos, roll=0, pitch=0, zang))
)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
@@ -249,25 +249,21 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountAction(tplayer, obj, seatNum)
continent.actor ! ZoneActor.RemoveFromBlockMap(player) //character doesn't need it
//DismountAction(...) uses vehicle service, so use that service to coordinate the remainder of the messages
- events ! VehicleServiceMessage(
- player.Name,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, PlayerStasisMessage(pguid)) //the stasis message
- )
//when the player dismounts, they will be positioned where the shuttle was when it disappeared in the sky
//the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone
//having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
- events ! VehicleServiceMessage(
- player.Name,
- VehicleAction.SendResponse(
- Service.defaultPlayerGUID,
- PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)) //cower in the shuttle bay
+ events ! BundledEnvelope(
+ MessageEnvelope(player.Name,
+ SendResponse(Seq(
+ PlayerStasisMessage(pguid),
+ PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
+ ))
+ ),
+ MessageEnvelope(continent.id, pguid,
+ SendResponse(GenericObjectActionMessage(pguid, code=9)) /* conceal the player */
)
)
- events ! VehicleServiceMessage(
- continent.id,
- VehicleAction.SendResponse(pguid, GenericObjectActionMessage(pguid, code=9)) //conceal the player
- )
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
@@ -293,9 +289,10 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountVehicleAction(tplayer, obj, seatNum)
case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.KickPassenger(tplayer.GUID, seat_num, unk2=true, obj.GUID)
+ tplayer.GUID,
+ VehicleAction.KickPassenger(seat_num, unk2=true, obj.GUID)
)
case Mountable.CanDismount(obj: PlanetSideGameObject with Mountable with FactionAffinity with InGameHistory, seatNum, _) =>
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 f6102dedb..da83bc6ed 100644
--- a/src/main/scala/net/psforever/actors/session/normal/VehicleHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/normal/VehicleHandlerLogic.scala
@@ -1,21 +1,23 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.normal
+import akka.actor.Actor.Receive
import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.AvatarActor
import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions}
import net.psforever.objects.avatar.SpecialCarry
-import net.psforever.objects.{GlobalDefinitions, Player, Tool, Vehicle, Vehicles}
+import net.psforever.objects.{GlobalDefinitions, Player, Vehicle, Vehicles}
import net.psforever.objects.equipment.{Equipment, JammableMountedWeapons, JammableUnit}
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects.serverobject.interior.Sidedness.OutsideOf
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
-import net.psforever.packet.game.{ChangeAmmoMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, HitHint, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ReloadMessage, ServerVehicleOverrideMsg, VehicleStateMessage, WeaponDryFireMessage}
+import net.psforever.packet.game.{ChatMsg, ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ServerVehicleOverrideMsg, VehicleStateMessage}
import net.psforever.services.Service
+import net.psforever.services.base.envelope.GenericResponseEnvelope
import net.psforever.services.local.support.CaptureFlagManager
-import net.psforever.services.vehicle.{VehicleResponse, VehicleServiceResponse}
+import net.psforever.services.vehicle.{VehicleAction, VehicleStamp}
import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
object VehicleHandlerLogic {
@@ -31,365 +33,319 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
private val galaxyService: ActorRef = ops.galaxyService
- /**
- * na
- *
- * @param toChannel na
- * @param guid na
- * @param reply na
- */
- def handle(toChannel: String, guid: PlanetSideGUID, reply: VehicleResponse.Response): Unit = {
- val resolvedPlayerGuid = if (player.HasGUID) {
- player.GUID
- } else {
- PlanetSideGUID(-1)
- }
- val isNotSameTarget = resolvedPlayerGuid != guid
- reply match {
- case VehicleResponse.VehicleState(
- vehicleGuid,
- unk1,
- pos,
- orient,
- vel,
- unk2,
- unk3,
- unk4,
- wheelDirection,
- unk5,
- unk6
- ) if isNotSameTarget && player.VehicleSeated.contains(vehicleGuid) =>
- //player who is also in the vehicle (not driver)
- sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, orient, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
- player.Position = pos
- player.Orientation = orient
- player.Velocity = vel
- sessionLogic.updateLocalBlockMap(pos)
- //llu destruction check
- if (player.Carrying.contains(SpecialCarry.CaptureFlag)) {
- continent
- .GUID(player.VehicleSeated)
- .collect { case vehicle: Vehicle =>
- CaptureFlagManager.ReasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, vehicle)
- }
- }
-
- case VehicleResponse.VehicleState(
- vehicleGuid,
- unk1,
- pos,
- ang,
- vel,
- unk2,
- unk3,
- unk4,
- wheelDirection,
- unk5,
- unk6
- ) if isNotSameTarget =>
- //player who is watching the vehicle from the outside
- sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
-
- case VehicleResponse.ChildObjectState(objectGuid, pitch, yaw) if isNotSameTarget =>
- sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
-
- case VehicleResponse.FrameVehicleState(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)
- if isNotSameTarget =>
- sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
-
- case VehicleResponse.ChangeFireState_Start(weaponGuid) if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Start(weaponGuid))
-
- case VehicleResponse.ChangeFireState_Stop(weaponGuid) if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
-
- case VehicleResponse.Reload(itemGuid) if isNotSameTarget =>
- sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
-
- case VehicleResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data) if isNotSameTarget =>
- sendResponse(ObjectDetachMessage(weapon_guid, previous_guid, Vector3.Zero, 0))
- //TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
- sendResponse(
- ObjectCreateMessage(
- ammo_id,
- ammo_guid,
- ObjectCreateMessageParent(weapon_guid, weapon_slot),
- ammo_data
- )
- )
- sendResponse(ChangeAmmoMessage(weapon_guid, 1))
-
- case VehicleResponse.WeaponDryFire(weaponGuid) if isNotSameTarget =>
- continent.GUID(weaponGuid).collect {
- case tool: Tool if tool.Magazine == 0 =>
- // check that the magazine is still empty before sending WeaponDryFireMessage
- // if it has been reloaded since then, other clients will not see it firing
- sendResponse(WeaponDryFireMessage(weaponGuid))
- }
-
- case VehicleResponse.DismountVehicle(bailType, wasKickedByDriver) if isNotSameTarget =>
- sendResponse(DismountVehicleMsg(guid, bailType, wasKickedByDriver))
-
- case VehicleResponse.MountVehicle(vehicleGuid, seat) if isNotSameTarget =>
- sendResponse(ObjectAttachMessage(vehicleGuid, guid, seat))
-
- case VehicleResponse.DeployRequest(objectGuid, state, unk1, unk2, pos) if isNotSameTarget =>
- sendResponse(DeployRequestMessage(guid, objectGuid, state, unk1, unk2, pos))
-
- case VehicleResponse.SendResponse(msg) =>
- sendResponse(msg)
-
- case VehicleResponse.AttachToRails(vehicleGuid, padGuid) =>
- sendResponse(ObjectAttachMessage(padGuid, vehicleGuid, slot=3))
-
- case VehicleResponse.ConcealPlayer(playerGuid) =>
- sendResponse(GenericObjectActionMessage(playerGuid, code=9))
-
- case VehicleResponse.DetachFromRails(vehicleGuid, padGuid, padPosition, padOrientationZ) =>
- val pad = continent.GUID(padGuid).get.asInstanceOf[VehicleSpawnPad].Definition
- sendResponse(
- ObjectDetachMessage(
- padGuid,
- vehicleGuid,
- padPosition + Vector3.z(pad.VehicleCreationZOffset),
- padOrientationZ + pad.VehicleCreationZOrientOffset
- )
- )
-
- case VehicleResponse.EquipmentInSlot(pkt) if isNotSameTarget =>
- sendResponse(pkt)
-
- case VehicleResponse.GenericObjectAction(objectGuid, action) if isNotSameTarget =>
- sendResponse(GenericObjectActionMessage(objectGuid, action))
-
- case VehicleResponse.HitHint(sourceGuid) if player.isAlive =>
- sendResponse(HitHint(sourceGuid, player.GUID))
-
- case VehicleResponse.InventoryState(obj, parentGuid, start, conData) if isNotSameTarget =>
- //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
- val objGuid = obj.GUID
- sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
- sendResponse(ObjectCreateDetailedMessage(
- obj.Definition.ObjectId,
- objGuid,
- ObjectCreateMessageParent(parentGuid, start),
- conData
- ))
-
- case VehicleResponse.KickPassenger(_, wasKickedByDriver, vehicleGuid) if resolvedPlayerGuid == guid =>
- //seat number (first field) seems to be correct if passenger is kicked manually by driver
- //but always seems to return 4 if user is kicked by mount permissions changing
- sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
- val typeOfRide = continent.GUID(vehicleGuid) match {
- case Some(obj: Vehicle) =>
- sessionLogic.general.unaccessContainer(obj)
- s"the ${obj.Definition.Name}'s seat by ${obj.OwnerName.getOrElse("the pilot")}"
- case _ =>
- s"${player.Sex.possessive} ride"
- }
- log.info(s"${player.Name} has been kicked from $typeOfRide!")
- player.WhichSide = OutsideOf
-
- case VehicleResponse.KickPassenger(_, wasKickedByDriver, _) =>
- //seat number (first field) seems to be correct if passenger is kicked manually by driver
- //but always seems to return 4 if user is kicked by mount permissions changing
- sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
-
- case VehicleResponse.InventoryState2(objGuid, parentGuid, value) if isNotSameTarget =>
- sendResponse(InventoryStateMessage(objGuid, unk=0, parentGuid, value))
-
- case VehicleResponse.LoadVehicle(vehicle, vtype, vguid, vdata) if isNotSameTarget =>
- //this is not be suitable for vehicles with people who are seated in it before it spawns (if that is possible)
- sendResponse(ObjectCreateMessage(vtype, vguid, vdata))
- Vehicles.ReloadAccessPermissions(vehicle, player.Name)
-
- case VehicleResponse.ObjectDelete(itemGuid) if isNotSameTarget =>
- sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
-
- case VehicleResponse.Ownership(vehicleGuid) if resolvedPlayerGuid == guid =>
- //Only the player that owns this vehicle needs the ownership packet
- avatarActor ! AvatarActor.SetVehicle(Some(vehicleGuid))
- sendResponse(PlanetsideAttributeMessage(resolvedPlayerGuid, attribute_type=21, vehicleGuid))
-
- case VehicleResponse.LoseOwnership(_, vehicleGuid) =>
- ops.announceAmsDecay(vehicleGuid,msg = "@ams_decaystarted")
-
- case VehicleResponse.PlanetsideAttribute(vehicleGuid, attributeType, attributeValue) if isNotSameTarget =>
- sendResponse(PlanetsideAttributeMessage(vehicleGuid, attributeType, attributeValue))
-
- case VehicleResponse.ResetSpawnPad(padGuid) =>
- sendResponse(GenericObjectActionMessage(padGuid, code=23))
-
- case VehicleResponse.RevealPlayer(playerGuid) =>
- sendResponse(GenericObjectActionMessage(playerGuid, code=10))
-
- case VehicleResponse.SeatPermissions(vehicleGuid, seatGroup, permission) if isNotSameTarget =>
- sendResponse(PlanetsideAttributeMessage(vehicleGuid, seatGroup, permission))
-
- case VehicleResponse.StowEquipment(vehicleGuid, slot, itemType, itemGuid, itemData) if isNotSameTarget =>
- //TODO prefer ObjectAttachMessage, but how to force ammo pools to update properly?
- sendResponse(ObjectCreateDetailedMessage(itemType, itemGuid, ObjectCreateMessageParent(vehicleGuid, slot), itemData))
-
- case VehicleResponse.UnloadVehicle(_, vehicleGuid) =>
- sendResponse(ObjectDeleteMessage(vehicleGuid, unk1=1))
- if (sessionLogic.zoning.spawn.prevSpawnPoint.map(_.Owner).exists {
- case ams: Vehicle =>
- ams.GUID == vehicleGuid &&
- ams.OwnerGuid.isEmpty
- case _ =>
- false
- }) {
- sessionLogic.zoning.spawn.prevSpawnPoint = None
- sendResponse(ChatMsg(ChatMessageType.UNK_229, "@ams_decayed"))
- }
-
- case VehicleResponse.UnstowEquipment(itemGuid) if isNotSameTarget =>
- //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
- sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
-
- case VehicleResponse.UpdateAmsSpawnPoint(list) =>
- sessionLogic.zoning.spawn.amsSpawnPoints = list.filter(tube => tube.Faction == player.Faction)
- sessionLogic.zoning.spawn.DrawCurrentAmsSpawnPoint()
-
- case VehicleResponse.TransferPassengerChannel(oldChannel, tempChannel, vehicle, vehicleToDelete) if isNotSameTarget =>
- sessionLogic.zoning.interstellarFerry = Some(vehicle)
- sessionLogic.zoning.interstellarFerryTopLevelGUID = Some(vehicleToDelete)
- continent.VehicleEvents ! Service.Leave(Some(oldChannel)) //old vehicle-specific channel (was s"${vehicle.Actor}")
- galaxyService ! Service.Join(tempChannel) //temporary vehicle-specific channel
- log.debug(s"TransferPassengerChannel: ${player.Name} now subscribed to $tempChannel for vehicle gating")
-
- case VehicleResponse.KickCargo(vehicle, speed, delay)
- if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive && speed > 0 =>
- val strafe = 1 + Vehicles.CargoOrientation(vehicle)
- val reverseSpeed = if (strafe > 1) { 0 } else { speed }
- //strafe or reverse, not both
- sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
- vehicle,
- ServerVehicleOverrideMsg(
- lock_accelerator=true,
- lock_wheel=true,
- reverse=true,
- unk4=false,
- lock_vthrust=0,
- strafe,
- reverseSpeed,
- unk8=Some(0)
- )
- )
- import scala.concurrent.ExecutionContext.Implicits.global
- import scala.concurrent.duration._
- context.system.scheduler.scheduleOnce(
- delay milliseconds,
- context.self,
- VehicleServiceResponse(toChannel, PlanetSideGUID(0), VehicleResponse.KickCargo(vehicle, speed=0, delay))
- )
-
- case VehicleResponse.KickCargo(cargo, _, _)
- if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive =>
- sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
-
- case VehicleResponse.StartPlayerSeatedInVehicle(vehicle, _)
- if player.VisibleSlots.contains(player.DrawnSlot) =>
- player.DrawnSlot = Player.HandsDownSlot
- startPlayerSeatedInVehicle(vehicle)
-
- case VehicleResponse.StartPlayerSeatedInVehicle(vehicle, _) =>
- startPlayerSeatedInVehicle(vehicle)
-
- case VehicleResponse.PlayerSeatedInVehicle(vehicle, _) =>
- Vehicles.ReloadAccessPermissions(vehicle, player.Name)
- sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
- vehicle,
- ServerVehicleOverrideMsg(
- lock_accelerator=true,
- lock_wheel=true,
- reverse=true,
- unk4=false,
- lock_vthrust=1,
- lock_strafe=0,
- movement_speed=0,
- unk8=Some(0)
- )
- )
- sessionLogic.vehicles.serverVehicleControlVelocity = Some(0)
-
- case VehicleResponse.ServerVehicleOverrideStart(vehicle, _) =>
- val vdef = vehicle.Definition
- sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
- vehicle,
- ServerVehicleOverrideMsg(
- lock_accelerator=true,
- lock_wheel=true,
- reverse=false,
- unk4=false,
- lock_vthrust=if (GlobalDefinitions.isFlightVehicle(vdef)) { 1 } else { 0 },
- lock_strafe=0,
- movement_speed=vdef.AutoPilotSpeed1,
- unk8=Some(0)
- )
- )
-
- case VehicleResponse.ServerVehicleOverrideEnd(vehicle, _) =>
- sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
-
- case VehicleResponse.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, data) =>
- val str = s"${data.getOrElse("The vehicle spawn pad where you placed your order is blocked.")}"
- val msg = if (str.contains("@")) {
- ChatMsg(ChatMessageType.UNK_229, str)
- } else {
- ChatMsg(ChatMessageType.CMT_OPEN, wideContents = true, recipient = "", str, note = None)
- }
- sendResponse(msg)
-
- case VehicleResponse.PeriodicReminder(_, data) =>
- val (isType, flag, msg): (ChatMessageType, Boolean, String) = data match {
- case Some(msg: String) if msg.startsWith("@") => (ChatMessageType.UNK_227, false, msg)
- case Some(msg: String) => (ChatMessageType.CMT_OPEN, true, msg)
- case _ => (ChatMessageType.CMT_OPEN, true, "Your vehicle order has been cancelled.")
- }
- sendResponse(ChatMsg(isType, flag, recipient="", msg, None))
-
- case VehicleResponse.ChangeLoadout(target, oldWeapons, addedWeapons, oldInventory, newInventory)
- if player.avatar.vehicle.contains(target) =>
- //TODO when vehicle weapons can be changed without visual glitches, rewrite this
- continent.GUID(target).collect { case vehicle: Vehicle =>
- import net.psforever.login.WorldSession.boolToInt
- //owner: must unregister old equipment, and register and install new equipment
- (oldWeapons ++ oldInventory).foreach {
- case (obj, eguid) =>
- sendResponse(ObjectDeleteMessage(eguid, unk1=0))
- TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
+ def receive: Receive = {
+ case VehicleAction.VehicleState(
+ vehicleGuid,
+ unk1,
+ pos,
+ orient,
+ vel,
+ unk2,
+ unk3,
+ unk4,
+ wheelDirection,
+ unk5,
+ unk6
+ ) if TestFilter(() => { NotSameTarget && player.VehicleSeated.contains(vehicleGuid) }) =>
+ //player who is also in the vehicle (not driver)
+ sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, orient, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
+ player.Position = pos
+ player.Orientation = orient
+ player.Velocity = vel
+ sessionLogic.updateLocalBlockMap(pos)
+ //llu destruction check
+ if (player.Carrying.contains(SpecialCarry.CaptureFlag)) {
+ continent
+ .GUID(player.VehicleSeated)
+ .collect { case vehicle: Vehicle =>
+ CaptureFlagManager.ReasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, vehicle)
}
- sessionLogic.general.applyPurchaseTimersBeforePackingLoadout(player, vehicle, addedWeapons ++ newInventory)
- //jammer or unjamm new weapons based on vehicle status
- val vehicleJammered = vehicle.Jammed
- addedWeapons
- .map { _.obj }
- .collect {
- case jamItem: JammableUnit if jamItem.Jammed != vehicleJammered =>
- jamItem.Jammed = vehicleJammered
- JammableMountedWeapons.JammedWeaponStatus(vehicle.Zone, jamItem, vehicleJammered)
- }
- changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
- }
+ }
- case VehicleResponse.ChangeLoadout(target, oldWeapons, _, oldInventory, _)
- if sessionLogic.general.accessedContainer.map(_.GUID).contains(target) =>
- //TODO when vehicle weapons can be changed without visual glitches, rewrite this
- continent.GUID(target).collect { case vehicle: Vehicle =>
- //external participant: observe changes to equipment
- (oldWeapons ++ oldInventory).foreach { case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0)) }
- changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
- }
+ case VehicleAction.VehicleState(
+ vehicleGuid,
+ unk1,
+ pos,
+ ang,
+ vel,
+ unk2,
+ unk3,
+ unk4,
+ wheelDirection,
+ unk5,
+ unk6
+ ) if TestFilter(NotSameTargetTest) =>
+ //player who is watching the vehicle from the outside
+ sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
- case VehicleResponse.ChangeLoadout(target, oldWeapons, _, oldInventory, _) =>
- //TODO when vehicle weapons can be changed without visual glitches, rewrite this
- continent.GUID(target).collect { case vehicle: Vehicle =>
- changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
- }
+ case VehicleAction.ChildObjectState(objectGuid, pitch, yaw)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
- case _ => ()
- }
+ case VehicleAction.FrameVehicleState(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
+
+ case VehicleAction.DismountVehicle(bailType, wasKickedByDriver)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(DismountVehicleMsg(FilterGuid, bailType, wasKickedByDriver))
+
+ case VehicleAction.MountVehicle(vehicleGuid, seat)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ObjectAttachMessage(vehicleGuid, FilterGuid, seat))
+
+ case VehicleAction.DeployRequest(objectGuid, state, unk1, unk2, pos)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(DeployRequestMessage(FilterGuid, objectGuid, state, unk1, unk2, pos))
+
+ case VehicleAction.EquipmentCreatedInSlot(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ case VehicleAction.InventoryState(obj, parentGuid, start, conData)
+ if TestFilter(NotSameTargetTest) =>
+ //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
+ val objGuid = obj.GUID
+ sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
+ sendResponse(ObjectCreateDetailedMessage(
+ obj.Definition.ObjectId,
+ objGuid,
+ ObjectCreateMessageParent(parentGuid, start),
+ conData
+ ))
+
+ case VehicleAction.KickPassenger(_, wasKickedByDriver, vehicleGuid)
+ if TestFilter(SameTargetTest) =>
+ //seat number (first field) seems to be correct if passenger is kicked manually by driver
+ //but always seems to return 4 if user is kicked by mount permissions changing
+ sendResponse(DismountVehicleMsg(FilterGuid, BailType.Kicked, wasKickedByDriver))
+ val typeOfRide = continent.GUID(vehicleGuid) match {
+ case Some(obj: Vehicle) =>
+ sessionLogic.general.unaccessContainer(obj)
+ s"the ${obj.Definition.Name}'s seat by ${obj.OwnerName.getOrElse("the pilot")}"
+ case _ =>
+ s"${player.Sex.possessive} ride"
+ }
+ log.info(s"${player.Name} has been kicked from $typeOfRide!")
+ player.WhichSide = OutsideOf
+
+ case VehicleAction.KickPassenger(_, wasKickedByDriver, _) =>
+ //seat number (first field) seems to be correct if passenger is kicked manually by driver
+ //but always seems to return 4 if user is kicked by mount permissions changing
+ sendResponse(DismountVehicleMsg(FilterGuid, BailType.Kicked, wasKickedByDriver))
+
+ case VehicleAction.InventoryState2(objGuid, parentGuid, value)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(InventoryStateMessage(objGuid, unk=0, parentGuid, value))
+
+ case VehicleAction.LoadVehicle(vehicle, vtype, vguid, vdata)
+ if TestFilter(NotSameTargetTest) =>
+ //this is not be suitable for vehicles with people who are seated in it before it spawns (if that is possible)
+ sendResponse(ObjectCreateMessage(vtype, vguid, vdata))
+ Vehicles.ReloadAccessPermissions(vehicle, player.Name)
+
+ case VehicleAction.Ownership(vehicleGuid)
+ if TestFilter(SameTargetTest) =>
+ //Only the player that owns this vehicle needs the ownership packet
+ avatarActor ! AvatarActor.SetVehicle(Some(vehicleGuid))
+ sendResponse(PlanetsideAttributeMessage(ResolvedGuid, attribute_type=21, vehicleGuid))
+
+ case VehicleAction.LoseOwnership(_, vehicleGuid) =>
+ ops.announceAmsDecay(vehicleGuid,msg = "@ams_decaystarted")
+
+ case VehicleAction.SeatPermissions(vehicleGuid, seatGroup, permission)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(PlanetsideAttributeMessage(vehicleGuid, seatGroup, permission))
+
+ case VehicleAction.StowCreatedEquipment(vehicleGuid, slot, itemType, itemGuid, itemData)
+ if TestFilter(NotSameTargetTest) =>
+ //TODO prefer ObjectAttachMessage, but how to force ammo pools to update properly?
+ sendResponse(ObjectCreateDetailedMessage(itemType, itemGuid, ObjectCreateMessageParent(vehicleGuid, slot), itemData))
+
+ case VehicleAction.UnloadVehicle(_, vehicleGuid) =>
+ sendResponse(ObjectDeleteMessage(vehicleGuid, unk1=1))
+ if (sessionLogic.zoning.spawn.prevSpawnPoint.map(_.Owner).exists {
+ case ams: Vehicle =>
+ ams.GUID == vehicleGuid &&
+ ams.OwnerGuid.isEmpty
+ case _ =>
+ false
+ }) {
+ sessionLogic.zoning.spawn.prevSpawnPoint = None
+ sendResponse(ChatMsg(ChatMessageType.UNK_229, "@ams_decayed"))
+ }
+
+ case VehicleAction.UnstowEquipment(itemGuid)
+ if TestFilter(NotSameTargetTest) =>
+ //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
+ sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
+
+ case VehicleAction.UpdateAmsSpawnList(list) =>
+ sessionLogic.zoning.spawn.amsSpawnPoints = list.filter(tube => tube.Faction == player.Faction)
+ sessionLogic.zoning.spawn.DrawCurrentAmsSpawnPoint()
+
+ case VehicleAction.TransferPassengerChannel(oldChannel, tempChannel, vehicle, vehicleToDelete)
+ if TestFilter(NotSameTargetTest) =>
+ sessionLogic.zoning.interstellarFerry = Some(vehicle)
+ sessionLogic.zoning.interstellarFerryTopLevelGUID = Some(vehicleToDelete)
+ continent.VehicleEvents ! Service.Leave(oldChannel) //old vehicle-specific channel (was s"${vehicle.Actor}")
+ galaxyService ! Service.Join(tempChannel) //temporary vehicle-specific channel
+ log.debug(s"TransferPassengerChannel: ${player.Name} now subscribed to $tempChannel for vehicle gating")
+
+ case VehicleAction.KickCargo(vehicle, speed, delay)
+ if TestFilter(() => { player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive && speed > 0 }) =>
+ val strafe = 1 + Vehicles.CargoOrientation(vehicle)
+ val reverseSpeed = if (strafe > 1) { 0 } else { speed }
+ //strafe or reverse, not both
+ sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
+ vehicle,
+ ServerVehicleOverrideMsg(
+ lock_accelerator=true,
+ lock_wheel=true,
+ reverse=true,
+ unk4=false,
+ lock_vthrust=0,
+ strafe,
+ reverseSpeed,
+ unk8=Some(0)
+ )
+ )
+ import scala.concurrent.ExecutionContext.Implicits.global
+ import scala.concurrent.duration._
+ val resp = GenericResponseEnvelope(
+ VehicleStamp,
+ "",
+ PlanetSideGUID(0),
+ VehicleAction.KickCargo(vehicle, speed=0, delay)
+ )
+ context.system.scheduler.scheduleOnce(delay milliseconds, context.self, resp)
+
+ case VehicleAction.KickCargo(cargo, _, _)
+ if TestFilter(() => { player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive }) =>
+ sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
+
+ case VehicleAction.ChangeLoadout(target, oldWeapons, addedWeapons, oldInventory, newInventory)
+ if TestFilter(() => { player.avatar.vehicle.contains(target) }) =>
+ //TODO when vehicle weapons can be changed without visual glitches, rewrite this
+ continent.GUID(target).collect { case vehicle: Vehicle =>
+ import net.psforever.login.WorldSession.boolToInt
+ //owner: must unregister old equipment, and register and install new equipment
+ (oldWeapons ++ oldInventory).foreach {
+ case (obj, eguid) =>
+ sendResponse(ObjectDeleteMessage(eguid, unk1=0))
+ TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
+ }
+ sessionLogic.general.applyPurchaseTimersBeforePackingLoadout(player, vehicle, addedWeapons ++ newInventory)
+ //jammer or unjamm new weapons based on vehicle status
+ val vehicleJammered = vehicle.Jammed
+ addedWeapons
+ .map { _.obj }
+ .collect {
+ case jamItem: JammableUnit if jamItem.Jammed != vehicleJammered =>
+ jamItem.Jammed = vehicleJammered
+ JammableMountedWeapons.JammedWeaponStatus(vehicle.Zone, jamItem, vehicleJammered)
+ }
+ changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
+ }
+
+ case VehicleAction.ChangeLoadout(target, oldWeapons, _, oldInventory, _)
+ if TestFilter(() => { sessionLogic.general.accessedContainer.map(_.GUID).contains(target) }) =>
+ //TODO when vehicle weapons can be changed without visual glitches, rewrite this
+ continent.GUID(target).collect { case vehicle: Vehicle =>
+ //external participant: observe changes to equipment
+ (oldWeapons ++ oldInventory).foreach { case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0)) }
+ changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
+ }
+
+ case VehicleAction.ChangeLoadout(target, oldWeapons, _, oldInventory, _) =>
+ //TODO when vehicle weapons can be changed without visual glitches, rewrite this
+ continent.GUID(target).collect { case vehicle: Vehicle =>
+ changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
+ }
+
+ case VehicleSpawnPad.AttachToRails(vehicle, pad) =>
+ sendResponse(ObjectAttachMessage(pad.GUID, vehicle.GUID, slot=3))
+
+ case VehicleSpawnPad.ConcealPlayer(playerGuid) =>
+ sendResponse(GenericObjectActionMessage(playerGuid, code=9))
+
+ case VehicleSpawnPad.DetachFromRails(vehicle, pad) =>
+ val padDefinition = pad.Definition
+ sendResponse(
+ ObjectDetachMessage(
+ pad.GUID,
+ vehicle.GUID,
+ pad.Position + Vector3.z(padDefinition.VehicleCreationZOffset),
+ pad.Orientation.z + padDefinition.VehicleCreationZOrientOffset
+ )
+ )
+
+ case VehicleSpawnPad.ResetSpawnPad(pad) =>
+ sendResponse(GenericObjectActionMessage(pad.GUID, code=23))
+
+ case VehicleSpawnPad.RevealPlayer(playerGuid) =>
+ sendResponse(GenericObjectActionMessage(playerGuid, code=10))
+
+ case VehicleSpawnPad.StartPlayerSeatedInVehicle(vehicle, _)
+ if TestFilter(() => { player.VisibleSlots.contains(player.DrawnSlot) }) =>
+ player.DrawnSlot = Player.HandsDownSlot
+ startPlayerSeatedInVehicle(vehicle)
+
+ case VehicleSpawnPad.StartPlayerSeatedInVehicle(vehicle, _) =>
+ startPlayerSeatedInVehicle(vehicle)
+
+ case VehicleSpawnPad.PlayerSeatedInVehicle(vehicle, _) =>
+ Vehicles.ReloadAccessPermissions(vehicle, player.Name)
+ sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
+ vehicle,
+ ServerVehicleOverrideMsg(
+ lock_accelerator=true,
+ lock_wheel=true,
+ reverse=true,
+ unk4=false,
+ lock_vthrust=1,
+ lock_strafe=0,
+ movement_speed=0,
+ unk8=Some(0)
+ )
+ )
+ sessionLogic.vehicles.serverVehicleControlVelocity = Some(0)
+
+ case VehicleSpawnPad.ServerVehicleOverrideStart(vehicle, _) =>
+ val vdef = vehicle.Definition
+ sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
+ vehicle,
+ ServerVehicleOverrideMsg(
+ lock_accelerator=true,
+ lock_wheel=true,
+ reverse=false,
+ unk4=false,
+ lock_vthrust=if (GlobalDefinitions.isFlightVehicle(vdef)) { 1 } else { 0 },
+ lock_strafe=0,
+ movement_speed=vdef.AutoPilotSpeed1,
+ unk8=Some(0)
+ )
+ )
+
+ case VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, _) =>
+ sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
+
+ case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, data) =>
+ val str = s"${data.getOrElse("The vehicle spawn pad where you placed your order is blocked.")}"
+ val msg = if (str.contains("@")) {
+ ChatMsg(ChatMessageType.UNK_229, str)
+ } else {
+ ChatMsg(ChatMessageType.CMT_OPEN, wideContents = true, recipient = "", str, note = None)
+ }
+ sendResponse(msg)
+
+ case VehicleSpawnPad.PeriodicReminder(_, data) =>
+ val (isType, flag, msg): (ChatMessageType, Boolean, String) = data match {
+ case Some(msg: String) if msg.startsWith("@") => (ChatMessageType.UNK_227, false, msg)
+ case Some(msg: String) => (ChatMessageType.CMT_OPEN, true, msg)
+ case _ => (ChatMessageType.CMT_OPEN, true, "Your vehicle order has been cancelled.")
+ }
+ sendResponse(ChatMsg(isType, flag, recipient="", msg, None))
}
private def changeLoadoutDeleteOldEquipment(
diff --git a/src/main/scala/net/psforever/actors/session/normal/VehicleLogic.scala b/src/main/scala/net/psforever/actors/session/normal/VehicleLogic.scala
index 883fbfe94..53affd906 100644
--- a/src/main/scala/net/psforever/actors/session/normal/VehicleLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/normal/VehicleLogic.scala
@@ -12,7 +12,9 @@ import net.psforever.objects.vehicles.control.BfrFlight
import net.psforever.objects.zones.Zone
import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game.{ChatMsg, ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.CachedEnvelope
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{ChatMessageType, DriveState, Vector3}
object VehicleLogic {
@@ -75,10 +77,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Position = position
obj.Orientation = angle
//
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! CachedEnvelope(
continent.id,
+ player.GUID,
VehicleAction.VehicleState(
- player.GUID,
vehicle_guid,
unk1,
position,
@@ -162,26 +164,11 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Position = position
obj.Orientation = angle
obj.DeploymentState = if (is_crouched || !notMountedState) DriveState.Kneeling else DriveState.Mobile
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.FrameVehicleState(
- player.GUID,
- vehicle_guid,
- unk1,
- position,
- angle,
- velocity,
- unk2,
- unk3,
- unk4,
- is_crouched,
- is_airborne,
- ascending_flight,
- flight_time,
- unk9,
- unkA
- )
- )
+ player.GUID,
+ VehicleAction.FrameVehicleState(vehicle_guid, unk1, position, angle, velocity, unk2, unk3, unk4, is_crouched, is_airborne, ascending_flight, flight_time, unk9, unkA)
+ ) //todo CachedMessage
sessionLogic.squad.updateSquad()
case (None, _) =>
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone")
@@ -230,10 +217,11 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
val angle = Vector3(0f, pitch, yaw)
tool.Orientation = angle
player.Orientation = angle
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.ChildObjectState(player.GUID, object_guid, pitch, yaw)
- )
+ player.GUID,
+ VehicleAction.ChildObjectState(object_guid, pitch, yaw)
+ ) //todo CachedMessage
}
//TODO status condition of "playing getting out of vehicle to allow for late packets without warning
if (player.death_by == -1) {
@@ -252,22 +240,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Velocity = vel
sessionLogic.updateBlockMap(obj, pos)
obj.zoneInteractions()
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! CachedEnvelope(
continent.id,
- VehicleAction.VehicleState(
- player.GUID,
- vehicle_guid,
- unk1,
- pos,
- ang,
- obj.Velocity,
- obj.Flying,
- 0,
- 0,
- 15,
- unk5 = false,
- obj.Cloaked
- )
+ player.GUID,
+ VehicleAction.VehicleState(vehicle_guid, unk1, pos, ang, obj.Velocity, obj.Flying, 0, 0, 15, unk5 = false, obj.Cloaked)
)
}
}
@@ -346,9 +322,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
val mobileShift: String = if (obj.DeploymentState != DriveState.Mobile) {
obj.DeploymentState = DriveState.Mobile
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero))
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.DeployRequest(player.GUID, obj.GUID, DriveState.Mobile, 0, unk2=false, Vector3.Zero)
+ player.GUID,
+ VehicleAction.DeployRequest(obj.GUID, DriveState.Mobile, 0, unk2=false, Vector3.Zero)
)
"; enforcing Mobile deployment state"
} else {
diff --git a/src/main/scala/net/psforever/actors/session/spectator/AvatarHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/AvatarHandlerLogic.scala
index cebbb5ba2..1f994d452 100644
--- a/src/main/scala/net/psforever/actors/session/spectator/AvatarHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/spectator/AvatarHandlerLogic.scala
@@ -1,6 +1,7 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.spectator
+import akka.actor.Actor.Receive
import akka.actor.{ActorContext, typed}
import net.psforever.actors.session.support.AvatarHandlerFunctions
import net.psforever.actors.zone.ZoneActor
@@ -8,6 +9,8 @@ import net.psforever.objects.Players
import net.psforever.objects.avatar.scoring.Kill
import net.psforever.objects.sourcing.PlayerSource
import net.psforever.packet.game.{AvatarImplantMessage, ImplantAction}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, PlanetsideAttribute, ReloadTool, SendResponse, WeaponDryFire}
import scala.concurrent.duration._
//
@@ -22,9 +25,8 @@ import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
import net.psforever.objects.vital.etc.ExplodingEntityReason
import net.psforever.objects.zones.Zoning
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
-import net.psforever.packet.game.{ArmorChangedMessage, AvatarDeadStateMessage, ChangeAmmoMessage, ChangeFireModeMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, DeadState, DestroyMessage, DrowningTarget, GenericActionMessage, GenericObjectActionMessage, HitHint, ItemTransactionResultMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectHeldMessage, OxygenStateMessage, PlanetsideAttributeMessage, PlayerStateMessage, ProjectileStateMessage, ReloadMessage, SetEmpireMessage, UseItemMessage, WeaponDryFireMessage}
-import net.psforever.services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage}
-import net.psforever.services.Service
+import net.psforever.packet.game.{ArmorChangedMessage, AvatarDeadStateMessage, ChangeAmmoMessage, ChangeFireModeMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChatMsg, DeadState, DestroyMessage, DrowningTarget, GenericActionMessage, GenericObjectActionMessage, ItemTransactionResultMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectHeldMessage, OxygenStateMessage, PlanetsideAttributeMessage, PlayerStateMessage, ProjectileStateMessage, ReloadMessage, UseItemMessage, WeaponDryFireMessage}
+import net.psforever.services.avatar.AvatarAction
import net.psforever.types.{ChatMessageType, PlanetSideGUID, TransactionType, Vector3}
import net.psforever.util.Config
@@ -39,546 +41,500 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
private val avatarActor: typed.ActorRef[AvatarActor.Command] = ops.avatarActor
- /**
- * na
- * @param toChannel na
- * @param guid na
- * @param reply na
- */
- def handle(toChannel: String, guid: PlanetSideGUID, reply: AvatarResponse.Response): Unit = {
- val resolvedPlayerGuid = if (player != null && player.HasGUID) {
- player.GUID
- } else {
- Service.defaultPlayerGUID
- }
- val isNotSameTarget = resolvedPlayerGuid != guid
- val isSameTarget = !isNotSameTarget
- reply match {
- /* special messages */
- case AvatarResponse.TeardownConnection() =>
- log.trace(s"ending ${player.Name}'s old session by event system request (relog)")
- context.stop(context.self)
+ def receive: Receive = {
+ /* special messages */
+ case AvatarAction.TeardownConnection =>
+ log.trace(s"ending ${player.Name}'s old session by event system request (relog)")
+ context.stop(context.self)
- /* really common messages (very frequently, every life) */
- case pstate @ AvatarResponse.PlayerState(
- pos,
- vel,
- yaw,
- pitch,
- yawUpper,
- _,
- isCrouching,
- isJumping,
- jumpThrust,
- isCloaking,
- isNotRendered,
- canSeeReallyFar
- ) if isNotSameTarget =>
- val pstateToSave = pstate.copy(timestamp = 0)
- val (lastMsg, lastTime, lastPosition, wasVisible, wasShooting) = ops.lastSeenStreamMessage.get(guid.guid) match {
- case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, shooting, time)) => (Some(msg), time, msg.pos, visible, shooting)
- case _ => (None, 0L, Vector3.Zero, false, None)
- }
- val drawConfig = Config.app.game.playerDraw //m
- val maxRange = drawConfig.rangeMax * drawConfig.rangeMax //sq.m
- val ourPosition = player.Position //xyz
- val currentDistance = Vector3.DistanceSquared(ourPosition, pos) //sq.m
- val inDrawableRange = currentDistance <= maxRange
- val now = System.currentTimeMillis() //ms
- if (
- sessionLogic.zoning.zoningStatus != Zoning.Status.Deconstructing &&
- !isNotRendered && inDrawableRange
+ /* really common messages (very frequently, every life) */
+ case pstate @ AvatarAction.PlayerState(
+ pos,
+ vel,
+ yaw,
+ pitch,
+ yawUpper,
+ _,
+ isCrouching,
+ isJumping,
+ jumpThrust,
+ isCloaking,
+ isNotRendered,
+ canSeeReallyFar
+ ) if TestFilter(NotSameTargetTest) =>
+ val pstateToSave = pstate.copy(timestamp = 0)
+ val (lastMsg, lastTime, lastPosition, wasVisible, wasShooting) = ops.lastSeenStreamMessage.get(FilterGuid.guid) match {
+ case Some(SessionAvatarHandlers.LastUpstream(Some(msg), visible, shooting, time)) => (Some(msg), time, msg.pos, visible, shooting)
+ case _ => (None, 0L, Vector3.Zero, false, None)
+ }
+ val drawConfig = Config.app.game.playerDraw //m
+ val maxRange = drawConfig.rangeMax * drawConfig.rangeMax //sq.m
+ val ourPosition = player.Position //xyz
+ val currentDistance = Vector3.DistanceSquared(ourPosition, pos) //sq.m
+ val inDrawableRange = currentDistance <= maxRange
+ val now = System.currentTimeMillis() //ms
+ if (
+ sessionLogic.zoning.zoningStatus != Zoning.Status.Deconstructing &&
+ !isNotRendered && inDrawableRange
+ ) {
+ //conditions where visibility is assured
+ val durationSince = now - lastTime //ms
+ lazy val previouslyInDrawableRange = Vector3.DistanceSquared(ourPosition, lastPosition) <= maxRange
+ lazy val targetDelay = {
+ val populationOver = math.max(
+ 0,
+ sessionLogic.localSector.livePlayerList.size - drawConfig.populationThreshold
+ )
+ val distanceAdjustment = math.pow(populationOver / drawConfig.populationStep * drawConfig.rangeStep, 2) //sq.m
+ val adjustedDistance = currentDistance + distanceAdjustment //sq.m
+ drawConfig.ranges.lastIndexWhere { dist => adjustedDistance > dist * dist } match {
+ case -1 => 1
+ case index => drawConfig.delays(index)
+ }
+ } //ms
+ if (!wasVisible ||
+ !previouslyInDrawableRange ||
+ durationSince > drawConfig.delayMax ||
+ (!lastMsg.contains(pstateToSave) &&
+ (canSeeReallyFar ||
+ currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
+ sessionLogic.general.canSeeReallyFar ||
+ durationSince > targetDelay
+ )
+ )
) {
- //conditions where visibility is assured
- val durationSince = now - lastTime //ms
- lazy val previouslyInDrawableRange = Vector3.DistanceSquared(ourPosition, lastPosition) <= maxRange
- lazy val targetDelay = {
- val populationOver = math.max(
- 0,
- sessionLogic.localSector.livePlayerList.size - drawConfig.populationThreshold
+ //must draw
+ sendResponse(
+ PlayerStateMessage(
+ FilterGuid,
+ pos,
+ vel,
+ yaw,
+ pitch,
+ yawUpper,
+ timestamp = 0, //is this okay?
+ isCrouching,
+ isJumping,
+ jumpThrust,
+ isCloaking
)
- val distanceAdjustment = math.pow(populationOver / drawConfig.populationStep * drawConfig.rangeStep, 2) //sq.m
- val adjustedDistance = currentDistance + distanceAdjustment //sq.m
- drawConfig.ranges.lastIndexWhere { dist => adjustedDistance > dist * dist } match {
- case -1 => 1
- case index => drawConfig.delays(index)
- }
- } //ms
- if (!wasVisible ||
- !previouslyInDrawableRange ||
- durationSince > drawConfig.delayMax ||
- (!lastMsg.contains(pstateToSave) &&
- (canSeeReallyFar ||
- currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
- sessionLogic.general.canSeeReallyFar ||
- durationSince > targetDelay
- )
- )
- ) {
- //must draw
- sendResponse(
- PlayerStateMessage(
- guid,
- pos,
- vel,
- yaw,
- pitch,
- yawUpper,
- timestamp = 0, //is this okay?
- isCrouching,
- isJumping,
- jumpThrust,
- isCloaking
- )
- )
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, now))
- } else {
- //is visible, but skip reinforcement
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, lastTime))
- }
+ )
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, now))
} else {
- //conditions where the target is not currently visible
- if (wasVisible) {
- //the target was JUST PREVIOUSLY visible; one last draw to move target beyond a renderable distance
- val lat = (1 + ops.hidingPlayerRandomizer.nextInt(continent.map.scale.height.toInt)).toFloat
- sendResponse(
- PlayerStateMessage(
- guid,
- Vector3(1f, lat, 1f),
- vel=None,
- facingYaw=0f,
- facingPitch=0f,
- facingYawUpper=0f,
- timestamp=0, //is this okay?
- is_cloaked = isCloaking
- )
+ //is visible, but skip reinforcement
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=true, wasShooting, lastTime))
+ }
+ } else {
+ //conditions where the target is not currently visible
+ if (wasVisible) {
+ //the target was JUST PREVIOUSLY visible; one last draw to move target beyond a renderable distance
+ val lat = (1 + ops.hidingPlayerRandomizer.nextInt(continent.map.scale.height.toInt)).toFloat
+ sendResponse(
+ PlayerStateMessage(
+ FilterGuid,
+ Vector3(1f, lat, 1f),
+ vel=None,
+ facingYaw=0f,
+ facingPitch=0f,
+ facingYawUpper=0f,
+ timestamp=0, //is this okay?
+ is_cloaked = isCloaking
)
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, now))
- } else {
- //skip drawing altogether
- ops.lastSeenStreamMessage.put(guid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, lastTime))
- }
+ )
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, now))
+ } else {
+ //skip drawing altogether
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, SessionAvatarHandlers.LastUpstream(Some(pstateToSave), visible=false, wasShooting, lastTime))
}
+ }
- case AvatarResponse.ObjectHeld(slot, _)
- if isSameTarget && player.VisibleSlots.contains(slot) =>
- sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
- //Stop using proximity terminals if player unholsters a weapon
- continent.GUID(sessionLogic.terminals.usingMedicalTerminal).collect {
- case term: Terminal with ProximityUnit => sessionLogic.terminals.StopUsingProximityUnit(term)
- }
- if (sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing) {
- sessionLogic.zoning.spawn.stopDeconstructing()
- }
+ case AvatarAction.ObjectHeld(slot, _)
+ if TestFilter(() => { SameTarget && player.VisibleSlots.contains(slot) }) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, slot, unk1=true))
+ //Stop using proximity terminals if player unholsters a weapon
+ continent.GUID(sessionLogic.terminals.usingMedicalTerminal).collect {
+ case term: Terminal with ProximityUnit => sessionLogic.terminals.StopUsingProximityUnit(term)
+ }
+ if (sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing) {
+ sessionLogic.zoning.spawn.stopDeconstructing()
+ }
- case AvatarResponse.ObjectHeld(slot, _)
- if isSameTarget && slot > -1 =>
- sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
+ case AvatarAction.ObjectHeld(slot, _)
+ if TestFilter(() => { SameTarget && slot > -1 }) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, slot, unk1=true))
- case AvatarResponse.ObjectHeld(_, _)
- if isSameTarget => ()
+ case AvatarAction.ObjectHeld(_, _)
+ if TestFilter(SameTargetTest) => ()
- case AvatarResponse.ObjectHeld(_, previousSlot) =>
- sendResponse(ObjectHeldMessage(guid, previousSlot, unk1=false))
+ case AvatarAction.ObjectHeld(_, previousSlot) =>
+ sendResponse(ObjectHeldMessage(FilterGuid, previousSlot, unk1=false))
- case AvatarResponse.ChangeFireState_Start(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- sendResponse(ChangeFireStateMessage_Start(weaponGuid))
- val entry = ops.lastSeenStreamMessage(guid.guid)
- ops.lastSeenStreamMessage.put(guid.guid, entry.copy(shooting = Some(weaponGuid)))
+ case ChangeFireState_Start(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible } }) =>
+ sendResponse(ChangeFireStateMessage_Start(weaponGuid))
+ val entry = ops.lastSeenStreamMessage(FilterGuid.guid)
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, entry.copy(shooting = Some(weaponGuid)))
- case AvatarResponse.ChangeFireState_Start(weaponGuid)
- if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Start(weaponGuid))
+ case ChangeFireState_Stop(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { msg => msg.visible || msg.shooting.nonEmpty } }) =>
+ sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
+ val entry = ops.lastSeenStreamMessage(FilterGuid.guid)
+ ops.lastSeenStreamMessage.put(FilterGuid.guid, entry.copy(shooting = None))
- case AvatarResponse.ChangeFireState_Stop(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { msg => msg.visible || msg.shooting.nonEmpty } =>
- sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
- val entry = ops.lastSeenStreamMessage(guid.guid)
- ops.lastSeenStreamMessage.put(guid.guid, entry.copy(shooting = None))
+ case AvatarAction.LoadCreatedPlayer(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
- case AvatarResponse.ChangeFireState_Stop(weaponGuid)
- if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
+ case AvatarAction.EquipmentCreatedInHand(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
- case AvatarResponse.LoadPlayer(pkt) if isNotSameTarget =>
- sendResponse(pkt)
+ case AvatarAction.Destroy(victim, killer, weapon, pos) =>
+ // guid = victim // killer = killer
+ sendResponse(DestroyMessage(victim, killer, weapon, pos))
- case AvatarResponse.EquipmentInHand(pkt) if isNotSameTarget =>
- sendResponse(pkt)
+ case AvatarAction.DestroyDisplay(killer, victim, method, unk) =>
+ sendResponse(ops.destroyDisplayMessage(killer, victim, method, unk))
- case AvatarResponse.PlanetsideAttribute(attributeType, attributeValue) if isNotSameTarget =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
+ case AvatarAction.TerminalOrderResult(terminalGuid, action, result)
+ if TestFilter(() => { result && (action == TransactionType.Buy || action == TransactionType.Loadout) }) =>
+ sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
+ sessionLogic.terminals.lastTerminalOrderFulfillment = true
+ AvatarActor.savePlayerData(player)
- case AvatarResponse.PlanetsideAttributeToAll(attributeType, attributeValue) =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
+ case AvatarAction.TerminalOrderResult(terminalGuid, action, result) =>
+ sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
+ sessionLogic.terminals.lastTerminalOrderFulfillment = true
- case AvatarResponse.PlanetsideAttributeSelf(attributeType, attributeValue) if isSameTarget =>
- sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
-
- case AvatarResponse.GenericObjectAction(objectGuid, actionCode) if isNotSameTarget =>
- sendResponse(GenericObjectActionMessage(objectGuid, actionCode))
-
- case AvatarResponse.HitHint(sourceGuid) if player.isAlive =>
- sendResponse(HitHint(sourceGuid, guid))
- sessionLogic.zoning.CancelZoningProcess()
-
- case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
- // guid = victim // killer = killer
- sendResponse(DestroyMessage(victim, killer, weapon, pos))
-
- case AvatarResponse.DestroyDisplay(killer, victim, method, unk) =>
- sendResponse(ops.destroyDisplayMessage(killer, victim, method, unk))
-
- case AvatarResponse.TerminalOrderResult(terminalGuid, action, result)
- if result && (action == TransactionType.Buy || action == TransactionType.Loadout) =>
- sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
- sessionLogic.terminals.lastTerminalOrderFulfillment = true
- AvatarActor.savePlayerData(player)
-
- case AvatarResponse.TerminalOrderResult(terminalGuid, action, result) =>
- sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
- sessionLogic.terminals.lastTerminalOrderFulfillment = true
-
- case AvatarResponse.ChangeExosuit(
- target,
- armor,
- exosuit,
- subtype,
- _,
- maxhand,
- oldHolsters,
- holsters,
- oldInventory,
- inventory,
- drop,
- delete
- ) if resolvedPlayerGuid == target =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to this player
- //cleanup
- sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=false))
- (oldHolsters ++ oldInventory ++ delete).foreach {
- case (_, dguid) => sendResponse(ObjectDeleteMessage(dguid, unk1=0))
- }
- //functionally delete
- delete.foreach { case (obj, _) => TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj)) }
- //redraw
- if (maxhand) {
- TaskWorkflow.execute(HoldNewEquipmentUp(player)(
- Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)),
- 0
- ))
- }
- //draw free hand
- player.FreeHand.Equipment.foreach { obj =>
+ case AvatarAction.ChangeExosuit(
+ target,
+ armor,
+ exosuit,
+ subtype,
+ _,
+ maxhand,
+ oldHolsters,
+ holsters,
+ oldInventory,
+ inventory,
+ drop,
+ delete
+ ) if TestFilter(() => { ResolvedGuid == target }) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to this player
+ //cleanup
+ sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=false))
+ (oldHolsters ++ oldInventory ++ delete).foreach {
+ case (_, dguid) => sendResponse(ObjectDeleteMessage(dguid, unk1=0))
+ }
+ //functionally delete
+ delete.foreach { case (obj, _) => TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj)) }
+ //redraw
+ if (maxhand) {
+ TaskWorkflow.execute(HoldNewEquipmentUp(player)(
+ Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)),
+ 0
+ ))
+ }
+ //draw free hand
+ player.FreeHand.Equipment.foreach { obj =>
+ val definition = obj.Definition
+ sendResponse(
+ ObjectCreateDetailedMessage(
+ definition.ObjectId,
+ obj.GUID,
+ ObjectCreateMessageParent(target, Player.FreeHandSlot),
+ definition.Packet.DetailedConstructorData(obj).get
+ )
+ )
+ }
+ //draw holsters and inventory
+ (holsters ++ inventory).foreach {
+ case InventoryItem(obj, index) =>
val definition = obj.Definition
sendResponse(
ObjectCreateDetailedMessage(
definition.ObjectId,
obj.GUID,
- ObjectCreateMessageParent(target, Player.FreeHandSlot),
+ ObjectCreateMessageParent(target, index),
definition.Packet.DetailedConstructorData(obj).get
)
)
- }
- //draw holsters and inventory
- (holsters ++ inventory).foreach {
- case InventoryItem(obj, index) =>
- val definition = obj.Definition
- sendResponse(
- ObjectCreateDetailedMessage(
- definition.ObjectId,
- obj.GUID,
- ObjectCreateMessageParent(target, index),
- definition.Packet.DetailedConstructorData(obj).get
- )
+ }
+ DropLeftovers(player)(drop)
+
+ case AvatarAction.ChangeExosuit(target, armor, exosuit, subtype, slot, _, oldHolsters, holsters, _, _, _, delete) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to some other player
+ sendResponse(ObjectHeldMessage(target, slot, unk1 = false))
+ //cleanup
+ (oldHolsters ++ delete).foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
+ //draw holsters
+ holsters.foreach {
+ case InventoryItem(obj, index) =>
+ val definition = obj.Definition
+ sendResponse(
+ ObjectCreateMessage(
+ definition.ObjectId,
+ obj.GUID,
+ ObjectCreateMessageParent(target, index),
+ definition.Packet.ConstructorData(obj).get
)
- }
- DropLeftovers(player)(drop)
-
- case AvatarResponse.ChangeExosuit(target, armor, exosuit, subtype, slot, _, oldHolsters, holsters, _, _, _, delete) =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to some other player
- sendResponse(ObjectHeldMessage(target, slot, unk1 = false))
- //cleanup
- (oldHolsters ++ delete).foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
- //draw holsters
- holsters.foreach {
- case InventoryItem(obj, index) =>
- val definition = obj.Definition
- sendResponse(
- ObjectCreateMessage(
- definition.ObjectId,
- obj.GUID,
- ObjectCreateMessageParent(target, index),
- definition.Packet.ConstructorData(obj).get
- )
- )
- }
-
- case AvatarResponse.ChangeLoadout(
- target,
- armor,
- exosuit,
- subtype,
- _,
- maxhand,
- oldHolsters,
- holsters,
- oldInventory,
- inventory,
- drops
- ) if resolvedPlayerGuid == target =>
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type = 4, armor))
- //happening to this player
- sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=true))
- //cleanup
- (oldHolsters ++ oldInventory).foreach {
- case (obj, objGuid) =>
- sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
- TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
- }
- drops.foreach(item => sendResponse(ObjectDeleteMessage(item.obj.GUID, unk1=0)))
- //redraw
- if (maxhand) {
- TaskWorkflow.execute(HoldNewEquipmentUp(player)(
- Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)),
- slot = 0
- ))
- }
- sessionLogic.general.applyPurchaseTimersBeforePackingLoadout(player, player, holsters ++ inventory)
- DropLeftovers(player)(drops)
-
- case AvatarResponse.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
- //redraw handled by callbacks
- sendResponse(ArmorChangedMessage(target, exosuit, subtype))
- sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
- //happening to some other player
- sendResponse(ObjectHeldMessage(target, slot, unk1=false))
- //cleanup
- oldHolsters.foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
-
- case AvatarResponse.UseKit(kguid, kObjId) =>
- sendResponse(
- UseItemMessage(
- resolvedPlayerGuid,
- kguid,
- resolvedPlayerGuid,
- unk2 = 4294967295L,
- unk3 = false,
- unk4 = Vector3.Zero,
- unk5 = Vector3.Zero,
- unk6 = 126,
- unk7 = 0, //sequence time?
- unk8 = 137,
- kObjId
)
- )
- sendResponse(ObjectDeleteMessage(kguid, unk1=0))
+ }
- case AvatarResponse.KitNotUsed(_, "") =>
- sessionLogic.general.kitToBeUsed = None
-
- case AvatarResponse.KitNotUsed(_, msg) =>
- sessionLogic.general.kitToBeUsed = None
- sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
-
- case AvatarResponse.UpdateKillsDeathsAssists(_, kda: Kill) if kda.experienceEarned > 0 =>
- continent.actor ! ZoneActor.RewardOurSupporters(
- PlayerSource(player),
- Players.produceContributionTranscriptFromKill(continent, player, kda),
- kda,
- kda.experienceEarned
- )
-
- case AvatarResponse.AwardBep(charId, bep, expType) =>
- //if the target player, always award (some) BEP
- if (charId == player.CharId) {
- avatarActor ! AvatarActor.AwardBep(bep, expType)
- }
-
- case AvatarResponse.AwardCep(charId, cep) =>
- //if the target player, always award (some) CEP
- if (charId == player.CharId) {
- avatarActor ! AvatarActor.AwardCep(cep)
- }
-
- case AvatarResponse.FacilityCaptureRewards(buildingId, zoneNumber, cep) =>
- ops.facilityCaptureRewards(buildingId, zoneNumber, cep)
-
- case AvatarResponse.SendResponse(pkt: AvatarImplantMessage)
- if pkt.player_guid == player.GUID && pkt.action == ImplantAction.Initialization =>
- //special spectator implants stay initialized and do not deinitialize
- ()
-
- case AvatarResponse.SendResponse(msg) =>
- sendResponse(msg)
-
- case AvatarResponse.SendResponseTargeted(targetGuid, msg) if resolvedPlayerGuid == targetGuid =>
- sendResponse(msg)
-
- /* common messages (maybe once every respawn) */
- case AvatarResponse.Reload(itemGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
-
- case AvatarResponse.Killed(_, mount) =>
- //log and chat messages
- val cause = player.LastDamage.flatMap { damage =>
- val interaction = damage.interaction
- val reason = interaction.cause
- val adversarial = interaction.adversarial.map { _.attacker }
- reason match {
- case r: ExplodingEntityReason if r.entity.isInstanceOf[VehicleSpawnPad] =>
- //also, @SVCP_Killed_TooCloseToPadOnCreate^n~ or "... within n meters of pad ..."
- sendResponse(ChatMsg(ChatMessageType.UNK_227, "@SVCP_Killed_OnPadOnCreate"))
- case _ => ()
- }
- adversarial.map {_.Name }.orElse { Some(s"a ${reason.getClass.getSimpleName}") }
- }.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
- log.info(s"${player.Name} has died, killed by $cause")
- if (sessionLogic.shooting.shotsWhileDead > 0) {
- log.warn(
- s"SHOTS_WHILE_DEAD: client of ${avatar.name} fired ${sessionLogic.shooting.shotsWhileDead} rounds while character was dead on server"
- )
- sessionLogic.shooting.shotsWhileDead = 0
- }
- sessionLogic.zoning.CancelZoningProcess()
-
- //player state changes
- sessionLogic.zoning.spawn.avatarActive = false
- AvatarActor.updateToolDischargeFor(avatar)
- player.FreeHand.Equipment.foreach { item =>
- DropEquipmentFromInventory(player)(item)
- }
- sessionLogic.general.dropSpecialSlotItem()
- sessionLogic.general.toggleMaxSpecialState(enable = false)
- sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
- sessionLogic.zoning.zoningStatus = Zoning.Status.None
- sessionLogic.zoning.spawn.deadState = DeadState.Dead
- continent.GUID(mount).collect { case obj: Vehicle =>
- sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
- sessionLogic.general.unaccessContainer(obj)
- }
- sessionLogic.actionsToCancel()
- sessionLogic.terminals.CancelAllProximityUnits()
- AvatarActor.savePlayerLocation(player)
- sessionLogic.zoning.spawn.ShiftPosition = Some(player.Position)
-
- //respawn
- sessionLogic.zoning.spawn.reviveTimer.cancel()
- if (player.death_by == 0) {
- sessionLogic.zoning.spawn.randomRespawn(300.seconds)
- } else {
- sessionLogic.zoning.spawn.HandleReleaseAvatar(player, continent)
- }
-
- case AvatarResponse.Release(tplayer) if isNotSameTarget =>
- sessionLogic.zoning.spawn.DepictPlayerAsCorpse(tplayer)
-
- case AvatarResponse.Revive(revivalTargetGuid) if resolvedPlayerGuid == revivalTargetGuid =>
- log.info(s"No time for rest, ${player.Name}. Back on your feet!")
- sessionLogic.zoning.spawn.reviveTimer.cancel()
- sessionLogic.zoning.spawn.deadState = DeadState.Alive
- player.Revive
- val health = player.Health
- sendResponse(PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
- sendResponse(AvatarDeadStateMessage(DeadState.Alive, timer_max=0, timer=0, player.Position, player.Faction, unk5=true))
- continent.AvatarEvents ! AvatarServiceMessage(
- continent.id,
- AvatarAction.PlanetsideAttributeToAll(revivalTargetGuid, attribute_type=0, health)
- )
-
- /* uncommon messages (utility, or once in a while) */
- case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- ops.changeAmmoProcedures(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
- sendResponse(ChangeAmmoMessage(weapon_guid, 1))
-
- case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
- if isNotSameTarget =>
- ops.changeAmmoProcedures(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
-
- case AvatarResponse.ChangeFireMode(itemGuid, mode) if isNotSameTarget =>
- sendResponse(ChangeFireModeMessage(itemGuid, mode))
-
- case AvatarResponse.ConcealPlayer() =>
- sendResponse(GenericObjectActionMessage(guid, code=9))
-
- case AvatarResponse.EnvironmentalDamage(_, _, _) =>
- //TODO damage marker?
- sessionLogic.zoning.CancelZoningProcess()
-
- case AvatarResponse.DropItem(pkt) if isNotSameTarget =>
- sendResponse(pkt)
-
- case AvatarResponse.ObjectDelete(itemGuid, unk) if isNotSameTarget =>
- sendResponse(ObjectDeleteMessage(itemGuid, unk))
-
- /* rare messages */
- case AvatarResponse.SetEmpire(objectGuid, faction) if isNotSameTarget =>
- sendResponse(SetEmpireMessage(objectGuid, faction))
-
- case AvatarResponse.DropSpecialItem() =>
- sessionLogic.general.dropSpecialSlotItem()
-
- case AvatarResponse.OxygenState(player, vehicle) =>
- sendResponse(OxygenStateMessage(
- DrowningTarget(player.guid, player.progress, player.state),
- vehicle.flatMap { vinfo => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) }
+ case AvatarAction.ChangeLoadout(
+ target,
+ armor,
+ exosuit,
+ subtype,
+ _,
+ maxhand,
+ oldHolsters,
+ holsters,
+ oldInventory,
+ inventory,
+ drops
+ ) if TestFilter(() => { ResolvedGuid == target }) =>
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type = 4, armor))
+ //happening to this player
+ sendResponse(ObjectHeldMessage(target, Player.HandsDownSlot, unk1=true))
+ //cleanup
+ (oldHolsters ++ oldInventory).foreach {
+ case (obj, objGuid) =>
+ sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
+ TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
+ }
+ drops.foreach(item => sendResponse(ObjectDeleteMessage(item.obj.GUID, unk1=0)))
+ //redraw
+ if (maxhand) {
+ TaskWorkflow.execute(HoldNewEquipmentUp(player)(
+ Tool(GlobalDefinitions.MAXArms(subtype, player.Faction)),
+ slot = 0
))
+ }
+ sessionLogic.general.applyPurchaseTimersBeforePackingLoadout(player, player, holsters ++ inventory)
+ DropLeftovers(player)(drops)
- case AvatarResponse.LoadProjectile(pkt) if isNotSameTarget =>
- sendResponse(pkt)
+ case AvatarAction.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
+ //redraw handled by callbacks
+ sendResponse(ArmorChangedMessage(target, exosuit, subtype))
+ sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
+ //happening to some other player
+ sendResponse(ObjectHeldMessage(target, slot, unk1=false))
+ //cleanup
+ oldHolsters.foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
- case AvatarResponse.ProjectileState(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid) if isNotSameTarget =>
- sendResponse(ProjectileStateMessage(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid))
-
- case AvatarResponse.ProjectileExplodes(projectileGuid, projectile) =>
- sendResponse(
- ProjectileStateMessage(
- projectileGuid,
- projectile.Position,
- shot_vel = Vector3.Zero,
- projectile.Orientation,
- sequence_num=0,
- end=true,
- hit_target_guid=PlanetSideGUID(0)
- )
+ case AvatarAction.UseKit(kguid, kObjId) =>
+ sendResponse(
+ UseItemMessage(
+ ResolvedGuid,
+ kguid,
+ ResolvedGuid,
+ unk2 = 4294967295L,
+ unk3 = false,
+ unk4 = Vector3.Zero,
+ unk5 = Vector3.Zero,
+ unk6 = 126,
+ unk7 = 0, //sequence time?
+ unk8 = 137,
+ kObjId
)
- sendResponse(ObjectDeleteMessage(projectileGuid, unk1=2))
+ )
+ sendResponse(ObjectDeleteMessage(kguid, unk1=0))
- case AvatarResponse.ProjectileAutoLockAwareness(mode) =>
- sendResponse(GenericActionMessage(mode))
+ case AvatarAction.KitNotUsed(_, "") =>
+ sessionLogic.general.kitToBeUsed = None
- case AvatarResponse.PutDownFDU(target) if isNotSameTarget =>
- sendResponse(GenericObjectActionMessage(target, code=53))
+ case AvatarAction.KitNotUsed(_, msg) =>
+ sessionLogic.general.kitToBeUsed = None
+ sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
- case AvatarResponse.StowEquipment(target, slot, item) if isNotSameTarget =>
- val definition = item.Definition
- sendResponse(
- ObjectCreateDetailedMessage(
- definition.ObjectId,
- item.GUID,
- ObjectCreateMessageParent(target, slot),
- definition.Packet.DetailedConstructorData(item).get
- )
- )
+ case AvatarAction.UpdateKillsDeathsAssists(_, kda: Kill)
+ if TestFilter(() => kda.experienceEarned > 0) =>
+ continent.actor ! ZoneActor.RewardOurSupporters(
+ PlayerSource(player),
+ Players.produceContributionTranscriptFromKill(continent, player, kda),
+ kda,
+ kda.experienceEarned
+ )
- case AvatarResponse.WeaponDryFire(weaponGuid)
- if isNotSameTarget && ops.lastSeenStreamMessage.get(guid.guid).exists { _.visible } =>
- continent.GUID(weaponGuid).collect {
- case tool: Tool if tool.Magazine == 0 =>
- // check that the magazine is still empty before sending WeaponDryFireMessage
- // if it has been reloaded since then, other clients will not see it firing
- sendResponse(WeaponDryFireMessage(weaponGuid))
+ case AvatarAction.AwardBep(charId, bep, expType) =>
+ //if the target player, always award (some) BEP
+ if (charId == player.CharId) {
+ avatarActor ! AvatarActor.AwardBep(bep, expType)
+ }
+
+ case AvatarAction.AwardCep(charId, cep) =>
+ //if the target player, always award (some) CEP
+ if (charId == player.CharId) {
+ avatarActor ! AvatarActor.AwardCep(cep)
+ }
+
+ case AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, cep) =>
+ ops.facilityCaptureRewards(buildingId, zoneNumber, cep)
+
+ case SendResponse(msgs) =>
+ msgs.foreach {
+ case pkt: AvatarImplantMessage
+ if pkt.player_guid == player.GUID && pkt.action == ImplantAction.Initialization =>
+ //special spectator implants stay initialized and do not deinitialize
+ ()
+ case msg =>
+ sendResponse(msg)
+ }
+
+ /* common messages (maybe once every respawn) */
+ case ReloadTool(itemGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible }}) =>
+ sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
+
+ case AvatarAction.Killed(_, mount) =>
+ //log and chat messages
+ val cause = player.LastDamage.flatMap { damage =>
+ val interaction = damage.interaction
+ val reason = interaction.cause
+ val adversarial = interaction.adversarial.map { _.attacker }
+ reason match {
+ case r: ExplodingEntityReason if r.entity.isInstanceOf[VehicleSpawnPad] =>
+ //also, @SVCP_Killed_TooCloseToPadOnCreate^n~ or "... within n meters of pad ..."
+ sendResponse(ChatMsg(ChatMessageType.UNK_227, "@SVCP_Killed_OnPadOnCreate"))
+ case _ => ()
}
+ adversarial.map {_.Name }.orElse { Some(s"a ${reason.getClass.getSimpleName}") }
+ }.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
+ log.info(s"${player.Name} has died, killed by $cause")
+ if (sessionLogic.shooting.shotsWhileDead > 0) {
+ log.warn(
+ s"SHOTS_WHILE_DEAD: client of ${avatar.name} fired ${sessionLogic.shooting.shotsWhileDead} rounds while character was dead on server"
+ )
+ sessionLogic.shooting.shotsWhileDead = 0
+ }
+ sessionLogic.zoning.CancelZoningProcess()
- case _ => ()
- }
+ //player state changes
+ sessionLogic.zoning.spawn.avatarActive = false
+ AvatarActor.updateToolDischargeFor(avatar)
+ player.FreeHand.Equipment.foreach { item =>
+ DropEquipmentFromInventory(player)(item)
+ }
+ sessionLogic.general.dropSpecialSlotItem()
+ sessionLogic.general.toggleMaxSpecialState(enable = false)
+ sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
+ sessionLogic.zoning.zoningStatus = Zoning.Status.None
+ sessionLogic.zoning.spawn.deadState = DeadState.Dead
+ continent.GUID(mount).collect { case obj: Vehicle =>
+ sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
+ sessionLogic.general.unaccessContainer(obj)
+ }
+ sessionLogic.actionsToCancel()
+ sessionLogic.terminals.CancelAllProximityUnits()
+ AvatarActor.savePlayerLocation(player)
+ sessionLogic.zoning.spawn.ShiftPosition = Some(player.Position)
+
+ //respawn
+ sessionLogic.zoning.spawn.reviveTimer.cancel()
+ if (player.death_by == 0) {
+ sessionLogic.zoning.spawn.randomRespawn(300.seconds)
+ } else {
+ sessionLogic.zoning.spawn.HandleReleaseAvatar(player, continent)
+ }
+
+ case AvatarAction.ReleasePlayer(tplayer)
+ if TestFilter(NotSameTargetTest) =>
+ sessionLogic.zoning.spawn.DepictPlayerAsCorpse(tplayer)
+
+ case AvatarAction.Revive(revivalTargetGuid)
+ if TestFilter(() => { ResolvedGuid == revivalTargetGuid }) =>
+ log.info(s"No time for rest, ${player.Name}. Back on your feet!")
+ sessionLogic.zoning.spawn.reviveTimer.cancel()
+ sessionLogic.zoning.spawn.deadState = DeadState.Alive
+ player.Revive
+ val health = player.Health
+ sendResponse(PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
+ sendResponse(AvatarDeadStateMessage(DeadState.Alive, timer_max=0, timer=0, player.Position, player.Faction, unk5=true))
+ continent.AvatarEvents ! MessageEnvelope(
+ continent.id,
+ PlanetsideAttribute(revivalTargetGuid, attribute_type=0, health)
+ )
+
+ /* uncommon messages (utility, or once in a while) */
+ case ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
+ if TestFilter(NotSameTargetTest) =>
+ ops.changeAmmoProcedure(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
+ sendResponse(ChangeAmmoMessage(weapon_guid, 1))
+
+ case AvatarAction.ChangeFireMode(itemGuid, mode)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ChangeFireModeMessage(itemGuid, mode))
+
+ case AvatarAction.EnvironmentalDamage(_, _, _) =>
+ //TODO damage marker?
+ sessionLogic.zoning.CancelZoningProcess()
+
+ case AvatarAction.DropCreatedItem(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ /* rare messages */
+ case AvatarAction.DropSpecialItem() =>
+ sessionLogic.general.dropSpecialSlotItem()
+
+ case AvatarAction.OxygenState(player, vehicle) =>
+ sendResponse(OxygenStateMessage(
+ DrowningTarget(player.guid, player.progress, player.state),
+ vehicle.flatMap { vinfo => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) }
+ ))
+
+ case AvatarAction.LoadCreatedProjectile(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ case AvatarAction.ProjectileState(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ProjectileStateMessage(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid))
+
+ case AvatarAction.ProjectileExplodes(projectileGuid, projectile) =>
+ sendResponse(
+ ProjectileStateMessage(
+ projectileGuid,
+ projectile.Position,
+ shot_vel = Vector3.Zero,
+ projectile.Orientation,
+ sequence_num=0,
+ end=true,
+ hit_target_guid=PlanetSideGUID(0)
+ )
+ )
+ sendResponse(ObjectDeleteMessage(projectileGuid, unk1=2))
+
+ case AvatarAction.ProjectileAutoLockAwareness(mode) =>
+ sendResponse(GenericActionMessage(mode))
+
+ case AvatarAction.PutDownFDU(target)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(GenericObjectActionMessage(target, code=53))
+
+ case AvatarAction.StowEquipment(target, slot, item)
+ if TestFilter(NotSameTargetTest) =>
+ val definition = item.Definition
+ sendResponse(
+ ObjectCreateDetailedMessage(
+ definition.ObjectId,
+ item.GUID,
+ ObjectCreateMessageParent(target, slot),
+ definition.Packet.DetailedConstructorData(item).get
+ )
+ )
+
+ case WeaponDryFire(weaponGuid)
+ if TestFilter(() => { NotSameTarget && ops.lastSeenStreamMessage.get(FilterGuid.guid).exists { _.visible } }) =>
+ continent.GUID(weaponGuid).collect {
+ case tool: Tool if tool.Magazine == 0 =>
+ sendResponse(WeaponDryFireMessage(weaponGuid))
+ }
}
}
diff --git a/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala
index 0987bfd1c..ebcf68ba3 100644
--- a/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala
@@ -16,7 +16,10 @@ import net.psforever.objects.zones.ZoneProjectile
import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.{ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitMembershipRequest, OutfitMembershipResponse, OutfitRequest, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, RequestDestroyMessage, TargetingImplantRequest, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage}
import net.psforever.services.account.AccountPersistenceService
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.CachedEnvelope
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.types.{ExoSuitType, Vector3}
import scala.concurrent.duration.DurationInt
@@ -74,10 +77,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
player.Crouching = isCrouching
player.Jumping = isJumping
player.Cloaked = player.ExoSuit == ExoSuitType.Infiltration && isCloaking
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! CachedEnvelope(
"spectator",
+ avatarGuid,
AvatarAction.PlayerState(
- avatarGuid,
player.Position,
player.Velocity,
yaw,
@@ -106,8 +109,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
}
def handleEmote(pkt: EmoteMsg): Unit = {
- val EmoteMsg(avatarGuid, emote) = pkt
- sendResponse(EmoteMsg(avatarGuid, emote))
+ sendResponse(pkt)
}
def handleDropItem(pkt: DropItemMessage): Unit = { /* intentionally blank */ }
@@ -228,9 +230,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case GenericAction.MaxAnchorsExtend_RCV =>
log.info(s"${player.Name} has anchored ${player.Sex.pronounObject}self to the ground")
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.PlanetsideAttribute(player.GUID, 19, 1)
+ player.GUID,
+ PlanetsideAttribute(player.GUID, 19, 1)
)
definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
@@ -249,9 +252,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case GenericAction.MaxAnchorsRelease_RCV =>
log.info(s"${player.Name} has released the anchors")
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.PlanetsideAttribute(player.GUID, 19, 0)
+ player.GUID,
+ PlanetsideAttribute(player.GUID, 19, 0)
)
definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
diff --git a/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala
index 42214bbd4..c56699848 100644
--- a/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala
@@ -12,9 +12,9 @@ import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.vehicle.VehicleAction
object MountHandlerLogic {
def apply(ops: SessionMountHandlers): MountHandlerLogic = {
@@ -61,9 +61,9 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
val (pos, zang) = Vehicles.dismountShuttle(obj, mountPoint)
tplayer.Position = pos
sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true))
- continent.LocalEvents ! LocalServiceMessage(
+ continent.LocalEvents ! MessageEnvelope(
continent.id,
- LocalAction.SendResponse(ObjectDetachMessage(sguid, pguid, pos, roll=0, pitch=0, zang))
+ SendResponse(ObjectDetachMessage(sguid, pguid, pos, roll=0, pitch=0, zang))
)
obj.Zone.actor ! ZoneActor.RemoveFromBlockMap(player)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
@@ -76,25 +76,21 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountAction(tplayer, obj, seatNum)
continent.actor ! ZoneActor.RemoveFromBlockMap(player) //character doesn't need it
//DismountAction(...) uses vehicle service, so use that service to coordinate the remainder of the messages
- events ! VehicleServiceMessage(
- player.Name,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, PlayerStasisMessage(pguid)) //the stasis message
- )
//when the player dismounts, they will be positioned where the shuttle was when it disappeared in the sky
//the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone
//having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
- events ! VehicleServiceMessage(
- player.Name,
- VehicleAction.SendResponse(
- Service.defaultPlayerGUID,
- PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)) //cower in the shuttle bay
+ events ! BundledEnvelope(
+ MessageEnvelope(player.Name,
+ SendResponse(Seq(
+ PlayerStasisMessage(pguid),
+ PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None))
+ ))
+ ),
+ MessageEnvelope(continent.id, pguid,
+ SendResponse(GenericObjectActionMessage(pguid, code=9)) /* conceal the player */
)
)
- events ! VehicleServiceMessage(
- continent.id,
- VehicleAction.SendResponse(pguid, GenericObjectActionMessage(pguid, code=9)) //conceal the player
- )
context.self ! SessionActor.SetMode(NormalMode)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
@@ -111,9 +107,10 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountVehicleAction(tplayer, obj, seatNum)
case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.KickPassenger(tplayer.GUID, seat_num, unk2=true, obj.GUID)
+ tplayer.GUID,
+ VehicleAction.KickPassenger(seat_num, unk2=true, obj.GUID)
)
case Mountable.CanDismount(obj: PlanetSideGameObject with PlanetSideGameObject with Mountable with FactionAffinity with InGameHistory, seatNum, _) =>
diff --git a/src/main/scala/net/psforever/actors/session/spectator/SpectatorMode.scala b/src/main/scala/net/psforever/actors/session/spectator/SpectatorMode.scala
index 483f13a31..59d438d3b 100644
--- a/src/main/scala/net/psforever/actors/session/spectator/SpectatorMode.scala
+++ b/src/main/scala/net/psforever/actors/session/spectator/SpectatorMode.scala
@@ -6,12 +6,12 @@ import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.{BattleRank, CommandRank, DeployableToolbox, FirstTimeEvents, Implant, ProgressDecoration, Shortcut => AvatarShortcut}
import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.ServerObject
-import net.psforever.objects.{GlobalDefinitions, Player, Session, SimpleItem, Vehicle}
+import net.psforever.objects.{Default, GlobalDefinitions, Player, Session, SimpleItem, Vehicle}
import net.psforever.packet.PlanetSidePacket
import net.psforever.packet.game.{DeployableInfo, DeployableObjectsInfoMessage, DeploymentAction, ObjectCreateDetailedMessage, ObjectDeleteMessage}
import net.psforever.packet.game.objectcreate.{ObjectClass, ObjectCreateMessageParent, RibbonBars}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.ObjectDelete
import net.psforever.services.chat.SpectatorChannel
import net.psforever.services.teamwork.{SquadAction, SquadServiceMessage}
import net.psforever.types.{CapacitorStateType, ChatMessageType, ExoSuitType, MeritCommendation, SquadRequestType}
@@ -68,7 +68,7 @@ class SpectatorModeLogic(data: SessionData) extends ModeLogic {
player.Inventory.Items
.foreach { entry => sendResponse(ObjectDeleteMessage(entry.GUID, 0)) }
sendResponse(ObjectDeleteMessage(player.avatar.locker.GUID, 0))
- continent.AvatarEvents ! AvatarServiceMessage(continent.id, AvatarAction.ObjectDelete(pguid, pguid))
+ continent.AvatarEvents ! MessageEnvelope(continent.id, pguid, ObjectDelete(pguid))
player.Holsters()
.collect { case slot if slot.Equipment.nonEmpty => sendResponse(ObjectDeleteMessage(slot.Equipment.get.GUID, 0)) }
val vehicleAndSeat = data.vehicles.GetMountableAndSeat(None, player, continent) match {
@@ -111,7 +111,7 @@ class SpectatorModeLogic(data: SessionData) extends ModeLogic {
.foreach { obj =>
sendResponse(DeployableObjectsInfoMessage(
DeploymentAction.Dismiss,
- DeployableInfo(obj.GUID, Deployable.Icon.apply(obj.Definition.Item), obj.Position, Service.defaultPlayerGUID)
+ DeployableInfo(obj.GUID, Deployable.Icon.apply(obj.Definition.Item), obj.Position, Default.GUID0)
))
}
if (player.silenced) {
diff --git a/src/main/scala/net/psforever/actors/session/spectator/SquadHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/SquadHandlerLogic.scala
index b73217603..b25d823f8 100644
--- a/src/main/scala/net/psforever/actors/session/spectator/SquadHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/spectator/SquadHandlerLogic.scala
@@ -10,7 +10,7 @@ import net.psforever.objects.avatar.Avatar
import net.psforever.packet.game.{CharacterKnowledgeInfo, CharacterKnowledgeMessage, ChatMsg, PlanetsideAttributeMessage, ReplicationStreamMessage, SquadAction, SquadDefinitionActionMessage, SquadDetailDefinitionUpdateMessage, SquadListing, SquadMemberEvent, SquadMembershipRequest, SquadMembershipResponse, SquadState, SquadStateInfo, SquadWaypointEvent, SquadWaypointRequest, WaypointEventAction}
import net.psforever.services.chat.SquadChannel
import net.psforever.services.teamwork.SquadResponse
-import net.psforever.types.{ChatMessageType, PlanetSideGUID, SquadListDecoration, SquadResponseType}
+import net.psforever.types.{PlanetSideGUID, SquadListDecoration, SquadResponseType}
object SquadHandlerLogic {
def apply(ops: SessionSquadHandlers): SquadHandlerLogic = {
diff --git a/src/main/scala/net/psforever/actors/session/spectator/VehicleHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/VehicleHandlerLogic.scala
index d68308a68..313254d87 100644
--- a/src/main/scala/net/psforever/actors/session/spectator/VehicleHandlerLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/spectator/VehicleHandlerLogic.scala
@@ -1,14 +1,16 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.spectator
+import akka.actor.Actor.Receive
import akka.actor.ActorContext
import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions}
-import net.psforever.objects.{Tool, Vehicle, Vehicles}
+import net.psforever.objects.{Vehicle, Vehicles}
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
-import net.psforever.packet.game.{ChangeAmmoMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, HitHint, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ReloadMessage, ServerVehicleOverrideMsg, VehicleStateMessage, WeaponDryFireMessage}
-import net.psforever.services.vehicle.{VehicleResponse, VehicleServiceResponse}
+import net.psforever.packet.game.{ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ServerVehicleOverrideMsg, VehicleStateMessage}
+import net.psforever.services.base.envelope.GenericResponseEnvelope
+import net.psforever.services.vehicle.{VehicleAction, VehicleStamp}
import net.psforever.types.{BailType, PlanetSideGUID, Vector3}
object VehicleHandlerLogic {
@@ -24,230 +26,184 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
//private val galaxyService: ActorRef = ops.galaxyService
- /**
- * na
- *
- * @param toChannel na
- * @param guid na
- * @param reply na
- */
- def handle(toChannel: String, guid: PlanetSideGUID, reply: VehicleResponse.Response): Unit = {
- val resolvedPlayerGuid = if (player.HasGUID) {
- player.GUID
- } else {
- PlanetSideGUID(-1)
- }
- val isNotSameTarget = resolvedPlayerGuid != guid
- reply match {
- case VehicleResponse.VehicleState(
- vehicleGuid,
- unk1,
- pos,
- orient,
- vel,
- unk2,
- unk3,
- unk4,
- wheelDirection,
- unk5,
- unk6
- ) if isNotSameTarget && player.VehicleSeated.contains(vehicleGuid) =>
- //player who is also in the vehicle (not driver)
- sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, orient, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
- player.Position = pos
- player.Orientation = orient
- player.Velocity = vel
- sessionLogic.updateLocalBlockMap(pos)
+ def receive: Receive = {
+ case VehicleAction.VehicleState(
+ vehicleGuid,
+ unk1,
+ pos,
+ orient,
+ vel,
+ unk2,
+ unk3,
+ unk4,
+ wheelDirection,
+ unk5,
+ unk6
+ ) if TestFilter(() => { NotSameTarget && player.VehicleSeated.contains(vehicleGuid) }) =>
+ //player who is also in the vehicle (not driver)
+ sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, orient, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
+ player.Position = pos
+ player.Orientation = orient
+ player.Velocity = vel
+ sessionLogic.updateLocalBlockMap(pos)
- case VehicleResponse.VehicleState(
- vehicleGuid,
- unk1,
- pos,
- ang,
- vel,
- unk2,
- unk3,
- unk4,
- wheelDirection,
- unk5,
- unk6
- ) if isNotSameTarget =>
- //player who is watching the vehicle from the outside
- sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
+ case VehicleAction.VehicleState(
+ vehicleGuid,
+ unk1,
+ pos,
+ ang,
+ vel,
+ unk2,
+ unk3,
+ unk4,
+ wheelDirection,
+ unk5,
+ unk6
+ ) if TestFilter(NotSameTargetTest) =>
+ //player who is watching the vehicle from the outside
+ sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
- case VehicleResponse.ChildObjectState(objectGuid, pitch, yaw) if isNotSameTarget =>
- sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
+ case VehicleAction.ChildObjectState(objectGuid, pitch, yaw)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
- case VehicleResponse.FrameVehicleState(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)
- if isNotSameTarget =>
- sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
+ case VehicleAction.FrameVehicleState(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
- case VehicleResponse.ChangeFireState_Start(weaponGuid) if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Start(weaponGuid))
+ case VehicleAction.DismountVehicle(bailType, wasKickedByDriver)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(DismountVehicleMsg(FilterGuid, bailType, wasKickedByDriver))
- case VehicleResponse.ChangeFireState_Stop(weaponGuid) if isNotSameTarget =>
- sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
+ case VehicleAction.MountVehicle(vehicleGuid, seat)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ObjectAttachMessage(vehicleGuid, FilterGuid, seat))
- case VehicleResponse.Reload(itemGuid) if isNotSameTarget =>
- sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
+ case VehicleAction.DeployRequest(objectGuid, state, unk1, unk2, pos)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(DeployRequestMessage(FilterGuid, objectGuid, state, unk1, unk2, pos))
- case VehicleResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data) if isNotSameTarget =>
- sendResponse(ObjectDetachMessage(weapon_guid, previous_guid, Vector3.Zero, 0))
- //TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
- sendResponse(
- ObjectCreateMessage(
- ammo_id,
- ammo_guid,
- ObjectCreateMessageParent(weapon_guid, weapon_slot),
- ammo_data
- )
+ case VehicleAction.EquipmentCreatedInSlot(pkt)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(pkt)
+
+ case VehicleAction.InventoryState(obj, parentGuid, start, conData)
+ if TestFilter(NotSameTargetTest) =>
+ //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
+ val objGuid = obj.GUID
+ sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
+ sendResponse(ObjectCreateDetailedMessage(
+ obj.Definition.ObjectId,
+ objGuid,
+ ObjectCreateMessageParent(parentGuid, start),
+ conData
+ ))
+
+ case VehicleAction.KickPassenger(_, wasKickedByDriver, vehicleGuid)
+ if TestFilter(NotSameTargetTest) =>
+ //seat number (first field) seems to be correct if passenger is kicked manually by driver
+ //but always seems to return 4 if user is kicked by mount permissions changing
+ sendResponse(DismountVehicleMsg(FilterGuid, BailType.Kicked, wasKickedByDriver))
+ continent.GUID(vehicleGuid) match {
+ case Some(obj: Vehicle) =>
+ sessionLogic.general.unaccessContainer(obj)
+ case _ => ()
+ }
+
+ case VehicleAction.KickPassenger(_, wasKickedByDriver, _) =>
+ //seat number (first field) seems to be correct if passenger is kicked manually by driver
+ //but always seems to return 4 if user is kicked by mount permissions changing
+ sendResponse(DismountVehicleMsg(FilterGuid, BailType.Kicked, wasKickedByDriver))
+
+ case VehicleAction.InventoryState2(objGuid, parentGuid, value)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(InventoryStateMessage(objGuid, unk=0, parentGuid, value))
+
+ case VehicleAction.LoadVehicle(vehicle, vtype, vguid, vdata)
+ if TestFilter(NotSameTargetTest) =>
+ //this is not be suitable for vehicles with people who are seated in it before it spawns (if that is possible)
+ sendResponse(ObjectCreateMessage(vtype, vguid, vdata))
+ Vehicles.ReloadAccessPermissions(vehicle, player.Name)
+
+ case VehicleAction.SeatPermissions(vehicleGuid, seatGroup, permission)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(PlanetsideAttributeMessage(vehicleGuid, seatGroup, permission))
+
+ case VehicleAction.UnloadVehicle(_, vehicleGuid) =>
+ sendResponse(ObjectDeleteMessage(vehicleGuid, unk1=1))
+
+ case VehicleAction.UnstowEquipment(itemGuid)
+ if TestFilter(NotSameTargetTest) =>
+ //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
+ sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
+
+ case VehicleAction.UpdateAmsSpawnList(list) =>
+ sessionLogic.zoning.spawn.amsSpawnPoints = list.filter(tube => tube.Faction == player.Faction)
+ sessionLogic.zoning.spawn.DrawCurrentAmsSpawnPoint()
+
+ case VehicleAction.KickCargo(vehicle, speed, delay)
+ if TestFilter(() => { player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive && speed > 0 }) =>
+ val strafe = 1 + Vehicles.CargoOrientation(vehicle)
+ val reverseSpeed = if (strafe > 1) { 0 } else { speed }
+ //strafe or reverse, not both
+ sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
+ vehicle,
+ ServerVehicleOverrideMsg(
+ lock_accelerator=true,
+ lock_wheel=true,
+ reverse=true,
+ unk4=false,
+ lock_vthrust=0,
+ strafe,
+ reverseSpeed,
+ unk8=Some(0)
)
- sendResponse(ChangeAmmoMessage(weapon_guid, 1))
+ )
+ import scala.concurrent.ExecutionContext.Implicits.global
+ import scala.concurrent.duration._
+ val resp = GenericResponseEnvelope(
+ VehicleStamp,
+ "",
+ PlanetSideGUID(0),
+ VehicleAction.KickCargo(vehicle, speed=0, delay)
+ )
+ context.system.scheduler.scheduleOnce(delay milliseconds, context.self, resp)
- case VehicleResponse.WeaponDryFire(weaponGuid) if isNotSameTarget =>
- continent.GUID(weaponGuid).collect {
- case tool: Tool if tool.Magazine == 0 =>
- // check that the magazine is still empty before sending WeaponDryFireMessage
- // if it has been reloaded since then, other clients will not see it firing
- sendResponse(WeaponDryFireMessage(weaponGuid))
- }
+ case VehicleAction.KickCargo(cargo, _, _)
+ if TestFilter(() => { player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive }) =>
+ sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
- case VehicleResponse.DismountVehicle(bailType, wasKickedByDriver) if isNotSameTarget =>
- sendResponse(DismountVehicleMsg(guid, bailType, wasKickedByDriver))
+ case VehicleSpawnPad.AttachToRails(vehicle, pad) =>
+ sendResponse(ObjectAttachMessage(pad.GUID, vehicle.GUID, slot=3))
- case VehicleResponse.MountVehicle(vehicleGuid, seat) if isNotSameTarget =>
- sendResponse(ObjectAttachMessage(vehicleGuid, guid, seat))
+ case VehicleSpawnPad.ConcealPlayer(playerGuid) =>
+ sendResponse(GenericObjectActionMessage(playerGuid, code=9))
- case VehicleResponse.DeployRequest(objectGuid, state, unk1, unk2, pos) if isNotSameTarget =>
- sendResponse(DeployRequestMessage(guid, objectGuid, state, unk1, unk2, pos))
-
- case VehicleResponse.SendResponse(msg) =>
- sendResponse(msg)
-
- case VehicleResponse.AttachToRails(vehicleGuid, padGuid) =>
- sendResponse(ObjectAttachMessage(padGuid, vehicleGuid, slot=3))
-
- case VehicleResponse.ConcealPlayer(playerGuid) =>
- sendResponse(GenericObjectActionMessage(playerGuid, code=9))
-
- case VehicleResponse.DetachFromRails(vehicleGuid, padGuid, padPosition, padOrientationZ) =>
- val pad = continent.GUID(padGuid).get.asInstanceOf[VehicleSpawnPad].Definition
- sendResponse(
- ObjectDetachMessage(
- padGuid,
- vehicleGuid,
- padPosition + Vector3.z(pad.VehicleCreationZOffset),
- padOrientationZ + pad.VehicleCreationZOrientOffset
- )
+ case VehicleSpawnPad.DetachFromRails(vehicle, pad) =>
+ val padDefinition = pad.Definition
+ sendResponse(
+ ObjectDetachMessage(
+ pad.GUID,
+ vehicle.GUID,
+ pad.Position + Vector3.z(padDefinition.VehicleCreationZOffset),
+ pad.Orientation.z + padDefinition.VehicleCreationZOrientOffset
)
+ )
- case VehicleResponse.EquipmentInSlot(pkt) if isNotSameTarget =>
- sendResponse(pkt)
+ case VehicleSpawnPad.ResetSpawnPad(pad) =>
+ sendResponse(GenericObjectActionMessage(pad.GUID, code=23))
- case VehicleResponse.GenericObjectAction(objectGuid, action) if isNotSameTarget =>
- sendResponse(GenericObjectActionMessage(objectGuid, action))
+ case VehicleSpawnPad.RevealPlayer(playerGuid) =>
+ sendResponse(GenericObjectActionMessage(playerGuid, code=10))
- case VehicleResponse.InventoryState(obj, parentGuid, start, conData) if isNotSameTarget =>
- //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
- val objGuid = obj.GUID
- sendResponse(ObjectDeleteMessage(objGuid, unk1=0))
- sendResponse(ObjectCreateDetailedMessage(
- obj.Definition.ObjectId,
- objGuid,
- ObjectCreateMessageParent(parentGuid, start),
- conData
- ))
+ case VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, _) =>
+ sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
- case VehicleResponse.KickPassenger(_, wasKickedByDriver, vehicleGuid) if resolvedPlayerGuid == guid =>
- //seat number (first field) seems to be correct if passenger is kicked manually by driver
- //but always seems to return 4 if user is kicked by mount permissions changing
- sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
- continent.GUID(vehicleGuid) match {
- case Some(obj: Vehicle) =>
- sessionLogic.general.unaccessContainer(obj)
- case _ => ()
- }
-
- case VehicleResponse.KickPassenger(_, wasKickedByDriver, _) =>
- //seat number (first field) seems to be correct if passenger is kicked manually by driver
- //but always seems to return 4 if user is kicked by mount permissions changing
- sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
-
- case VehicleResponse.InventoryState2(objGuid, parentGuid, value) if isNotSameTarget =>
- sendResponse(InventoryStateMessage(objGuid, unk=0, parentGuid, value))
-
- case VehicleResponse.LoadVehicle(vehicle, vtype, vguid, vdata) if isNotSameTarget =>
- //this is not be suitable for vehicles with people who are seated in it before it spawns (if that is possible)
- sendResponse(ObjectCreateMessage(vtype, vguid, vdata))
- Vehicles.ReloadAccessPermissions(vehicle, player.Name)
-
- case VehicleResponse.ObjectDelete(itemGuid) if isNotSameTarget =>
- sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
-
- case VehicleResponse.PlanetsideAttribute(vehicleGuid, attributeType, attributeValue) if isNotSameTarget =>
- sendResponse(PlanetsideAttributeMessage(vehicleGuid, attributeType, attributeValue))
-
- case VehicleResponse.ResetSpawnPad(padGuid) =>
- sendResponse(GenericObjectActionMessage(padGuid, code=23))
-
- case VehicleResponse.RevealPlayer(playerGuid) =>
- sendResponse(GenericObjectActionMessage(playerGuid, code=10))
-
- case VehicleResponse.SeatPermissions(vehicleGuid, seatGroup, permission) if isNotSameTarget =>
- sendResponse(PlanetsideAttributeMessage(vehicleGuid, seatGroup, permission))
-
- case VehicleResponse.UnloadVehicle(_, vehicleGuid) =>
- sendResponse(ObjectDeleteMessage(vehicleGuid, unk1=1))
-
- case VehicleResponse.UnstowEquipment(itemGuid) if isNotSameTarget =>
- //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
- sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
-
- case VehicleResponse.UpdateAmsSpawnPoint(list) =>
- sessionLogic.zoning.spawn.amsSpawnPoints = list.filter(tube => tube.Faction == player.Faction)
- sessionLogic.zoning.spawn.DrawCurrentAmsSpawnPoint()
-
- case VehicleResponse.KickCargo(vehicle, speed, delay)
- if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive && speed > 0 =>
- val strafe = 1 + Vehicles.CargoOrientation(vehicle)
- val reverseSpeed = if (strafe > 1) { 0 } else { speed }
- //strafe or reverse, not both
- sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
- vehicle,
- ServerVehicleOverrideMsg(
- lock_accelerator=true,
- lock_wheel=true,
- reverse=true,
- unk4=false,
- lock_vthrust=0,
- strafe,
- reverseSpeed,
- unk8=Some(0)
- )
- )
- import scala.concurrent.ExecutionContext.Implicits.global
- import scala.concurrent.duration._
- context.system.scheduler.scheduleOnce(
- delay milliseconds,
- context.self,
- VehicleServiceResponse(toChannel, PlanetSideGUID(0), VehicleResponse.KickCargo(vehicle, speed=0, delay))
- )
-
- case VehicleResponse.KickCargo(cargo, _, _)
- if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive =>
- sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
-
- case VehicleResponse.ServerVehicleOverrideEnd(vehicle, _) =>
- sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
-
- case VehicleResponse.ChangeLoadout(target, oldWeapons, _, oldInventory, _) =>
- //TODO when vehicle weapons can be changed without visual glitches, rewrite this
- continent.GUID(target).collect { case vehicle: Vehicle =>
- changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
- }
-
- case _ => ()
- }
+ case VehicleAction.ChangeLoadout(target, oldWeapons, _, oldInventory, _) =>
+ //TODO when vehicle weapons can be changed without visual glitches, rewrite this
+ continent.GUID(target).collect { case vehicle: Vehicle =>
+ changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
+ }
}
private def changeLoadoutDeleteOldEquipment(
diff --git a/src/main/scala/net/psforever/actors/session/spectator/VehicleLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/VehicleLogic.scala
index c61499dd8..d20548bd3 100644
--- a/src/main/scala/net/psforever/actors/session/spectator/VehicleLogic.scala
+++ b/src/main/scala/net/psforever/actors/session/spectator/VehicleLogic.scala
@@ -7,7 +7,9 @@ import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.Vehicle
import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.packet.game.{ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.CachedEnvelope
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{DriveState, Vector3}
object VehicleLogic {
@@ -39,22 +41,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Velocity = vel
sessionLogic.updateBlockMap(obj, pos)
obj.zoneInteractions()
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! CachedEnvelope(
continent.id,
- VehicleAction.VehicleState(
- player.GUID,
- vehicle_guid,
- unk1,
- pos,
- ang,
- obj.Velocity,
- obj.Flying,
- 0,
- 0,
- 15,
- unk5 = false,
- obj.Cloaked
- )
+ player.GUID,
+ VehicleAction.VehicleState(vehicle_guid, unk1, pos, ang, obj.Velocity, obj.Flying, 0, 0, 15, unk5 = false, obj.Cloaked)
)
case _ => ()
}
@@ -92,9 +82,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
val mobileShift: String = if (obj.DeploymentState != DriveState.Mobile) {
obj.DeploymentState = DriveState.Mobile
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero))
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.DeployRequest(player.GUID, obj.GUID, DriveState.Mobile, 0, unk2=false, Vector3.Zero)
+ player.GUID,
+ VehicleAction.DeployRequest(obj.GUID, DriveState.Mobile, 0, unk2=false, Vector3.Zero)
)
"; enforcing Mobile deployment state"
} else {
diff --git a/src/main/scala/net/psforever/actors/session/support/ChatOperations.scala b/src/main/scala/net/psforever/actors/session/support/ChatOperations.scala
index b721628b3..0294b7531 100644
--- a/src/main/scala/net/psforever/actors/session/support/ChatOperations.scala
+++ b/src/main/scala/net/psforever/actors/session/support/ChatOperations.scala
@@ -17,10 +17,10 @@ import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.zones.{Zone, ZoneInfo}
import net.psforever.packet.game.TimeOfDayMessage.GetTimeOfDayValue
import net.psforever.packet.game.{SetChatFilterMessage, TimeOfDayMessage}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import net.psforever.services.chat.{DefaultChannel, OutfitChannel, SquadChannel}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.local.support.{CaptureEnvelope, HackCaptureActor}
import net.psforever.services.teamwork.{SquadResponse, SquadService, SquadServiceResponse}
import net.psforever.types.ChatMessageType.CMT_QUIT
import org.log4s.Logger
@@ -405,10 +405,7 @@ class ChatOperations(
}
else {
if (building.CaptureTerminalIsHacked) {
- zone.LocalEvents ! LocalServiceMessage(
- zone.id,
- LocalAction.ResecureCaptureTerminal(terminal, PlayerSource.Nobody)
- )
+ zone.LocalEvents ! CaptureEnvelope(HackCaptureActor.ResecureCaptureTerminal(terminal, zone, PlayerSource.Nobody))
}
building.Actor ! BuildingActor.SetFaction(faction)
building.Actor ! BuildingActor.AmenityStateChange(terminal, Some(false))
@@ -1444,10 +1441,7 @@ class ChatOperations(
val msg = TimeOfDayMessage(zone.GetTimeOfDay(), zone.GetTimeOfDaySpeed())
// update players in zone
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, msg)
- )
+ zone.AvatarEvents ! MessageEnvelope(zone.id, SendResponse(msg))
sendResponse(ChatMsg(messageType = UNK_227, contents = f"@CMT_SETTIME_OK^$hh~^$mm%02d~"))
case _ =>
@@ -1482,10 +1476,7 @@ class ChatOperations(
val msg = TimeOfDayMessage(zone.GetTimeOfDay(), zone.GetTimeOfDaySpeed())
// update players in zone
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, msg)
- )
+ zone.AvatarEvents ! MessageEnvelope(zone.id, SendResponse(msg))
sendResponse(ChatMsg(messageType = UNK_227, contents = s"@CMT_SETTIMESPEED_OK^$timeSpeed~"))
case _ =>
diff --git a/src/main/scala/net/psforever/actors/session/support/CommonHandlerFunctions.scala b/src/main/scala/net/psforever/actors/session/support/CommonHandlerFunctions.scala
new file mode 100644
index 000000000..488406c7f
--- /dev/null
+++ b/src/main/scala/net/psforever/actors/session/support/CommonHandlerFunctions.scala
@@ -0,0 +1,100 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.actors.session.support
+
+import akka.actor.Actor.Receive
+import net.psforever.objects.{Default, Player}
+import net.psforever.services.base.message.EventResponse
+import net.psforever.types.PlanetSideGUID
+
+/**
+ * A shared filter container utilized by all response handlers connected by a certain mode.
+ * It is expected that the filters are treated in a true-oriented context -
+ * always check `isNotSameTarget` and not `!isSameTarget`, etc..
+ */
+protected[support] class CommonHandlerFilters {
+ var resolvedGuid: PlanetSideGUID = Default.GUID0
+ var filterGuid: PlanetSideGUID = Default.GUID0
+ var isNotSameTarget: Boolean = false
+ var isSameTarget: Boolean = false
+
+ def Configure(player: Player, guid: PlanetSideGUID): Unit = {
+ filterGuid = guid
+ if (player != null && player.HasGUID) {
+ resolvedGuid = player.GUID
+ isNotSameTarget = resolvedGuid != filterGuid
+ isSameTarget = resolvedGuid == filterGuid
+ } else {
+ resolvedGuid = Default.GUID0
+ isNotSameTarget = false
+ isSameTarget = false
+ }
+ }
+}
+
+trait CommonHandlerFunctions {
+ _: CommonSessionInterfacingFunctionality =>
+ final def ResolvedGuid: PlanetSideGUID = sessionLogic.handlerFilters.resolvedGuid
+ final def FilterGuid: PlanetSideGUID = sessionLogic.handlerFilters.filterGuid
+ final def NotSameTarget: Boolean = sessionLogic.handlerFilters.isNotSameTarget
+ final def SameTarget: Boolean = sessionLogic.handlerFilters.isSameTarget
+
+ val NotSameTargetTest: () => Boolean = () => NotSameTarget
+
+ val SameTargetTest: () => Boolean = () => SameTarget
+
+ private var ignoreFilter: Boolean = false
+
+ final def IgnoreFilter: Boolean = ignoreFilter
+
+ final def IgnoreFilter_=(state: Boolean): Boolean = {
+ ignoreFilter = state
+ IgnoreFilter
+ }
+
+ /**
+ * Process the output of a received response envelope.
+ * Sets the response handler filter.
+ * @param toChannel set of subscribers on an event system bus the envelope should reach
+ * @param guid a specific subscriber endpoint to be excluded
+ * @param reply output payload transported by this envelope
+ * @return `true`, if the response was processed; `false`, otherwise
+ */
+ final def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Boolean = {
+ sessionLogic.handlerFilters.Configure(player, guid)
+ tryToHandle(reply)
+ }
+
+ /**
+ * Can the response handler process this message (with the guard boolean permissions set as they currently are).
+ * @see `Actor.isDefinedAt`
+ * @param x payload for processing
+ * @return `true`, if the payload was processed; `false`, otherwise
+ */
+ def isDefinedAt(x: Any): Boolean = receive.isDefinedAt(x)
+
+ /**
+ * Process the output.
+ * @param x payload for processing
+ * @return `true`, if the payload was processed; `false`, otherwise
+ */
+ final def tryToHandle(x: Any): Boolean = {
+ var passed = true
+ receive.applyOrElse(x, (_: Any) => { passed = false })
+ passed
+ }
+
+ /**
+ * If ignoring guard booleans (filters), always pass.
+ * If not, test filters using the provided function.
+ * @param filter contained guard booleans
+ * @return `true`. if ignoring filter tests or the filter test passed; `false`, otherwise
+ */
+ final def TestFilter(filter: () => Boolean): Boolean = {
+ ignoreFilter || filter()
+ }
+
+ /**
+ * @see `Actor.receive`
+ */
+ def receive: Receive
+}
diff --git a/src/main/scala/net/psforever/actors/session/support/CommonHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/support/CommonHandlerLogic.scala
new file mode 100644
index 000000000..c66fff0f8
--- /dev/null
+++ b/src/main/scala/net/psforever/actors/session/support/CommonHandlerLogic.scala
@@ -0,0 +1,65 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.actors.session.support
+
+import akka.actor.Actor.Receive
+import akka.actor.ActorContext
+import net.psforever.objects.Tool
+import net.psforever.packet.game.{ChangeAmmoMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, GenericObjectActionMessage, HitHint, ObjectDeleteMessage, PlanetsideAttributeMessage, ReloadMessage, SetEmpireMessage, WeaponDryFireMessage}
+import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, ConcealPlayer, GenericObjectAction, HintsAtAttacker, ObjectDelete, PlanetsideAttribute, ReloadTool, SendResponse, SetEmpire, WeaponDryFire}
+
+class CommonHandlerLogic(val sessionLogic: SessionData, implicit val context: ActorContext)
+ extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
+
+ def receive: Receive = {
+ case PlanetsideAttribute(target_guid, attributeType, attributeValue)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(PlanetsideAttributeMessage(target_guid, attributeType, attributeValue))
+
+ case GenericObjectAction(objectGuid, actionCode)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(GenericObjectActionMessage(objectGuid, actionCode))
+
+ case ObjectDelete(itemGuid, unk)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ObjectDeleteMessage(itemGuid, unk))
+
+ case ChangeFireState_Start(weaponGuid)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ChangeFireStateMessage_Start(weaponGuid))
+
+ case ChangeFireState_Stop(weaponGuid)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
+
+ case ReloadTool(itemGuid)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
+
+ case ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
+ if TestFilter(NotSameTargetTest) =>
+ sessionLogic.avatarResponse.changeAmmoProcedure(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
+ sendResponse(ChangeAmmoMessage(weapon_guid, 1))
+
+ case WeaponDryFire(weaponGuid)
+ if TestFilter(NotSameTargetTest) =>
+ continent.GUID(weaponGuid).collect {
+ case tool: Tool if tool.Magazine == 0 =>
+ sendResponse(WeaponDryFireMessage(weaponGuid))
+ }
+
+ case HintsAtAttacker(sourceGuid)
+ if TestFilter(() => { player.isAlive }) =>
+ sendResponse(HitHint(sourceGuid, FilterGuid))
+ sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
+
+ case SetEmpire(objectGuid, faction)
+ if TestFilter(NotSameTargetTest) =>
+ sendResponse(SetEmpireMessage(objectGuid, faction))
+
+ case ConcealPlayer(_) =>
+ sendResponse(GenericObjectActionMessage(FilterGuid, code=9))
+
+ case SendResponse(msgs) =>
+ msgs.foreach(sendResponse)
+ }
+}
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 9899a1b2c..3d34e5071 100644
--- a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala
+++ b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala
@@ -17,8 +17,12 @@ import net.psforever.objects.sourcing.{DeployableSource, PlayerSource, VehicleSo
import net.psforever.objects.vehicles.Utility.InternalTelepad
import net.psforever.objects.zones.blockmap.BlockMapEntity
import net.psforever.objects.zones.exp.ToDatabase
-import net.psforever.services.RemoverActor
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.avatar.support.GroundEnvelope
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
+import net.psforever.services.base.support.RemoverActor
+import net.psforever.services.local.support.{CaptureEnvelope, HackCaptureActor}
+import net.psforever.services.local.LocalAction
import scala.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global
@@ -48,9 +52,9 @@ import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
import net.psforever.packet.game.objectcreate._
import net.psforever.packet.game._
import net.psforever.services.account.AccountPersistenceService
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
import net.psforever.services.local.support.CaptureFlagManager
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.services.Service
import net.psforever.types._
import net.psforever.util.Config
@@ -193,6 +197,32 @@ class GeneralOperations(
private[session] var progressBarUpdate: Cancellable = Default.Cancellable
private var charSavedTimer: Cancellable = Default.Cancellable
+ def handleEmote(pkt: EmoteMsg): Unit = {
+ val guid = player.GUID
+ val zone = player.Zone
+ val events = zone.LocalEvents
+ //todo better way to collect csr players while utilizing the aforementioned benefit of localSector
+ val position = player.Position
+ val rangeSq = {
+ val range = math.sqrt(2 * math.pow(sessionLogic.localSector.rangeX.toDouble, 2))
+ range * range
+ }
+ val msg = SendResponse(pkt)
+ val (localRecipients, localRecipientMessages) = sessionLogic
+ .localSector
+ .livePlayerList
+ .filter(_.GUID != guid)
+ .map { p => (p.Name, MessageEnvelope(p.Name, msg)) }
+ .unzip
+ val otherRecipientMessages = zone
+ .AllPlayers
+ .filter { p =>
+ !p.allowInteraction && p.GUID != guid && !localRecipients.contains(p.Name) && Vector3.DistanceSquared(p.Position, position) < rangeSq
+ }
+ .map(p => MessageEnvelope(p.Name, msg))
+ events ! BundledEnvelope(localRecipientMessages ++ otherRecipientMessages)
+ }
+
def handleDropItem(pkt: DropItemMessage): GeneralOperations.ItemDropState.Behavior = {
val DropItemMessage(itemGuid) = pkt
(sessionLogic.validObject(itemGuid, decorator = "DropItem"), player.FreeHand.Equipment) match {
@@ -376,7 +406,7 @@ class GeneralOperations(
val detectedTargets = sessionLogic.shooting.FindDetectedProjectileTargets(targets)
val mode = 7 + (if (weapon.Projectile == GlobalDefinitions.wasp_rocket_projectile) 1 else 0)
detectedTargets.foreach { target =>
- continent.AvatarEvents ! AvatarServiceMessage(target, AvatarAction.ProjectileAutoLockAwareness(mode))
+ continent.AvatarEvents ! MessageEnvelope(target, AvatarAction.ProjectileAutoLockAwareness(mode))
}
case _ => ()
}
@@ -456,7 +486,7 @@ class GeneralOperations(
case attacker
if attacker.Faction != player.Faction &&
System.currentTimeMillis() - llu.LastCollectionTime >= Config.app.game.experience.cep.lluSlayerCreditDuration.toMillis =>
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
attacker.Name,
AvatarAction.AwardCep(attacker.CharId, Config.app.game.experience.cep.lluSlayerCredit)
)
@@ -714,7 +744,7 @@ class GeneralOperations(
* @param channel the channel name
*/
private def unaccessContainerChannel(events: ActorRef, channel: String): Unit = {
- events ! Service.Leave(Some(channel))
+ events ! Service.Leave(channel)
}
/**
@@ -851,7 +881,7 @@ class GeneralOperations(
case _ if continent.EquipmentOnGround.contains(obj) =>
obj.Position = Vector3.Zero
continent.Ground ! Zone.Ground.RemoveItem(objectGuid)
- continent.AvatarEvents ! AvatarServiceMessage.Ground(RemoverActor.ClearSpecific(List(obj), continent))
+ continent.AvatarEvents ! GroundEnvelope(RemoverActor.ClearSpecific(List(obj), continent))
true
case _ =>
Zone.EquipmentIs.Where(obj, objectGuid, continent) match {
@@ -876,9 +906,22 @@ class GeneralOperations(
* @param unk2 na
*/
def hackObject(targetGuid: PlanetSideGUID, unk1: Long, unk2: HackState7): Unit = {
- sendResponse(HackMessage(HackState1.Unk0, targetGuid, player_guid=Service.defaultPlayerGUID, progress=100, unk1.toFloat, HackState.Hacked, unk2))
+ sendResponse(HackMessage(HackState1.Unk0, targetGuid, player_guid=Default.GUID0, progress=100, unk1.toFloat, HackState.Hacked, unk2))
}
+ /**
+ * Send a PlanetsideAttributeMessage packet to the client
+ * @param targetGuid The target of the attribute
+ * @param attribute The attribute
+ * @param attributeValue The attribute value
+ */
+ def sendPlanetsideAttributeMessage(
+ targetGuid: PlanetSideGUID,
+ attribute: PlanetsideAttributeEnum,
+ attributeValue: Long
+ ): Unit = {
+ sendPlanetsideAttributeMessage(targetGuid, attribute.id, attributeValue)
+ }
/**
* Send a PlanetsideAttributeMessage packet to the client
* @param targetGuid The target of the attribute
@@ -887,7 +930,7 @@ class GeneralOperations(
*/
def sendPlanetsideAttributeMessage(
targetGuid: PlanetSideGUID,
- attributeNumber: PlanetsideAttributeEnum,
+ attributeNumber: Int,
attributeValue: Long
): Unit = {
sendResponse(PlanetsideAttributeMessage(targetGuid, attributeNumber, attributeValue))
@@ -986,18 +1029,18 @@ class GeneralOperations(
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ArmorShieldOff"))
}
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.PlanetsideAttributeToAll(player.GUID, 8, 0)
+ PlanetsideAttribute(player.GUID, 8, 0)
)
}
}
}
private def activateMaxSpecialStateMessage(): Unit = {
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.PlanetsideAttributeToAll(player.GUID, 8, 1)
+ PlanetsideAttribute(player.GUID, 8, 1)
)
}
@@ -1010,9 +1053,10 @@ class GeneralOperations(
case (Some(obj), Some(seatNum)) =>
tplayer.VehicleSeated = None
obj.Seats(seatNum).unmount(tplayer)
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.KickPassenger(tplayer.GUID, seatNum, unk2=false, obj.GUID)
+ tplayer.GUID,
+ VehicleAction.KickPassenger(seatNum, unk2=false, obj.GUID)
)
case _ => ()
}
@@ -1249,7 +1293,7 @@ class GeneralOperations(
continent.GUID(specialItemSlotGuid) match {
case Some(llu: CaptureFlag) =>
if (llu.Target.GUID == captureTerminal.Owner.GUID) {
- continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.LluCaptured(llu))
+ continent.LocalEvents ! CaptureEnvelope(HackCaptureActor.FlagCaptured(llu))
} else {
log.info(
s"LLU target is not this base. Target GUID: ${llu.Target.GUID} This base: ${captureTerminal.Owner.GUID}"
@@ -1432,23 +1476,21 @@ class GeneralOperations(
val events = continent.AvatarEvents
val zoneid = continent.id
val destinationPosition = dest.Position
- events ! AvatarServiceMessage(zoneid, AvatarAction.ObjectDelete(pguid, pguid))
- events ! AvatarServiceMessage(player.Name,
- AvatarAction.SendResponse(PlanetSideGUID(0), PlayerStateShiftMessage(ShiftState(0, destinationPosition, player.Orientation.z)))
- )
player.Position = destinationPosition
- events ! AvatarServiceMessage(zoneid, AvatarAction.LoadPlayer(
- pguid,
- player.Definition.ObjectId,
- pguid,
- player.Definition.Packet.ConstructorData(player).get,
- None
- ))
- useRouterTelepadEffect(pguid, sguid, dguid)
- continent.LocalEvents ! LocalServiceMessage(
- continent.id,
- LocalAction.RouterTelepadTransport(pguid, pguid, sguid, dguid)
+ events ! BundledEnvelope(
+ MessageEnvelope(zoneid, pguid, ObjectDelete(pguid)),
+ MessageEnvelope(player.Name,
+ SendResponse(PlayerStateShiftMessage(ShiftState(0, destinationPosition, player.Orientation.z)))
+ ),
+ MessageEnvelope(zoneid, pguid, AvatarAction.LoadPlayer(
+ player.Definition.ObjectId,
+ pguid,
+ player.Definition.Packet.ConstructorData(player).get,
+ None
+ )),
+ MessageEnvelope(zoneid, pguid, LocalAction.RouterTelepadTransport(pguid, sguid, dguid))
)
+ useRouterTelepadEffect(pguid, sguid, dguid)
sessionLogic.zoning.spawn.ShiftPosition = destinationPosition
player.LogActivity(TelepadUseActivity(VehicleSource(router), DeployableSource(remoteTelepad), PlayerSource(player)))
} else {
diff --git a/src/main/scala/net/psforever/actors/session/support/SessionAvatarHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionAvatarHandlers.scala
index 7c7002e51..2ac39d632 100644
--- a/src/main/scala/net/psforever/actors/session/support/SessionAvatarHandlers.scala
+++ b/src/main/scala/net/psforever/actors/session/support/SessionAvatarHandlers.scala
@@ -7,8 +7,9 @@ import net.psforever.objects.{Default, PlanetSideGameObject, Player, Vehicle}
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, UniquePlayer}
import net.psforever.packet.game.objectcreate.ConstructorData
import net.psforever.objects.zones.exp
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage, AvatarServiceResponse}
+import net.psforever.services.avatar.{AvatarAction, AvatarStamp}
+import net.psforever.services.base.envelope.{GenericResponseEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SendResponse
import net.psforever.services.chat.OutfitChannel
import scala.collection.mutable
@@ -16,14 +17,11 @@ import scala.collection.mutable
import net.psforever.actors.session.AvatarActor
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.packet.game._
-import net.psforever.services.avatar.AvatarResponse
import net.psforever.types._
import net.psforever.util.Config
-trait AvatarHandlerFunctions extends CommonSessionInterfacingFunctionality {
+trait AvatarHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
val ops: SessionAvatarHandlers
-
- def handle(toChannel: String, guid: PlanetSideGUID, reply: AvatarResponse.Response): Unit
}
class SessionAvatarHandlers(
@@ -36,7 +34,7 @@ class SessionAvatarHandlers(
mutable.LongMap[SessionAvatarHandlers.LastUpstream]()
private[session] val hidingPlayerRandomizer = new scala.util.Random
- def changeAmmoProcedures(
+ def changeAmmoProcedure(
weaponGuid: PlanetSideGUID,
previousAmmoGuid: PlanetSideGUID,
ammoTypeId: Int,
@@ -45,7 +43,7 @@ class SessionAvatarHandlers(
ammoData: ConstructorData
): Unit = {
sendResponse(ObjectDetachMessage(weaponGuid, previousAmmoGuid, Vector3.Zero, 0))
- //TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
+ sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
sendResponse(
ObjectCreateMessage(
ammoTypeId,
@@ -140,7 +138,7 @@ class SessionAvatarHandlers(
val playersInZone = killer.Zone.Players.map { avatar => (avatar.id, avatar.basic.name) }
val squadMembersHere = playersInZone.filter(member => squadMembers.contains(member._2))
squadMembersHere.foreach { member =>
- killer.Zone.AvatarEvents ! AvatarServiceMessage(
+ killer.Zone.AvatarEvents ! MessageEnvelope(
member._2,
AvatarAction.AwardBep(member._1, expSplit, ExperienceType.Normal))
}
@@ -155,7 +153,7 @@ class SessionAvatarHandlers(
val playersInZone = vehicle.Zone.Players.map { avatar => (avatar.id, avatar.basic.name) }
val squadMembersHere = playersInZone.filter(member => squadMembers.contains(member._2))
squadMembersHere.foreach { member =>
- vehicle.Zone.AvatarEvents ! AvatarServiceMessage(
+ vehicle.Zone.AvatarEvents ! MessageEnvelope(
member._2,
AvatarAction.AwardBep(member._1, exp, ExperienceType.Normal))
}
@@ -212,12 +210,11 @@ class SessionAvatarHandlers(
def killedWhileMounted(obj: PlanetSideGameObject with Mountable, playerGuid: PlanetSideGUID): Unit = {
val playerName = player.Name
//boot cadaver from mount on client
- context.self ! AvatarServiceResponse(
+ context.self ! GenericResponseEnvelope(
+ AvatarStamp,
playerName,
- Service.defaultPlayerGUID,
- AvatarResponse.SendResponse(
- ObjectDetachMessage(obj.GUID, playerGuid, player.Position, Vector3.Zero)
- )
+ Default.GUID0,
+ SendResponse(ObjectDetachMessage(obj.GUID, playerGuid, player.Position, Vector3.Zero))
)
//player no longer seated
obj.PassengerInSeat(player).foreach { seatNumber =>
@@ -239,7 +236,7 @@ class SessionAvatarHandlers(
object SessionAvatarHandlers {
private[session] case class LastUpstream(
- msg: Option[AvatarResponse.PlayerState],
+ msg: Option[AvatarAction.PlayerState],
visible: Boolean,
shooting: Option[PlanetSideGUID],
time: Long
diff --git a/src/main/scala/net/psforever/actors/session/support/SessionData.scala b/src/main/scala/net/psforever/actors/session/support/SessionData.scala
index 33b838102..7368c358f 100644
--- a/src/main/scala/net/psforever/actors/session/support/SessionData.scala
+++ b/src/main/scala/net/psforever/actors/session/support/SessionData.scala
@@ -4,6 +4,7 @@ package net.psforever.actors.session.support
import akka.actor.typed.receptionist.Receptionist
import akka.actor.typed.scaladsl.adapter._
import akka.actor.{ActorContext, ActorRef, typed}
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.chat.ChatService
import scala.collection.mutable
@@ -31,7 +32,7 @@ import net.psforever.packet._
import net.psforever.packet.game._
import net.psforever.services.account.AccountPersistenceService
import net.psforever.services.ServiceManager.LookupResult
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.services.{Service, InterstellarClusterService => ICS}
import net.psforever.types._
import net.psforever.util.Config
@@ -119,6 +120,8 @@ class SessionData(
def zoning: ZoningOperations = zoningOpt.orNull
def chat: ChatOperations = chatOpt.orNull
+ val handlerFilters: CommonHandlerFilters = new CommonHandlerFilters()
+
ServiceManager.serviceManager ! Lookup("accountIntermediary")
ServiceManager.serviceManager ! Lookup("accountPersistence")
ServiceManager.serviceManager ! Lookup("galaxy")
@@ -567,9 +570,10 @@ class SessionData(
case (Some(obj), Some(seatNum)) =>
tplayer.VehicleSeated = None
obj.Seats(seatNum).unmount(tplayer)
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.KickPassenger(tplayer.GUID, seatNum, unk2=false, obj.GUID)
+ tplayer.GUID,
+ VehicleAction.KickPassenger(seatNum, unk2=false, obj.GUID)
)
case _ => ()
}
@@ -615,12 +619,12 @@ class SessionData(
squadResponseOpt.foreach(_.stop())
zoningOpt.foreach(_.stop())
chatOpt.foreach(_.stop())
- continent.AvatarEvents ! Service.Leave()
- continent.LocalEvents ! Service.Leave()
- continent.VehicleEvents ! Service.Leave()
- galaxyService ! Service.Leave()
+ continent.AvatarEvents ! Service.LeaveAll
+ continent.LocalEvents ! Service.LeaveAll
+ continent.VehicleEvents ! Service.LeaveAll
+ galaxyService ! Service.LeaveAll
if (avatar != null && squadService != Default.Actor) {
- squadService ! Service.Leave()
+ squadService ! Service.LeaveAll
}
}
}
diff --git a/src/main/scala/net/psforever/actors/session/support/SessionGalaxyHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionGalaxyHandlers.scala
index ad7614296..419c74c0d 100644
--- a/src/main/scala/net/psforever/actors/session/support/SessionGalaxyHandlers.scala
+++ b/src/main/scala/net/psforever/actors/session/support/SessionGalaxyHandlers.scala
@@ -3,16 +3,13 @@ package net.psforever.actors.session.support
import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.packet.game.FriendsResponse
-//
-import net.psforever.actors.session.AvatarActor
-import net.psforever.services.galaxy.GalaxyResponse
-trait GalaxyHandlerFunctions extends CommonSessionInterfacingFunctionality {
+import net.psforever.actors.session.AvatarActor
+
+trait GalaxyHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
def ops: SessionGalaxyHandlers
def handleUpdateIgnoredPlayers(pkt: FriendsResponse): Unit
-
- def handle(reply: GalaxyResponse.Response): Unit
}
class SessionGalaxyHandlers(
diff --git a/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala
index 8480a1d55..583a83f87 100644
--- a/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala
+++ b/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala
@@ -7,17 +7,14 @@ import net.psforever.objects.ce.Deployable
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects.serverobject.interior.Sidedness
import net.psforever.packet.game.{GenericObjectActionMessage, ObjectDeleteMessage, PlanetsideAttributeMessage, TriggerEffectMessage}
-import net.psforever.services.local.LocalResponse
import net.psforever.types.{PlanetSideGUID, Vector3}
-trait LocalHandlerFunctions extends CommonSessionInterfacingFunctionality {
+trait LocalHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
def ops: SessionLocalHandlers
def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit
def handleDeployableIsDismissed(obj: Deployable): Unit
-
- def handle(toChannel: String, guid: PlanetSideGUID, reply: LocalResponse.Response): Unit
}
class SessionLocalHandlers(
diff --git a/src/main/scala/net/psforever/actors/session/support/SessionMountHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionMountHandlers.scala
index 7f5004529..67c410492 100644
--- a/src/main/scala/net/psforever/actors/session/support/SessionMountHandlers.scala
+++ b/src/main/scala/net/psforever/actors/session/support/SessionMountHandlers.scala
@@ -5,11 +5,14 @@ import akka.actor.{ActorContext, typed}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.interior.Sidedness.OutsideOf
import net.psforever.objects.{PlanetSideGameObject, Tool, Vehicle}
-import net.psforever.objects.vehicles.{CargoBehavior, MountableWeapons}
+import net.psforever.objects.vehicles.MountableWeapons
+import net.psforever.objects.vehicles.control.CargoBehavior
import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{DismountVehicleCargoMsg, GenericObjectActionMessage, InventoryStateMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectAttachMessage, ObjectDetachMessage, PlanetsideAttributeMessage}
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.CachedEnvelope
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, PlanetSideGUID, Vector3}
//
import net.psforever.actors.session.AvatarActor
@@ -185,9 +188,10 @@ class SessionMountHandlers(
avatarActor ! AvatarActor.DeactivateActiveImplants
avatarActor ! AvatarActor.SuspendStaminaRegeneration(3.seconds)
sendResponse(ObjectAttachMessage(objGuid, playerGuid, seatNum))
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.MountVehicle(playerGuid, objGuid, seatNum)
+ playerGuid,
+ VehicleAction.MountVehicle(objGuid, seatNum)
)
}
@@ -202,13 +206,12 @@ class SessionMountHandlers(
if (tplayer.BailProtection) {
tplayer.ContributionFrom(obj)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, PlanetsideAttributeMessage(obj.GUID, 81, 1))
- )
- continent.VehicleEvents ! VehicleServiceMessage(
- continent.id,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, ObjectDetachMessage(obj.GUID, tplayer.GUID, tplayer.Position, obj.Orientation))
+ SendResponse(
+ PlanetsideAttributeMessage(obj.GUID, 81, 1),
+ ObjectDetachMessage(obj.GUID, tplayer.GUID, tplayer.Position, obj.Orientation)
+ )
)
}
else {
@@ -223,22 +226,10 @@ class SessionMountHandlers(
sessionLogic.vehicles.ServerVehicleOverrideStop(v)
}*/
v.Velocity = Vector3.Zero
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! CachedEnvelope(
continent.id,
- VehicleAction.VehicleState(
- tplayer.GUID,
- v.GUID,
- unk1 = 0,
- tplayer.Position,
- v.Orientation,
- v.Velocity,
- v.Flying,
- unk3 = 0,
- unk4 = 0,
- wheel_direction = 15,
- unk5 = false,
- unk6 = v.Cloaked
- )
+ tplayer.GUID,
+ VehicleAction.VehicleState(v.GUID, unk1 = 0, tplayer.Position, v.Orientation, v.Velocity, v.Flying, unk3 = 0, unk4 = 0, wheel_direction = 15, unk5 = false, unk6 = v.Cloaked)
)
case _ => ()
}
@@ -260,9 +251,10 @@ class SessionMountHandlers(
BailType.Normal
}
sendResponse(DismountVehicleMsg(playerGuid, bailType, wasKickedByDriver = false))
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.DismountVehicle(playerGuid, bailType, unk2 = false)
+ playerGuid,
+ VehicleAction.DismountVehicle(bailType, unk2 = false)
)
}
diff --git a/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala
index 80bebf9c9..8fc619912 100644
--- a/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala
+++ b/src/main/scala/net/psforever/actors/session/support/SessionOutfitHandlers.scala
@@ -8,7 +8,9 @@ import net.psforever.objects.Player
import net.psforever.packet.game.OutfitEventAction.{Initial, Leaving, OutfitInfo, OutfitRankNames, Unk1, Update, UpdateMemberCount}
import net.psforever.packet.game.OutfitMembershipResponse.PacketType.CreateResponse
import net.psforever.packet.game._
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.services.chat.OutfitChannel
import net.psforever.types.ChatMessageType
import net.psforever.util.Config
@@ -48,58 +50,62 @@ object SessionOutfitHandlers {
import scala.concurrent.Future
def HandleOutfitForm(outfitName: String, player: Player, session: SessionData): Unit = {
+ val zone = player.Zone
+ val zoneid = zone.id
+ val charid = player.CharId
+ val pname = player.Name
val cleanedName = sanitizeOutfitName(outfitName)
cleanedName match {
case Some(validName) =>
ctx.run(findOutfitByName(validName)).flatMap {
case existing if existing.nonEmpty =>
- PlayerControl.sendResponse(player.Zone, player.Name,
- ChatMsg(ChatMessageType.UNK_227, "@OutfitErrorNameAlreadyTaken"))
+ PlayerControl.sendResponse(zone, pname,
+ ChatMsg(ChatMessageType.UNK_227, "@OutfitErrorNameAlreadyTaken")
+ )
Future.successful(())
case _ =>
- createNewOutfit(validName, player.Faction.id, player.CharId).map { outfit =>
- val seconds: Long =
- outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
-
- PlayerControl.sendResponse(player.Zone, player.Name,
- OutfitEvent(outfit.id, Update(
- OutfitInfo(
- outfit.name, 0, 0, 1,
- OutfitRankNames("", "", "", "", "", "", "", ""),
- "",
- 14, unk11 = true, 0, seconds, 0, 0, 0))))
-
- PlayerControl.sendResponse(player.Zone, player.Name,
- OutfitMemberUpdate(outfit.id, player.CharId, 7, flag = true))
-
- PlayerControl.sendResponse(player.Zone, player.Name,
- ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateSuccess"))
-
- PlayerControl.sendResponse(player.Zone, player.Name,
- OutfitMembershipResponse(CreateResponse, 0, 0, player.CharId, 0, "", "", flag = true))
-
- player.outfit_id = outfit.id
- player.outfit_name = outfit.name
-
- player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(player.GUID, 39, outfit.id))
-
- player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.id,
- AvatarAction.PlanetsideStringAttribute(player.GUID, 0, outfit.name))
-
- session.chat.JoinChannel(OutfitChannel(player.outfit_id))
+ createNewOutfit(validName, player.Faction.id, charid).map { outfit =>
+ val outfitId = outfit.id
+ val outfitName = outfit.name
+ val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
+ player.outfit_id = outfitId
+ player.outfit_name = outfitName
+ zone.AvatarEvents ! BundledEnvelope(
+ MessageEnvelope(pname, SendResponse(
+ OutfitEvent(outfitId, Update(
+ OutfitInfo(
+ outfitName, 0, 0, 1,
+ OutfitRankNames("", "", "", "", "", "", "", ""),
+ "",
+ 14, unk11 = true, 0, seconds, 0, 0, 0)
+ )),
+ OutfitMemberUpdate(outfitId, charid, 7, flag = true),
+ ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateSuccess"),
+ OutfitMembershipResponse(CreateResponse, 0, 0, charid, 0, "", "", flag = true),
+ )),
+ MessageEnvelope(
+ zoneid,
+ PlanetsideAttribute(player.GUID, 39, outfitId)
+ ),
+ MessageEnvelope(
+ zoneid,
+ player.GUID,
+ AvatarAction.PlanetsideStringAttribute(0, outfitName)
+ )
+ )
+ session.chat.JoinChannel(OutfitChannel(outfitId))
}
.recover { case e =>
e.printStackTrace()
- PlayerControl.sendResponse(player.Zone, player.Name,
- ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
+ PlayerControl.sendResponse(zone, pname,
+ ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure")
+ )
}
}
case None =>
- PlayerControl.sendResponse(player.Zone, player.Name,
- ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
+ PlayerControl.sendResponse(zone, pname, ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
}
}
@@ -120,69 +126,80 @@ object SessionOutfitHandlers {
}
def HandleOutfitInviteAccept(invited: Player, session: SessionData): Unit = {
- OutfitInviteManager.getOutfitInvite(invited.CharId) match {
+ val toName = invited.Name
+ val toCharId = invited.CharId
+ val toZone = invited.Zone
+ val toZoneId = toZone.id
+ val toGuid = invited.GUID
+ OutfitInviteManager.getOutfitInvite(toCharId) match {
case Some(outfitInvite) =>
+ val fromName = outfitInvite.sentFrom.Name
+ val fromCharId = outfitInvite.sentFrom.CharId
+ val fromZone = outfitInvite.sentFrom.Zone
val outfitId = outfitInvite.sentFrom.outfit_id
-
(for {
- _ <- addMemberToOutfit(outfitId, invited.CharId)
+ _ <- addMemberToOutfit(outfitId, toCharId)
outfitOpt <- ctx.run(getOutfitById(outfitId)).map(_.headOption)
memberCount <- ctx.run(getOutfitMemberCount(outfitId))
points <- ctx.run(getOutfitPoints(outfitId)).map(_.headOption.map(_.points).getOrElse(0L))
} yield (outfitOpt, memberCount, points))
.map {
case (Some(outfit), memberCount, points) =>
-
- PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
- OutfitMembershipResponse(
- OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
- invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = false))
-
- PlayerControl.sendResponse(invited.Zone, invited.Name,
- OutfitMembershipResponse(
- OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
- invited.CharId, outfitInvite.sentFrom.CharId, invited.Name, outfit.name, flag = true))
-
- PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
- OutfitEvent(outfitId, UpdateMemberCount(memberCount)))
-
- PlayerControl.sendResponse(outfitInvite.sentFrom.Zone, outfitInvite.sentFrom.Name,
- OutfitMemberEvent(outfitId, invited.CharId,
- OutfitMemberEventAction.Update(invited.Name, 0, 0, 0,
- OutfitMemberEventAction.PacketType.Padding, 0)))
-
+ val outfitName = outfit.name
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
- PlayerControl.sendResponse(invited.Zone, invited.Name,
- OutfitEvent(outfitId, Initial(OutfitInfo(
- outfit.name, points, points, memberCount,
- OutfitRankNames("", "", "", "", "", "", "", ""),
- outfit.motd.getOrElse(""),
- 14, unk11 = true, 0, seconds, 0, 0, 0))))
-
- PlayerControl.sendResponse(invited.Zone, invited.Name,
- OutfitMemberUpdate(outfit.id, invited.CharId, 0, flag=true))
-
- OutfitInviteManager.removeOutfitInvite(invited.CharId)
-
- session.chat.JoinChannel(OutfitChannel(outfit.id))
- invited.outfit_id = outfit.id
- invited.outfit_name = outfit.name
-
- invited.Zone.AvatarEvents ! AvatarServiceMessage(invited.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(invited.GUID, 39, outfit.id))
-
- invited.Zone.AvatarEvents ! AvatarServiceMessage(invited.Zone.id,
- AvatarAction.PlanetsideStringAttribute(invited.GUID, 0, outfit.name))
- case (None, _, _) =>
-
- PlayerControl.sendResponse(invited.Zone, invited.Name,
- ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit"))
- }
- .recover { case _ =>
- PlayerControl.sendResponse(invited.Zone, invited.Name,
- ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit"))
+ fromZone.AvatarEvents ! BundledEnvelope(
+ MessageEnvelope(fromName, SendResponse(
+ OutfitMembershipResponse(
+ OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
+ toCharId, fromCharId, toName, outfitName, flag = false
+ ),
+ OutfitEvent(outfitId, UpdateMemberCount(memberCount)),
+ OutfitMemberEvent(outfitId, toCharId,
+ OutfitMemberEventAction.Update(toName, 0, 0, 0,
+ OutfitMemberEventAction.PacketType.Padding, 0
+ )
+ )
+ ))
+ )
+ toZone.AvatarEvents ! BundledEnvelope(
+ MessageEnvelope(toName, SendResponse(
+ OutfitMembershipResponse(
+ OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
+ toCharId, fromCharId, toName, outfitName, flag = true
+ ),
+ OutfitEvent(outfitId, Initial(OutfitInfo(
+ outfitName, points, points, memberCount,
+ OutfitRankNames("", "", "", "", "", "", "", ""),
+ outfit.motd.getOrElse(""),
+ 14, unk11 = true, 0, seconds, 0, 0, 0
+ ))),
+ OutfitMemberUpdate(outfitId, toCharId, 0, flag=true)
+ )),
+ MessageEnvelope(
+ toZoneId,
+ PlanetsideAttribute(toGuid, 39, outfitId)
+ ),
+ MessageEnvelope(
+ toZoneId,
+ toGuid,
+ AvatarAction.PlanetsideStringAttribute(0, outfitName)
+ )
+ )
+ OutfitInviteManager.removeOutfitInvite(toCharId)
+ session.chat.JoinChannel(OutfitChannel(outfitId))
+ invited.outfit_id = outfitId
+ invited.outfit_name = outfitName
+ case (None, _, _) => ()
+ PlayerControl.sendResponse(toZone, toName,
+ ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")
+ )
}
- case None =>
+ .recover { case _ =>
+ PlayerControl.sendResponse(toZone, toName,
+ ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")
+ )
+ }
+ case None => ()
}
}
@@ -206,72 +223,76 @@ object SessionOutfitHandlers {
}
def HandleOutfitKick(zones: Seq[Zone], kickedId: Long, kickedBy: Player, session: SessionData): Unit = {
+ val outfit_id = kickedBy.outfit_id
// if same id, player has left the outfit by their own choice
if (kickedId == kickedBy.CharId) {
-
// store outfit_id since it will be nulled soon
- val outfit_id = kickedBy.outfit_id
-
removeMemberFromOutfit(outfit_id, kickedId).map {
case (deleted, _) =>
if (deleted > 0) {
-
- PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
- OutfitEvent(outfit_id, Leaving())
+ kickedBy.Zone.AvatarEvents ! BundledEnvelope(
+ MessageEnvelope(kickedBy.Name, SendResponse(OutfitEvent(outfit_id, Leaving()))),
+ MessageEnvelope(
+ kickedBy.Zone.id,
+ PlanetsideAttribute(kickedBy.GUID, 39, 0)
+ ),
+ MessageEnvelope(
+ kickedBy.Zone.id,
+ kickedBy.GUID,
+ AvatarAction.PlanetsideStringAttribute(0, "")
+ )
)
-
session.chat.LeaveChannel(OutfitChannel(outfit_id))
kickedBy.outfit_name = ""
kickedBy.outfit_id = 0
- zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers)
- .filter(p => p.outfit_id == outfit_id).foreach(outfitMember =>
- PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
- OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
- )
-
- kickedBy.Zone.AvatarEvents ! AvatarServiceMessage(kickedBy.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(kickedBy.GUID, 39, 0))
-
- kickedBy.Zone.AvatarEvents ! AvatarServiceMessage(kickedBy.Zone.id,
- AvatarAction.PlanetsideStringAttribute(kickedBy.GUID, 0, ""))
+ zones
+ .filter(z => z.AllPlayers.nonEmpty)
+ .flatMap(_.AllPlayers)
+ .filter(p => p.outfit_id == outfit_id)
+ .foreach(outfitMember =>
+ PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
+ OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked())
+ )
+ )
}
}.recover { case e =>
e.printStackTrace()
}
}
else {
- removeMemberFromOutfit(kickedBy.outfit_id, kickedId).map {
+ removeMemberFromOutfit(outfit_id, kickedId).map {
case (deleted, _) =>
if (deleted > 0) {
findPlayerByIdForOutfitAction(zones, kickedId, kickedBy).foreach { kicked =>
-
- PlayerControl.sendResponse(kicked.Zone, kicked.Name,
- OutfitEvent(kickedBy.outfit_id, Leaving())
+ kicked.Zone.AvatarEvents ! BundledEnvelope(
+ MessageEnvelope(kicked.Name, SendResponse(
+ OutfitEvent(outfit_id, Leaving()),
+ OutfitMembershipResponse(
+ OutfitMembershipResponse.PacketType.YouGotKicked, 0, 1,
+ kickedBy.CharId, kicked.CharId, kickedBy.Name, kicked.Name, flag = false
+ )
+ )),
+ MessageEnvelope(kicked.Zone.id,
+ PlanetsideAttribute(kicked.GUID, 39, 0)
+ ),
+ MessageEnvelope(
+ kicked.Zone.id,
+ kicked.GUID,
+ AvatarAction.PlanetsideStringAttribute(0, "")
+ ),
+ MessageEnvelope(kicked.Name,
+ AvatarAction.RemoveFromOutfitChat(outfit_id)
+ ),
+ MessageEnvelope(kicked.Name, SendResponse(
+ OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked())
+ ))
)
-
- PlayerControl.sendResponse(kicked.Zone, kicked.Name,
- OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouGotKicked, 0, 1,
- kickedBy.CharId, kicked.CharId, kickedBy.Name, kicked.Name, flag = false))
-
- kicked.Zone.AvatarEvents ! AvatarServiceMessage(kicked.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(kicked.GUID, 39, 0))
-
- kicked.Zone.AvatarEvents ! AvatarServiceMessage(kicked.Zone.id,
- AvatarAction.PlanetsideStringAttribute(kicked.GUID, 0, ""))
-
- kicked.Zone.AvatarEvents ! AvatarServiceMessage(
- kicked.Name, AvatarAction.RemoveFromOutfitChat(kickedBy.outfit_id))
-
kicked.outfit_id = 0
kicked.outfit_name = ""
- PlayerControl.sendResponse(kicked.Zone, kicked.Name,
- OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
}
val avatarName: Future[Option[String]] =
- ctx.run(
- quote { query[Avatar].filter(_.id == lift(kickedId)).map(_.name) }
- ).map(_.headOption)
+ ctx.run(quote { query[Avatar].filter(_.id == lift(kickedId)).map(_.name) }).map(_.headOption)
avatarName.foreach {
case Some(name) => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
@@ -280,10 +301,14 @@ object SessionOutfitHandlers {
case None => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouKicked, 0, 1, kickedBy.CharId, kickedId, "NameNotFound", "", flag = true))
}
- zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers)
- .filter(p => p.outfit_id == kickedBy.outfit_id).foreach(outfitMember =>
- PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
- OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
+ zones
+ .filter(z => z.AllPlayers.nonEmpty)
+ .flatMap(_.AllPlayers)
+ .filter(p => p.outfit_id == kickedBy.outfit_id)
+ .foreach(outfitMember =>
+ PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
+ OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked())
+ )
)
// this needs to be the kicked player
// session.chat.LeaveChannel(OutfitChannel(kickedBy.outfit_id))
@@ -297,18 +322,13 @@ object SessionOutfitHandlers {
}
def HandleOutfitPromote(zones: Seq[Zone], promotedId: Long, newRank: Int, promoter: Player): Unit = {
-
val outfit_id = promoter.outfit_id
-
findPlayerByIdForOutfitAction(zones, promotedId, promoter).foreach { promoted =>
-
if (newRank == 7) {
-
// demote owner to rank 6
// promote promoted to rank 7
// update outfit
updateOutfitOwner(outfit_id, promoter.avatar.id, promoted.avatar.id)
-
// TODO: does every member get the notification like this?
getOutfitMemberPoints(outfit_id, promoter.avatar.id).map {
owner_points =>
@@ -324,7 +344,6 @@ object SessionOutfitHandlers {
})
})
}
-
// update promoter rank
PlayerControl.sendResponse(
promoter.Zone, promoter.Name,
@@ -338,17 +357,19 @@ object SessionOutfitHandlers {
// TODO: does every member get the notification like this?
getOutfitMemberPoints(outfit_id, promoted.avatar.id).map {
member_points =>
- // tell everyone about the new rank of the promoted member
- zones.foreach(zone => {
- zone.AllPlayers
+ zones.foreach { zone =>
+ // tell everyone about the new rank of the promoted member
+ val messages = zone.AllPlayers
.filter(_.outfit_id == outfit_id)
- .foreach(player => {
- PlayerControl.sendResponse(
- zone, player.Name,
+ .map { player =>
+ MessageEnvelope(player.Name, SendResponse(
OutfitMemberEvent(outfit_id, promoted.avatar.id,
- OutfitMemberEventAction.Update(promoted.Name, newRank, member_points, 0, OutfitMemberEventAction.PacketType.Padding, 0)))
- })
- })
+ OutfitMemberEventAction.Update(promoted.Name, newRank, member_points, 0, OutfitMemberEventAction.PacketType.Padding, 0)
+ )
+ ))
+ }
+ zone.AvatarEvents ! BundledEnvelope(messages)
+ }
}
// update promoted rank
@@ -364,7 +385,6 @@ object SessionOutfitHandlers {
memberCount <- ctx.run(query[Outfitmember].filter(_.outfit_id == lift(outfitId)).size)
pointsTotal <- ctx.run(querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(outfitId)))
} yield (outfitOpt, memberCount, pointsTotal.headOption.map(_.points).getOrElse(0L))
-
val membersF = ctx.run(getOutfitMembersWithDetails(outfitId))
for {
@@ -373,43 +393,42 @@ object SessionOutfitHandlers {
} yield {
outfitOpt.foreach { outfit =>
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
-
- PlayerControl.sendResponse(player.Zone, player.Name,
- OutfitEvent(outfit.id, Initial(OutfitInfo(
- outfit.name,
- totalPoints,
- totalPoints,
- memberCount,
- OutfitRankNames(
- outfit.rank0.getOrElse(""),
- outfit.rank1.getOrElse(""),
- outfit.rank2.getOrElse(""),
- outfit.rank3.getOrElse(""),
- outfit.rank4.getOrElse(""),
- outfit.rank5.getOrElse(""),
- outfit.rank6.getOrElse(""),
- outfit.rank7.getOrElse(""),
- ),
- outfit.motd.getOrElse(""),
- 14, unk11 = true, 0, seconds, 0, 0, 0))))
-
- members.foreach { case (avatarId, avatarName, points, rank, login) =>
+ val outfitEventInitial = OutfitEvent(outfit.id, Initial(OutfitInfo(
+ outfit.name,
+ totalPoints,
+ totalPoints,
+ memberCount,
+ OutfitRankNames(
+ outfit.rank0.getOrElse(""),
+ outfit.rank1.getOrElse(""),
+ outfit.rank2.getOrElse(""),
+ outfit.rank3.getOrElse(""),
+ outfit.rank4.getOrElse(""),
+ outfit.rank5.getOrElse(""),
+ outfit.rank6.getOrElse(""),
+ outfit.rank7.getOrElse(""),
+ ),
+ outfit.motd.getOrElse(""),
+ 14, unk11 = true, 0, seconds, 0, 0, 0))
+ )
+ val memberEventList = members.map { case (avatarId, avatarName, points, rank, login) =>
val lastLogin = findPlayerByIdForOutfitAction(zones, avatarId, player) match {
case Some(_) => 0L
case None if player.Name == avatarName => 0L
case None => (System.currentTimeMillis() - login.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli) / 1000
}
- PlayerControl.sendResponse(player.Zone, player.Name,
- OutfitMemberEvent(outfit.id, avatarId,
- OutfitMemberEventAction.Update(
- avatarName,
- rank,
- points,
- lastLogin,
- OutfitMemberEventAction.PacketType.Padding, 0)))
+ OutfitMemberEvent(outfit.id, avatarId,
+ OutfitMemberEventAction.Update(
+ avatarName,
+ rank,
+ points,
+ lastLogin,
+ OutfitMemberEventAction.PacketType.Padding, 0)
+ )
}
- PlayerControl.sendResponse(player.Zone, player.Name,
- OutfitEvent(outfit.id, Unk1()))
+ player.Zone.AvatarEvents ! MessageEnvelope(player.Name, SendResponse(
+ outfitEventInitial +: memberEventList :+ OutfitEvent(outfit.id, Unk1())
+ ))
}
}
}
@@ -420,16 +439,13 @@ object SessionOutfitHandlers {
futureResult.onComplete {
case Success(rows) =>
- rows.foreach { case (outfitId, points, name, leaderName, memberCount) =>
- PlayerControl.sendResponse(player.Zone, player.Name,
+ player.Zone.AvatarEvents ! MessageEnvelope(player.Name, SendResponse(
+ rows.map { case (outfitId, points, name, leaderName, memberCount) =>
OutfitListEvent(
- OutfitListEventAction.ListElementOutfit(
- outfitId,
- points,
- memberCount,
- name,
- leaderName)))
- }
+ OutfitListEventAction.ListElementOutfit(outfitId, points, memberCount, name, leaderName)
+ )
+ }
+ ))
case Failure(_) =>
PlayerControl.sendResponse(player.Zone, player.Name,
@@ -439,9 +455,7 @@ object SessionOutfitHandlers {
}
def HandleOutfitMotd(zones: Seq[Zone], message: String, player: Player): Unit = {
-
val outfit_id = player.outfit_id
-
val outfitDetails = for {
_ <- updateOutfitMotd(outfit_id, message)
outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption)
@@ -453,9 +467,8 @@ object SessionOutfitHandlers {
(outfitOpt, memberCount, totalPoints) <- outfitDetails
} yield {
outfitOpt.foreach { outfit =>
-
// send to all online players in outfit
- val outfit_event = OutfitEvent(
+ val outfit_event = SendResponse(OutfitEvent(
outfit_id,
Update(
OutfitInfo(
@@ -483,19 +496,15 @@ object SessionOutfitHandlers {
unk25 = 0
)
)
- )
+ ))
- zones.foreach(zone => {
- zone.AllPlayers
- .filter(_.outfit_id == outfit_id)
- .filter(_.outfit_window_open)
- .foreach(player => {
- PlayerControl.sendResponse(
- zone, player.Name,
- outfit_event
- )
- })
- })
+ zones.foreach { zone =>
+ zone.AvatarEvents ! BundledEnvelope(
+ zone.AllPlayers
+ .filter { p => p.outfit_id == outfit_id && p.outfit_window_open }
+ .map(p => MessageEnvelope(p.Name, outfit_event))
+ )
+ }
}
}
@@ -504,9 +513,7 @@ object SessionOutfitHandlers {
}
def HandleOutfitRank(zones: Seq[Zone], list: List[Option[String]], player: Player): Unit = {
-
val outfit_id = player.outfit_id
-
val outfitDetails = for {
_ <- updateOutfitRanks(outfit_id, list)
outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption)
@@ -518,9 +525,8 @@ object SessionOutfitHandlers {
(outfitOpt, memberCount, totalPoints) <- outfitDetails
} yield {
outfitOpt.foreach { outfit =>
-
// send to all online players in outfit with window open
- val outfit_event = OutfitEvent(
+ val outfit_event = SendResponse(OutfitEvent(
outfit_id,
Update(
OutfitInfo(
@@ -548,19 +554,15 @@ object SessionOutfitHandlers {
unk25 = 0
)
)
- )
+ ))
- zones.foreach(zone => {
- zone.AllPlayers
- .filter(_.outfit_id == outfit_id)
- .filter(_.outfit_window_open)
- .foreach(player => {
- PlayerControl.sendResponse(
- zone, player.Name,
- outfit_event
- )
- })
- })
+ zones.foreach { zone =>
+ zone.AvatarEvents ! BundledEnvelope(
+ zone.AllPlayers
+ .filter { p => p.outfit_id == outfit_id && p.outfit_window_open }
+ .map(p => MessageEnvelope(p.Name, outfit_event))
+ )
+ }
}
}
}
@@ -596,29 +598,34 @@ object SessionOutfitHandlers {
.map {
case (Some(outfit), memberCount, points) =>
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
-
- PlayerControl.sendResponse(player.Zone, player.Name,
- OutfitEvent(outfitId, Update(OutfitInfo(
- outfit.name, points, points, memberCount,
- OutfitRankNames(outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""),
- outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""),
- outfit.rank6.getOrElse(""), outfit.rank7.getOrElse("")),
- outfit.motd.getOrElse(""),
- 14, unk11 = true, 0, seconds, 0, 0, 0))))
-
- PlayerControl.sendResponse(player.Zone, player.Name,
- OutfitMemberUpdate(outfit.id, player.CharId, membership.rank, flag = true))
-
+ player.Zone.AvatarEvents ! BundledEnvelope(
+ MessageEnvelope(player.Name, SendResponse(
+ OutfitEvent(outfitId, Update(OutfitInfo(
+ outfit.name, points, points, memberCount,
+ OutfitRankNames(
+ outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""),
+ outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""),
+ outfit.rank6.getOrElse(""), outfit.rank7.getOrElse("")
+ ),
+ outfit.motd.getOrElse(""),
+ 14, unk11 = true, 0, seconds, 0, 0, 0
+ ))),
+ OutfitMemberUpdate(outfit.id, player.CharId, membership.rank, flag = true)
+ )),
+ MessageEnvelope(
+ player.Zone.id,
+ PlanetsideAttribute(player.GUID, 39, outfit.id)
+ ),
+ MessageEnvelope(
+ player.Zone.id,
+ player.GUID,
+ AvatarAction.PlanetsideStringAttribute(0, outfit.name)
+ )
+ )
session.chat.JoinChannel(OutfitChannel(outfit.id))
player.outfit_id = outfit.id
player.outfit_name = outfit.name
- player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(player.GUID, 39, outfit.id))
-
- player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.id,
- AvatarAction.PlanetsideStringAttribute(player.GUID, 0, outfit.name))
-
case (None, _, _) =>
PlayerControl.sendResponse(player.Zone, player.Name,
ChatMsg(ChatMessageType.UNK_227, "Failed to load outfit"))
@@ -849,7 +856,7 @@ object SessionOutfitHandlers {
query[Outfit]
.filter(_.id == lift(outfit_id))
.update(
- _.rank0 -> lift(colorized(0)),
+ _.rank0 -> lift(colorized.head),
_.rank1 -> lift(colorized(1)),
_.rank2 -> lift(colorized(2)),
_.rank3 -> lift(colorized(3)),
diff --git a/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala
index 8f5e0e5b2..fa9da51e7 100644
--- a/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala
+++ b/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala
@@ -2,6 +2,8 @@
package net.psforever.actors.session.support
import akka.actor.{ActorContext, ActorRef, typed}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.teamwork.SquadServiceResponse
import scala.collection.mutable
@@ -10,7 +12,6 @@ import net.psforever.actors.session.AvatarActor
import net.psforever.objects.teamwork.Squad
import net.psforever.objects.{Default, Player}
import net.psforever.packet.game._
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.teamwork.{SquadResponse, SquadServiceMessage, SquadAction => SquadServiceAction}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
@@ -105,9 +106,10 @@ class SessionSquadHandlers(
squadUI.get(player.CharId) match {
case Some(elem) =>
sendResponse(PlanetsideAttributeMessage(player.GUID, 31, squad_supplement_id))
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
s"${player.Faction}",
- AvatarAction.PlanetsideAttribute(player.GUID, 31, squad_supplement_id)
+ player.GUID,
+ PlanetsideAttribute(player.GUID, 31, squad_supplement_id)
)
sendResponse(PlanetsideAttributeMessage(player.GUID, 32, elem.index))
case _ =>
@@ -286,7 +288,7 @@ class SessionSquadHandlers(
* @param value value to associate the player
*/
def GiveSquadColorsForOthers(guid: PlanetSideGUID, factionChannel: String, value: Long): Unit = {
- continent.AvatarEvents ! AvatarServiceMessage(factionChannel, AvatarAction.PlanetsideAttribute(guid, 31, value))
+ continent.AvatarEvents ! MessageEnvelope(factionChannel, guid, PlanetsideAttribute(guid, 31, value))
}
/**
diff --git a/src/main/scala/net/psforever/actors/session/support/SessionVehicleHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionVehicleHandlers.scala
index b493b1ff2..3b46b874f 100644
--- a/src/main/scala/net/psforever/actors/session/support/SessionVehicleHandlers.scala
+++ b/src/main/scala/net/psforever/actors/session/support/SessionVehicleHandlers.scala
@@ -5,13 +5,10 @@ import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.AvatarActor
import net.psforever.objects.Vehicle
import net.psforever.packet.game.ChatMsg
-import net.psforever.services.vehicle.VehicleResponse
import net.psforever.types.{ChatMessageType, DriveState, PlanetSideGUID}
-trait VehicleHandlerFunctions extends CommonSessionInterfacingFunctionality {
+trait VehicleHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
def ops: SessionVehicleHandlers
-
- def handle(toChannel: String, guid: PlanetSideGUID, reply: VehicleResponse.Response): Unit
}
class SessionVehicleHandlers(
diff --git a/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala b/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala
index 790343fc8..93dc18e4d 100644
--- a/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala
+++ b/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala
@@ -27,7 +27,9 @@ import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.packet.game.UplinkRequest
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.CachedEnvelope
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, ReloadTool, SendResponse, WeaponDryFire}
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, ValidPlanetSideGUID, Vector3}
import net.psforever.util.Config
@@ -45,8 +47,8 @@ import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.turret.FacilityTurret
import net.psforever.objects._
import net.psforever.packet.game._
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{ExoSuitType, PlanetSideGUID}
trait WeaponAndProjectileFunctions extends CommonSessionInterfacingFunctionality {
@@ -281,14 +283,12 @@ class WeaponAndProjectileOperations(
.orElse { continent.GUID(weapon_guid) }
.collect {
case _: Equipment if containerOpt.exists(_.isInstanceOf[Player]) =>
- continent.AvatarEvents ! AvatarServiceMessage(
- continent.id,
- AvatarAction.WeaponDryFire(player.GUID, weapon_guid)
- )
+ continent.AvatarEvents ! MessageEnvelope(continent.id, player.GUID, WeaponDryFire(weapon_guid))
case _: Equipment =>
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.WeaponDryFire(player.GUID, weapon_guid)
+ player.GUID,
+ WeaponDryFire(weapon_guid)
)
}
.orElse {
@@ -348,14 +348,21 @@ class WeaponAndProjectileOperations(
sendResponse(UplinkResponse(code.value, 0))
sendResponse(PlanetsideAttributeMessage(player.GUID, 59, 1200000))
avatarActor ! AvatarActor.UpdateCUDTime("emp_blast")
- player.Zone.LocalEvents ! LocalServiceMessage(s"${player.Zone.id}",
- LocalAction.SendPacket(TriggerEffectMessage(ValidPlanetSideGUID(0), empColor, None, Some(TriggeredEffectLocation(player.Position, Vector3(0, 0, 90))))))
+ player.Zone.LocalEvents ! MessageEnvelope(
+ s"${player.Zone.id}",
+ PlanetSideGUID(-1),
+ SendResponse(TriggerEffectMessage(Default.GUID0, empColor, None, Some(TriggeredEffectLocation(player.Position, Vector3(0, 0, 90)))))
+ )
context.system.scheduler.scheduleOnce(delay = 1 seconds) {
Zone.serverSideDamage(player.Zone, player, empSize, SpecialEmp.createEmpInteraction(empSize, player.Position),
ExplosiveDeployableControl.detectionForExplosiveSource(player), Zone.findAllTargets)
}
case UplinkRequestType.OrbitalStrike =>
- player.Zone.LocalEvents ! LocalServiceMessage(s"$playerFaction", LocalAction.SendPacket(OrbitalStrikeWaypointMessage(player.GUID, pos.get.x, pos.get.y)))
+ player.Zone.LocalEvents ! MessageEnvelope(
+ s"$playerFaction",
+ PlanetSideGUID(-1),
+ SendResponse(OrbitalStrikeWaypointMessage(player.GUID, pos.get.x, pos.get.y))
+ )
sendResponse(UplinkResponse(code.value, 0))
orbitalStrikePos = pos
case UplinkRequestType.Unknown5 =>
@@ -380,9 +387,16 @@ class WeaponAndProjectileOperations(
sendResponse(PlanetsideAttributeMessage(player.GUID, 60, 10800000))
avatarActor ! AvatarActor.UpdateCUDTime("orbital_strike")
context.system.scheduler.scheduleOnce(delay = 5 seconds) {
- player.Zone.LocalEvents ! LocalServiceMessage(s"${player.Zone.id}",
- LocalAction.SendPacket(TriggerEffectMessage(ValidPlanetSideGUID(0), strikeType, None, Some(TriggeredEffectLocation(orbitalStrikePos.get, Vector3(0, 0, 90))))))
- player.Zone.LocalEvents ! LocalServiceMessage(s"$playerFaction", LocalAction.SendPacket(OrbitalStrikeWaypointMessage(player.GUID, None)))
+ player.Zone.LocalEvents ! MessageEnvelope(
+ s"${player.Zone.id}",
+ PlanetSideGUID(-1),
+ SendResponse(TriggerEffectMessage(ValidPlanetSideGUID(0), strikeType, None, Some(TriggeredEffectLocation(orbitalStrikePos.get, Vector3(0, 0, 90)))))
+ )
+ player.Zone.LocalEvents ! MessageEnvelope(
+ s"$playerFaction",
+ PlanetSideGUID(-1),
+ SendResponse(OrbitalStrikeWaypointMessage(player.GUID, None))
+ )
context.system.scheduler.scheduleOnce(delay = 5 seconds) {
val sectorTargets = Zone.findOrbitalStrikeTargets(player.Zone, orbitalStrikePos.get, osSize.DamageRadius, Zone.getOrbitbalStrikeTargets)
val withinRange = sectorTargets.filter { target => Zone.orbitalStrikeDistanceCheck(orbitalStrikePos.get, target.Position, osSize.DamageRadius) }
@@ -457,9 +471,10 @@ class WeaponAndProjectileOperations(
log.info(s"${player.Name} changed ${player.Sex.possessive} ${obj.Definition.Name}'s fire mode to #$modeIndex")
}
sendResponse(ChangeFireModeMessage(item_guid, modeIndex))
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
sessionLogic.zoning.zoneChannel,
- AvatarAction.ChangeFireMode(player.GUID, item_guid, modeIndex)
+ player.GUID,
+ AvatarAction.ChangeFireMode(item_guid, modeIndex)
)
}
case Some(_) =>
@@ -478,10 +493,10 @@ class WeaponAndProjectileOperations(
projectile.Position = shot_pos
projectile.Orientation = shot_orient
projectile.Velocity = shot_vel
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! CachedEnvelope(
continent.id,
+ player.GUID,
AvatarAction.ProjectileState(
- player.GUID,
projectileGlobalUID,
shot_pos,
shot_vel,
@@ -742,12 +757,9 @@ class WeaponAndProjectileOperations(
(target.GUID, (target, proxyCopy, proxyCopy.shot_origin, target.Position))
}.unzip
//chain lash effect
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.SendResponse(
- PlanetSideGUID(0),
- ChainLashMessage(hitPos, projectile.profile.ObjectId, guidRefs.toList)
- )
+ SendResponse(ChainLashMessage(hitPos, projectile.profile.ObjectId, guidRefs.toList))
)
//chain lash target output
outputRefs.toList
@@ -931,12 +943,9 @@ class WeaponAndProjectileOperations(
tool.Magazine = 0
sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, weapon_guid, 0))
sendResponse(ChangeFireStateMessage_Stop(weapon_guid))
- continent.AvatarEvents ! AvatarServiceMessage(
- continent.id,
- AvatarAction.ChangeFireState_Stop(player.GUID, weapon_guid)
- )
+ continent.AvatarEvents ! MessageEnvelope(continent.id, player.GUID, ChangeFireState_Stop(weapon_guid))
sendResponse(WeaponDryFireMessage(weapon_guid))
- continent.AvatarEvents ! AvatarServiceMessage(continent.id, AvatarAction.WeaponDryFire(player.GUID, weapon_guid))
+ continent.AvatarEvents ! MessageEnvelope(continent.id, player.GUID, WeaponDryFire(weapon_guid))
}
/**
@@ -952,7 +961,7 @@ class WeaponAndProjectileOperations(
.map { sessionLogic.validObject(_, decorator="FindDetectedProjectileTargets") }
.flatMap {
case Some(obj: Vehicle) if !obj.Cloaked =>
- //TODO hint: vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.ProjectileAutoLockAwareness(mode))
+ //TODO hint: vehicleService ! MessageEnvelope(s"${obj.Actor}", VehicleAction.ProjectileAutoLockAwareness(mode))
obj.Seats.values.flatMap { seat => seat.occupants.map(_.Name) }
case Some(obj: Mountable) =>
obj.Seats.values.flatMap { seat => seat.occupants.map(_.Name) }
@@ -1077,9 +1086,10 @@ class WeaponAndProjectileOperations(
}
def fireStateStartPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
sessionLogic.zoning.zoneChannel,
- AvatarAction.ChangeFireState_Start(player.GUID, itemGuid)
+ player.GUID,
+ ChangeFireState_Start(itemGuid)
)
}
@@ -1088,9 +1098,10 @@ class WeaponAndProjectileOperations(
case turret: FacilityTurret if continent.map.cavern =>
turret.Actor ! VanuSentry.ChangeFireStart
}
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.ChangeFireState_Start(player.GUID, itemGuid)
+ player.GUID,
+ ChangeFireState_Start(itemGuid)
)
}
@@ -1116,9 +1127,10 @@ class WeaponAndProjectileOperations(
}
def fireStateStopPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
sessionLogic.zoning.zoneChannel,
- AvatarAction.ChangeFireState_Stop(player.GUID, itemGuid)
+ player.GUID,
+ ChangeFireState_Stop(itemGuid)
)
}
@@ -1127,9 +1139,10 @@ class WeaponAndProjectileOperations(
case turret: FacilityTurret if continent.map.cavern =>
turret.Actor ! VanuSentry.ChangeFireStop
}
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.ChangeFireState_Stop(player.GUID, itemGuid)
+ player.GUID,
+ ChangeFireState_Stop(itemGuid)
)
}
@@ -1186,16 +1199,14 @@ class WeaponAndProjectileOperations(
used by ReloadMessage handling
*/
def reloadPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
- continent.AvatarEvents ! AvatarServiceMessage(
- sessionLogic.zoning.zoneChannel,
- AvatarAction.Reload(player.GUID, itemGuid)
- )
+ continent.AvatarEvents ! MessageEnvelope(sessionLogic.zoning.zoneChannel, player.GUID, ReloadTool(itemGuid))
}
def reloadVehicleMessages(itemGuid: PlanetSideGUID): Unit = {
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.Reload(player.GUID, itemGuid)
+ player.GUID,
+ ReloadTool(itemGuid)
)
}
@@ -1369,10 +1380,10 @@ class WeaponAndProjectileOperations(
val previous_box_guid = previousBox.GUID
val boxDef = box.Definition
sendResponse(ChangeAmmoMessage(tool_guid, box.Capacity))
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
sessionLogic.zoning.zoneChannel,
- AvatarAction.ChangeAmmo(
- player.GUID,
+ player.GUID,
+ ChangeAmmo(
tool_guid,
ammoSlotIndex,
previous_box_guid,
@@ -1470,15 +1481,10 @@ class WeaponAndProjectileOperations(
def modifyAmmunitionInMountable(obj: PlanetSideServerObject with Container)(box: AmmoBox, reloadValue: Int): Unit = {
modifyAmmunition(obj)(box, reloadValue)
obj.Find(box).collect { index =>
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
s"${obj.Actor}",
- VehicleAction.InventoryState(
- player.GUID,
- box,
- obj.GUID,
- index,
- box.Definition.Packet.DetailedConstructorData(box).get
- )
+ player.GUID,
+ VehicleAction.InventoryState(box, obj.GUID, index, box.Definition.Packet.DetailedConstructorData(box).get)
)
}
}
@@ -1582,10 +1588,7 @@ class WeaponAndProjectileOperations(
shootingStop.clear()
(prefire ++ shooting).foreach { guid =>
sendResponse(ChangeFireStateMessage_Stop(guid))
- continent.AvatarEvents ! AvatarServiceMessage(
- continent.id,
- AvatarAction.ChangeFireState_Stop(player.GUID, guid)
- )
+ continent.AvatarEvents ! MessageEnvelope(continent.id, player.GUID, ChangeFireState_Stop(guid))
}
prefire.clear()
shooting.clear()
diff --git a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala
index a69a4a724..6ffe99ebb 100644
--- a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala
+++ b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala
@@ -18,10 +18,14 @@ import net.psforever.objects.serverobject.mount.Seat
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource}
+import net.psforever.objects.vehicles.control.{CargoBehavior, CarrierBehavior}
import net.psforever.objects.vital.{InGameHistory, IncarnationActivity, ReconstructionActivity, SpawningActivity}
import net.psforever.objects.zones.blockmap.BlockMapEntity
import net.psforever.packet.game.GenericAction.FirstPersonViewWithEffect
-import net.psforever.packet.game.{CampaignStatistic, ChangeFireStateMessage_Start, CloudInfo, GenericActionMessage, GenericObjectActionEnum, HackState7, MailMessage, ObjectDetectedMessage, SessionStatistic, StormInfo, TriggeredSound, TrainingZoneMessage, WeatherMessage}
+import net.psforever.packet.game.{CampaignStatistic, ChangeFireStateMessage_Start, CloudInfo, GenericActionMessage, GenericObjectActionEnum, HackState7, MailMessage, ObjectDetectedMessage, SessionStatistic, StormInfo, TrainingZoneMessage, TriggeredSound, WeatherMessage}
+import net.psforever.services.avatar.support.{CorpseEnvelope, ReleaseEnvelope}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{GenericObjectAction, ObjectDelete, PlanetsideAttribute, SendResponse}
import net.psforever.services.chat.DefaultChannel
import scala.concurrent.duration._
@@ -62,16 +66,16 @@ import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectCreateMess
import net.psforever.packet.game.objectcreate.ObjectClass
import net.psforever.packet.{PlanetSideGamePacket, game}
import net.psforever.persistence.Savedplayer
-import net.psforever.services.RemoverActor
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
import net.psforever.services.account.{AccountPersistenceService, PlayerToken}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.support.RemoverActor
+import net.psforever.services.galaxy.GalaxyAction
import net.psforever.services.hart.HartTimer
import net.psforever.services.local.support.HackCaptureActor
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.local.LocalAction
import net.psforever.services.properties.PropertyOverrideManager
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.services.{CavernRotationService, Service, ServiceManager, InterstellarClusterService => ICS}
import net.psforever.types._
import net.psforever.util.{Config, DefinitionUtil}
@@ -118,7 +122,7 @@ object ZoningOperations {
additionalChannels: List[String]
): Unit = {
val events = zone.LocalEvents
- val effectMessage = LocalAction.TriggerEffectLocation(Service.defaultPlayerGUID, s"respawn_$faction", position, orientation)
+ val effectMessage = LocalAction.TriggerEffectLocation(s"respawn_$faction", position, orientation)
(zone
.blockMap
.sector(position, range = 100f)
@@ -126,7 +130,7 @@ object ZoningOperations {
.filter(p => Sidedness.equals(side, p.WhichSide))
.map(_.Name) ++ additionalChannels)
.foreach { target =>
- events ! LocalServiceMessage(target, effectMessage)
+ events ! MessageEnvelope(target, effectMessage)
}
}
@@ -152,13 +156,13 @@ object ZoningOperations {
Vector3.DistanceSquared(t.Position.xy, posxy) < 2500f && /* literal 50m */
heightDiff < 5f && heightDiff > -1f
}
- val effectMessage = LocalAction.TriggerEffectLocation(Service.defaultPlayerGUID, s"respawn_$faction", position, orientation)
+ val effectMessage = LocalAction.TriggerEffectLocation(s"respawn_$faction", position, orientation)
(effectTargets.map(_.Name) ++ additionalChannels).foreach { target =>
- events ! LocalServiceMessage(target, effectMessage)
+ events ! MessageEnvelope(target, effectMessage)
}
- val soundMessage = LocalAction.TriggerSound(Service.defaultPlayerGUID, TriggeredSound.SpawnInTube, position, 50, 0.69803923f)
+ val soundMessage = LocalAction.TriggerSound(TriggeredSound.SpawnInTube, position, 50, 0.69803923f)
(soundTargets.map(_.Name) ++ additionalChannels).foreach { target =>
- events ! LocalServiceMessage(target, soundMessage)
+ events ! MessageEnvelope(target, soundMessage)
}
}
@@ -547,8 +551,8 @@ class ZoningOperations(
sendResponse(OCM.apply(projectile))
}
//spawn point update request
- continent.VehicleEvents ! VehicleServiceMessage(
- continent.id,
+ continent.VehicleEvents ! MessageEnvelope(
+ player.Name,
VehicleAction.UpdateAmsSpawnPoint(continent)
)
spawn.upstreamMessageCount = 0
@@ -595,14 +599,14 @@ class ZoningOperations(
context.self
)
LivePlayerList.Add(avatar.id, avatar)
- galaxyService.tell(GalaxyServiceMessage(GalaxyAction.LogStatusChange(avatar.name)), context.parent)
+ galaxyService.tell(MessageEnvelope("", GalaxyAction.LogStatusChange(avatar.name)), context.parent)
//PropertyOverrideMessage
ServiceManager.serviceManager ! Lookup("propertyOverrideManager")
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
spawn.initializeFriendsAndIgnoredLists()
//the following subscriptions last until character switch/logout
- galaxyService ! Service.Join("galaxy") //for galaxy-wide messages
+ galaxyService ! Service.Join("") //for galaxy-wide messages
galaxyService ! Service.Join(s"${avatar.faction}") //for hotspots, etc.
sessionLogic.squadService ! Service.Join(s"${avatar.faction}") //channel will be player.Faction
sessionLogic.squadService ! Service.Join(s"${avatar.id}") //channel will be player.CharId (in order to work with packets)
@@ -618,9 +622,9 @@ class ZoningOperations(
//the only zone-level event system subscription necessary before BeginZoningMessage (for persistence purposes)
zone.AvatarEvents ! Service.Join(player.Name)
sessionLogic.persist()
- oldZone.AvatarEvents ! Service.Leave()
- oldZone.LocalEvents ! Service.Leave()
- oldZone.VehicleEvents ! Service.Leave()
+ oldZone.AvatarEvents ! Service.LeaveAll
+ oldZone.LocalEvents ! Service.LeaveAll
+ oldZone.VehicleEvents ! Service.LeaveAll
if (player.isAlive && zoningType != Zoning.Method.Reset) {
if (player.HasGUID) {
@@ -649,9 +653,9 @@ class ZoningOperations(
val oldZone = session.zone
session = session.copy(zone = foundZone)
sessionLogic.persist()
- oldZone.AvatarEvents ! Service.Leave()
- oldZone.LocalEvents ! Service.Leave()
- oldZone.VehicleEvents ! Service.Leave()
+ oldZone.AvatarEvents ! Service.LeaveAll
+ oldZone.LocalEvents ! Service.LeaveAll
+ oldZone.VehicleEvents ! Service.LeaveAll
//the only zone-level event system subscription necessary before BeginZoningMessage (for persistence purposes)
foundZone.AvatarEvents ! Service.Join(player.Name)
foundZone.Population ! Zone.Population.Join(avatar)
@@ -760,7 +764,7 @@ class ZoningOperations(
case _ =>
interstellarFerry match {
case None =>
- galaxyService ! Service.Leave(Some(temp_channel)) //no longer being transferred between zones
+ galaxyService ! Service.Leave(temp_channel) //no longer being transferred between zones
interstellarFerryTopLevelGUID = None
case Some(_) => () //wait patiently
}
@@ -768,7 +772,7 @@ class ZoningOperations(
}
private def handleTransferPassengerVehicle(vehicle: Vehicle, temporaryChannel: String): Unit = {
- galaxyService ! Service.Leave(Some(temporaryChannel)) //temporary vehicle-specific channel (see above)
+ galaxyService ! Service.Leave(temporaryChannel) //temporary vehicle-specific channel (see above)
spawn.deadState = DeadState.Release
sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, player.Faction, unk5=true))
interstellarFerry = Some(vehicle) //on the other continent and registered to that continent's GUID system
@@ -851,7 +855,7 @@ class ZoningOperations(
case None =>
spawn.deadState = DeadState.Release // cancel movement updates
player.Position = position
- // continent.AvatarEvents ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID))
+ // continent.AvatarEvents ! MessageEnvelope(continent.Id, ObjectDelete(player.GUID, player.GUID))
spawn.LoadZonePhysicalSpawnPoint(zoneId, position, Vector3.Zero, 0 seconds, None)
case _ => // seated in something that is not a vehicle or the vehicle is cargo, in which case we can't move
}
@@ -1121,7 +1125,7 @@ class ZoningOperations(
case obj if obj.Destroyed => configAmenityAsDestroyed(obj)
case obj => configAmenityAsWorking(obj)
}
- //sendResponse(HackMessage(HackState1.Unk3, guid, Service.defaultPlayerGUID, progress=0, -1f, HackState.HackCleared, HackState7.Unk8))
+ //sendResponse(HackMessage(HackState1.Unk3, guid, Default.GUID0, progress=0, -1f, HackState.HackCleared, HackState7.Unk8))
}
}
@@ -1205,9 +1209,10 @@ class ZoningOperations(
sendResponse(OCM.apply(llu))
// Attach it to a player if it has a carrier
if (llu.Carrier.nonEmpty) {
- continent.LocalEvents ! LocalServiceMessage(
+ continent.LocalEvents ! MessageEnvelope(
continent.id,
- LocalAction.SendPacket(ObjectAttachMessage(llu.Carrier.get.GUID, llu.GUID, 252))
+ PlanetSideGUID(-1),
+ SendResponse(ObjectAttachMessage(llu.Carrier.get.GUID, llu.GUID, 252))
)
}
case _ => ()
@@ -1349,9 +1354,10 @@ class ZoningOperations(
val pguid = player.GUID
val toChannel = manifest.file
val topLevel = interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID)
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
s"${vehicle.Actor}",
- VehicleAction.TransferPassengerChannel(pguid, s"${vehicle.Actor}", toChannel, vehicle, topLevel)
+ pguid,
+ VehicleAction.TransferPassengerChannel(s"${vehicle.Actor}", toChannel, vehicle, topLevel)
)
manifest.cargo.foreach {
case ManifestPassengerEntry("MISSING_DRIVER", index) =>
@@ -1362,9 +1368,10 @@ class ZoningOperations(
cargo.Actor ! CargoBehavior.StartCargoDismounting(bailed = false)
case entry =>
val cargo = vehicle.CargoHolds(entry.mount).occupant.get
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
entry.name,
- VehicleAction.TransferPassengerChannel(pguid, s"${cargo.Actor}", toChannel, cargo, topLevel)
+ pguid,
+ VehicleAction.TransferPassengerChannel(s"${cargo.Actor}", toChannel, cargo, topLevel)
)
}
//
@@ -1393,9 +1400,10 @@ class ZoningOperations(
interstellarFerryTopLevelGUID =
if (manifest.passengers.isEmpty && manifest.cargo.count { !_.name.equals("MISSING_DRIVER") } == 0) {
//do not delete if vehicle has passengers or cargo
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
continent.id,
- VehicleAction.UnloadVehicle(pguid, vehicle, topLevel)
+ pguid,
+ VehicleAction.UnloadVehicle(vehicle, topLevel)
)
None
} else {
@@ -1470,17 +1478,14 @@ class ZoningOperations(
case Some(manifest) =>
val toChannel = manifest.file
val topLevel = interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID)
- galaxyService ! GalaxyServiceMessage(
- toChannel,
- GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest)
- )
+ galaxyService ! MessageEnvelope(toChannel, GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest))
vehicle.CargoHolds.values
.collect {
case hold if hold.isOccupied =>
val cargo = hold.occupant.get
cargo.Continent = toZoneId
//point to the cargo vehicle to instigate cargo vehicle driver transportation
- // galaxyService ! GalaxyServiceMessage(
+ // galaxyService ! MesdsageEnvelope(
// toChannel,
// GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest)
// )
@@ -1972,7 +1977,7 @@ class ZoningOperations(
guid,
Deployable.Icon(obj.Definition.Item),
obj.Position,
- obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID)
+ obj.OwnerGuid.getOrElse(Default.GUID0)
)))
}
}
@@ -2191,7 +2196,7 @@ class ZoningOperations(
log.info(s"RestoreInfo: player $name is already logged in zone ${inZone.id}; rejoining that character")
sessionLogic.persistFunc = UpdatePersistence(from)
//tell the old WorldSessionActor to kill itself by using its own subscriptions against itself
- inZone.AvatarEvents ! AvatarServiceMessage(name, AvatarAction.TeardownConnection())
+ inZone.AvatarEvents ! MessageEnvelope(name, AvatarAction.TeardownConnection)
spawn.switchAvatarStatisticsFieldToRefreshAfterRespawn()
//find and reload previous player
(
@@ -2594,9 +2599,10 @@ class ZoningOperations(
vehicle.CargoHolds.values
.collect { case hold if hold.isOccupied => hold.occupant.get }
.foreach { _.MountedIn = vguid }
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
zoneid,
- VehicleAction.LoadVehicle(player.GUID, vehicle, vObjectId, vguid, data)
+ player.GUID,
+ VehicleAction.LoadVehicle(vehicle, vObjectId, vguid, data)
)
carrierInfo match {
case (Some(carrier), Some((index, _))) =>
@@ -2621,9 +2627,10 @@ class ZoningOperations(
//do not dispatch delete action if any hierarchical occupant has not gotten this far through the summoning process
val vehicleToDelete = interstellarFerryTopLevelGUID.orElse(originalSeated).getOrElse(PlanetSideGUID(0))
val zone = vehicle.PreviousGatingManifest().get.origin
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.UnloadVehicle(player.GUID, vehicle, vehicleToDelete)
+ player.GUID,
+ VehicleAction.UnloadVehicle(vehicle, vehicleToDelete)
)
log.debug(
s"AvatarCreate: cleaning up ghost of transitioning vehicle ${vehicle.Definition.Name}@${vehicleToDelete.guid} in zone ${zone.id}"
@@ -2638,9 +2645,10 @@ class ZoningOperations(
val definition = player.avatar.definition
val guid = player.GUID
sendResponse(OCM.detailed(player))
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
s"spectator",
- AvatarAction.LoadPlayer(guid, definition.ObjectId, guid, definition.Packet.ConstructorData(player).get, None)
+ guid,
+ AvatarAction.LoadPlayer(definition.ObjectId, guid, definition.Packet.ConstructorData(player).get, None)
)
case _ =>
@@ -2649,9 +2657,10 @@ class ZoningOperations(
val guid = player.GUID
usingSpawnTubeAnimation()
sendResponse(OCM.detailed(player))
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
zoneid,
- AvatarAction.LoadPlayer(guid, definition.ObjectId, guid, definition.Packet.ConstructorData(player).get, None)
+ guid,
+ AvatarAction.LoadPlayer(definition.ObjectId, guid, definition.Packet.ConstructorData(player).get, None)
)
}
continent.Population ! Zone.Population.Spawn(avatar, player, avatarActor)
@@ -2721,10 +2730,10 @@ class ZoningOperations(
interimUngunnedVehicle = Some(vguid)
interimUngunnedVehicleSeat = Some(seat)
}
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
+ pguid,
AvatarAction.LoadPlayer(
- pguid,
pdef.ObjectId,
pguid,
pdef.Packet.ConstructorData(tplayer).get,
@@ -2880,9 +2889,9 @@ class ZoningOperations(
case _ => ()
}
if (player.VisibleSlots.contains(index)) {
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
zoneId,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, obj.GUID)
+ ObjectDelete(obj.GUID)
)
} else {
sendResponse(ObjectDeleteMessage(obj.GUID, 0))
@@ -2898,7 +2907,6 @@ class ZoningOperations(
* To the game, that is a backpack (or some pastry, festive graphical modification allowing).
* @see `AvatarAction.ObjectDelete`
* @see `AvatarAction.Release`
- * @see `AvatarServiceMessage`
* @see `FriskDeadBody`
* @see `GUIDTask.unregisterPlayer`
* @see `ObjectDeleteMessage`
@@ -2916,7 +2924,7 @@ class ZoningOperations(
val pguid = tplayer.GUID
zone.Population ! Zone.Population.Release(avatar)
sendResponse(ObjectDeleteMessage(pguid, 0))
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.ObjectDelete(pguid, pguid))
+ zone.AvatarEvents ! MessageEnvelope(zone.id, pguid, ObjectDelete(pguid))
TaskWorkflow.execute(GUIDTask.unregisterPlayer(zone.GUID, tplayer))
}
}
@@ -2926,7 +2934,6 @@ class ZoningOperations(
* To the game, that is a backpack (or some pastry, festive graphical modification allowing).
* A player who has been kicked may not turn into a corpse.
* @see `AvatarAction.Release`
- * @see `AvatarServiceMessage`
* @see `CorpseConverter.converter`
* @see `DepictPlayerAsCorpse`
* @see `Player.Release`
@@ -2939,7 +2946,7 @@ class ZoningOperations(
tplayer.Release
DepictPlayerAsCorpse(tplayer)
zone.Population ! Zone.Corpse.Add(tplayer)
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.Release(tplayer, zone))
+ zone.AvatarEvents ! ReleaseEnvelope(zone.id, AvatarAction.Release(tplayer, zone))
}
/**
@@ -2978,7 +2985,7 @@ class ZoningOperations(
*/
def TryDisposeOfLootedCorpse(obj: Player): Boolean = {
if (obj.isBackpack && WellLootedDeadBody(obj)) {
- obj.Zone.AvatarEvents ! AvatarServiceMessage.Corpse(RemoverActor.HurrySpecific(List(obj), obj.Zone))
+ obj.Zone.AvatarEvents ! CorpseEnvelope(RemoverActor.HurrySpecific(List(obj), obj.Zone))
true
} else {
false
@@ -3172,9 +3179,10 @@ class ZoningOperations(
// entering or exiting VR zones uses a fade-out effect for the player instead of the usual green cloud deconstruction effect
val effect = if (player.IsInVRZone || zoneId.startsWith("tz")) 2 else 1
sendResponse(ObjectDeleteMessage(player_guid, unk1=effect))
- continent.AvatarEvents ! AvatarServiceMessage(
+ continent.AvatarEvents ! MessageEnvelope(
continent.id,
- AvatarAction.ObjectDelete(player_guid, player_guid, unk=effect)
+ player_guid,
+ ObjectDelete(player_guid, unk=effect)
)
InGameHistory.SpawnReconstructionActivity(player, toZoneNumber, betterSpawnPoint)
LoadZoneAsPlayerUsing(player, pos, ori, toSide, zoneId)
@@ -3338,7 +3346,7 @@ class ZoningOperations(
//looking for squad (members)
if (tplayer.avatar.lookingForSquad) {
sendResponse(PlanetsideAttributeMessage(guid, 53, 1))
- continent.AvatarEvents ! AvatarServiceMessage(continent.id, AvatarAction.PlanetsideAttribute(guid, 53, 1))
+ continent.AvatarEvents ! MessageEnvelope(continent.id, guid, PlanetsideAttribute(guid, 53, 1))
}
sendResponse(AvatarSearchCriteriaMessage(guid, List(0, 0, 0, 0, 0, 0)))
//these are facilities and towers and bunkers in the zone, but not necessarily all of them for some reason
@@ -3364,7 +3372,7 @@ class ZoningOperations(
if (tplayer.ExoSuit == ExoSuitType.MAX) {
sendResponse(PlanetsideAttributeMessage(guid, 7, tplayer.Capacitor.toLong))
sendResponse(PlanetsideAttributeMessage(guid, 4, tplayer.Armor))
- continent.AvatarEvents ! AvatarServiceMessage(continent.id, AvatarAction.PlanetsideAttributeToAll(guid, 4, tplayer.Armor))
+ continent.AvatarEvents ! MessageEnvelope(continent.id, PlanetsideAttribute(guid, 4, tplayer.Armor))
}
// for issue #1269
continent.AllPlayers.filter(_.ExoSuit == ExoSuitType.MAX).foreach(max => sendResponse(PlanetsideAttributeMessage(max.GUID, 4, max.Armor)))
@@ -3388,9 +3396,10 @@ class ZoningOperations(
continent.GUID(tplayer.avatar.vehicle) match {
case Some(vehicle: Vehicle) if vehicle.OwnerName.contains(tplayer.Name) =>
vehicle.OwnerGuid = guid
- continent.VehicleEvents ! VehicleServiceMessage(
+ continent.VehicleEvents ! MessageEnvelope(
s"${tplayer.Faction}",
- VehicleAction.Ownership(guid, vehicle.GUID)
+ guid,
+ VehicleAction.Ownership(vehicle.GUID)
)
case _ =>
avatarActor ! AvatarActor.SetVehicle(None)
@@ -3487,13 +3496,13 @@ class ZoningOperations(
case Some(b: Building) if b.hasCavernLockBenefit =>
tplayer.MaxHealth = 120
tplayer.Health = 120
- tplayer.Zone.AvatarEvents ! AvatarServiceMessage(
- tplayer.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 0, 120)
- )
- tplayer.Zone.AvatarEvents ! AvatarServiceMessage(
- tplayer.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 1, 120)
+ val guid = tplayer.GUID
+ val zone = tplayer.Zone
+ val channel = zone.id
+ val events = zone.AvatarEvents
+ events ! MessageEnvelope(
+ channel,
+ SendResponse(PlanetsideAttributeMessage(guid, 0, 120), PlanetsideAttributeMessage(guid, 1, 120))
)
case _ => ()
}
@@ -3996,13 +4005,20 @@ class ZoningOperations(
}
GoToDeploymentMap()
val pZone = player.Zone
+ val msg = GenericObjectAction(player.GUID, GenericObjectActionEnum.PlayerDeconstructs.id)
sendResponse(GenericActionMessage(FirstPersonViewWithEffect))
- pZone.blockMap.sector(player).livePlayerList.collect { case t if t.GUID != player.GUID =>
- pZone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendGenericObjectActionMessage(t.GUID, player.GUID, GenericObjectActionEnum.PlayerDeconstructs))
- }
- pZone.AllPlayers.collect { case t if t.GUID != player.GUID && !t.allowInteraction =>
- pZone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendGenericObjectActionMessage(t.GUID, player.GUID, GenericObjectActionEnum.PlayerDeconstructs))
- }
+ val (localMessageRecipients, localMesages) = pZone.blockMap.sector(player).livePlayerList
+ .collect {
+ case t if t.GUID != player.GUID =>
+ (t.Name, MessageEnvelope(t.Name, msg))
+ }
+ .unzip
+ val otherMessages: Seq[MessageEnvelope] = pZone.AllPlayers
+ .collect {
+ case t if t.GUID != player.GUID && !t.allowInteraction && !localMessageRecipients.contains(t.Name) =>
+ MessageEnvelope(t.Name, msg)
+ }
+ pZone.LocalEvents ! BundledEnvelope(localMesages ++ otherMessages)
}
def stopDeconstructing(): Unit = {
diff --git a/src/main/scala/net/psforever/actors/zone/BuildingActor.scala b/src/main/scala/net/psforever/actors/zone/BuildingActor.scala
index 0f385dae4..3aabbf12e 100644
--- a/src/main/scala/net/psforever/actors/zone/BuildingActor.scala
+++ b/src/main/scala/net/psforever/actors/zone/BuildingActor.scala
@@ -11,8 +11,9 @@ import net.psforever.objects.zones.Zone
import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.ContinentalLockUpdateMessage
import net.psforever.persistence
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{SendResponse, SetEmpire}
+import net.psforever.services.galaxy.GalaxyAction
import net.psforever.services.{InterstellarClusterService, ServiceManager}
import net.psforever.types.PlanetSideEmpire
import net.psforever.util.Database.ctx
@@ -167,7 +168,7 @@ object BuildingActor {
val building = details.building
val zone = building.Zone
building.Faction = faction
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SetEmpire(building.GUID, faction))
+ zone.LocalEvents ! MessageEnvelope(zone.id, SetEmpire(building.GUID, faction))
}
}
@@ -231,8 +232,10 @@ class BuildingActor(
Behaviors.same
case MapUpdate() =>
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(details.building.densityLevelUpdateMessage(building)))
+ details.galaxyService ! BundledEnvelope(
+ MessageEnvelope("", GalaxyAction.MapUpdate(details.building.infoUpdateMessage())),
+ MessageEnvelope("", SendResponse(details.building.densityLevelUpdateMessage(building)))
+ )
Behaviors.same
case AmenityStateChange(amenity, data) =>
@@ -254,15 +257,15 @@ class BuildingActor(
logic.ntu(details, msg)
case DensityLevelUpdate(building) =>
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(details.building.densityLevelUpdateMessage(building)))
+ details.galaxyService ! MessageEnvelope("", SendResponse(details.building.densityLevelUpdateMessage(building)))
Behaviors.same
case ContinentalLock(zone) =>
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(ContinentalLockUpdateMessage(zone.Number, zone.lockedBy)))
+ details.galaxyService ! MessageEnvelope("", SendResponse(ContinentalLockUpdateMessage(zone.Number, zone.lockedBy)))
Behaviors.same
case HomeLockBenefits(msg) =>
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(msg))
+ details.galaxyService ! MessageEnvelope("", SendResponse(msg))
Behaviors.same
}
}
diff --git a/src/main/scala/net/psforever/actors/zone/ShootingRangeTargetSpawnerActor.scala b/src/main/scala/net/psforever/actors/zone/ShootingRangeTargetSpawnerActor.scala
index 1325caf09..214d7b5be 100644
--- a/src/main/scala/net/psforever/actors/zone/ShootingRangeTargetSpawnerActor.scala
+++ b/src/main/scala/net/psforever/actors/zone/ShootingRangeTargetSpawnerActor.scala
@@ -6,9 +6,10 @@ import net.psforever.objects.{Default, GlobalDefinitions, Tool, Vehicle}
import net.psforever.objects.avatar.{AvatarBot, AvatarBotActor}
import net.psforever.objects.guid.{GUIDTask, StraightforwardTask, TaskBundle, TaskWorkflow}
import net.psforever.objects.zones.Zone
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
-import net.psforever.types.{CharacterSex, CharacterVoice, ExoSuitType, PlanetSideEmpire, PlanetSideGUID, Vector3}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.local.LocalAction
+import net.psforever.services.vehicle.VehicleAction
+import net.psforever.types.{CharacterSex, CharacterVoice, ExoSuitType, PlanetSideEmpire, Vector3}
import net.psforever.util.Config
import scala.collection.mutable.ListBuffer
@@ -282,7 +283,6 @@ class ShootingRangeTargetSpawnerActor(zone: Zone) extends Actor {
* @param bot the bot to remove
*/
private def RemoveBot(bot: AvatarBot): Boolean = {
- import net.psforever.services.Service
activeInfantryTargets.indexOf(bot) match {
case -1 =>
log.warn(s"Failed to remove bot with GUID ${bot.GUID} from ${zone.id}'s active targets list! This shouldn't happen... and probably just caused a leak.")
@@ -290,9 +290,9 @@ class ShootingRangeTargetSpawnerActor(zone: Zone) extends Actor {
case index =>
activeInfantryTargets.remove(index)
}
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerEffectLocation(Service.defaultPlayerGUID, "bot_destroyed_effect", bot.Position, bot.Orientation)
+ LocalAction.TriggerEffectLocation("bot_destroyed_effect", bot.Position, bot.Orientation)
)
//spawn a replacement bot
context.system.scheduler.scheduleOnce(
@@ -356,10 +356,9 @@ class ShootingRangeTargetSpawnerActor(zone: Zone) extends Actor {
def action(): Future[Any] = {
zone.Transport ! Zone.Vehicle.Spawn(localVehicle)
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
VehicleAction.LoadVehicle(
- PlanetSideGUID(0),
localVehicle,
localVehicle.Definition.ObjectId,
localVehicle.GUID,
diff --git a/src/main/scala/net/psforever/actors/zone/ZoneActor.scala b/src/main/scala/net/psforever/actors/zone/ZoneActor.scala
index 391b0a7c8..f781db5c5 100644
--- a/src/main/scala/net/psforever/actors/zone/ZoneActor.scala
+++ b/src/main/scala/net/psforever/actors/zone/ZoneActor.scala
@@ -20,7 +20,8 @@ import net.psforever.objects.zones.exp.{ExperienceCalculator, SupportExperienceC
import net.psforever.packet.game.{BuildingInfoUpdateMessage, PlanetsideAttributeMessage}
import net.psforever.util.Database._
import net.psforever.persistence
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import scala.collection.mutable
import scala.util.{Failure, Success}
@@ -234,26 +235,26 @@ class ZoneActor(
}
buildingOpt.foreach { building =>
if (msg.generator_state == PlanetSideGeneratorState.Normal && building.hasCavernLockBenefit) {
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 1))
+ SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 1))
)
}
msg.is_hacked match {
case true if building.BuildingType == StructureType.Facility && !zone.map.cavern =>
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
+ SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
)
case false if building.hasCavernLockBenefit =>
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 1))
+ SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 1))
)
case false if building.BuildingType == StructureType.Facility && !zone.map.cavern && !building.hasCavernLockBenefit =>
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
+ SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
)
case _ =>
}
diff --git a/src/main/scala/net/psforever/actors/zone/building/CavernFacilityLogic.scala b/src/main/scala/net/psforever/actors/zone/building/CavernFacilityLogic.scala
index ebfb38a80..b09d15dea 100644
--- a/src/main/scala/net/psforever/actors/zone/building/CavernFacilityLogic.scala
+++ b/src/main/scala/net/psforever/actors/zone/building/CavernFacilityLogic.scala
@@ -7,9 +7,10 @@ import net.psforever.actors.commands.NtuCommand
import net.psforever.actors.zone.{BuildingActor, BuildingControlDetails, ZoneActor}
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType}
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior}
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.galaxy.GalaxyAction
+import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
+import net.psforever.types.PlanetSideEmpire
/**
* The logic that governs facilities and structures found in the cavern regions.
@@ -52,12 +53,12 @@ case object CavernFacilityLogic
// When a CC is hacked (or resecured) all currently hacked amenities for the base should return to their default unhacked state
building.HackableAmenities.foreach(amenity => {
if (amenity.HackedBy.isDefined) {
- building.Zone.LocalEvents ! LocalServiceMessage(amenity.Zone.id,LocalAction.ClearTemporaryHack(PlanetSideGUID(0), amenity))
+ building.Zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(amenity))
}
})
// No map update needed - will be sent by `HackCaptureActor` when required
case _ =>
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
+ details.galaxyService ! MessageEnvelope("", GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
}
Behaviors.same
}
diff --git a/src/main/scala/net/psforever/actors/zone/building/FacilityLogic.scala b/src/main/scala/net/psforever/actors/zone/building/FacilityLogic.scala
index 1290b9956..db12a7555 100644
--- a/src/main/scala/net/psforever/actors/zone/building/FacilityLogic.scala
+++ b/src/main/scala/net/psforever/actors/zone/building/FacilityLogic.scala
@@ -7,9 +7,10 @@ import net.psforever.actors.commands.NtuCommand
import net.psforever.actors.zone.{BuildingActor, BuildingControlDetails}
import net.psforever.objects.serverobject.structures.{Amenity, Building}
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior}
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.galaxy.GalaxyAction
+import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
+import net.psforever.types.PlanetSideEmpire
/**
* The logic that governs standard facilities and structures.
@@ -52,12 +53,12 @@ case object FacilityLogic
// When a CC is hacked (or resecured) all currently hacked amenities for the base should return to their default unhacked state
building.HackableAmenities.foreach(amenity => {
if (amenity.HackedBy.isDefined) {
- building.Zone.LocalEvents ! LocalServiceMessage(amenity.Zone.id, LocalAction.ClearTemporaryHack(PlanetSideGUID(0), amenity))
+ building.Zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(amenity))
}
})
// No map update needed - will be sent by `HackCaptureActor` when required
case _ =>
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
+ details.galaxyService ! MessageEnvelope("", GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
}
Behaviors.same
}
diff --git a/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala b/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala
index c90579c55..676838bcc 100644
--- a/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala
+++ b/src/main/scala/net/psforever/actors/zone/building/MajorFacilityLogic.scala
@@ -13,12 +13,13 @@ import net.psforever.objects.serverobject.resourcesilo.ResourceSiloControl
import net.psforever.objects.serverobject.structures.{Amenity, Building}
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior}
import net.psforever.objects.sourcing.PlayerSource
-import net.psforever.packet.game.PlanetsideAttributeMessage
-import net.psforever.services.{InterstellarClusterService, Service}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
+import net.psforever.packet.game.{GenericObjectActionMessage, PlanetsideAttributeMessage}
+import net.psforever.services.InterstellarClusterService
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{GenericObjectAction, PlanetsideAttribute, SendResponse}
+import net.psforever.services.galaxy.GalaxyAction
+import net.psforever.services.local.support.{CaptureEnvelope, HackCaptureActor, HackClearActor, HackClearEnvelope}
+import net.psforever.types.PlanetSideEmpire
/**
* A package class that conveys the important information for handling facility updates.
@@ -101,10 +102,7 @@ case object MajorFacilityLogic
hackedAmenities
}
amenitiesToClear.foreach { amenity =>
- building.Zone.LocalEvents ! LocalServiceMessage(
- amenity.Zone.id,
- LocalAction.ClearTemporaryHack(PlanetSideGUID(0), amenity)
- )
+ building.Zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(amenity))
}
// No map update needed - will be sent by `HackCaptureActor` when required
case dome: ForceDomePhysics =>
@@ -120,7 +118,7 @@ case object MajorFacilityLogic
.filter(amenity => applicable.contains(amenity.Definition))
.foreach { _.Actor ! msg }
case _ =>
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
+ details.galaxyService ! MessageEnvelope("", GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
}
Behaviors.same
}
@@ -205,30 +203,24 @@ case object MajorFacilityLogic
case Some(GeneratorControl.Event.UnderAttack) =>
val events = zone.AvatarEvents
val guid = building.GUID
- val msg = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, guid, 15)
- building.PlayersInSOI.foreach { player =>
- events ! AvatarServiceMessage(player.Name, msg)
- }
+ val msg = GenericObjectAction(guid, 15)
+ events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) })
false
case Some(GeneratorControl.Event.Critical) =>
val events = zone.AvatarEvents
val guid = building.GUID
- val msg = AvatarAction.PlanetsideAttributeToAll(guid, 46, 1)
- building.PlayersInSOI.foreach { player =>
- events ! AvatarServiceMessage(player.Name, msg)
- }
+ val msg = PlanetsideAttribute(guid, 46, 1)
+ events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) })
true
case Some(GeneratorControl.Event.Destabilized) =>
val events = zone.AvatarEvents
val guid = building.GUID
- val msg = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, guid, 16)
- building.PlayersInSOI.foreach { player =>
- events ! AvatarServiceMessage(player.Name, msg)
- }
+ val msg = GenericObjectAction(guid, 16)
+ events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) })
if (building.hasCavernLockBenefit) {
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
+ SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
)
}
false
@@ -237,10 +229,9 @@ case object MajorFacilityLogic
case Some(GeneratorControl.Event.Offline) =>
powerLost(details)
val zone = building.Zone
- val msg = AvatarAction.PlanetsideAttributeToAll(building.GUID, 46, 2)
- building.PlayersInSOI.foreach { player =>
- zone.AvatarEvents ! AvatarServiceMessage(player.Name, msg)
- } //???
+ val events = zone.AvatarEvents
+ val msg = PlanetsideAttribute(building.GUID, 46, 2)
+ events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) }) //???
true
case Some(GeneratorControl.Event.Normal) =>
true
@@ -249,13 +240,13 @@ case object MajorFacilityLogic
powerRestored(details)
val events = zone.AvatarEvents
val guid = building.GUID
- val msg1 = AvatarAction.PlanetsideAttributeToAll(guid, 46, 0)
- val msg2 = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, guid, 17)
- building.PlayersInSOI.foreach { player =>
- val name = player.Name
- events ! AvatarServiceMessage(name, msg1) //reset ???; might be global?
- events ! AvatarServiceMessage(name, msg2) //This facility's generator is back on line
- }
+ //1. reset ???; might be global?
+ //2. This facility's generator is back on line
+ val list = SendResponse(
+ PlanetsideAttributeMessage(guid, 46, 0),
+ GenericObjectActionMessage(guid, 17)
+ )
+ events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, list) })
true
case _ =>
false
@@ -283,7 +274,7 @@ case object MajorFacilityLogic
(bldg.GetFlag, bldg.CaptureTerminal) match {
case (Some(flag), Some(terminal)) if (flag.Target eq building) && flag.Faction != building.Faction =>
//our hack destination may have been compromised and the hack needs to be cancelled
- bldg.Zone.LocalEvents ! LocalServiceMessage("", LocalAction.ResecureCaptureTerminal(terminal, PlayerSource.Nobody))
+ bldg.Zone.LocalEvents ! CaptureEnvelope(HackCaptureActor.ResecureCaptureTerminal(terminal, terminal.Zone, PlayerSource.Nobody))
case _ => ()
}
Behaviors.same
@@ -305,10 +296,12 @@ case object MajorFacilityLogic
building.Amenities.foreach { amenity =>
amenity.Actor ! powerMsg
}
- //amenities disabled; red warning lights
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 48, 1))
- //disable spawn target on deployment map
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 38, 0))
+ //1. amenities disabled; red warning lights
+ //2 .disable spawn target on deployment map
+ events ! MessageEnvelope(
+ zoneId,
+ SendResponse(PlanetsideAttributeMessage(guid, 48, 1), PlanetsideAttributeMessage(guid, 38, 0))
+ )
Behaviors.same
}
@@ -328,10 +321,12 @@ case object MajorFacilityLogic
building.Amenities.foreach { amenity =>
amenity.Actor ! powerMsg
}
- //amenities enabled; normal lights
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 48, 0))
- //enable spawn target on deployment map
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 38, 1))
+ //1. amenities enabled; normal lights
+ //2. enable spawn target on deployment map
+ events ! MessageEnvelope(
+ zoneId,
+ SendResponse(PlanetsideAttributeMessage(guid, 48, 0), PlanetsideAttributeMessage(guid, 38, 1))
+ )
Behaviors.same
}
diff --git a/src/main/scala/net/psforever/actors/zone/building/WarpGateLogic.scala b/src/main/scala/net/psforever/actors/zone/building/WarpGateLogic.scala
index b3eb01c1f..ec60d2f8d 100644
--- a/src/main/scala/net/psforever/actors/zone/building/WarpGateLogic.scala
+++ b/src/main/scala/net/psforever/actors/zone/building/WarpGateLogic.scala
@@ -4,9 +4,10 @@ package net.psforever.actors.zone.building
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors
import net.psforever.actors.commands.NtuCommand
-import net.psforever.actors.zone.{BuildingActor, ZoneActor}
+import net.psforever.actors.zone.BuildingActor
import net.psforever.objects.serverobject.structures.{Amenity, Building, WarpGate}
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.galaxy.GalaxyAction
import net.psforever.types.PlanetSideEmpire
import net.psforever.util.Config
@@ -182,7 +183,7 @@ case object WarpGateLogic
val pairedWgFaction = pairedWg.Faction
if (pairedWgFaction != terminalWgFaction) {
pairedWg.Faction = terminalWgFaction
- details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(pairedWg.infoUpdateMessage()))
+ details.galaxyService ! MessageEnvelope("", GalaxyAction.MapUpdate(pairedWg.infoUpdateMessage()))
}
//the terminal warpgate can not be considered broadcast for other faction
if (terminalWg.AllowBroadcastFor.contains(pairedWgFaction)) {
@@ -208,9 +209,7 @@ case object WarpGateLogic
warpgate.Zone.Number, warpgate.MapId, previousAllowances, setBroadcastTo
)
warpgate.AllowBroadcastFor = setBroadcastTo
- (setBroadcastTo ++ previousAllowances).foreach { faction =>
- events ! GalaxyServiceMessage(faction.toString, msg)
- }
+ events ! BundledEnvelope((setBroadcastTo ++ previousAllowances).map { faction => MessageEnvelope(faction.toString, msg) })
}
/**
diff --git a/src/main/scala/net/psforever/login/WorldSession.scala b/src/main/scala/net/psforever/login/WorldSession.scala
index e24360396..d89c31765 100644
--- a/src/main/scala/net/psforever/login/WorldSession.scala
+++ b/src/main/scala/net/psforever/login/WorldSession.scala
@@ -15,8 +15,9 @@ import net.psforever.objects.sourcing.AmenitySource
import net.psforever.objects.vital.TerminalUsedActivity
import net.psforever.objects.zones.Zone
import net.psforever.types.{ExoSuitType, PlanetSideGUID, TransactionType, Vector3}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.ObjectDelete
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
@@ -280,7 +281,7 @@ object WorldSession {
* @throws `RuntimeException` if slot is not a player visible slot (holsters)
* @see `ask`
* @see `AvatarAction.ObjectDelete`
- * @see `AvatarAction.SendResponse`
+ * @see `SendResponse`
* @see `Containable.CanNotPutItemInSlot`
* @see `Containable.PutItemInSlotOnly`
* @see `GUIDTask.registerEquipment`
@@ -289,7 +290,7 @@ object WorldSession {
* @see `ObjectHeldMessage`
* @see `Player.DrawnSlot`
* @see `Player.LastDrawnSlot`
- * @see `Service.defaultPlayerGUID`
+ * @see `Default.GUID0`
* @see `TaskBundle`
* @see `Zone.AvatarEvents`
* @param player the player whose visible slot will be equipped and drawn
@@ -326,10 +327,7 @@ object WorldSession {
case _ =>
forcedTolowerRaisedArm(localPlayer, localPlayer.GUID, localZone)
localPlayer.DrawnSlot = localSlot
- localZone.AvatarEvents ! AvatarServiceMessage(
- localZone.id,
- AvatarAction.ObjectHeld(localGUID, localSlot, localSlot)
- )
+ localZone.AvatarEvents ! MessageEnvelope(localZone.id, localGUID, AvatarAction.ObjectHeld(localSlot, localSlot))
}
Future(this)
}
@@ -370,10 +368,7 @@ object WorldSession {
localZone.GUID(item_guid) match {
case Some(_) => ()
case None => //acting on old data?
- localZone.AvatarEvents ! AvatarServiceMessage(
- localZone.id,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item_guid)
- )
+ localZone.AvatarEvents ! MessageEnvelope(localZone.id, ObjectDelete(item_guid))
}
case _ => ()
}
@@ -532,7 +527,6 @@ object WorldSession {
* Failure of this process is not supported and may lead to irregular behavior.
* @see `ActorRef`
* @see `AvatarAction.ObjectDelete`
- * @see `AvatarServiceMessage`
* @see `Containable.MoveItem`
* @see `Container`
* @see `Equipment`
@@ -597,10 +591,7 @@ object WorldSession {
localGUID match {
case Some(guid) =>
//see LockerContainerControl.RemoveItemFromSlotCallback
- localSource.Zone.AvatarEvents ! AvatarServiceMessage(
- localChannel,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
- )
+ localSource.Zone.AvatarEvents ! MessageEnvelope(localChannel, ObjectDelete(guid))
case None => ()
}
val moveResult = ask(localDestination.Actor, Containable.PutItemInSlotOrAway(localItem, Some(localDestSlot)))
@@ -625,8 +616,7 @@ object WorldSession {
* Remove an item from a player's locker inventory.
* Failure of this process is not supported and may lead to irregular behavior.
* @see `ActorRef`
- * @see `AvatarAction.ObjectDelete`
- * @see `AvatarServiceMessage`
+ * @see `ObjectDelete`
* @see `Containable.MoveItem`
* @see `Container`
* @see `Equipment`
@@ -702,10 +692,7 @@ object WorldSession {
localGUID match {
case Some(guid) =>
//see LockerContainerControl.RemoveItemFromSlotCallback
- localSource.Zone.AvatarEvents ! AvatarServiceMessage(
- localChannel,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
- )
+ localSource.Zone.AvatarEvents ! MessageEnvelope(localChannel, ObjectDelete(guid))
case None => ()
}
val moveResult = ask(localDestination.Actor, Containable.PutItemInSlotOrAway(localItem, Some(localDestSlot)))
@@ -742,8 +729,7 @@ object WorldSession {
* If the player's already-drawn hand is the same as the one that will hold the grenade (first sidearm holster),
* treat it like the sidearm occupier rather than the already-drawn weapon -
* the old weapon goes into the backpack or onto the ground.
- * @see `AvatarAction.ObjectHeld`
- * @see `AvatarServiceMessage`
+ * @see `ObjectHeld`
* @see `Containable.RemoveItemFromSlot`
* @see `countRestrictAttempts`
* @see `forcedTolowerRaisedArm`
@@ -795,10 +781,7 @@ object WorldSession {
}
//put up hand with grenade in it
tplayer.DrawnSlot = slotNum
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.ObjectHeld(guid, slotNum, slotNum)
- )
+ zone.AvatarEvents ! MessageEnvelope(zone.id, guid, AvatarAction.ObjectHeld(slotNum, slotNum))
log.info(s"${tplayer.Name} has quickly drawn a ${grenade.Definition.Name}")
None
case None =>
@@ -872,8 +855,7 @@ object WorldSession {
/**
* If the player has a raised arm, lower it.
* Do it manually, bypassing the checks in the normal procedure.
- * @see `AvatarAction.ObjectHeld`
- * @see `AvatarServiceMessage`
+ * @see `ObjectHeld`
* @see `Player.DrawnSlot`
* @see `Player.HandsDownSlot`
* @param tplayer the player
@@ -885,10 +867,7 @@ object WorldSession {
val slot = tplayer.DrawnSlot
if (slot != Player.HandsDownSlot) {
tplayer.DrawnSlot = Player.HandsDownSlot
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.ObjectHeld(guid, Player.HandsDownSlot, slot)
- )
+ zone.AvatarEvents ! MessageEnvelope(zone.id, guid, AvatarAction.ObjectHeld(Player.HandsDownSlot, slot))
true
} else {
false
@@ -951,7 +930,7 @@ object WorldSession {
player.ContributionFrom(term)
}
}
- player.Zone.AvatarEvents ! AvatarServiceMessage(
+ player.Zone.AvatarEvents ! MessageEnvelope(
player.Name,
AvatarAction.TerminalOrderResult(guid, transaction, result)
)
diff --git a/src/main/scala/net/psforever/objects/BoomerDeployable.scala b/src/main/scala/net/psforever/objects/BoomerDeployable.scala
index 6cf03ddb6..22ce1938d 100644
--- a/src/main/scala/net/psforever/objects/BoomerDeployable.scala
+++ b/src/main/scala/net/psforever/objects/BoomerDeployable.scala
@@ -11,9 +11,9 @@ import net.psforever.objects.vital.Vitality
import net.psforever.objects.vital.etc.TriggerUsedReason
import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.zones.Zone
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.ObjectDelete
+import net.psforever.services.local.LocalAction
import net.psforever.types.PlanetSideEmpire
import scala.annotation.unused
@@ -87,9 +87,9 @@ class BoomerDeployableControl(mine: BoomerDeployable)
val events = mine.Zone.LocalEvents
val msg = LocalAction.DeployItem(mine)
originalOwner.collect { name =>
- events ! LocalServiceMessage(name, msg)
+ events ! MessageEnvelope(name, msg)
}
- events ! LocalServiceMessage(player.Name, msg)
+ events ! MessageEnvelope(player.Name, msg)
}
override def dismissDeployable() : Unit = {
@@ -107,10 +107,7 @@ class BoomerDeployableControl(mine: BoomerDeployable)
zone.Ground ! Zone.Ground.RemoveItem(guid)
case _ => ()
}
- zone.AvatarEvents! AvatarServiceMessage(
- zone.id,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
- )
+ zone.AvatarEvents! MessageEnvelope(zone.id, ObjectDelete(guid))
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, trigger))
case None => ()
}
diff --git a/src/main/scala/net/psforever/objects/Default.scala b/src/main/scala/net/psforever/objects/Default.scala
index 09cd99b87..b94c2c8f2 100644
--- a/src/main/scala/net/psforever/objects/Default.scala
+++ b/src/main/scala/net/psforever/objects/Default.scala
@@ -1,7 +1,12 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects
+import net.psforever.types.{PlanetSideGUID, ValidPlanetSideGUID}
+
object Default {
+ //'g'lobal 'u'nique 'id'entifier
+ final val GUID0: PlanetSideGUID = ValidPlanetSideGUID(0)
+
//cancellable
import akka.actor.Cancellable
protected class InternalCancellable extends Cancellable {
diff --git a/src/main/scala/net/psforever/objects/Deployables.scala b/src/main/scala/net/psforever/objects/Deployables.scala
index c75057197..6fa64bd33 100644
--- a/src/main/scala/net/psforever/objects/Deployables.scala
+++ b/src/main/scala/net/psforever/objects/Deployables.scala
@@ -9,8 +9,9 @@ import net.psforever.objects.ce.{Deployable, DeployedItem}
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
import net.psforever.objects.zones.Zone
import net.psforever.packet.game._
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.PlanetSideGUID
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.local.LocalAction
object Deployables {
//private val log = org.log4s.getLogger("Deployables")
@@ -92,13 +93,9 @@ object Deployables {
}
target.AssignOwnership(None)
}
- events ! LocalServiceMessage(
+ events ! MessageEnvelope(
s"${target.Faction}",
- LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
- DeploymentAction.Dismiss,
- DeployableInfo(target.GUID, Deployable.Icon(item), target.Position, PlanetSideGUID(0))
- )
+ LocalAction.DeployableMapIcon(DeploymentAction.Dismiss, DeployableInfo(target.GUID, Deployable.Icon(item), target.Position, PlanetSideGUID(0)))
)
}
diff --git a/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala b/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala
index ceea45622..075f756d6 100644
--- a/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala
+++ b/src/main/scala/net/psforever/objects/ExplosiveDeployable.scala
@@ -17,9 +17,9 @@ import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.zones.Zone
import net.psforever.types.Vector3
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.local.LocalAction
import scala.annotation.unused
import scala.concurrent.duration._
@@ -182,7 +182,7 @@ object ExplosiveDeployableControl {
target.Health = 1 // short-circuit logic in DestructionAwareness
val zone = target.Zone
zone.Activity ! Zone.HotSpot.Activity(cause)
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.Detonate(target.GUID, target))
+ zone.LocalEvents ! MessageEnvelope(zone.id, LocalAction.Detonate(target.GUID, target))
Zone.serverSideDamage(
zone,
target,
@@ -210,14 +210,14 @@ object ExplosiveDeployableControl {
Some(if (target.Jammed || target.Destroyed) 0 seconds else 500 milliseconds)
)
target.Destroyed = true
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.Destroy(target.GUID, attribution, Service.defaultPlayerGUID, target.Position)
+ AvatarAction.Destroy(target.GUID, attribution, Default.GUID0, target.Position)
)
if (target.Health == 0) {
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerEffect(Service.defaultPlayerGUID, "detonate_damaged_mine", target.GUID)
+ LocalAction.TriggerEffect("detonate_damaged_mine", target.GUID)
)
}
}
diff --git a/src/main/scala/net/psforever/objects/FieldTurretDeployable.scala b/src/main/scala/net/psforever/objects/FieldTurretDeployable.scala
index be51a5cba..2ebf81e88 100644
--- a/src/main/scala/net/psforever/objects/FieldTurretDeployable.scala
+++ b/src/main/scala/net/psforever/objects/FieldTurretDeployable.scala
@@ -12,8 +12,8 @@ import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObjec
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, TurretSource}
import net.psforever.objects.vital.{DismountingActivity, InGameActivity, MountingActivity, ShieldCharge}
import net.psforever.packet.game.HackState1
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
-import net.psforever.types.PlanetSideGUID
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import scala.annotation.unused
@@ -98,9 +98,9 @@ class FieldTurretControl(turret: TurretDeployable)
if (canChargeShields) {
turret.LogActivity(ShieldCharge(amount, motivator))
turret.Shields = turret.Shields + amount
- turret.Zone.VehicleEvents ! VehicleServiceMessage(
+ turret.Zone.VehicleEvents ! MessageEnvelope(
s"${turret.Actor}",
- VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), turret.GUID, turret.Definition.shieldUiAttribute, turret.Shields)
+ PlanetsideAttribute(turret.GUID, turret.Definition.shieldUiAttribute, turret.Shields)
)
}
}
diff --git a/src/main/scala/net/psforever/objects/Players.scala b/src/main/scala/net/psforever/objects/Players.scala
index 720a84728..7aa3fee0d 100644
--- a/src/main/scala/net/psforever/objects/Players.scala
+++ b/src/main/scala/net/psforever/objects/Players.scala
@@ -19,11 +19,13 @@ import net.psforever.objects.vital.{InGameActivity, InGameHistory, RevivingActiv
import net.psforever.objects.zones.Zone
import net.psforever.packet.game._
import net.psforever.types.{ChatMessageType, ExoSuitType, PlanetSideGUID, Vector3}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{ObjectDelete, SendResponse}
+import net.psforever.services.local.LocalAction
import scala.annotation.tailrec
+import scala.collection.mutable.ArrayBuffer
object Players {
private val log = org.log4s.getLogger("Players")
@@ -48,10 +50,7 @@ object Players {
) {
val events = target.Zone.AvatarEvents
val uname = user.Name
- events ! AvatarServiceMessage(
- uname,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, RepairMessage(target.GUID, progress.toInt))
- )
+ events ! MessageEnvelope(uname, SendResponse(RepairMessage(target.GUID, progress.toInt)))
true
} else {
false
@@ -61,7 +60,7 @@ object Players {
/**
* na
* @see `AvatarAction.Revive`
- * @see `AvatarResponse.Revive`
+ * @see `AvatarAction.Revive`
* @param target the player being revived
* @param medic the name of the player doing the reviving
* @param item the tool being used to revive the target player
@@ -76,12 +75,12 @@ object Players {
PlayerControl.sendResponse(
target.Zone,
medicName,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ Default.GUID0,
+ SendResponse(
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine)
)
)
- PlayerControl.sendResponse(target.Zone, name, AvatarAction.Revive(target.GUID))
+ PlayerControl.sendResponse(target.Zone, name, Default.GUID0, AvatarAction.Revive(target.GUID))
}
/**
@@ -163,7 +162,7 @@ object Players {
ExoSuitDefinition.Select(exosuit, player.Faction).Permissions match {
case Nil =>
true
- case permissions if player.IsInVRZone =>
+ case _ if player.IsInVRZone =>
true
case permissions if subtype != 0 =>
val certs = player.avatar.certifications
@@ -316,7 +315,7 @@ object Players {
): Boolean = {
if (player.Zone == obj.Zone && addFunc(obj)) {
obj.Actor ! Deployable.Ownership(player)
- player.Zone.LocalEvents ! LocalServiceMessage(player.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
+ player.Zone.LocalEvents ! MessageEnvelope(player.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
true
} else {
false
@@ -333,7 +332,7 @@ object Players {
//sent to avatar event bus to preempt additional tool management
buildCooldownReset(zone, channel, obj.GUID)
//sent to local event bus to cooperate with deployable management
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
channel,
LocalAction.DeployableUIFor(obj.Definition.Item)
)
@@ -347,10 +346,7 @@ object Players {
*/
def buildCooldownReset(zone: Zone, channel: String, guid: PlanetSideGUID): Unit = {
//sent to avatar event bus to preempt additional tool management
- zone.AvatarEvents ! AvatarServiceMessage(
- channel,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, GenericObjectActionMessage(guid, 21))
- )
+ zone.AvatarEvents ! MessageEnvelope(channel, SendResponse(GenericObjectActionMessage(guid, 21)))
}
/**
@@ -406,10 +402,7 @@ object Players {
}
}) {
val zone = player.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, tool.GUID)
- )
+ zone.AvatarEvents ! MessageEnvelope(zone.id, ObjectDelete(tool.GUID))
true
} else {
false
@@ -444,27 +437,20 @@ object Players {
if ((player.Slot(index).Equipment = obj).contains(obj)) {
val fireMode = tool.FireModeIndex
val ammoType = tool.AmmoTypeIndex
+ val list: ArrayBuffer[MessageEnvelope] = ArrayBuffer()
player.Inventory -= x.start
obj.FireModeIndex = fireMode
//TODO any penalty for being handed an OCM version of the tool?
- events ! AvatarServiceMessage(
- zone.id,
- AvatarAction.EquipmentInHand(Service.defaultPlayerGUID, pguid, index, obj)
- )
+ list.append(MessageEnvelope(zone.id, AvatarAction.EquipmentInHand(pguid, index, obj)))
if (obj.AmmoTypeIndex != ammoType) {
obj.AmmoTypeIndex = ammoType
- events ! AvatarServiceMessage(
- name,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ChangeAmmoMessage(obj.GUID, ammoType))
- )
+ list.append(MessageEnvelope(name, SendResponse(ChangeAmmoMessage(obj.GUID, ammoType))))
}
if (player.DrawnSlot == Player.HandsDownSlot) {
player.DrawnSlot = index
- events ! AvatarServiceMessage(
- zone.id,
- AvatarAction.ObjectHeld(pguid, index, index)
- )
+ list.append(MessageEnvelope(zone.id, pguid, AvatarAction.ObjectHeld(index, index)))
}
+ events ! BundledEnvelope(list)
}
case Nil => ; //no replacements found
}
diff --git a/src/main/scala/net/psforever/objects/SensorDeployable.scala b/src/main/scala/net/psforever/objects/SensorDeployable.scala
index cd08bedb3..77e812a23 100644
--- a/src/main/scala/net/psforever/objects/SensorDeployable.scala
+++ b/src/main/scala/net/psforever/objects/SensorDeployable.scala
@@ -12,10 +12,10 @@ import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.repair.RepairableEntity
import net.psforever.objects.vital.SimpleResolutions
import net.psforever.objects.vital.interaction.DamageResult
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{PlanetSideGUID, Vector3}
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.message.PlanetsideAttribute
+import net.psforever.services.local.LocalAction
import scala.annotation.unused
import scala.concurrent.duration._
@@ -75,9 +75,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
override def StartJammeredSound(target: Any, dur: Int): Unit =
target match {
case obj: PlanetSideServerObject if !jammedSound =>
- obj.Zone.VehicleEvents ! VehicleServiceMessage(
+ obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1)
+ PlanetsideAttribute(obj.GUID, 54, 1)
)
super.StartJammeredSound(obj, dur)
case _ => ;
@@ -87,9 +87,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
target match {
case obj: PlanetSideServerObject with JammableUnit =>
val zone = obj.Zone
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, unk1=false, 1000)
+ LocalAction.TriggerEffectInfo(obj.GUID, "on", unk1=false, 1000)
)
super.StartJammeredStatus(obj, dur)
case _ => ;
@@ -99,9 +99,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
target match {
case obj: PlanetSideServerObject if jammedSound =>
val zone = obj.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0)
+ PlanetsideAttribute(obj.GUID, 54, 0)
)
case _ => ;
}
@@ -112,9 +112,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
target match {
case obj: PlanetSideServerObject with JammableUnit if obj.Jammed =>
val zone = sensor.Zone
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, unk1=true, 1000)
+ LocalAction.TriggerEffectInfo(obj.GUID, "on", unk1=true, 1000)
)
case _ => ;
}
@@ -124,9 +124,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
override def finalizeDeployable(callback: ActorRef) : Unit = {
super.finalizeDeployable(callback)
val zone = sensor.Zone
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", sensor.GUID, unk1=true, 1000)
+ LocalAction.TriggerEffectInfo(sensor.GUID, "on", unk1=true, 1000)
)
}
}
@@ -141,9 +141,9 @@ object SensorDeployableControl {
def DestructionAwareness(target: Deployable, attribution: PlanetSideGUID): Unit = {
Deployables.AnnounceDestroyDeployable(target, Some(1 seconds))
val zone = target.Zone
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", target.GUID, unk1=false, 1000)
+ LocalAction.TriggerEffectInfo(target.GUID, "on", unk1=false, 1000)
)
//position the explosion effect near the bulky area of the sensor stalk
val ang = target.Orientation
@@ -157,9 +157,9 @@ object SensorDeployableControl {
pos.z + math.cos(yRadians).toFloat * 0.875f
)
}
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerEffectLocation(Service.defaultPlayerGUID, "motion_sensor_destroyed", explosionPos, ang)
+ LocalAction.TriggerEffectLocation("motion_sensor_destroyed", explosionPos, ang)
)
//TODO replaced by an alternate model (charred stub)?
}
diff --git a/src/main/scala/net/psforever/objects/ShieldGeneratorDeployable.scala b/src/main/scala/net/psforever/objects/ShieldGeneratorDeployable.scala
index 15a7ceadc..42282ca57 100644
--- a/src/main/scala/net/psforever/objects/ShieldGeneratorDeployable.scala
+++ b/src/main/scala/net/psforever/objects/ShieldGeneratorDeployable.scala
@@ -13,21 +13,21 @@ import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.repair.RepairableEntity
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.vital.resolution.ResolutionCalculations
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.types.PlanetSideGUID
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
class ShieldGeneratorDeployable(cdef: ShieldGeneratorDefinition)
extends Deployable(cdef)
with Hackable
with JammableUnit
-class ShieldGeneratorDefinition extends DeployableDefinition(240)
+class ShieldGeneratorDefinition extends DeployableDefinition(objectId = 240)
with WithShields {
Packet = new ShieldGeneratorConverter
DeployCategory = DeployableCategory.ShieldGenerators
- override def Initialize(obj: Deployable, context: ActorContext) = {
+ override def Initialize(obj: Deployable, context: ActorContext): Unit = {
obj.Actor =
context.actorOf(Props(classOf[ShieldGeneratorControl], obj), PlanetSideServerObject.UniqueActorName(obj))
}
@@ -39,10 +39,10 @@ class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
with JammableBehavior
with DamageableEntity
with RepairableEntity {
- def DeployableObject = gen
- def JammableObject = gen
- def DamageableObject = gen
- def RepairableObject = gen
+ def DeployableObject: ShieldGeneratorDeployable = gen
+ def JammableObject: ShieldGeneratorDeployable = gen
+ def DamageableObject: ShieldGeneratorDeployable = gen
+ def RepairableObject: ShieldGeneratorDeployable = gen
deletionType = 1 //from DeployableBehavior
override def postStop(): Unit = {
@@ -125,9 +125,9 @@ class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
override def StartJammeredStatus(target: Any, dur: Int): Unit =
target match {
case obj: PlanetSideServerObject with JammableUnit =>
- obj.Zone.VehicleEvents ! VehicleServiceMessage(
+ obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1)
+ PlanetsideAttribute(obj.GUID, 27, 1)
)
super.StartJammeredStatus(obj, dur)
case _ => ;
@@ -138,9 +138,9 @@ class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
override def CancelJammeredStatus(target: Any): Unit = {
target match {
case obj: PlanetSideServerObject with JammableUnit if obj.Jammed =>
- obj.Zone.VehicleEvents ! VehicleServiceMessage(
+ obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 0)
+ PlanetsideAttribute(obj.GUID, 27, 0)
)
case _ => ;
}
@@ -160,9 +160,9 @@ object ShieldGeneratorControl {
//shields
if (damageToShields) {
val zone = target.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 68, target.Shields)
+ PlanetsideAttribute(target.GUID, 68, target.Shields)
)
}
}
diff --git a/src/main/scala/net/psforever/objects/TelepadDeployable.scala b/src/main/scala/net/psforever/objects/TelepadDeployable.scala
index a0cfa954a..c524f7f24 100644
--- a/src/main/scala/net/psforever/objects/TelepadDeployable.scala
+++ b/src/main/scala/net/psforever/objects/TelepadDeployable.scala
@@ -11,7 +11,8 @@ import net.psforever.objects.vehicles.Utility.InternalTelepad
import net.psforever.objects.vital.SimpleResolutions
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.local.LocalAction
import scala.concurrent.duration._
@@ -133,6 +134,6 @@ object TelepadControl {
}
def TelepadError(zone: Zone, channel: String, msg: String): Unit = {
- zone.LocalEvents ! LocalServiceMessage(channel, LocalAction.RouterTelepadMessage(msg))
+ zone.LocalEvents ! MessageEnvelope(channel, LocalAction.RouterTelepadMessage(msg))
}
}
diff --git a/src/main/scala/net/psforever/objects/Tools.scala b/src/main/scala/net/psforever/objects/Tools.scala
index 6744550b3..459e4f4ce 100644
--- a/src/main/scala/net/psforever/objects/Tools.scala
+++ b/src/main/scala/net/psforever/objects/Tools.scala
@@ -3,8 +3,8 @@ package net.psforever.objects
import net.psforever.objects.equipment.ChargeFireModeDefinition
import net.psforever.packet.game.QuantityUpdateMessage
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
object Tools {
/**
@@ -22,12 +22,9 @@ object Tools {
tool.FireMode match {
case mode: ChargeFireModeDefinition if tool.Magazine > 0 =>
val magazine = tool.Magazine -= mode.RoundsPerInterval
- player.Zone.AvatarEvents ! AvatarServiceMessage(
+ player.Zone.AvatarEvents ! MessageEnvelope(
player.Name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, magazine)
- )
+ SendResponse(QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, magazine))
)
player.isAlive
case _ =>
diff --git a/src/main/scala/net/psforever/objects/TurretDeployable.scala b/src/main/scala/net/psforever/objects/TurretDeployable.scala
index f21f74707..7b0cc5f3e 100644
--- a/src/main/scala/net/psforever/objects/TurretDeployable.scala
+++ b/src/main/scala/net/psforever/objects/TurretDeployable.scala
@@ -20,7 +20,8 @@ import net.psforever.objects.vital.resistance.StandardResistanceProfile
import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance}
import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game.TriggeredSound
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.vehicle.VehicleAction
import scala.concurrent.duration.FiniteDuration
@@ -109,9 +110,10 @@ abstract class TurretDeployableControl
case player: Player =>
seat.unmount(player)
player.VehicleSeated = None
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.KickPassenger(player.GUID, 4, wasKickedByDriver, TurretObject.GUID)
+ player.GUID,
+ VehicleAction.KickPassenger(4, wasKickedByDriver, TurretObject.GUID)
)
}
}
diff --git a/src/main/scala/net/psforever/objects/Vehicles.scala b/src/main/scala/net/psforever/objects/Vehicles.scala
index 019f4d7f2..fbee9477c 100644
--- a/src/main/scala/net/psforever/objects/Vehicles.scala
+++ b/src/main/scala/net/psforever/objects/Vehicles.scala
@@ -9,13 +9,16 @@ import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.transfer.TransferContainer
import net.psforever.objects.serverobject.structures.WarpGate
import net.psforever.objects.vehicles._
+import net.psforever.objects.vehicles.control.CargoBehavior
import net.psforever.objects.zones.Zone
-import net.psforever.packet.game.{ChatMsg, FrameVehicleStateMessage, GenericObjectActionEnum, GenericObjectActionMessage, HackMessage, HackState, HackState1, HackState7, TriggeredSound, VehicleStateMessage}
+import net.psforever.packet.game.{ChatMsg, FrameVehicleStateMessage, GenericObjectActionEnum, HackMessage, HackState, HackState1, HackState7, TriggeredSound, VehicleStateMessage}
import net.psforever.types.{ChatMessageType, DriveState, PlanetSideEmpire, PlanetSideGUID, Vector3}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{GenericObjectAction, PlanetsideAttribute, SendResponse, SetEmpire}
+import net.psforever.services.local.LocalAction
+import net.psforever.services.vehicle.VehicleAction
+
+import scala.collection.mutable.ArrayBuffer
//import scala.concurrent.duration._
@@ -45,9 +48,10 @@ object Vehicles {
val locked = VehicleLockState.Locked.id
Array(0, 3).foreach(group => vehicle.PermissionGroup(group, locked))
Vehicles.ReloadAccessPermissions(vehicle, tplayer.Faction.toString)
- vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
+ vehicle.Zone.VehicleEvents ! MessageEnvelope(
vehicle.Zone.id,
- VehicleAction.Ownership(tplayer.GUID, vehicle.GUID)
+ tplayer.GUID,
+ VehicleAction.Ownership(vehicle.GUID)
)
Some(vehicle)
case None =>
@@ -88,9 +92,9 @@ object Vehicles {
val empire = VehicleLockState.Empire.id
(0 to 2).foreach(group => vehicle.PermissionGroup(group, empire))
ReloadAccessPermissions(vehicle, vehicle.Faction.toString)
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.LoseOwnership(ownerGuid.getOrElse(Service.defaultPlayerGUID), guid)
+ VehicleAction.LoseOwnership(ownerGuid.getOrElse(Default.GUID0), guid)
)
result
}
@@ -138,13 +142,14 @@ object Vehicles {
val pguid = player.GUID
if (vehicle.OwnerGuid.contains(pguid)) {
vehicle.AssignOwnership(None)
- //vehicle.Zone.VehicleEvents ! VehicleServiceMessage(player.Name, VehicleAction.Ownership(pguid, PlanetSideGUID(0)))
+ //vehicle.Zone.VehicleEvents ! MessageEnvelope(player.Name, pguid, VehicleAction.Ownership(pguid, PlanetSideGUID(0)))
//val vguid = vehicle.GUID
val empire = VehicleLockState.Empire.id
(0 to 2).foreach(group => {
vehicle.PermissionGroup(group, empire)
- /*vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
+ /*vehicle.Zone.VehicleEvents ! MessageEnvelope(
s"${vehicle.Faction}",
+ pguid,
VehicleAction.SeatPermissions(pguid, vguid, group, empire)
)*/
})
@@ -167,9 +172,9 @@ object Vehicles {
def ReloadAccessPermissions(vehicle: Vehicle, toChannel: String): Unit = {
val vehicle_guid = vehicle.GUID
(0 to 3).foreach(group => {
- vehicle.Zone.AvatarEvents ! AvatarServiceMessage(
+ vehicle.Zone.AvatarEvents ! MessageEnvelope(
toChannel,
- AvatarAction.PlanetsideAttributeToAll(vehicle_guid, group + 10, vehicle.PermissionGroup(group).get.id)
+ PlanetsideAttribute(vehicle_guid, group + 10, vehicle.PermissionGroup(group).get.id)
)
})
}
@@ -246,16 +251,15 @@ object Vehicles {
val hFaction = hacker.Faction
val zone = target.Zone
val zoneid = zone.id
+ val avatarEvents = zone.AvatarEvents
val vehicleEvents = zone.VehicleEvents
- val localEvents = zone.LocalEvents
val previousOwnerName = target.OwnerName.getOrElse("")
- vehicleEvents ! VehicleServiceMessage(
+ val occupantMessages: ArrayBuffer[MessageEnvelope] = ArrayBuffer()
+ val vehicleMessages: ArrayBuffer[MessageEnvelope] = ArrayBuffer()
+ vehicleMessages.append(MessageEnvelope(
zoneid,
- VehicleAction.SendResponse(
- Service.defaultPlayerGUID,
- HackMessage(HackState1.Unk2, tGuid, hGuid, 100, 0f, HackState.Hacked, HackState7.Unk8)
- )
- )
+ SendResponse(HackMessage(HackState1.Unk2, tGuid, hGuid, 100, 0f, HackState.Hacked, HackState7.Unk8))
+ ))
target.Actor ! CommonMessages.Hack(hacker, target)
// Forcefully dismount any cargo
target.CargoHolds.foreach { case (_, cargoHold) =>
@@ -269,24 +273,29 @@ object Vehicles {
player: Player =>
seat.unmount(player)
player.VehicleSeated = None
- vehicleEvents ! VehicleServiceMessage(
+ occupantMessages.append(MessageEnvelope(
zoneid,
- VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, tGuid)
- )
+ player.GUID,
+ VehicleAction.KickPassenger(4, unk2 = false, tGuid)
+ ))
}
// In case BFR is occupied and may or may not be crouched
if (GlobalDefinitions.isBattleFrameVehicle(target.Definition) && target.Seat(0).isDefined) {
- zone.LocalEvents ! LocalServiceMessage(
- zoneid,
- LocalAction.SendGenericObjectActionMessage(PlanetSideGUID(-1), target.GUID, GenericObjectActionEnum.BFRShieldsDown))
- zone.LocalEvents ! LocalServiceMessage(
- zoneid,
- LocalAction.SendResponse(
- FrameVehicleStateMessage(target.GUID, 0, target.Position, target.Orientation, Some(Vector3(0f, 0f, 0f)), unk2=false, 0, 0, is_crouched=true, is_airborne=false, ascending_flight=false, 10, 0, 0)))
- zone.LocalEvents ! LocalServiceMessage(
- zoneid,
- LocalAction.SendResponse(
- VehicleStateMessage(target.GUID, 0, target.Position, target.Orientation, Some(Vector3(0f, 0f, 0f)), None, 0, 0, 15, is_decelerating=false, is_cloaked=false)))
+ vehicleMessages.appendAll(List(
+ MessageEnvelope(zoneid,
+ GenericObjectAction(target.GUID, GenericObjectActionEnum.BFRShieldsDown.id)
+ ),
+ MessageEnvelope(zoneid,
+ SendResponse(
+ FrameVehicleStateMessage(target.GUID, 0, target.Position, target.Orientation, Some(Vector3(0f, 0f, 0f)), unk2=false, 0, 0, is_crouched=true, is_airborne=false, ascending_flight=false, 10, 0, 0)
+ )
+ ),
+ MessageEnvelope(zoneid,
+ SendResponse(
+ VehicleStateMessage(target.GUID, 0, target.Position, target.Orientation, Some(Vector3(0f, 0f, 0f)), None, 0, 0, 15, is_decelerating=false, is_cloaked=false)
+ )
+ )
+ ))
}
})
// If the vehicle can fly and is flying: deconstruct it; and well played to whomever managed to hack a plane in mid air
@@ -311,25 +320,17 @@ object Vehicles {
Vehicles.Own(target, hacker)
//todo: Send HackMessage -> HackCleared to vehicle? can be found in packet captures. Not sure if necessary.
// And broadcast the faction change to other clients
- zone.AvatarEvents ! AvatarServiceMessage(
- zoneid,
- AvatarAction.SetEmpire(Service.defaultPlayerGUID, tGuid, hFaction)
- )
+ vehicleMessages.append(MessageEnvelope(zoneid, SetEmpire(tGuid, hFaction)))
}
- localEvents ! LocalServiceMessage(
+ vehicleMessages.append(MessageEnvelope(
zoneid,
- LocalAction.TriggerSound(hGuid, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)
- )
+ hGuid,
+ LocalAction.TriggerSound(TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)
+ ))
if (zone.Players.exists(_.name.equals(previousOwnerName))) {
- localEvents ! LocalServiceMessage(
- previousOwnerName,
- LocalAction.SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackStolen"))
- )
+ vehicleMessages.append(MessageEnvelope(previousOwnerName, SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackStolen"))))
}
- localEvents ! LocalServiceMessage(
- hacker.Name,
- LocalAction.SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackVehicleOwned"))
- )
+ occupantMessages.append(MessageEnvelope(hacker.Name, SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackVehicleOwned"))))
// Clean up after specific vehicles, e.g. remove router telepads
// If AMS is deployed, swap it to the new faction
target.Definition match {
@@ -341,16 +342,15 @@ object Vehicles {
util.Actor ! TelepadLike.Activate(util)
}
case GlobalDefinitions.ams if target.DeploymentState == DriveState.Deployed =>
- vehicleEvents ! VehicleServiceMessage.AMSDeploymentChange(zone)
+ vehicleMessages.append(MessageEnvelope(zone.id, VehicleAction.AMSDeploymentChange(zone)))
case _ => ()
}
- vehicleEvents ! VehicleServiceMessage(
+ vehicleMessages.append(MessageEnvelope(
zoneid,
- VehicleAction.SendResponse(
- Service.defaultPlayerGUID,
- HackMessage(HackState1.Unk2, tGuid, tGuid, 0, 1L, HackState.HackCleared, HackState7.Unk8)
- )
- )
+ SendResponse(HackMessage(HackState1.Unk2, tGuid, tGuid, 0, 1L, HackState.HackCleared, HackState7.Unk8))
+ ))
+ avatarEvents ! BundledEnvelope(occupantMessages)
+ vehicleEvents ! BundledEnvelope(vehicleMessages)
target.Actor ! CommonMessages.ClearHack()
}
diff --git a/src/main/scala/net/psforever/objects/avatar/AvatarBotActor.scala b/src/main/scala/net/psforever/objects/avatar/AvatarBotActor.scala
index 486289d66..b388fa988 100644
--- a/src/main/scala/net/psforever/objects/avatar/AvatarBotActor.scala
+++ b/src/main/scala/net/psforever/objects/avatar/AvatarBotActor.scala
@@ -4,7 +4,6 @@ package net.psforever.objects.avatar
import akka.actor.{Actor, ActorRef}
import net.psforever.actors.zone.ShootingRangeTargetSpawner
import net.psforever.objects.{GlobalDefinitions, Tool}
-import net.psforever.objects.avatar.AvatarBot
import net.psforever.objects.equipment._
import net.psforever.objects.serverobject.aura.{Aura, AuraEffectBehavior}
import net.psforever.objects.serverobject.CommonMessages
@@ -14,18 +13,17 @@ import net.psforever.objects.vital.resolution.ResolutionCalculations.Output
import net.psforever.objects.zones._
import net.psforever.packet.game._
import net.psforever.types._
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.avatar.AvatarAction
import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment
import net.psforever.objects.serverobject.repair.Repairable
import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.vital.{HealFromEquipment, RepairFromEquipment}
import net.psforever.objects.vital.etc.SuicideReason
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import java.util.concurrent.{Executors, TimeUnit}
-
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.util.Random
@@ -53,7 +51,7 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
def InteractiveObject: AvatarBot = bot
- private[this] val log = org.log4s.getLogger(bot.Name)
+ //private[this] val log = org.log4s.getLogger(bot.Name)
private[this] val damageLog = org.log4s.getLogger(Damageable.LogChannel)
private val scheduler = Executors.newScheduledThreadPool(2)
/** suffocating, or regaining breath? */
@@ -107,14 +105,13 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
if (!(bot.isMoving || user.isMoving)) { //only allow stationary heals
val newHealth = bot.Health = originalHealth + 10
val magazine = item.Discharge()
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
uname,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
)
)
- events ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth))
+ events ! MessageEnvelope(zone.id, PlanetsideAttribute(guid, 0, newHealth))
bot.LogActivity(
HealFromEquipment(
PlayerSource(user),
@@ -124,10 +121,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
)
}
//progress bar remains visible for all heal attempts
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
uname,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
RepairMessage(guid, bot.Health * 100 / definition.MaxHealth)
)
)
@@ -150,14 +146,13 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
val newArmor = bot.Armor =
originalArmor + Repairable.applyLevelModifier(user, item, RepairToolValue(item)).toInt + definition.RepairMod
val magazine = item.Discharge()
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
uname,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
)
)
- events ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttributeToAll(guid, 4, bot.Armor))
+ events ! MessageEnvelope(zone.id, PlanetsideAttribute(guid, 4, bot.Armor))
bot.LogActivity(
RepairFromEquipment(
PlayerSource(user),
@@ -167,10 +162,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
)
}
//progress bar remains visible for all repair attempts
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
uname,
- AvatarAction
- .SendResponse(Service.defaultPlayerGUID, RepairMessage(guid, bot.Armor * 100 / bot.MaxArmor))
+ SendResponse(RepairMessage(guid, bot.Armor * 100 / bot.MaxArmor))
)
}
@@ -231,9 +225,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
//always do armor update
if (damageToArmor > 0) {
val zone = target.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttributeToAll(target.GUID, 4, target.Armor)
+ PlanetsideAttribute(target.GUID, 4, target.Armor)
)
}
//choose
@@ -280,16 +274,13 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
announceConfrontation = true //TODO should we?
}
if (damageToHealth > 0) {
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 0, health))
+ events ! MessageEnvelope(zoneId, PlanetsideAttribute(targetGUID, 0, health))
announceConfrontation = true
}
val countableDamage = damageToHealth + damageToArmor
if(announceConfrontation) {
if (aggravated) {
- events ! AvatarServiceMessage(
- zoneId,
- AvatarAction.SendResponse(targetGUID, AggravatedDamageMessage(targetGUID, countableDamage))
- )
+ events ! MessageEnvelope(zoneId, targetGUID, SendResponse(AggravatedDamageMessage(targetGUID, countableDamage)))
} else {
//activity on map
zone.Activity ! Zone.HotSpot.Activity(cause)
@@ -332,22 +323,22 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
cause.adversarial match {
case Some(a) =>
damageLog.info(s"${a.defender.Name} was killed by ${a.attacker.Name}")
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
zoneChannel,
AvatarAction.DestroyDisplay(a.attacker, a.defender, a.implement)
)
case _ =>
damageLog.info(s"${bot.Name} killed ${bot.Sex.pronounObject}self")
- events ! AvatarServiceMessage(zoneChannel, AvatarAction.DestroyDisplay(cause.interaction.target, cause.interaction.target, 0))
+ events ! MessageEnvelope(zoneChannel, AvatarAction.DestroyDisplay(cause.interaction.target, cause.interaction.target, 0))
}
- events ! AvatarServiceMessage(nameChannel, AvatarAction.Killed(bot_guid, cause, None)) //align client interface fields with state
- events ! AvatarServiceMessage(zoneChannel, AvatarAction.PlanetsideAttributeToAll(bot_guid, 0, 0)) //health
+ events ! MessageEnvelope(nameChannel, bot_guid, AvatarAction.Killed(cause, None)) //align client interface fields with state
+ events ! MessageEnvelope(zoneChannel, PlanetsideAttribute(bot_guid, 0, 0)) //health
val attribute = DamageableEntity.attributionTo(cause, target.Zone, bot_guid)
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
nameChannel,
- AvatarAction.SendResponse(
- bot_guid,
+ bot_guid,
+ SendResponse(
DestroyMessage(bot_guid, attribute, bot_guid, pos)
) //how many players get this message?
)
@@ -402,13 +393,13 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
private def performEmote(): Unit = {
val zone = bot.Zone
zone.blockMap.sector(bot).livePlayerList.collect { t =>
- zone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendResponse(TriggerBotAction(bot.GUID)))
+ zone.LocalEvents ! MessageEnvelope(t.Name, SendResponse(TriggerBotAction(bot.GUID)))
}
}
private def tickLogic(): Unit = {
val zone = bot.Zone
- if (!bot.Destroyed && zone.AllPlayers.size > 0) {
+ if (!bot.Destroyed && zone.AllPlayers.nonEmpty) {
bot.zoneInteractions()
val rotateRNG = Random.nextDouble()
if (canRotate) {
@@ -424,10 +415,10 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
)
}
}
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
+ bot.GUID,
AvatarAction.PlayerState(
- bot.GUID,
bot.Position,
bot.Velocity,
bot.Orientation.z,
@@ -436,10 +427,10 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
0,
bot.Crouching,
bot.Jumping,
- false,
- bot.Cloaked,
- false,
- false
+ jump_thrust = false,
+ is_cloaked = bot.Cloaked,
+ spectator = false,
+ weaponInHand = false
)
)
if (canEmote) {
@@ -469,9 +460,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
override def StartJammeredSound(target: Any, dur: Int): Unit =
target match {
case obj: AvatarBot if !jammedSound =>
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 1)
+ PlanetsideAttribute(obj.GUID, 27, 1)
)
super.StartJammeredSound(obj, 3000)
case _ => ;
@@ -502,9 +493,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
override def CancelJammeredSound(target: Any): Unit =
target match {
case obj: AvatarBot if jammedSound =>
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 0)
+ PlanetsideAttribute(obj.GUID, 27, 0)
)
super.CancelJammeredSound(obj)
case _ => ;
@@ -521,10 +512,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
}
def UpdateAuraEffect(target: AuraEffectBehavior.Target) : Unit = {
- import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
val zone = target.Zone
val value = target.Aura.foldLeft(0)(_ + AvatarBotActor.auraEffectToAttributeValue(_))
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttributeToAll(target.GUID, 54, value))
+ zone.AvatarEvents ! MessageEnvelope(zone.id, PlanetsideAttribute(target.GUID, 54, value))
}
}
diff --git a/src/main/scala/net/psforever/objects/avatar/CorpseControl.scala b/src/main/scala/net/psforever/objects/avatar/CorpseControl.scala
index 6e1cafafe..3537cfbd7 100644
--- a/src/main/scala/net/psforever/objects/avatar/CorpseControl.scala
+++ b/src/main/scala/net/psforever/objects/avatar/CorpseControl.scala
@@ -8,8 +8,8 @@ import net.psforever.objects.serverobject.containable.{Containable, ContainableB
import net.psforever.packet.game.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage}
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.types.{PlanetSideEmpire, Vector3}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{ObjectDelete, SendResponse}
class CorpseControl(player: Player) extends Actor with ContainableBehavior {
def ContainerObject = player
@@ -25,9 +25,9 @@ class CorpseControl(player: Player) extends Actor with ContainableBehavior {
val obj = ContainerObject
obj.Find(item) match {
case Some(slot) =>
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
player.Zone.id,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectAttachMessage(obj.GUID, item.GUID, slot))
+ SendResponse(ObjectAttachMessage(obj.GUID, item.GUID, slot))
)
case None => ;
}
@@ -40,7 +40,7 @@ class CorpseControl(player: Player) extends Actor with ContainableBehavior {
val zone = obj.Zone
val events = zone.AvatarEvents
item.Faction = PlanetSideEmpire.NEUTRAL
- events ! AvatarServiceMessage(zone.id, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID))
+ events ! MessageEnvelope(zone.id, ObjectDelete(item.GUID))
}
def PutItemInSlotCallback(item: Equipment, slot: Int): Unit = {
@@ -48,10 +48,9 @@ class CorpseControl(player: Player) extends Actor with ContainableBehavior {
val zone = obj.Zone
val events = zone.AvatarEvents
val definition = item.Definition
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
zone.id,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
ObjectCreateDetailedMessage(
definition.ObjectId,
item.GUID,
@@ -65,12 +64,9 @@ class CorpseControl(player: Player) extends Actor with ContainableBehavior {
def SwapItemCallback(item: Equipment, fromSlot: Int): Unit = {
val obj = ContainerObject
val zone = obj.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- ObjectDetachMessage(obj.GUID, item.GUID, Vector3.Zero, 0f)
- )
+ SendResponse(ObjectDetachMessage(obj.GUID, item.GUID, Vector3.Zero, 0f))
)
}
}
diff --git a/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala b/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala
index d597ea565..b25803856 100644
--- a/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala
+++ b/src/main/scala/net/psforever/objects/avatar/PlayerControl.scala
@@ -25,9 +25,8 @@ import net.psforever.objects.zones._
import net.psforever.packet.game._
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.types._
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.local.LocalAction
import net.psforever.objects.locker.LockerContainerControl
import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment
import net.psforever.objects.serverobject.repair.Repairable
@@ -36,6 +35,8 @@ import net.psforever.objects.vital.collision.CollisionReason
import net.psforever.objects.vital.etc.{PainboxReason, SuicideReason}
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.packet.PlanetSideGamePacket
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{EventMessage, HintsAtAttacker, ObjectDelete, PlanetsideAttribute, SendResponse}
import org.joda.time.{LocalDateTime, Seconds}
import scala.concurrent.duration._
@@ -125,7 +126,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val zoneId = zone.id
sendResponse(zone, zoneId, PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
sendResponse(zone, zoneId, AvatarDeadStateMessage(DeadState.Alive, timer_max=0, timer=0, player.Position, player.Faction, unk5=true))
- sendResponse(zone, zoneId, AvatarAction.PlanetsideAttributeToAll(revivalTargetGuid, attribute_type=0, health))
+ sendResponse(zone, zoneId, PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
avatarActor ! AvatarActor.InitializeImplants
avatarActor ! AvatarActor.SuspendStaminaRegeneration(Duration(1, "second"))
@@ -147,14 +148,11 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
if (!(player.isMoving || user.isMoving)) { //only allow stationary heals
val newHealth = player.Health = originalHealth + 10
val magazine = item.Discharge()
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
uname,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
- )
+ SendResponse(InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong))
)
- events ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth))
+ events ! MessageEnvelope(zone.id, PlanetsideAttribute(guid, 0, newHealth))
player.LogActivity(
HealFromEquipment(
PlayerSource(user),
@@ -174,14 +172,11 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
}
if (player != user) {
//"Someone is trying to heal you"
- events ! AvatarServiceMessage(player.Name, AvatarAction.PlanetsideAttributeToAll(guid, 55, 1))
+ events ! MessageEnvelope(player.Name, PlanetsideAttribute(guid, 55, 1))
//progress bar remains visible for all heal attempts
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
uname,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- RepairMessage(guid, player.Health * 100 / definition.MaxHealth)
- )
+ SendResponse(RepairMessage(guid, player.Health * 100 / definition.MaxHealth))
)
}
}
@@ -219,14 +214,11 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val newArmor = player.Armor =
originalArmor + Repairable.applyLevelModifier(user, item, RepairToolValue(item)).toInt + definition.RepairMod
val magazine = item.Discharge()
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
uname,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
- )
+ SendResponse(InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong))
)
- events ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttributeToAll(guid, 4, player.Armor))
+ events ! MessageEnvelope(zone.id, PlanetsideAttribute(guid, 4, player.Armor))
player.LogActivity(
RepairFromEquipment(
PlayerSource(user),
@@ -247,16 +239,15 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
if (player != user) {
if (player.isAlive) {
//"Someone is trying to repair you" gets strobed twice for visibility
- val msg = AvatarServiceMessage(player.Name, AvatarAction.PlanetsideAttributeToAll(guid, 56, 1))
+ val msg = MessageEnvelope(player.Name, PlanetsideAttribute(guid, 56, 1))
events ! msg
import scala.concurrent.ExecutionContext.Implicits.global
context.system.scheduler.scheduleOnce(250 milliseconds, events, msg)
}
//progress bar remains visible for all repair attempts
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
uname,
- AvatarAction
- .SendResponse(Service.defaultPlayerGUID, RepairMessage(guid, player.Armor * 100 / player.MaxArmor))
+ SendResponse(RepairMessage(guid, player.Armor * 100 / player.MaxArmor))
)
}
}
@@ -321,16 +312,16 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
avatarActor ! AvatarActor.UpdateUseTime(kdef)
player.Slot(slot).Equipment = None //remove from slot immediately; must exist on client for now
TaskWorkflow.execute(GUIDTask.unregisterEquipment(zone.GUID, kit))
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttributeToAll(player.GUID, attribute, value)
+ PlanetsideAttribute(player.GUID, attribute, value)
)
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
player.Name,
AvatarAction.UseKit(kguid, kdef.ObjectId)
)
case _ =>
- player.Zone.AvatarEvents ! AvatarServiceMessage(
+ player.Zone.AvatarEvents ! MessageEnvelope(
player.Name,
AvatarAction.KitNotUsed(kit.GUID, msg)
)
@@ -344,15 +335,17 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val events = player.Zone.AvatarEvents
val resistance = player.TestArmMotion(slot)
if (resistance && !updateMyHolsterArm) {
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
player.Name,
- AvatarAction.ObjectHeld(player.GUID, before, -1)
+ player.GUID,
+ AvatarAction.ObjectHeld(before, -1)
)
} else if ((!resistance && before != slot && (player.DrawnSlot = slot) != before) && ItemSwapSlot != before) {
val mySlot = if (updateMyHolsterArm) slot else -1 //use as a short-circuit
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
Players.ZoneChannelIfSpectating(player),
- AvatarAction.ObjectHeld(player.GUID, mySlot, player.LastDrawnSlot)
+ player.GUID,
+ AvatarAction.ObjectHeld(mySlot, player.LastDrawnSlot)
)
val isHolsters = player.VisibleSlots.contains(slot)
val equipment = player.Slot(slot).Equipment.orElse { player.Slot(before).Equipment }
@@ -362,9 +355,10 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
log.info(s"${player.Name} has drawn a ${unholsteredItem.Definition.Name} from its holster")
if (unholsteredItem.Definition == GlobalDefinitions.remote_electronics_kit) {
//rek beam/icon colour must match the player's correct hack level
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
Players.ZoneChannelIfSpectating(player),
- AvatarAction.PlanetsideAttribute(unholsteredItem.GUID, 116, player.avatar.hackingSkillLevel())
+ unholsteredItem.GUID,
+ PlanetsideAttribute(unholsteredItem.GUID, 116, player.avatar.hackingSkillLevel())
)
}
case None => ()
@@ -376,7 +370,11 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
//make sure the player didn't just initialte an orbital strike. If not (the if below is true), make sure waypoint is removed
if (holsteredEquipment.Definition == GlobalDefinitions.command_detonater && player.avatar.cr.value > 3 &&
!player.avatar.cooldowns.purchase.exists(os => os._1 == "orbital_strike" && Seconds.secondsBetween(os._2, LocalDateTime.now()).getSeconds < 12)) {
- player.Zone.LocalEvents ! LocalServiceMessage(s"${player.Faction}", LocalAction.SendPacket(OrbitalStrikeWaypointMessage(player.GUID, None)))
+ player.Zone.LocalEvents ! MessageEnvelope(
+ s"${player.Faction}",
+ PlanetSideGUID(-1),
+ SendResponse(OrbitalStrikeWaypointMessage(player.GUID, None))
+ )
}
case None =>
log.info(s"${player.Name} lowers ${player.Sex.possessive} hand")
@@ -400,7 +398,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
if (exosuit == ExoSuitType.MAX) {
player.ResistArmMotion(PlayerControl.maxRestriction)
}
- player.Zone.AvatarEvents ! AvatarServiceMessage(
+ player.Zone.AvatarEvents ! MessageEnvelope(
player.Name,
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result)
)
@@ -532,7 +530,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
Deployables.initializeConstructionItem(player.avatar.certifications, citem)
}
val zone = player.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
Players.ZoneChannelIfSpectating(player),
AvatarAction.ChangeLoadout(
player.GUID,
@@ -548,7 +546,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
itemsToDrop
)
)
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
player.Name,
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result=true)
)
@@ -577,9 +575,9 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case Zone.Ground.CanNotPickupItem(_, item_guid, reason) =>
log.warn(s"${player.Name} failed to pick up an item ($item_guid) from the ground because $reason")
if (reason.startsWith("@")) {
- player.Zone.AvatarEvents ! AvatarServiceMessage(
+ player.Zone.AvatarEvents ! MessageEnvelope(
player.Name,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ChatMsg(ChatMessageType.UNK_227, reason))
+ SendResponse(ChatMsg(ChatMessageType.UNK_227, reason))
)
}
@@ -597,7 +595,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val trigger = new BoomerTrigger
trigger.Companion = obj.GUID
obj.Trigger = trigger
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, tool.GUID))
+ zone.AvatarEvents ! MessageEnvelope(zone.id, ObjectDelete(tool.GUID))
TaskWorkflow.execute(GUIDTask.unregisterEquipment(zone.GUID, tool))
player.Find(tool) match {
case Some(index) if player.VisibleSlots.contains(index) =>
@@ -649,7 +647,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case Player.LoseDeployable(obj) =>
if (player.avatar.deployables.Remove(obj)) {
- player.Zone.LocalEvents ! LocalServiceMessage(player.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
+ player.Zone.LocalEvents ! MessageEnvelope(player.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
}
case _ => ;
@@ -722,7 +720,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
//insert
afterHolsters.foreach(elem => player.Slot(elem.start).Equipment = elem.obj)
afterInventory.foreach(elem => player.Inventory.InsertQuickly(elem.start, elem.obj))
- player.Zone.AvatarEvents ! AvatarServiceMessage(
+ player.Zone.AvatarEvents ! MessageEnvelope(
Players.ZoneChannelIfSpectating(player),
AvatarAction.ChangeExosuit(
player.GUID,
@@ -748,7 +746,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
def loseDeployableOwnership(obj: Deployable): Boolean = {
if (player.avatar.deployables.Remove(obj)) {
obj.Actor ! Deployable.Ownership(None)
- player.Zone.LocalEvents ! LocalServiceMessage(player.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
+ player.Zone.LocalEvents ! MessageEnvelope(player.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
true
}
else {
@@ -769,18 +767,15 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case GlobalDefinitions.router_telepad => () /* no special animation */
case GlobalDefinitions.ace
if obj.Definition.deployAnimation == DeployAnimation.Standard =>
- zone.LocalEvents ! LocalServiceMessage(
+ val ownerGuid = obj.OwnerGuid.getOrElse(Default.GUID0)
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerEffectLocation(
- obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID),
- "spawn_object_effect",
- obj.Position,
- obj.Orientation
- )
+ ownerGuid,
+ LocalAction.TriggerEffectLocation("spawn_object_effect", obj.Position, obj.Orientation)
)
case GlobalDefinitions.advanced_ace
if obj.Definition.deployAnimation == DeployAnimation.Fdu =>
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PutDownFDU(player.GUID))
+ zone.AvatarEvents ! MessageEnvelope(zone.id, AvatarAction.PutDownFDU(player.GUID))
case _ =>
org.log4s
.getLogger(name = "Deployables")
@@ -883,9 +878,9 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
//always do armor update
if (damageToArmor > 0) {
val zone = target.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttributeToAll(target.GUID, 4, target.Armor)
+ PlanetsideAttribute(target.GUID, 4, target.Armor)
)
}
//choose
@@ -941,10 +936,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
target.LogActivity(cause)
//stat changes
if (damageToCapacitor > 0) {
- events ! AvatarServiceMessage(
- target.Name,
- AvatarAction.PlanetsideAttributeSelf(targetGUID, 7, target.Capacitor.toLong)
- )
+ events ! MessageEnvelope(target.Name, PlanetsideAttribute(targetGUID, 7, target.Capacitor.toLong))
announceConfrontation = true //TODO should we?
}
if (damageToStamina > 0) {
@@ -952,15 +944,15 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
announceConfrontation = true //TODO should we?
}
if (damageToHealth > 0) {
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 0, health))
+ events ! MessageEnvelope(zoneId, PlanetsideAttribute(targetGUID, 0, health))
announceConfrontation = true
}
val countableDamage = damageToHealth + damageToArmor
if(announceConfrontation) {
if (aggravated) {
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
zoneId,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, AggravatedDamageMessage(targetGUID, countableDamage))
+ SendResponse(AggravatedDamageMessage(targetGUID, countableDamage))
)
} else {
//activity on map
@@ -973,42 +965,37 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val name = pSource.Name
zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
case Some(tplayer) =>
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
target.Name,
- AvatarAction.HitHint(tplayer.GUID, target.GUID)
+ target.GUID,
+ HintsAtAttacker(tplayer.GUID)
)
case None =>
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
target.Name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- DamageWithPositionMessage(countableDamage, pSource.Position)
- )
+ SendResponse(DamageWithPositionMessage(countableDamage, pSource.Position))
)
}
case source =>
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
target.Name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- DamageWithPositionMessage(countableDamage, source.Position)
- )
+ SendResponse(DamageWithPositionMessage(countableDamage, source.Position))
)
}
case None =>
cause.interaction.cause match {
case o: PainboxReason =>
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
target.Name,
AvatarAction.EnvironmentalDamage(target.GUID, o.entity.GUID, countableDamage)
)
case _: CollisionReason =>
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
zoneId,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, AggravatedDamageMessage(targetGUID, countableDamage))
+ SendResponse(AggravatedDamageMessage(targetGUID, countableDamage))
)
case _ =>
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
target.Name,
AvatarAction.EnvironmentalDamage(target.GUID, ValidPlanetSideGUID(0), countableDamage)
)
@@ -1064,19 +1051,16 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
damageLog.info(s"${player.Name} killed ${player.Sex.pronounObject}self")
}
- events ! AvatarServiceMessage(nameChannel, AvatarAction.Killed(player_guid, cause, target.VehicleSeated)) //align client interface fields with state
- events ! AvatarServiceMessage(zoneChannel, AvatarAction.PlanetsideAttributeToAll(player_guid, 0, 0)) //health
+ events ! MessageEnvelope(nameChannel, player_guid, AvatarAction.Killed(cause, target.VehicleSeated)) //align client interface fields with state
+ events ! MessageEnvelope(zoneChannel, PlanetsideAttribute(player_guid, 0, 0)) //health
if (target.Capacitor > 0) {
target.Capacitor = 0
- events ! AvatarServiceMessage(nameChannel, AvatarAction.PlanetsideAttributeToAll(player_guid, 7, 0)) // capacitor
+ events ! MessageEnvelope(nameChannel, PlanetsideAttribute(player_guid, 7, 0)) // capacitor
}
val attribute = DamageableEntity.attributionTo(cause, target.Zone, player_guid)
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
nameChannel,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- DestroyMessage(player_guid, attribute, Service.defaultPlayerGUID, pos)
- ) //how many players get this message?
+ SendResponse(DestroyMessage(player_guid, attribute, Default.GUID0, pos)) //how many players get this message?
)
}
@@ -1105,12 +1089,12 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
override def StartJammeredSound(target: Any, dur: Int): Unit =
target match {
case obj: Player if !jammedSound =>
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 1)
+ PlanetsideAttribute(obj.GUID, 27, 1)
)
super.StartJammeredSound(obj, 3000)
- case _ => ;
+ case _ => ()
}
/**
@@ -1141,12 +1125,12 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
override def CancelJammeredSound(target: Any): Unit =
target match {
case obj: Player if jammedSound =>
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id,
- AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 0)
+ PlanetsideAttribute(obj.GUID, 27, 0)
)
super.CancelJammeredSound(obj)
- case _ => ;
+ case _ => ()
}
def RepairToolValue(item: Tool): Float = {
@@ -1167,9 +1151,9 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
obj.Find(item) match {
case Some(slot) =>
PutItemInSlotCallback(item, slot)
- case None => ;
+ case None => ()
}
- case _ => ;
+ case _ => ()
}
}
@@ -1188,7 +1172,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
if (slot == obj.DrawnSlot) {
obj.DrawnSlot = Player.HandsDownSlot
}
- events ! AvatarServiceMessage(toChannel, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID))
+ events ! MessageEnvelope(toChannel, ObjectDelete(item.GUID))
}
def PutItemInSlotCallback(item: Equipment, slot: Int): Unit = {
@@ -1209,10 +1193,10 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case Some(obj: BoomerDeployable) =>
val deployables = player.avatar.deployables
if (!deployables.Contains(obj) && deployables.Valid(obj)) {
- events ! AvatarServiceMessage(toChannel, AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- GenericObjectAction2Message(1, player.GUID, trigger.GUID)
- ))
+ events ! MessageEnvelope(
+ toChannel,
+ SendResponse(GenericObjectAction2Message(1, player.GUID, trigger.GUID))
+ )
Players.gainDeployableOwnership(player, obj, deployables.AddOverLimit)
}
case _ => ()
@@ -1228,15 +1212,12 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case _ => ()
}
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
toChannel,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- OCM.detailed(item, ObjectCreateMessageParent(guid, slot))
- )
+ SendResponse(OCM.detailed(item, ObjectCreateMessageParent(guid, slot)))
)
if (!player.isBackpack && willBeVisible) {
- events ! AvatarServiceMessage(zone.id, AvatarAction.EquipmentInHand(guid, guid, slot, item))
+ events ! MessageEnvelope(zone.id, guid, AvatarAction.EquipmentInHand(guid, slot, item))
}
}
@@ -1250,17 +1231,16 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
} else {
player.Name
}
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
toChannel,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID)
+ ObjectDelete(item.GUID)
)
}
def UpdateAuraEffect(target: AuraEffectBehavior.Target) : Unit = {
- import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
val zone = target.Zone
val value = target.Aura.foldLeft(0)(_ + PlayerControl.auraEffectToAttributeValue(_))
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttributeToAll(target.GUID, 54, value))
+ zone.AvatarEvents ! MessageEnvelope(zone.id, PlanetsideAttribute(target.GUID, 54, value))
}
}
@@ -1290,11 +1270,11 @@ object PlayerControl {
}
def sendResponse(zone: Zone, channel: String, msg: PlanetSideGamePacket): Unit = {
- zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.SendResponse(Service.defaultPlayerGUID, msg))
+ zone.AvatarEvents ! MessageEnvelope(channel, SendResponse(msg))
}
- def sendResponse(zone: Zone, channel: String, msg: AvatarAction.Action): Unit = {
- zone.AvatarEvents ! AvatarServiceMessage(channel, msg)
+ def sendResponse(zone: Zone, channel: String, filter: PlanetSideGUID, msg: EventMessage): Unit = {
+ zone.AvatarEvents ! MessageEnvelope(channel, filter, msg)
}
def maxRestriction(player: Player, slot: Int): Boolean = {
diff --git a/src/main/scala/net/psforever/objects/avatar/interaction/WithEntrance.scala b/src/main/scala/net/psforever/objects/avatar/interaction/WithEntrance.scala
index 4e15faf4f..0e475b85f 100644
--- a/src/main/scala/net/psforever/objects/avatar/interaction/WithEntrance.scala
+++ b/src/main/scala/net/psforever/objects/avatar/interaction/WithEntrance.scala
@@ -6,6 +6,8 @@ import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, Env
import net.psforever.objects.serverobject.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
import net.psforever.objects.serverobject.interior.{Sidedness, TraditionalInteriorAware}
import net.psforever.objects.zones.interaction.InteractsWithZone
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import net.psforever.types.Vector3
import scala.annotation.unused
@@ -90,33 +92,32 @@ class WithEntrance()
): Sidedness = {
import net.psforever.objects.{Player, Vehicle}
import net.psforever.packet.game.ChatMsg
- import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
- import net.psforever.types.{ChatMessageType, PlanetSideGUID}
+ import net.psforever.types.ChatMessageType
val channel = obj match {
case p: Player => p.Name
case v: Vehicle => v.Actor.toString()
case _ => ""
}
if (door.Outwards == Vector3.Zero) {
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
channel,
- AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "Door not configured."))
+ SendResponse(ChatMsg(ChatMessageType.UNK_229, "Door not configured."))
)
WhichSide
} else {
val result = Vector3.DotProduct(Vector3.Unit(obj.Position - door.Position), door.Outwards) > 0f
if (result && WhichSide != Sidedness.OutsideOf) {
//outside
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
channel,
- AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "You are now outside"))
+ SendResponse(ChatMsg(ChatMessageType.UNK_229, "You are now outside"))
)
Sidedness.OutsideOf
} else if (!result && WhichSide != Sidedness.InsideOf) {
//inside
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
channel,
- AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "You are now inside"))
+ SendResponse(ChatMsg(ChatMessageType.UNK_229, "You are now inside"))
)
Sidedness.InsideOf
} else {
diff --git a/src/main/scala/net/psforever/objects/avatar/interaction/WithGantry.scala b/src/main/scala/net/psforever/objects/avatar/interaction/WithGantry.scala
index 09d4a330a..dc20521f6 100644
--- a/src/main/scala/net/psforever/objects/avatar/interaction/WithGantry.scala
+++ b/src/main/scala/net/psforever/objects/avatar/interaction/WithGantry.scala
@@ -7,8 +7,8 @@ import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, Env
import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad
import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game.{ChatMsg, PlayerStateShiftMessage, ShiftState}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import net.psforever.services.hart.ShuttleState
import net.psforever.types.ChatMessageType
@@ -35,18 +35,12 @@ class WithGantry(val channel: String)
player.VehicleSeated.isEmpty =>
val (pos, ang) = Vehicles.dismountShuttle(shuttle, field.mountPoint)
val events = shuttle.Zone.AvatarEvents
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
channel,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- PlayerStateShiftMessage(ShiftState(0, pos, ang, None)))
- )
- events ! AvatarServiceMessage(
+ SendResponse(PlayerStateShiftMessage(ShiftState(0, pos, ang, None))))
+ events ! MessageEnvelope(
channel,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- ChatMsg(ChatMessageType.UNK_227, "@Vehicle_OS_PlacedOutsideHallway")
- )
+ SendResponse(ChatMsg(ChatMessageType.UNK_227, "@Vehicle_OS_PlacedOutsideHallway"))
)
case (Some(_: Vehicle) , _)=>
obj.Actor ! RespondsToZoneEnvironment.Timer(
diff --git a/src/main/scala/net/psforever/objects/avatar/interaction/WithWater.scala b/src/main/scala/net/psforever/objects/avatar/interaction/WithWater.scala
index 73af2ad60..ae2ca54af 100644
--- a/src/main/scala/net/psforever/objects/avatar/interaction/WithWater.scala
+++ b/src/main/scala/net/psforever/objects/avatar/interaction/WithWater.scala
@@ -7,7 +7,8 @@ import net.psforever.objects.serverobject.environment.interaction.common.Watery
import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction}
import net.psforever.objects.zones.interaction.InteractsWithZone
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.OxygenState
import scala.concurrent.duration._
@@ -299,7 +300,7 @@ class WithWater(val channel: String)
cond: OxygenStateTarget,
data: Option[OxygenStateTarget]
): Unit = {
- obj.Zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.OxygenState(cond, data))
+ obj.Zone.AvatarEvents ! MessageEnvelope(channel, AvatarAction.OxygenState(cond, data))
}
}
diff --git a/src/main/scala/net/psforever/objects/avatar/scoring/Statistic.scala b/src/main/scala/net/psforever/objects/avatar/scoring/Statistic.scala
index e6b5b03a3..10dcd36b9 100644
--- a/src/main/scala/net/psforever/objects/avatar/scoring/Statistic.scala
+++ b/src/main/scala/net/psforever/objects/avatar/scoring/Statistic.scala
@@ -2,7 +2,7 @@
package net.psforever.objects.avatar.scoring
/**
- * Organizes the eight fields one would find in an `AvatarServiceMessage` statistic field.
+ * Organizes the eight fields one would find in an statistic field.
* The `_c` fields and the `_s` fields are paired when the values populate the packet
* where `c` stands for "campaign" and `s` stands for "session".
* "Session" values reflect on the UI as the K in K/D
diff --git a/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala b/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala
index fbdfa85ca..18a4585fa 100644
--- a/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala
+++ b/src/main/scala/net/psforever/objects/ce/DeployableBehavior.scala
@@ -6,9 +6,9 @@ import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects._
import net.psforever.objects.zones.Zone
import net.psforever.packet.game._
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SetEmpire
+import net.psforever.services.local.LocalAction
import net.psforever.types.PlanetSideEmpire
import scala.concurrent.duration._
@@ -111,7 +111,7 @@ trait DeployableBehavior {
obj,
toOwner = "",
toFaction,
- DeployableInfo(obj.GUID, Deployable.Icon.apply(obj.Definition.Item), obj.Position, Service.defaultPlayerGUID)
+ DeployableInfo(obj.GUID, Deployable.Icon.apply(obj.Definition.Item), obj.Position, Default.GUID0)
)
startOwnerlessDecay()
}
@@ -198,14 +198,13 @@ trait DeployableBehavior {
None
}
//zone build
- localEvents ! LocalServiceMessage(zone.id, LocalAction.DeployItem(obj))
- //zone map icon
- localEvents ! LocalServiceMessage(
- obj.Faction.toString,
- LocalAction.DeployableMapIcon(
- Service.defaultPlayerGUID,
- DeploymentAction.Build,
- DeployableInfo(obj.GUID, Deployable.Icon(obj.Definition.Item), obj.Position, obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID))
+ localEvents ! BundledEnvelope(
+ /* zone build */
+ MessageEnvelope(zone.id, LocalAction.DeployItem(obj)),
+ /* zone map icon */
+ MessageEnvelope(
+ obj.Faction.toString,
+ LocalAction.DeployableMapIcon(DeploymentAction.Build, DeployableInfo(obj.GUID, Deployable.Icon(obj.Definition.Item), obj.Position, obj.OwnerGuid.getOrElse(Default.GUID0)))
)
)
//local build management
@@ -250,7 +249,7 @@ trait DeployableBehavior {
//there's no special meaning behind directing any replies from from zone governance straight back to zone governance
//this deployable control agency, however, will be expiring and can not be a recipient
zone.Deployables ! Zone.Deployable.Dismiss(obj)
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
LocalAction.EliminateDeployable(obj, obj.GUID, obj.Position, deletionType)
)
@@ -285,27 +284,21 @@ object DeployableBehavior {
val localEvents = zone.LocalEvents
if (originalFaction != toFaction) {
obj.Faction = toFaction
- //visual tells in regards to ownership by faction
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.SetEmpire(Service.defaultPlayerGUID, dGuid, toFaction)
- )
- //remove knowledge by the previous owner's faction
- localEvents ! LocalServiceMessage(
- originalFaction.toString,
- LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Dismiss, info)
+ localEvents ! BundledEnvelope(
+ /* visual tells in regards to ownership by faction */
+ MessageEnvelope(zone.id, SetEmpire(dGuid, toFaction)),
+ /* remove knowledge by the previous owner's faction */
+ MessageEnvelope(originalFaction.toString, LocalAction.DeployableMapIcon(DeploymentAction.Dismiss, info)),
+ /* display to the given faction */
+ MessageEnvelope(toFaction.toString, LocalAction.DeployableMapIcon(DeploymentAction.Build, info))
)
//remove deployable from original owner's toolbox and UI counter
- zone.AllPlayers.filter(p => obj.OriginalOwnerName.contains(p.Name))
- .foreach { originalOwner =>
+ localEvents ! BundledEnvelope(zone.AllPlayers
+ .filter(p => obj.OriginalOwnerName.contains(p.Name))
+ .map { originalOwner =>
originalOwner.avatar.deployables.Remove(obj)
- originalOwner.Zone.LocalEvents ! LocalServiceMessage(originalOwner.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
- }
- //display to the given faction
- localEvents ! LocalServiceMessage(
- toFaction.toString,
- LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Build, info)
- )
+ MessageEnvelope(originalOwner.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
+ })
}
}
}
diff --git a/src/main/scala/net/psforever/objects/ce/TelepadLike.scala b/src/main/scala/net/psforever/objects/ce/TelepadLike.scala
index ad018f418..f90273a38 100644
--- a/src/main/scala/net/psforever/objects/ce/TelepadLike.scala
+++ b/src/main/scala/net/psforever/objects/ce/TelepadLike.scala
@@ -9,7 +9,9 @@ import net.psforever.objects.vehicles.Utility.InternalTelepad
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{GenericObjectActionMessage, ObjectCreateMessage, ObjectDeleteMessage}
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.local.LocalAction
import net.psforever.types.PlanetSideGUID
trait TelepadLike {
@@ -113,24 +115,22 @@ object TelepadLike {
normally dispatched while the Router is transitioned into its Deploying state
it is safe, however, to perform these actions at any time during and after the Deploying state
*/
- events ! LocalServiceMessage(
- zoneId,
- LocalAction.SendResponse(
- ObjectCreateMessage(
- udef.ObjectId,
- utilityGUID,
- ObjectCreateMessageParent(routerGUID, 2), //TODO stop assuming slot number
- udef.Packet.ConstructorData(obj).get
+ events ! BundledEnvelope(
+ MessageEnvelope(
+ zoneId,
+ SendResponse(
+ ObjectCreateMessage(
+ udef.ObjectId,
+ utilityGUID,
+ ObjectCreateMessageParent(routerGUID, 2), //TODO stop assuming slot number
+ udef.Packet.ConstructorData(obj).get
+ )
)
- )
- )
- events ! LocalServiceMessage(
- zoneId,
- LocalAction.SendResponse(GenericObjectActionMessage(utilityGUID, 27))
- )
- events ! LocalServiceMessage(
- zoneId,
- LocalAction.SendResponse(GenericObjectActionMessage(utilityGUID, 30))
+ ),
+ MessageEnvelope(zoneId, SendResponse(Seq(
+ GenericObjectActionMessage(utilityGUID, 27),
+ GenericObjectActionMessage(utilityGUID, 30)
+ )))
)
LinkTelepad(zone, utilityGUID)
}
@@ -138,14 +138,10 @@ object TelepadLike {
def LinkTelepad(zone: Zone, telepadGUID: PlanetSideGUID): Unit = {
val events = zone.LocalEvents
val zoneId = zone.id
- events ! LocalServiceMessage(
- zoneId,
- LocalAction.SendResponse(GenericObjectActionMessage(telepadGUID, 27))
- )
- events ! LocalServiceMessage(
- zoneId,
- LocalAction.SendResponse(GenericObjectActionMessage(telepadGUID, 28))
- )
+ events ! MessageEnvelope(zoneId, SendResponse(Seq(
+ GenericObjectActionMessage(telepadGUID, 27),
+ GenericObjectActionMessage(telepadGUID, 28)
+ )))
}
def InitializeTelepadDeployable(zone: Zone, internal: InternalTelepad, pad: TelepadDeployable): Unit = {
@@ -175,7 +171,7 @@ class TelepadControl(obj: InternalTelepad) extends akka.actor.Actor {
oldTpad.Actor ! TelepadLike.SeverLink(obj)
}
obj.Telepad = None
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendResponse(ObjectDeleteMessage(obj.GUID, 0)))
+ zone.LocalEvents ! MessageEnvelope(zone.id, SendResponse(ObjectDeleteMessage(obj.GUID, 0)))
case TelepadLike.RequestLink(tpad: TelepadDeployable) =>
val zone = obj.Zone
@@ -196,7 +192,7 @@ class TelepadControl(obj: InternalTelepad) extends akka.actor.Actor {
}
} else {
val channel = obj.Owner.asInstanceOf[Vehicle].OwnerName.getOrElse("")
- zone.LocalEvents ! LocalServiceMessage(channel, LocalAction.RouterTelepadMessage("@Teleport_NotDeployed"))
+ zone.LocalEvents ! MessageEnvelope(channel, LocalAction.RouterTelepadMessage("@Teleport_NotDeployed"))
tpad.Actor ! TelepadLike.SeverLink(obj)
}
@@ -204,7 +200,7 @@ class TelepadControl(obj: InternalTelepad) extends akka.actor.Actor {
if (obj.Telepad.contains(tpad.GUID)) {
obj.Telepad = None
val zone = obj.Zone
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendResponse(ObjectDeleteMessage(obj.GUID, 0)))
+ zone.LocalEvents ! MessageEnvelope(zone.id, SendResponse(ObjectDeleteMessage(obj.GUID, 0)))
}
case _ => ()
diff --git a/src/main/scala/net/psforever/objects/equipment/ArmorSiphonBehavior.scala b/src/main/scala/net/psforever/objects/equipment/ArmorSiphonBehavior.scala
index 5547f36fd..9341e324d 100644
--- a/src/main/scala/net/psforever/objects/equipment/ArmorSiphonBehavior.scala
+++ b/src/main/scala/net/psforever/objects/equipment/ArmorSiphonBehavior.scala
@@ -10,8 +10,8 @@ import net.psforever.objects.vital.RepairFromArmorSiphon
import net.psforever.objects.vital.etc.{ArmorSiphonModifiers, ArmorSiphonReason}
import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.packet.game.QuantityUpdateMessage
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.types.PlanetSideGUID
import scala.collection.mutable
@@ -78,9 +78,9 @@ object ArmorSiphonBehavior {
if(before < after) {
obj.LogActivity(RepairFromArmorSiphon(asr.siphon.Definition, VehicleSource(obj), before - after))
val zone = obj.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 0, after)
+ PlanetsideAttribute(obj.GUID, 0, after)
)
}
case _ => ;
@@ -97,9 +97,9 @@ object ArmorSiphonBehavior {
val siphon = siphonSlot.Equipment.get.asInstanceOf[Tool]
val zone = obj.Zone
//update current charge level
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
obj.Actor.toString,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, QuantityUpdateMessage(siphon.AmmoSlot.Box.GUID, siphon.Magazine))
+ SendResponse(QuantityUpdateMessage(siphon.AmmoSlot.Box.GUID, siphon.Magazine))
)
siphonRecharge.put(guid, context.system.scheduler.scheduleWithFixedDelay(
initialDelay = 3000 milliseconds,
@@ -119,9 +119,9 @@ object ArmorSiphonBehavior {
val before = siphon.Magazine
val after = siphon.Magazine = before + 1
if (after > before) {
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
obj.Actor.toString,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, QuantityUpdateMessage(siphon.AmmoSlot.Box.GUID, after))
+ SendResponse(QuantityUpdateMessage(siphon.AmmoSlot.Box.GUID, after))
)
if (after == siphon.MaxMagazine) {
endSiphonRecharge(guid)
diff --git a/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala b/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala
index 84443d560..cd50540b2 100644
--- a/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala
+++ b/src/main/scala/net/psforever/objects/equipment/JammingUnit.scala
@@ -8,9 +8,9 @@ import net.psforever.objects.vehicles.MountedWeapons
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.zones.{Zone, ZoneAware}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.types.Vector3
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.collection.mutable
import scala.concurrent.duration._
@@ -234,7 +234,6 @@ trait JammableBehavior {
* @see `Service`
* @see `VehicleAction`
* @see `VehicleService`
- * @see `VehicleServiceMessage`
* @see `Zone.VehicleEvents`
*/
trait JammableMountedWeapons extends JammableBehavior {
@@ -243,9 +242,9 @@ trait JammableMountedWeapons extends JammableBehavior {
override def StartJammeredSound(target: Any, dur: Int): Unit = {
target match {
case obj: PlanetSideServerObject with MountedWeapons with JammableUnit if !jammedSound =>
- obj.Zone.VehicleEvents ! VehicleServiceMessage(
+ obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1)
+ PlanetsideAttribute(obj.GUID, 27, 1)
)
super.StartJammeredSound(target, dur)
case _ => ;
@@ -264,9 +263,9 @@ trait JammableMountedWeapons extends JammableBehavior {
override def CancelJammeredSound(target: Any): Unit = {
target match {
case obj: PlanetSideServerObject if jammedSound =>
- obj.Zone.VehicleEvents ! VehicleServiceMessage(
+ obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 0)
+ PlanetsideAttribute(obj.GUID, 27, 0)
)
case _ => ;
}
@@ -308,9 +307,9 @@ object JammableMountedWeapons {
def JammedWeaponStatus(zone: Zone, target: Equipment with JammableUnit, statusCode: Int): Unit = {
target.Jammed = statusCode == 1
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 27, statusCode)
+ PlanetsideAttribute(target.GUID, 27, statusCode)
)
}
}
diff --git a/src/main/scala/net/psforever/objects/inventory/GridInventory.scala b/src/main/scala/net/psforever/objects/inventory/GridInventory.scala
index eafc880bb..d77f30dd1 100644
--- a/src/main/scala/net/psforever/objects/inventory/GridInventory.scala
+++ b/src/main/scala/net/psforever/objects/inventory/GridInventory.scala
@@ -702,15 +702,18 @@ object GridInventory {
*/
private def sortKnapsack(list: List[InventoryItem], width: Int, height: Int): Unit = {
val root = new KnapsackNode(0, 0, width, height)
- list.foreach(item => {
- findKnapsackSpace(root, item.obj.Tile.Width, item.obj.Tile.Height) match {
+ list.foreach { item =>
+ val tile = item.obj.Tile
+ val twidth = tile.Width
+ val theight = tile.Height
+ findKnapsackSpace(root, twidth, theight) match {
case Some(node) =>
- splitKnapsackSpace(node, item.obj.Tile.Width, item.obj.Tile.Height)
+ splitKnapsackSpace(node, twidth, theight)
item.start = node.y * width + node.x
- case _ => ;
+ case _ =>
item.start = -1
}
- })
+ }
}
/**
@@ -720,42 +723,32 @@ object GridInventory {
* Horizontal space for the `down` child is emphasized over vertical space for the `right` child.
* By dividing and reducing a defined space like this, it can be tightly packed with a given number of elements.
*
- * Due to the nature of the knapsack problem and the naivette of the algorithm, small holes in the solution are bound to crop-up.
+ * Due to the nature of the knapsack problem and the naivete of the algorithm, small holes in the solution are bound to crop-up.
* @param x the x-coordinate, upper left corner
* @param y the y-coordinate, upper left corner
* @param width the width
* @param height the height
*/
- private class KnapsackNode(var x: Int, var y: Int, var width: Int, var height: Int) {
- private var used: Boolean = false
- var down: Option[KnapsackNode] = None
- var right: Option[KnapsackNode] = None
+ private class KnapsackNode(val x: Int, val y: Int, val width: Int, val height: Int) {
+ private var used: Boolean = false
+ private var down: Option[KnapsackNode] = None
+ private var right: Option[KnapsackNode] = None
def Used: Boolean = used
- /**
- * Initialize the `down` and `right` children of this node.
- */
- def Split(): Unit = {
- used = true
- down = Some(new KnapsackNode(0, 0, 0, 0))
- right = Some(new KnapsackNode(0, 0, 0, 0))
- }
+ def Down: Option[KnapsackNode] = down
+
+ def Right: Option[KnapsackNode] = right
/**
- * Change the dimensions of the node.
- *
- * Use: `{node}(nx, ny, nw, nh)`
- * @param nx the new x-coordinate, upper left corner
- * @param ny the new y-coordinate, upper left corner
- * @param nw the new width
- * @param nh the new height
- */
- def apply(nx: Int, ny: Int, nw: Int, nh: Int): Unit = {
- x = nx
- y = ny
- width = nw
- height = nh
+ * Initialize the `down` and `right` children of this node.
+ * @param insertDown new "down" knapsack division
+ * @param insertRight new "right" knapsack division
+ */
+ def Split(insertDown: KnapsackNode, insertRight: KnapsackNode): Unit = {
+ used = true
+ down = Some(insertDown)
+ right = Some(insertRight)
}
}
@@ -768,7 +761,7 @@ object GridInventory {
*/
private def findKnapsackSpace(node: KnapsackNode, width: Int, height: Int): Option[KnapsackNode] = {
if (node.Used) {
- findKnapsackSpace(node.right.get, width, height).orElse(findKnapsackSpace(node.down.get, width, height))
+ findKnapsackSpace(node.Right.get, width, height).orElse(findKnapsackSpace(node.Down.get, width, height))
} else if (width <= node.width && height <= node.height) {
Some(node)
} else {
@@ -787,13 +780,14 @@ object GridInventory {
* @param height height of the element
*/
private def splitKnapsackSpace(node: KnapsackNode, width: Int, height: Int): Unit = {
- node.Split()
- node.down.get(node.x, node.y + height, node.width, node.height - height)
- node.right.get(node.x + width, node.y, node.width - width, height)
+ node.Split(
+ new KnapsackNode(node.x, node.y + height, node.width, node.height - height),
+ new KnapsackNode(node.x + width, node.y, node.width - width, height)
+ )
}
def toPrintedList(inv: GridInventory): String = {
- val list = new StringBuilder
+ val list = new mutable.StringBuilder
list.append("\n")
inv.Items.zipWithIndex.foreach {
case (InventoryItem(obj, start), index) =>
@@ -803,6 +797,6 @@ object GridInventory {
}
def toPrintedGrid(inv: GridInventory): String = {
- new StringBuilder().append("\n").append(inv.grid.toSeq.grouped(inv.width).mkString("\n")).toString
+ new mutable.StringBuilder().append("\n").append(inv.grid.toSeq.grouped(inv.width).mkString("\n")).toString
}
}
diff --git a/src/main/scala/net/psforever/objects/locker/LockerContainerControl.scala b/src/main/scala/net/psforever/objects/locker/LockerContainerControl.scala
index 67eab42f8..bef430721 100644
--- a/src/main/scala/net/psforever/objects/locker/LockerContainerControl.scala
+++ b/src/main/scala/net/psforever/objects/locker/LockerContainerControl.scala
@@ -6,8 +6,8 @@ import net.psforever.objects.equipment.Equipment
import net.psforever.objects.serverobject.containable.{Containable, ContainableBehavior}
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.packet.game.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{ObjectDelete, SendResponse}
import net.psforever.types.{PlanetSideEmpire, Vector3}
/**
@@ -19,7 +19,7 @@ import net.psforever.types.{PlanetSideEmpire, Vector3}
class LockerContainerControl(locker: LockerContainer, toChannel: String)
extends Actor
with ContainableBehavior {
- def ContainerObject = locker
+ def ContainerObject: LockerContainer = locker
def receive: Receive =
containerBehavior
@@ -34,9 +34,9 @@ class LockerContainerControl(locker: LockerContainer, toChannel: String)
val obj = ContainerObject
obj.Find(item) match {
case Some(slot) =>
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
toChannel,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectAttachMessage(obj.GUID, item.GUID, slot))
+ SendResponse(ObjectAttachMessage(obj.GUID, item.GUID, slot))
)
case None => ;
}
@@ -46,17 +46,16 @@ class LockerContainerControl(locker: LockerContainer, toChannel: String)
def RemoveItemFromSlotCallback(item: Equipment, slot: Int): Unit = {
val zone = locker.Zone
- zone.AvatarEvents ! AvatarServiceMessage(toChannel, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID))
+ zone.AvatarEvents ! MessageEnvelope(toChannel, ObjectDelete(item.GUID))
}
def PutItemInSlotCallback(item: Equipment, slot: Int): Unit = {
val zone = locker.Zone
val definition = item.Definition
item.Faction = PlanetSideEmpire.NEUTRAL
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
toChannel,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
ObjectCreateDetailedMessage(
definition.ObjectId,
item.GUID,
@@ -69,12 +68,9 @@ class LockerContainerControl(locker: LockerContainer, toChannel: String)
def SwapItemCallback(item: Equipment, fromSlot: Int): Unit = {
val zone = locker.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
toChannel,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- ObjectDetachMessage(locker.GUID, item.GUID, Vector3.Zero, 0f)
- )
+ SendResponse(ObjectDetachMessage(locker.GUID, item.GUID, Vector3.Zero, 0f))
)
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableAmenity.scala b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableAmenity.scala
index b9369c38a..ec412e277 100644
--- a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableAmenity.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableAmenity.scala
@@ -3,7 +3,9 @@ package net.psforever.objects.serverobject.damage
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.vital.interaction.DamageResult
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.packet.game.PlanetsideAttributeMessage
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
/**
* The "control" `Actor` mixin for damage-handling code
@@ -25,8 +27,7 @@ object DamageableAmenity {
* A destroyed `Amenity` target dispatches two messages to chance its model and operational states.
* The common manifestation is a sparking entity that will no longer report being accessible.
* These `PlanetSideAttributeMessage` attributes are the same as reported during zone load client configuration.
- * @see `AvatarAction.PlanetsideAttributeToAll`
- * @see `AvatarServiceMessage`
+ * @see `PlanetsideAttribute`
* @see `Zone.AvatarEvents`
* @param target the entity being destroyed
* @param cause historical information about the damage
@@ -36,7 +37,9 @@ object DamageableAmenity {
val zoneId = zone.id
val events = zone.AvatarEvents
val targetGUID = target.GUID
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 50, 1))
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 51, 1))
+ events ! MessageEnvelope(
+ zoneId,
+ SendResponse(PlanetsideAttributeMessage(targetGUID, 50, 1), PlanetsideAttributeMessage(targetGUID, 51, 1))
+ )
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableEntity.scala b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableEntity.scala
index e594de2db..1e5224f04 100644
--- a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableEntity.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableEntity.scala
@@ -1,14 +1,16 @@
//Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.damage
+import net.psforever.objects.Default
import net.psforever.objects.equipment.JammableUnit
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.vital.resolution.ResolutionCalculations
import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideGUID
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
/**
* The "control" `Actor` mixin for damage-handling code,
@@ -140,12 +142,11 @@ object DamageableEntity {
* - reports its adjusted its health;
* - alert the activity monitor for that `Zone` about the damage; and,
* - provide a feedback message regarding the damage.
- * @see `AvatarAction.PlanetsideAttributeToAll`
- * @see `AvatarAction.SendResponse`
- * @see `AvatarServiceMessage`
+ * @see `PlanetsideAttribute`
+ * @see `SendResponse`
* @see `DamageFeedbackMessage`
* @see `JammableUnit.Jammered`
- * @see `Service.defaultPlayerGUID`
+ * @see `Default.GUID0`
* @see `Zone.Activity`
* @see `Zone.AvatarEvents`
* @see `Zone.HotSpot.Activity`
@@ -165,9 +166,9 @@ object DamageableEntity {
def DamageToHealth(target: Damageable.Target, cause: DamageResult, amount: Int): Boolean = {
if (amount > 0 && !target.Destroyed) {
val zone = target.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttributeToAll(target.GUID, 0, target.Health)
+ PlanetsideAttribute(target.GUID, 0, target.Health)
)
true
}
@@ -181,8 +182,7 @@ object DamageableEntity {
* - reports its adjusted its health; and,
* - report about its destruction.
* @see `AvatarAction.Destroy`
- * @see `AvatarAction.PlanetsideAttribute`
- * @see `AvatarServiceMessage`
+ * @see `PlanetsideAttribute`
* @see `DamageFeedbackMessage`
* @see `JammableUnit.ClearJammeredSound`
* @see `JammableUnit.ClearJammeredStatus`
@@ -199,12 +199,12 @@ object DamageableEntity {
val zoneId = zone.id
val tguid = target.GUID
val attribution = attributionTo(cause, target.Zone)
- zone.AvatarEvents ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, target.Health))
+ zone.AvatarEvents ! MessageEnvelope(zoneId, PlanetsideAttribute(tguid, 0, target.Health))
if (target.isInstanceOf[SpawnTube]) {}//do nothing to prevent issue #1057
else {
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zoneId,
- AvatarAction.Destroy(tguid, attribution, Service.defaultPlayerGUID, target.Position)
+ AvatarAction.Destroy(tguid, attribution, Default.GUID0, target.Position)
)
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableMountable.scala b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableMountable.scala
index 2356fb11b..90e859a9e 100644
--- a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableMountable.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableMountable.scala
@@ -1,13 +1,14 @@
//Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.damage
-import net.psforever.objects.Player
+import net.psforever.objects.{Default, Player}
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.packet.game.DamageWithPositionMessage
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{HintsAtAttacker, SendResponse}
/**
* Functions to assist other damage-dealing code for objects that contain users.
@@ -17,12 +18,11 @@ object DamageableMountable {
/**
* A damaged target alerts its occupants (as it is a `Mountable` object) of the source of the damage.
*
- * @see `AvatarAction.HitHint`
- * @see `AvatarAction.SendResponse`
- * @see `AvatarServiceMessage`
+ * @see `HitHint`
+ * @see `SendResponse`
* @see `DamageWithPositionMessage`
* @see `Mountable.Seats`
- * @see `Service.defaultPlayerGUID`
+ * @see `Default.GUID0`
* @see `Zone.AvatarEvents`
* @see `Zone.LivePlayers`
* @param target the entity being damaged
@@ -37,32 +37,34 @@ object DamageableMountable {
val zone = target.Zone
val events = zone.AvatarEvents
val occupants = target.Seats.values.toSeq.flatMap { seat => seat.occupants.filter(_.isAlive) }
- ((cause.adversarial match {
- case Some(adversarial) => Some(adversarial.attacker)
- case None => None
- }) match {
- case Some(pSource: PlayerSource) => //player damage
- val name = pSource.Name
- (zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
- case Some(player) =>
- AvatarAction.HitHint(player.GUID, player.GUID)
- case None =>
- AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(countableDamage, pSource.Position))
- }) match {
- case AvatarAction.HitHint(_, guid) =>
- occupants.map { tplayer => (tplayer.Name, AvatarAction.HitHint(guid, tplayer.GUID)) }
- case msg =>
- occupants.map { tplayer => (tplayer.Name, msg) }
- }
- case Some(source) => //object damage
- val msg = AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(countableDamage, source.Position))
- occupants.map { tplayer => (tplayer.Name, msg) }
- case None =>
- List.empty
- }).foreach {
- case (channel, msg) =>
- events ! AvatarServiceMessage(channel, msg)
- }
+ events ! BundledEnvelope(
+ ((cause.adversarial match {
+ case Some(adversarial) => Some(adversarial.attacker)
+ case None => None
+ }) match {
+ case Some(pSource: PlayerSource) => //player damage
+ val name = pSource.Name
+ (zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
+ case Some(player) =>
+ HintsAtAttacker(player.GUID)
+ case None =>
+ SendResponse(DamageWithPositionMessage(countableDamage, pSource.Position))
+ }) match {
+ case msg @ HintsAtAttacker(guid) =>
+ occupants.map { tplayer => (tplayer.Name, guid, msg) }
+ case msg =>
+ occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
+ }
+ case Some(source) => //object damage
+ val msg = SendResponse(DamageWithPositionMessage(countableDamage, source.Position))
+ occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
+ case None =>
+ List.empty
+ }).map {
+ case (channel, filter, msg) =>
+ MessageEnvelope(channel, filter, msg)
+ }
+ )
}
/**
@@ -78,7 +80,7 @@ object DamageableMountable {
val targets = target.Seats.values.flatMap(_.occupant).filter(_.isAlive)
targets.foreach { player =>
//make llu visible to others in zone if passenger is carrying one
- player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.DropSpecialItem())
+ player.Zone.AvatarEvents ! MessageEnvelope(player.Name, AvatarAction.DropSpecialItem())
//player.LogActivity(cause)
player.Actor ! Player.Die(
DamageInteraction(interaction.resolution, SourceEntry(player), interaction.cause, interaction.hitPos)
diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableVehicle.scala b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableVehicle.scala
index 28cb07aae..4d609076a 100644
--- a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableVehicle.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableVehicle.scala
@@ -2,7 +2,7 @@
package net.psforever.objects.serverobject.damage
import akka.actor.{Actor, Cancellable}
-import net.psforever.objects.{Vehicle, Vehicles}
+import net.psforever.objects.{Default, Vehicle, Vehicles}
import net.psforever.objects.equipment.JammableUnit
import net.psforever.objects.serverobject.damage.Damageable.Target
import net.psforever.objects.sourcing.VehicleSource
@@ -12,8 +12,8 @@ import net.psforever.objects.vital.resolution.ResolutionCalculations
import net.psforever.objects.zones.Zone
import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.packet.game.DamageWithPositionMessage
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.types.Vector3
import scala.concurrent.duration._
@@ -102,10 +102,9 @@ trait DamageableVehicle
* Most all vehicles and the weapons mounted to them can jam
* if the projectile that strikes (near) them has jammering properties.
* If this vehicle has shields that were affected by previous damage, that is also reported to the clients.
- * @see `Service.defaultPlayerGUID`
+ * @see `Default.GUID0`
* @see `Vehicle.CargoHolds`
- * @see `VehicleAction.PlanetsideAttribute`
- * @see `VehicleServiceMessage`
+ * @see `PlanetsideAttribute`
* @param target the entity being destroyed
* @param cause historical information about the damage
* @param amount how much damage was performed
@@ -142,27 +141,27 @@ trait DamageableVehicle
}
//stat changes
if (damageToShields > 0) {
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
shieldChannel,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, obj.Definition.shieldUiAttribute, obj.Shields)
+ PlanetsideAttribute(targetGUID, obj.Definition.shieldUiAttribute, obj.Shields)
)
announceConfrontation = true
}
if (damageToHealth > 0) {
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
healthChannel,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, obj.Health)
+ PlanetsideAttribute(targetGUID, 0, obj.Health)
)
announceConfrontation = true
}
}
if (announceConfrontation) {
if (showAsAggravated) {
- val msg = VehicleAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(totalDamage, Vector3.Zero))
+ val msg = SendResponse(DamageWithPositionMessage(totalDamage, Vector3.Zero))
obj.Seats.values
.collect { case seat if seat.occupant.nonEmpty => seat.occupant.get.Name }
.foreach { channel =>
- events ! VehicleServiceMessage(channel, msg)
+ events ! MessageEnvelope(channel, msg)
}
}
else {
@@ -180,13 +179,11 @@ trait DamageableVehicle
* Finally, the vehicle is tasked for deconstruction.
* @see `Deployment.TryDeploymentChange`
* @see `DriveState.Undeploying`
- * @see `Service.defaultPlayerGUID`
+ * @see `Default.GUID0`
* @see `Vehicle.CargoHolds`
- * @see `VehicleAction.PlanetsideAttribute`
+ * @see `PlanetsideAttribute`
* @see `RemoverActor.AddTask`
* @see `RemoverActor.ClearSpecific`
- * @see `VehicleServiceMessage`
- * @see `VehicleServiceMessage.Decon`
* @see `Zone.VehicleEvents`
* @param target the entity being destroyed
* @param cause historical information about the damage
@@ -217,9 +214,9 @@ trait DamageableVehicle
//shields
if (obj.Shields > 0) {
obj.Shields = 0
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, obj.Definition.shieldUiAttribute, 0)
+ PlanetsideAttribute(target.GUID, obj.Definition.shieldUiAttribute, 0)
)
}
//database entry
@@ -243,22 +240,22 @@ trait DamageableVehicle
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
val obj = DamageableObject
- val guid0 = Service.defaultPlayerGUID
+ val guid0 = Default.GUID0
val zone = obj.Zone
val zoneid = zone.id
val events = zone.VehicleEvents
//health to 1, shields to 0
obj.Health = 1
val guid = obj.GUID
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
zoneid,
- VehicleAction.PlanetsideAttribute(guid0, guid, 0, 1)
+ PlanetsideAttribute(guid, 0, 1)
)
if (obj.Shields > 0) {
obj.Shields = 0
- zone.VehicleEvents ! VehicleServiceMessage(
+ events ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, obj.Definition.shieldUiAttribute, 0)
+ PlanetsideAttribute(obj.GUID, obj.Definition.shieldUiAttribute, 0)
)
}
//aggravation cancel
diff --git a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableWeaponTurret.scala b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableWeaponTurret.scala
index bef9a243a..250aa61c2 100644
--- a/src/main/scala/net/psforever/objects/serverobject/damage/DamageableWeaponTurret.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/damage/DamageableWeaponTurret.scala
@@ -9,10 +9,10 @@ import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.types.Vector3
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.vehicle.support.TurretUpgrader
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
+import net.psforever.services.base.support.SupportActor
+import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader}
/**
* The "control" `Actor` mixin for damage-handling code for `WeaponTurret` objects.
@@ -62,21 +62,22 @@ trait DamageableWeaponTurret
//TODO some turrets have shields
if (damageToHealth > 0) {
DamageableMountable.DamageAwareness(DamageableObject, cause, damageToHealth)
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
zoneId,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, obj.Health)
+ PlanetsideAttribute(targetGUID, 0, obj.Health)
)
announceConfrontation = true
}
}
if (announceConfrontation) {
if (aggravated) {
- val msg = VehicleAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(damageToHealth, Vector3.Zero))
- obj.Seats.values
+ val msg = SendResponse(DamageWithPositionMessage(damageToHealth, Vector3.Zero))
+ events ! BundledEnvelope(obj.Seats.values
.collect { case seat if seat.occupant.nonEmpty => seat.occupant.get.Name }
- .foreach { channel =>
- events ! VehicleServiceMessage(channel, msg)
+ .map { channel =>
+ MessageEnvelope(channel, msg)
}
+ )
}
else {
//activity on map
@@ -103,16 +104,15 @@ object DamageableWeaponTurret {
* A destroyed target dispatches a message to conceal (delete) its weapons from users.
* If affected by a jammer property, the jammer propoerty will be removed.
* If the type of entity is a `WeaponTurret`, the weapons are converted to their "normal" upgrade state.
- * @see `AvatarAction.DeleteObject`
- * @see `AvatarServiceMessage`
+ * @see `DeleteObject`
* @see `MountedWeapons`
* @see `MountedWeapons.Weapons`
- * @see `Service.defaultPlayerGUID`
+ * @see `Default.GUID0`
* @see `TurretUpgrade.None`
* @see `TurretUpgrader.AddTask`
* @see `TurretUpgrader.ClearSpecific`
* @see `WeaponTurret`
- * @see `VehicleServiceMessage.TurretUpgrade`
+ * @see `TurretMessage`
* @see `Zone.AvatarEvents`
* @see `Zone.VehicleEvents`
* @param target the entity being destroyed;
@@ -125,20 +125,18 @@ object DamageableWeaponTurret {
val zone = target.Zone
val zoneId = zone.id
val avatarEvents = zone.AvatarEvents
- target.Weapons.values
- .filter {
- _.Equipment.nonEmpty
+ avatarEvents ! BundledEnvelope(target.Weapons.values
+ .filter(_.Equipment.nonEmpty)
+ .map { slot =>
+ MessageEnvelope(zoneId, ObjectDelete(slot.Equipment.get.GUID))
}
- .foreach(slot => {
- val wep = slot.Equipment.get
- avatarEvents ! AvatarServiceMessage(zoneId, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, wep.GUID))
- })
+ )
target match {
case turret: WeaponTurret =>
if (turret.Upgrade != TurretUpgrade.None) {
val vehicleEvents = zone.VehicleEvents
- vehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(turret), zone))
- vehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(turret, zone, TurretUpgrade.None))
+ vehicleEvents ! TurretEnvelope(SupportActor.ClearSpecific(List(turret), zone))
+ vehicleEvents ! TurretEnvelope(TurretUpgrader.AddTask(turret, zone, TurretUpgrade.None))
}
case _ =>
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/deploy/DeploymentBehavior.scala b/src/main/scala/net/psforever/objects/serverobject/deploy/DeploymentBehavior.scala
index 0eb8cf718..2544b2ded 100644
--- a/src/main/scala/net/psforever/objects/serverobject/deploy/DeploymentBehavior.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/deploy/DeploymentBehavior.scala
@@ -4,8 +4,8 @@ package net.psforever.objects.serverobject.deploy
import akka.actor.{Actor, ActorRef, Cancellable}
import net.psforever.objects.Default
import net.psforever.types.{DriveState, Vector3}
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.vehicle.VehicleAction
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -97,16 +97,15 @@ trait DeploymentBehavior {
val guid = obj.GUID
val zone = obj.Zone
val zoneChannel = zone.id
- val GUID0 = Service.defaultPlayerGUID
//TODO remove this arbitrary allowance angle when no longer helpful
if (obj.Orientation.x > 30 && obj.Orientation.x < 330) {
obj.DeploymentState = prevState
prevState
} else if (state == DriveState.Deploying) {
obj.Velocity = Some(Vector3.Zero) //no velocity
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zoneChannel,
- VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero)
+ VehicleAction.DeployRequest(guid, state, 0, unk2=false, Vector3.Zero)
)
deploymentTimer.cancel()
deploymentTimer = context.system.scheduler.scheduleOnce(obj.DeployTime.milliseconds)({
@@ -115,9 +114,9 @@ trait DeploymentBehavior {
state
} else if (state == DriveState.Deployed) {
obj.Velocity = Some(Vector3.Zero) //no velocity
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zoneChannel,
- VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero)
+ VehicleAction.DeployRequest(guid, state, 0, unk2=false, Vector3.Zero)
)
state
} else {
@@ -134,11 +133,10 @@ trait DeploymentBehavior {
val guid = obj.GUID
val zone = obj.Zone
val zoneChannel = zone.id
- val GUID0 = Service.defaultPlayerGUID
if (state == DriveState.Undeploying) {
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zoneChannel,
- VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero)
+ VehicleAction.DeployRequest(guid, state, 0, unk2=false, Vector3.Zero)
)
import scala.concurrent.ExecutionContext.Implicits.global
deploymentTimer.cancel()
@@ -147,9 +145,9 @@ trait DeploymentBehavior {
})
state
} else if (state == DriveState.Mobile) {
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zoneChannel,
- VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero)
+ VehicleAction.DeployRequest(guid, state, 0, unk2=false, Vector3.Zero)
)
state
} else {
diff --git a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala
index 802a6ed31..56a18b455 100644
--- a/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/dome/ForceDomeControl.scala
@@ -14,8 +14,9 @@ import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.prop.DamageWithPosition
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.ChatMsg
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.local.LocalAction
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGeneratorState, Vector3}
import scala.annotation.unused
@@ -45,9 +46,9 @@ object ForceDomeControl {
val owner = dome.Owner
val zone = owner.Zone
owner.Actor ! BuildingActor.AmenityStateChange(dome)
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.UpdateForceDomeStatus(Service.defaultPlayerGUID, owner.GUID, activationState)
+ LocalAction.UpdateForceDomeStatus(owner.GUID, activationState)
)
}
@@ -124,11 +125,11 @@ object ForceDomeControl {
state: Boolean
): Unit = {
val zone = building.Zone
- val message = LocalAction.SendResponse(ChatMsg(
+ val message = SendResponse(ChatMsg(
ChatMessageType.UNK_229,
s"The Capitol force dome at ${building.Name} will remain ${if (state) "activated" else "deactivated"}."
))
- zone.LocalEvents ! LocalServiceMessage(zone.id, message)
+ zone.LocalEvents ! MessageEnvelope(zone.id, message)
}
/**
@@ -138,13 +139,13 @@ object ForceDomeControl {
*/
def NormalDomeStateMessage(building: Building): Unit = {
val events = building.Zone.LocalEvents
- val message = LocalAction.SendResponse(ChatMsg(
+ val message = SendResponse(ChatMsg(
ChatMessageType.UNK_227,
"Expected capitol force dome state change will resume."
))
- building.PlayersInSOI.foreach { player =>
- events ! LocalServiceMessage(player.Name, message)
- }
+ events ! BundledEnvelope(building.PlayersInSOI.map { player =>
+ MessageEnvelope(player.Name, message)
+ })
}
/**
diff --git a/src/main/scala/net/psforever/objects/serverobject/doors/Door.scala b/src/main/scala/net/psforever/objects/serverobject/doors/Door.scala
index eb90ed91d..9d8d635ee 100644
--- a/src/main/scala/net/psforever/objects/serverobject/doors/Door.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/doors/Door.scala
@@ -67,37 +67,10 @@ object Door {
*/
sealed trait Exchange
- /**
- * Message that carries the result of the processed request message back to the original user (`player`).
- * @param player the player who sent this request message
- * @param msg the original packet carrying the request
- * @param response the result of the processed request
- */
- final case class DoorMessage(player: Player, msg: UseItemMessage, response: Exchange)
-
- /**
- * This door will open.
- */
- final case class OpenEvent() extends Exchange
-
- /**
- * This door will close.
- */
- final case class CloseEvent() extends Exchange
-
- /**
- * This door will do nothing.
- */
- final case class NoEvent() extends Exchange
-
type LockingMechanismLogic = (PlanetSideServerObject, Door) => Boolean
final case class UpdateMechanism(mechanism: LockingMechanismLogic) extends Exchange
- case object Lock extends Exchange
-
- case object Unlock extends Exchange
-
/**
* Overloaded constructor.
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
diff --git a/src/main/scala/net/psforever/objects/serverobject/doors/DoorControl.scala b/src/main/scala/net/psforever/objects/serverobject/doors/DoorControl.scala
index 1cd30f116..056966621 100644
--- a/src/main/scala/net/psforever/objects/serverobject/doors/DoorControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/doors/DoorControl.scala
@@ -7,8 +7,10 @@ import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObjec
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.structures.PoweredAmenityControl
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse}
+import net.psforever.services.base.envelope.GenericResponseEnvelope
+import net.psforever.services.base.support.SupportActor
+import net.psforever.services.local.support.{DoorCloseActor, DoorMessage}
+import net.psforever.services.local.{LocalAction, LocalStamp}
/**
* An `Actor` that handles messages being dispatched to a specific `Door`.
@@ -19,24 +21,21 @@ class DoorControl(door: Door)
with FactionAffinityBehavior.Check {
def FactionObject: FactionAffinity = door
- private var isLocked: Boolean = false
private var lockingMechanism: Door.LockingMechanismLogic = DoorControl.alwaysOpen
def commonBehavior: Receive = checkBehavior
.orElse {
- case Door.Lock =>
- isLocked = true
+ case Door.UpdateMechanism(logic) =>
+ lockingMechanism = logic
if (door.isOpen) {
val zone = door.Zone
door.Open = None
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.DoorSlamsShut(door))
+ zone.LocalEvents ! DoorMessage(
+ zone.id,
+ LocalAction.DoorCloses(door.GUID),
+ SupportActor.ClearSpecific(List(door), zone)
+ )
}
-
- case Door.Unlock =>
- isLocked = false
-
- case Door.UpdateMechanism(logic) =>
- lockingMechanism = logic
}
def poweredStateLogic: Receive =
@@ -48,7 +47,7 @@ class DoorControl(door: Door)
case CommonMessages.Use(player, _) =>
testToOpenDoor(player, door, door.Definition.initialOpeningDistance, sender())
- case IFFLock.DoorOpenResponse(target: Player) if !isLocked =>
+ case IFFLock.DoorOpenResponse(target: Player) =>
DoorControl.openDoor(target, door)
case _ => ()
@@ -57,7 +56,7 @@ class DoorControl(door: Door)
def unpoweredStateLogic: Receive = {
commonBehavior
.orElse {
- case CommonMessages.Use(player, _) if !isLocked =>
+ case CommonMessages.Use(player, _) =>
//without power, the door opens freely
DoorControl.openDoor(player, door)
@@ -83,7 +82,7 @@ class DoorControl(door: Door)
): Unit = {
if (
Doors.testForSpecificTargetHoldingDoorOpen(player, door, maximumDistance * maximumDistance).contains(player) &&
- lockingMechanism(player, door) && !isLocked
+ lockingMechanism(player, door)
) {
DoorControl.openDoor(player, door, replyTo)
}
@@ -107,20 +106,21 @@ object DoorControl {
*/
private def openDoor(player: Player, door: Door, replyTo: ActorRef = Default.Actor): Unit = {
val zone = door.Zone
- val doorGUID = door.GUID
if (!door.isOpen) {
//global open
door.Open = player
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! DoorMessage(
zone.id,
- LocalAction.DoorOpens(Service.defaultPlayerGUID, zone, door)
+ LocalAction.DoorOpens(zone, door),
+ DoorCloseActor.DoorIsOpen(door, zone, System.currentTimeMillis())
)
} else {
//the door should already open, but the requesting player does not see it as open
- replyTo ! LocalServiceResponse(
+ replyTo ! GenericResponseEnvelope(
+ LocalStamp,
player.Name,
- Service.defaultPlayerGUID,
- LocalResponse.DoorOpens(doorGUID)
+ Default.GUID0,
+ LocalAction.DoorOpens(door.Zone, door)
)
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala b/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala
index a7b0c78d5..223354272 100644
--- a/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/generator/GeneratorControl.scala
@@ -12,9 +12,9 @@ import net.psforever.objects.serverobject.terminals.{GeneratorTerminalDefinition
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.TriggerEffectMessage
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{PlanetSideGeneratorState, Vector3}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.message.SendResponse
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
@@ -111,12 +111,9 @@ class GeneratorControl(gen: Generator)
super.DestructionAwareness(gen, gen.LastDamage.get)
GeneratorControl.UpdateOwner(gen, Some(GeneratorControl.Event.Destroyed))
//kaboom
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- TriggerEffectMessage(gen.GUID, "explosion_generator", None, None)
- )
+ SendResponse(TriggerEffectMessage(gen.GUID, "explosion_generator", None, None))
)
queuedExplosion.cancel()
queuedExplosion = Default.Cancellable
diff --git a/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala b/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala
index b52f4afd6..bc29ce162 100644
--- a/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/hackable/GenericHackables.scala
@@ -11,9 +11,10 @@ import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObjec
import net.psforever.objects.zones.blockmap.BlockMapEntity
import net.psforever.packet.game.{GenericObjectActionMessage, HackMessage, HackState, HackState1, HackState7, TriggeredSound}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope, HackEntityEnvelope}
+import net.psforever.services.local.LocalAction
import scala.annotation.unused
import scala.util.{Failure, Success}
@@ -88,10 +89,9 @@ object GenericHackables {
} else {
(HackState.Ongoing, progress.toInt)
}
- target.Zone.AvatarEvents ! AvatarServiceMessage(
+ target.Zone.AvatarEvents ! MessageEnvelope(
hacker.Name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
HackMessage(progressType, target.GUID, hacker.GUID, progressGrade, 0L, progressState, HackState7.Unk8)
)
)
@@ -171,14 +171,17 @@ object GenericHackables {
val zoneId = zone.id
val pguid = tplayer.GUID
log.info(s"${user.Name} hacked a ${target.Definition.Name}")
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zoneId,
- LocalAction.TriggerSound(pguid, target.HackSound, tplayer.Position, 30, 0.49803925f)
+ pguid,
+ LocalAction.TriggerSound(target.HackSound, tplayer.Position, 30, 0.49803925f)
)
- zone.LocalEvents ! LocalServiceMessage(
+ val duration = target.HackEffectDuration(user.avatar.hackingSkillLevel())
+ zone.LocalEvents ! HackEntityEnvelope(
zoneId,
- LocalAction
- .HackTemporarily(pguid, zone, target, hackValue, hackClearValue, target.HackEffectDuration(user.avatar.hackingSkillLevel()))
+ pguid,
+ LocalAction.HackObject(target.GUID, hackValue, HackState7.Unk8),
+ HackClearActor.ObjectIsHacked(target, zone, hackClearValue, HackState7.Unk8, duration)
)
case Failure(_) =>
log.warn(s"Hack message failed on target: ${target.Definition.Name}@${target.GUID.guid}")
@@ -203,29 +206,19 @@ object GenericHackables {
val currVirus = building.virusId
building.virusId = 8
building.virusInstalledBy = None
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction
- .ClearTemporaryHack(pguid, target)
- )
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(target))
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 60))
+ SendResponse(GenericObjectActionMessage(target.GUID, 60))
)
currVirus match {
case 0L =>
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach { iff =>
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction.ClearTemporaryHack(PlanetSideGUID(0), iff)
- )
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(iff))
}
case 4L =>
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach { term =>
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction.ClearTemporaryHack(PlanetSideGUID(0), term)
- )
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(term))
}
case _ => ()
}
@@ -239,19 +232,13 @@ object GenericHackables {
case 0L =>
if (virus != 0) {
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach { iff =>
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction.ClearTemporaryHack(PlanetSideGUID(0), iff)
- )
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(iff))
}
}
case 4L =>
if (virus != 4) {
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach { term =>
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction.ClearTemporaryHack(PlanetSideGUID(0), term)
- )
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(term))
}
}
case _ => ()
@@ -274,42 +261,42 @@ object GenericHackables {
val hackState = hackStateMap.getOrElse(virus, HackState7.Unk8)
building.virusId = virus
building.virusInstalledBy = Some(tplayer.Faction.id)
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zoneId,
- LocalAction.TriggerSound(pguid, TriggeredSound.TREKSuccessful, tplayer.Position, 30, 0.49803925f)
+ pguid,
+ LocalAction.TriggerSound(TriggeredSound.TREKSuccessful, tplayer.Position, 30, 0.49803925f)
)
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! HackEntityEnvelope(
zoneId,
- LocalAction
- .HackTemporarily(pguid, zone, target, installedVirusDuration, hackClearValue, installedVirusDuration, unk2=hackState)
+ pguid,
+ LocalAction.HackObject(target.GUID, installedVirusDuration.toLong, hackState),
+ HackClearActor.ObjectIsHacked(target, zone, hackClearValue, hackState, installedVirusDuration)
)
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 61))
- )
- zone.LocalEvents ! LocalServiceMessage(
- zone.id,
- LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 58))
+ SendResponse(GenericObjectActionMessage(target.GUID, 61), GenericObjectActionMessage(target.GUID, 58))
)
//amenities if applicable
virus match {
case 0L =>
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach{ iff =>
- var setHacked = iff.asInstanceOf[PlanetSideServerObject with Hackable]
- setHacked.HackedBy = tplayer
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction.HackTemporarily(pguid, zone, iff, hackValue, hackClearValue, installedVirusDuration)
- )
+ iff.HackedBy = tplayer
+ zone.LocalEvents ! HackEntityEnvelope(
+ zoneId,
+ pguid,
+ LocalAction.HackObject(target.GUID, hackValue.toLong, HackState7.Unk8),
+ HackClearActor.ObjectIsHacked(target, zone, hackClearValue, HackState7.Unk8, installedVirusDuration)
+ )
}
case 4L =>
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach{ term =>
- var setHacked = term.asInstanceOf[PlanetSideServerObject with Hackable]
- setHacked.HackedBy = tplayer
- zone.LocalEvents ! LocalServiceMessage(
- zoneId,
- LocalAction.HackTemporarily(pguid, zone, term, hackValue, hackClearValue, installedVirusDuration)
- )
+ term.HackedBy = tplayer
+ zone.LocalEvents ! HackEntityEnvelope(
+ zoneId,
+ pguid,
+ LocalAction.HackObject(term.GUID, hackValue.toLong, HackState7.Unk8),
+ HackClearActor.ObjectIsHacked(target, zone, hackClearValue, HackState7.Unk8, installedVirusDuration)
+ )
}
case _ => ()
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/locks/IFFLocks.scala b/src/main/scala/net/psforever/objects/serverobject/locks/IFFLocks.scala
index 4e10f1fba..da3516190 100644
--- a/src/main/scala/net/psforever/objects/serverobject/locks/IFFLocks.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/locks/IFFLocks.scala
@@ -1,8 +1,7 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.locks
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
object IFFLocks {
@@ -14,9 +13,6 @@ object IFFLocks {
*/
def FinishResecuringIFFLock(lock: IFFLock)(): Unit = {
val zone = lock.Zone
- lock.Zone.LocalEvents ! LocalServiceMessage(
- zone.id,
- LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, lock)
- )
+ lock.Zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(lock))
}
}
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 29bd0f511..21a78ed9b 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnControl.scala
@@ -11,6 +11,7 @@ import net.psforever.objects.sourcing.AmenitySource
import net.psforever.objects.vital.TerminalUsedActivity
import net.psforever.objects.zones.{Zone, ZoneAware, Zoning}
import net.psforever.objects.{Default, PlanetSideGameObject, Player, Vehicle}
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{PlanetSideGUID, TransactionType, Vector3}
import scala.annotation.tailrec
@@ -128,7 +129,7 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
}
trackedOrder = None
handleOrderFunc = NewTasking
- pad.Zone.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad) //cautious animation reset
+ pad.Zone.VehicleEvents ! MessageEnvelope(pad.Zone.id, VehicleSpawnPad.ResetSpawnPad(pad)) //cautious animation reset
self ! akka.actor.Kill //should cause the actor to restart, which will abort any trapped messages
case _ => ()
@@ -164,19 +165,17 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
//first queued order
orders = List(order)
queueManagementTask()
- pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(
+ pad.Zone.VehicleEvents ! MessageEnvelope(
name,
- VehicleSpawnPad.Reminders.Queue,
- Some(s"@SVCP_PositionInQueue^2~^2~")
+ VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_PositionInQueue^2~^2~"))
)
case -1 =>
//new order
orders = orders :+ order
val size = orders.size + 1
- pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(
+ pad.Zone.VehicleEvents ! MessageEnvelope(
name,
- VehicleSpawnPad.Reminders.Queue,
- Some(s"@SVCP_PositionInQueue^$size~^$size~")
+ VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_PositionInQueue^$size~^$size~"))
)
case n if orders(n).vehicle.Definition ne order.vehicle.Definition =>
//replace existing order with new order
@@ -185,10 +184,9 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
val originalVehicle = originalOrder.vehicle.Definition.Name
orders = (orders.take(n) :+ order) ++ orders.drop(n+1)
VehicleSpawnControl.DisposeVehicle(originalOrder.vehicle, zone)
- zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(
+ zone.VehicleEvents ! MessageEnvelope(
name,
- VehicleSpawnPad.Reminders.Queue,
- Some(s"@SVCP_ReplacedVehicleWithVehicle^@$originalVehicle~^@${order.vehicle.Definition.Name}~")
+ VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_ReplacedVehicleWithVehicle^@$originalVehicle~^@${order.vehicle.Definition.Name}~"))
)
case _ =>
//order is the duplicate of an existing order; do nothing to the queue
@@ -245,10 +243,9 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
val newOrder = VehicleSpawnControl.Order(driver, vehicle)
recursiveOrderReminder(orders.iterator, size)
trace(s"processing next order - a ${vehicle.Definition.Name} for $name")
- pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(
+ pad.Zone.VehicleEvents ! MessageEnvelope(
name,
- VehicleSpawnPad.Reminders.Queue,
- Some(s"@SVCP_PositionInQueue^1~^$size~")
+ VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_PositionInQueue^1~^$size~"))
)
trackedOrder = Some(newOrder) //guard on
context.system.scheduler.scheduleOnce(2000 milliseconds, concealPlayer, newOrder)
@@ -324,7 +321,10 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
private def CancelOrder(vehicle: Vehicle, player: Player, msg: Option[String]): Unit = {
if (vehicle.Seats.values.count(_.isOccupied) == 0) {
VehicleSpawnControl.DisposeSpawnedVehicle(vehicle, player, pad.Zone)
- pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(player.Name, VehicleSpawnPad.Reminders.Cancelled, msg)
+ pad.Zone.VehicleEvents ! MessageEnvelope(
+ player.Name,
+ VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Cancelled, msg)
+ )
}
}
@@ -451,10 +451,9 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
entry: VehicleSpawnPad.VehicleOrder,
cause: Option[Any]
): Unit = {
- pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(
+ pad.Zone.VehicleEvents ! MessageEnvelope(
entry.player.Name,
- VehicleSpawnPad.Reminders.Blocked,
- cause
+ VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, cause)
)
}
@@ -465,10 +464,9 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
): Unit = {
if (iter.hasNext) {
val recipient = iter.next()
- pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder(
+ pad.Zone.VehicleEvents ! MessageEnvelope(
recipient.player.Name,
- VehicleSpawnPad.Reminders.Queue,
- Some(s"@SVCP_PositionInQueue^$position~^$size~")
+ VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_PositionInQueue^$position~^$size~"))
)
recursiveOrderReminder(iter, size, position + 1)
}
@@ -564,7 +562,7 @@ object VehicleSpawnControl {
*/
private def DisposeSpawnedVehicle(vehicle: Vehicle, player: Player, zone: Zone): Unit = {
DisposeVehicle(vehicle, zone)
- zone.VehicleEvents ! VehicleSpawnPad.RevealPlayer(player.GUID)
+ zone.VehicleEvents ! MessageEnvelope(zone.id, VehicleSpawnPad.RevealPlayer(player.GUID))
}
/**
diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala b/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala
index 4b9bb47c4..340cb235d 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/VehicleSpawnPad.scala
@@ -5,6 +5,7 @@ import net.psforever.objects.serverobject.interior.Sidedness
import net.psforever.objects.{Player, Vehicle}
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.serverobject.terminals.Terminal
+import net.psforever.services.base.message.SelfRespondingEvent
import net.psforever.types.PlanetSideGUID
/**
@@ -25,7 +26,6 @@ class VehicleSpawnPad(spDef: VehicleSpawnPadDefinition) extends Amenity {
}
object VehicleSpawnPad {
-
/**
* Message to the spawn pad to enqueue the following vehicle order.
* This is the entry point to vehicle spawn pad functionality.
@@ -39,14 +39,14 @@ object VehicleSpawnPad {
* @see `GenericObjectActionMessage`
* @param player_guid the player
*/
- final case class ConcealPlayer(player_guid: PlanetSideGUID)
+ final case class ConcealPlayer(player_guid: PlanetSideGUID) extends SelfRespondingEvent
/**
* Message is intended to undo the effects of the above message, `ConcealPlayer`.
* @see `ConcealPlayer`
* @param player_guid the player
*/
- final case class RevealPlayer(player_guid: PlanetSideGUID)
+ final case class RevealPlayer(player_guid: PlanetSideGUID) extends SelfRespondingEvent
/**
* Message to attach the vehicle to the spawn pad's lifting platform ("put on rails").
@@ -55,7 +55,7 @@ object VehicleSpawnPad {
* @param vehicle the vehicle being spawned
* @param pad the spawn pad
*/
- final case class AttachToRails(vehicle: Vehicle, pad: VehicleSpawnPad)
+ final case class AttachToRails(vehicle: Vehicle, pad: VehicleSpawnPad) extends SelfRespondingEvent
/**
* Message to detach the vehicle from the spawn pad's lifting platform ("put on rails").
@@ -63,72 +63,64 @@ object VehicleSpawnPad {
* @param vehicle the vehicle being spawned
* @param pad the spawn pad
*/
- final case class DetachFromRails(vehicle: Vehicle, pad: VehicleSpawnPad)
+ final case class DetachFromRails(vehicle: Vehicle, pad: VehicleSpawnPad) extends SelfRespondingEvent
/**
* Message that resets the spawn pad for its next order fulfillment operation by lowering the lifting platform.
* @see `GenericObjectActionMessage`
* @param pad the spawn pad
*/
- final case class ResetSpawnPad(pad: VehicleSpawnPad)
+ final case class ResetSpawnPad(pad: VehicleSpawnPad) extends SelfRespondingEvent
/**
* Message that acts as callback to the driver that the process of sitting in the driver mount will be initiated soon.
* This information should only be communicated to the driver's client only.
- * @param driver_name the person who will drive the vehicle
* @param vehicle the vehicle being spawned
* @param pad the spawn pad
*/
- final case class StartPlayerSeatedInVehicle(driver_name: String, vehicle: Vehicle, pad: VehicleSpawnPad)
+ final case class StartPlayerSeatedInVehicle(vehicle: Vehicle, pad: VehicleSpawnPad) extends SelfRespondingEvent
/**
* Message that acts as callback to the driver that the process of sitting in the driver mount should be finished.
* This information should only be communicated to the driver's client only.
- * @param driver_name the person who will drive the vehicle
* @param vehicle the vehicle being spawned
* @param pad the spawn pad
*/
- final case class PlayerSeatedInVehicle(
- driver_name: String,
- vehicle: Vehicle,
- pad: VehicleSpawnPad
- ) //TODO while using fake rails
+ //TODO while using fake rails (later edit: what does this mean?)
+ final case class PlayerSeatedInVehicle(vehicle: Vehicle, pad: VehicleSpawnPad) extends SelfRespondingEvent
/**
* Message that starts the newly-spawned vehicle to begin driving away from the spawn pad.
* Information about the driving process is available on the vehicle itself.
* This information should only be communicated to the driver's client only.
* @see `VehicleDefinition`
- * @param driver_name the person who will drive the vehicle
* @param vehicle the vehicle
* @param pad the spawn pad
*/
- final case class ServerVehicleOverrideStart(driver_name: String, vehicle: Vehicle, pad: VehicleSpawnPad)
+ final case class ServerVehicleOverrideStart(vehicle: Vehicle, pad: VehicleSpawnPad) extends SelfRespondingEvent
/**
* Message that transitions the newly-spawned vehicle into a cancellable auto-drive state.
* Information about the driving process is available on the vehicle itself.
* This information should only be communicated to the driver's client only.
* @see `VehicleDefinition`
- * @param driver_name the person who will drive the vehicle
* @param vehicle the vehicle
* @param pad the spawn pad
*/
- final case class ServerVehicleOverrideEnd(driver_name: String, vehicle: Vehicle, pad: VehicleSpawnPad)
+ final case class ServerVehicleOverrideEnd(vehicle: Vehicle, pad: VehicleSpawnPad) extends SelfRespondingEvent
/**
* Message to initiate the process of properly disposing of the vehicle that may have been or was spawned into the game world.
* @param vehicle the vehicle
*/
- final case class DisposeVehicle(vehicle: Vehicle)
+ final case class DisposeVehicle(vehicle: Vehicle) extends SelfRespondingEvent
/**
* Message to send targeted messages to the clients of specific users.
- * @param driver_name the person who will drive the vehicle
* @param reason the nature of the message
* @param data optional information for rendering the message to the client
*/
- final case class PeriodicReminder(driver_name: String, reason: Reminders.Value, data: Option[Any] = None)
+ final case class PeriodicReminder(reason: Reminders.Value, data: Option[Any] = None) extends SelfRespondingEvent
/**
* An `Enumeration` of reasons for sending a periodic reminder to the user.
diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlConcealPlayer.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlConcealPlayer.scala
index b035a7849..dc8391395 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlConcealPlayer.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlConcealPlayer.scala
@@ -3,6 +3,7 @@ package net.psforever.objects.serverobject.pad.process
import akka.actor.Props
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
+import net.psforever.services.base.envelope.MessageEnvelope
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -28,7 +29,7 @@ class VehicleSpawnControlConcealPlayer(pad: VehicleSpawnPad) extends VehicleSpaw
case order @ VehicleSpawnControl.Order(driver, vehicle) =>
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) {
trace(s"hiding ${driver.Name}")
- pad.Zone.VehicleEvents ! VehicleSpawnPad.ConcealPlayer(driver.GUID)
+ pad.Zone.VehicleEvents ! MessageEnvelope(pad.Zone.id, VehicleSpawnPad.ConcealPlayer(driver.GUID))
context.system.scheduler.scheduleOnce(2000 milliseconds, loadVehicle, order)
} else {
trace(s"integral component lost; abort order fulfillment")
diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlDriverControl.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlDriverControl.scala
index dbef9a3c8..8632a10f9 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlDriverControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlDriverControl.scala
@@ -3,6 +3,7 @@ package net.psforever.objects.serverobject.pad.process
import akka.actor.Props
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
+import net.psforever.services.base.envelope.MessageEnvelope
/**
* An `Actor` that handles vehicle spawning orders for a `VehicleSpawnPad`.
@@ -24,7 +25,7 @@ class VehicleSpawnControlDriverControl(pad: VehicleSpawnPad) extends VehicleSpaw
case order @ VehicleSpawnControl.Order(driver, vehicle) =>
trace(s"returning control of ${vehicle.Definition.Name} to its current driver")
if (vehicle.PassengerInSeat(driver).nonEmpty) {
- pad.Zone.VehicleEvents ! VehicleSpawnPad.ServerVehicleOverrideEnd(driver.Name, vehicle, pad)
+ pad.Zone.VehicleEvents ! MessageEnvelope(driver.Name, VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, pad))
}
finalClear ! order
diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlFinalClearance.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlFinalClearance.scala
index 67c8d6e61..d67eff488 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlFinalClearance.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlFinalClearance.scala
@@ -4,8 +4,9 @@ package net.psforever.objects.serverobject.pad.process
import akka.actor.Cancellable
import net.psforever.objects.Default
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
-import net.psforever.types.{PlanetSideGUID, Vector3}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.types.Vector3
+import net.psforever.services.vehicle.VehicleAction
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -35,15 +36,9 @@ class VehicleSpawnControlFinalClearance(pad: VehicleSpawnPad) extends VehicleSpa
//ensure the vacant vehicle is above the trench and the doors
vehicle.Position = pad.Position + Vector3.z(pad.Definition.VehicleCreationZOffset)
val definition = vehicle.Definition
- pad.Zone.VehicleEvents ! VehicleServiceMessage(
+ pad.Zone.VehicleEvents ! MessageEnvelope(
s"${pad.Continent}",
- VehicleAction.LoadVehicle(
- PlanetSideGUID(0),
- vehicle,
- definition.ObjectId,
- vehicle.GUID,
- definition.Packet.ConstructorData(vehicle).get
- )
+ VehicleAction.LoadVehicle(vehicle, definition.ObjectId, vehicle.GUID, definition.Packet.ConstructorData(vehicle).get)
)
}
context.parent ! VehicleSpawnControl.ProcessControl.Reminder
@@ -70,7 +65,7 @@ class VehicleSpawnControlFinalClearance(pad: VehicleSpawnPad) extends VehicleSpa
}
case VehicleSpawnControlFinalClearance.NextOrder =>
- pad.Zone.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad)
+ pad.Zone.VehicleEvents ! MessageEnvelope(pad.Zone.id, VehicleSpawnPad.ResetSpawnPad(pad))
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
case _ => ()
diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala
index 7bbb1123c..3460b4fd8 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlLoadVehicle.scala
@@ -7,8 +7,8 @@ import akka.util.Timeout
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.objects.zones.Zone
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.Vector3
import net.psforever.zones.Zones
@@ -68,9 +68,9 @@ class VehicleSpawnControlLoadVehicle(pad: VehicleSpawnPad) extends VehicleSpawnC
val vtype = definition.ObjectId
val vguid = v.GUID
val vdata = definition.Packet.ConstructorData(v).get
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.LoadVehicle(Service.defaultPlayerGUID, v, vtype, vguid, vdata)
+ VehicleAction.LoadVehicle(v, vtype, vguid, vdata)
)
railJack ! temp.get
temp = None
diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala
index c7740c7da..4dda6e120 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlRailJack.scala
@@ -11,6 +11,7 @@ import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.objects.vital.prop.DamageProperties
import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.Zone
+import net.psforever.services.base.envelope.MessageEnvelope
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -40,7 +41,7 @@ class VehicleSpawnControlRailJack(pad: VehicleSpawnPad) extends VehicleSpawnCont
pad.Definition.killBox(pad, vehicle.Definition.CanFly),
Zone.findAllTargets
)
- pad.Zone.VehicleEvents ! VehicleSpawnPad.AttachToRails(vehicle, pad)
+ pad.Zone.VehicleEvents ! MessageEnvelope(pad.Zone.id, VehicleSpawnPad.AttachToRails(vehicle, pad))
context.system.scheduler.scheduleOnce(10 milliseconds, seatDriver, order)
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala
index 520d0c1ec..6c7218b17 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala
@@ -4,6 +4,7 @@ package net.psforever.objects.serverobject.pad.process
import akka.actor.{ActorRef, Props}
import net.psforever.objects.{Default, Vehicle}
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
+import net.psforever.services.base.envelope.MessageEnvelope
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -46,7 +47,7 @@ class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnCo
vehicle.Actor ! Vehicle.Deconstruct(Some(pad.Definition.VehicleCreationDeconstructTime.seconds))
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) {
trace("driver to be made seated in vehicle")
- pad.Zone.VehicleEvents ! VehicleSpawnPad.StartPlayerSeatedInVehicle(driver.Name, vehicle, pad)
+ pad.Zone.VehicleEvents ! MessageEnvelope(driver.Name, VehicleSpawnPad.StartPlayerSeatedInVehicle(vehicle, pad))
} else {
trace("driver lost; vehicle stranded on pad")
}
@@ -58,7 +59,7 @@ class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnCo
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty &&
entry.vehicle.PassengerInSeat(entry.driver).contains(0)) {
trace(s"driver ${entry.driver.Name} has taken the wheel")
- pad.Zone.VehicleEvents ! VehicleSpawnPad.PlayerSeatedInVehicle(entry.driver.Name, entry.vehicle, pad)
+ pad.Zone.VehicleEvents ! MessageEnvelope(entry.driver.Name, VehicleSpawnPad.PlayerSeatedInVehicle(entry.vehicle, pad))
} else {
trace("driver lost, but operations can continue")
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala
index bbec75af4..496d06938 100644
--- a/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala
@@ -3,6 +3,7 @@ package net.psforever.objects.serverobject.pad.process
import akka.actor.Props
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.Vector3
import scala.concurrent.ExecutionContext.Implicits.global
@@ -31,18 +32,18 @@ class VehicleSpawnControlServerVehicleOverride(pad: VehicleSpawnPad) extends Veh
val driverFailState =
!driver.isAlive || driver.Continent != pad.Continent || !vehicle.PassengerInSeat(driver).contains(0)
vehicle.MountedIn = None
- pad.Zone.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad)
+ pad.Zone.VehicleEvents ! MessageEnvelope(pad.Zone.id, VehicleSpawnPad.DetachFromRails(vehicle, pad))
if (vehicleFailState || driverFailState) {
if (vehicleFailState) {
trace(s"vehicle was already destroyed")
} else {
trace(s"driver is not ready")
}
- pad.Zone.VehicleEvents ! VehicleSpawnPad.RevealPlayer(order.DriverGUID)
+ pad.Zone.VehicleEvents ! MessageEnvelope(pad.Zone.id, VehicleSpawnPad.RevealPlayer(order.DriverGUID))
driverControl ! order
} else {
trace(s"telling ${driver.Name} that the server is assuming control of the ${vehicle.Definition.Name}")
- pad.Zone.VehicleEvents ! VehicleSpawnPad.ServerVehicleOverrideStart(driver.Name, vehicle, pad)
+ pad.Zone.VehicleEvents ! MessageEnvelope(driver.Name, VehicleSpawnPad.ServerVehicleOverrideStart(vehicle, pad))
context.system.scheduler.scheduleOnce(4000 milliseconds, driverControl, order)
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/painbox/PainboxControl.scala b/src/main/scala/net/psforever/objects/serverobject/painbox/PainboxControl.scala
index 4e673d621..b246a6edb 100644
--- a/src/main/scala/net/psforever/objects/serverobject/painbox/PainboxControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/painbox/PainboxControl.scala
@@ -59,7 +59,7 @@ class PainboxControl(painbox: Painbox) extends PoweredAmenityControl {
}
var commonBehavior: Receive = {
- case Service.Startup() =>
+ case Service.Startup =>
if (!disabled && domain.midpoint == Vector3.Zero) {
initialStartup()
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableAmenity.scala b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableAmenity.scala
index 1042acfe4..88b8cbe25 100644
--- a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableAmenity.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableAmenity.scala
@@ -5,7 +5,9 @@ import net.psforever.objects.Tool
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.sourcing.{SourceEntry, SourceWithHealthEntry}
import net.psforever.objects.vital.{DamagingActivity, RepairFromEquipment, SpawningActivity}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.packet.game.PlanetsideAttributeMessage
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
/**
* The "control" `Actor` mixin for repair-handling code
@@ -27,8 +29,7 @@ object RepairableAmenity {
/**
* A restored `Amenity` target dispatches two messages to chance its model and operational states.
* These `PlanetSideAttributeMessage` attributes are the same as reported during zone load client configuration.
- * @see `AvatarAction.PlanetsideAttributeToAll`
- * @see `AvatarServiceMessage`
+ * @see `PlanetsideAttribute`
* @see `Zone.AvatarEvents`
* @param target the entity being destroyed
*/
@@ -37,8 +38,10 @@ object RepairableAmenity {
val zoneId = zone.id
val events = zone.AvatarEvents
val targetGUID = target.GUID
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 50, 0))
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 51, 0))
+ events ! MessageEnvelope(
+ zoneId,
+ SendResponse(PlanetsideAttributeMessage(targetGUID, 50, 0), PlanetsideAttributeMessage(targetGUID, 51, 0))
+ )
RestorationOfHistory(target)
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableEntity.scala b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableEntity.scala
index 232a3c8c5..53130db81 100644
--- a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableEntity.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableEntity.scala
@@ -8,8 +8,8 @@ import net.psforever.objects.vital.RepairFromEquipment
import net.psforever.objects.{Player, Tool}
import net.psforever.packet.game.{ChatMsg, InventoryStateMessage, RepairMessage}
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, Vector3}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
/**
* The "control" `Actor` mixin for repair-handling code,
@@ -67,13 +67,13 @@ trait RepairableEntity extends Repairable {
* Calculate the health points change and enact that repair action if the targets are stationary.
* Restore the target entity to a not destroyed state if applicable.
* Always show the repair progress bar window by using the appropriate packet.
- * @see `AvatarAction.PlanetsideAttributeToAll`
- * @see `AvatarAction.SendResponse`
+ * @see `PlanetsideAttribute`
+ * @see `SendResponse`
* @see `AvatarService`
* @see `InventoryStateMessage`
* @see `PlanetSideGameObject.isMoving`
* @see `RepairMessage`
- * @see `Service.defaultPlayerGUID`
+ * @see `Default.GUID0`
* @see `Tool.Discharge`
* @see `Zone.AvatarEvents`
* @param target the entity being repaired
@@ -89,12 +89,9 @@ trait RepairableEntity extends Repairable {
if (!(player.isMoving(test = 1f) || target.isMoving(test = 1f))) { //only allow stationary repairs within margin of error
val repairValue = Repairable.applyLevelModifier(player, item, RepairToolValue(item)).toInt + target.Definition.RepairMod
val magazine = item.Discharge()
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
player.Name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
- )
+ SendResponse(InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong))
)
target.LogActivity(
RepairFromEquipment(
@@ -108,12 +105,9 @@ trait RepairableEntity extends Repairable {
originalHealth
}
//progress bar remains visible
- events ! AvatarServiceMessage(
+ events ! MessageEnvelope(
name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- RepairMessage(target.GUID, updatedHealth * 100 / definition.MaxHealth)
- )
+ SendResponse(RepairMessage(target.GUID, updatedHealth * 100 / definition.MaxHealth))
)
//if vehicle and vehicle is owned by another player, send repair chat message to the vehicle's owner
if (target.Zone.Vehicles.exists(_.GUID == target.GUID)) {
@@ -146,11 +140,11 @@ trait RepairableEntity extends Repairable {
val newHealth = target.Health = target.Health + amount
if (target.Destroyed) {
if (newHealth >= target.Definition.RepairRestoresAt) {
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
+ events ! MessageEnvelope(zoneId, PlanetsideAttribute(tguid, 0, newHealth))
Restoration(target)
}
} else {
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
+ events ! MessageEnvelope(zoneId, PlanetsideAttribute(tguid, 0, newHealth))
}
newHealth
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableWeaponTurret.scala b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableWeaponTurret.scala
index f7f5fd693..5c716411f 100644
--- a/src/main/scala/net/psforever/objects/serverobject/repair/RepairableWeaponTurret.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/repair/RepairableWeaponTurret.scala
@@ -5,8 +5,8 @@ import net.psforever.objects.Tool
import net.psforever.objects.equipment.EquipmentSlot
import net.psforever.objects.serverobject.turret.WeaponTurret
import net.psforever.objects.vehicles.MountedWeapons
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.vehicle.VehicleAction
/**
* The "control" `Actor` mixin for repair-handling code for `WeaponTurret` objects.
@@ -28,10 +28,9 @@ object RepairableWeaponTurret {
* and may have been concealed/deleted when the target was destroyed.
* @see `MountedWeapons`
* @see `MountedWeapons.Weapons`
- * @see `Service.defaultPlayerGUID`
+ * @see `Default.GUID0`
* @see `WeaponTurret`
- * @see `VehicleAction.EquipmentInSlot`
- * @see `VehicleServiceMessage`
+ * @see `EquipmentInSlot`
* @see `Zone.VehicleEvents`
* @param target the entity being destroyed;
* note: `MountedWeapons` is a parent of `WeaponTurret`
@@ -42,14 +41,15 @@ object RepairableWeaponTurret {
val zoneId = zone.id
val tguid = target.GUID
val events = zone.VehicleEvents
- target.Weapons
+ events ! BundledEnvelope(target.Weapons
.map({ case (index, slot: EquipmentSlot) => (index, slot.Equipment) })
.collect {
case (index: Int, Some(tool: Tool)) =>
- events ! VehicleServiceMessage(
+ MessageEnvelope(
zoneId,
- VehicleAction.EquipmentInSlot(Service.defaultPlayerGUID, tguid, index, tool)
+ VehicleAction.EquipmentInSlot(tguid, index, tool)
)
}
+ )
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala b/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala
index 996b4d876..9f6b2b0ff 100644
--- a/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/resourcesilo/ResourceSiloControl.scala
@@ -11,8 +11,9 @@ import net.psforever.objects.zones
import net.psforever.objects.{GlobalDefinitions, Ntu, NtuContainer, NtuStorageBehavior, Vehicle}
import net.psforever.types.{ExperienceType, PlanetSideEmpire}
import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.util.Config
import scala.concurrent.ExecutionContext.Implicits.global
@@ -39,7 +40,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
private var drainMultiplier: Float = 1.0f
def receive: Receive = {
- case Service.Startup() =>
+ case Service.Startup =>
resourceSilo.Owner match {
case building: Building =>
UpdateChargeLevel(amount = 0)
@@ -106,9 +107,9 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
log.trace(s"LowNtuWarning: Silo ${resourceSilo.GUID} low ntu warning set to $enabled")
val building = resourceSilo.Owner
val zone = building.Zone
- building.Zone.AvatarEvents ! AvatarServiceMessage(
+ building.Zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttribute(building.GUID, 47, if (resourceSilo.LowNtuWarningOn) 1 else 0)
+ PlanetsideAttribute(building.GUID, 47, if (resourceSilo.LowNtuWarningOn) 1 else 0)
)
}
@@ -129,9 +130,9 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
log.trace(
s"UpdateChargeLevel: silo ${resourceSilo.GUID} NTU bar level has changed from $siloDisplayBeforeChange to ${resourceSilo.CapacitorDisplay}"
)
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)
+ PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)
)
building.Actor ! BuildingActor.MapUpdate()
}
@@ -202,12 +203,16 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
(Config.app.game.experience.sep.ntuSiloDepositReward.toFloat *
amount * resourceSilo.Definition.ChargeTime.toSeconds.toFloat / resourceSilo.MaxNtuCapacitor
).toLong
- vehicle.Zone.AvatarEvents ! AvatarServiceMessage(
- owner.name,
- AvatarAction.AwardBep(owner.charId, deposit, ExperienceType.Normal)
+ vehicle.Zone.AvatarEvents ! BundledEnvelope(
+ MessageEnvelope(
+ owner.name,
+ AvatarAction.AwardBep(owner.charId, deposit, ExperienceType.Normal)
+ ),
+ MessageEnvelope(
+ owner.name,
+ AvatarAction.ShareAntExperienceWithSquad(owner, deposit, vehicle)
+ )
)
- vehicle.Zone.AvatarEvents ! AvatarServiceMessage(
- owner.name, AvatarAction.ShareAntExperienceWithSquad(owner, deposit, vehicle))
zones.exp.ToDatabase.reportNtuActivity(owner.charId, resourceSilo.Zone.Number, resourceSilo.Owner.GUID.guid, deposit)
}
}
@@ -229,9 +234,9 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
val amount = (if (trigger > 0) {
// panel glow & orb particles on
val zone = resourceSilo.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, resourceSilo.GUID, 49, 1)
+ PlanetsideAttribute(resourceSilo.GUID, 49, 1)
)
math.min(resourceSilo.MaxNtuCapacitor - currentlyHas, trigger)
} else if (trigger < 0) {
@@ -240,9 +245,9 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
} else {
// panel glow & orb particles off
val zone = resourceSilo.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, resourceSilo.GUID, 49, 0)
+ PlanetsideAttribute(resourceSilo.GUID, 49, 0)
)
0
}) * 0.9f
diff --git a/src/main/scala/net/psforever/objects/serverobject/shuttle/OrbitalShuttlePadControl.scala b/src/main/scala/net/psforever/objects/serverobject/shuttle/OrbitalShuttlePadControl.scala
index 7173f5990..380d7b95c 100644
--- a/src/main/scala/net/psforever/objects/serverobject/shuttle/OrbitalShuttlePadControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/shuttle/OrbitalShuttlePadControl.scala
@@ -8,9 +8,12 @@ import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.ChatMsg
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.base.support.SupportActor
+import net.psforever.services.local.LocalAction
import net.psforever.services.hart.{HartTimer, HartTimerActions}
+import net.psforever.services.local.support.DoorMessage
import net.psforever.services.{Service, ServiceManager}
import net.psforever.types.ChatMessageType
@@ -48,8 +51,13 @@ class OrbitalShuttlePadControl(pad: OrbitalShuttlePad) extends Actor {
managedDoors.foreach { door =>
door.Actor ! Door.UpdateMechanism(OrbitalShuttlePadControl.lockedWaitingForShuttle)
val zone = pad.Zone
- if(door.isOpen) {
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.DoorSlamsShut(door))
+ if (door.isOpen) {
+ door.Open = None
+ zone.LocalEvents ! DoorMessage(
+ zone.id,
+ LocalAction.DoorCloses(door.GUID),
+ SupportActor.ClearSpecific(List(door), zone)
+ )
}
}
@@ -98,7 +106,7 @@ class OrbitalShuttlePadControl(pad: OrbitalShuttlePad) extends Actor {
* register and add the shuttle as a common vehicle of the said zone
*/
val startUp: Receive = {
- case Service.Startup() =>
+ case Service.Startup =>
import net.psforever.types.Vector3
import net.psforever.types.Vector3.DistanceSquared
import net.psforever.objects.GlobalDefinitions._
@@ -175,8 +183,7 @@ object OrbitalShuttlePadControl {
* Logic for door mechanism that keeps select doors shut when the shuttle is not ready for boarding.
* A message flashes onscreen to explain this reason.
* The message will not flash if the door has no expectation of ever opening for a user.
- * @see `AvatarAction.SendResponse`
- * @see `AvatarServiceMessage`
+ * @see `SendResponse`
* @see `ChatMessageType`
* @see `ChatMsg`
* @see `Player`
@@ -190,15 +197,14 @@ object OrbitalShuttlePadControl {
val zone = door.Zone
obj match {
case p: Player if p.Faction == door.Faction =>
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
p.Name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
ChatMsg(ChatMessageType.UNK_225, wideContents=false, "", "@DoorWillOpenWhenShuttleReturns", None)
)
)
p.Name
- case _ => ;
+ case _ => ()
}
false
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/participation/FacilityHackParticipation.scala b/src/main/scala/net/psforever/objects/serverobject/structures/participation/FacilityHackParticipation.scala
index a4962f5a9..24da2b2a6 100644
--- a/src/main/scala/net/psforever/objects/serverobject/structures/participation/FacilityHackParticipation.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/structures/participation/FacilityHackParticipation.scala
@@ -4,6 +4,9 @@ package net.psforever.objects.serverobject.structures.participation
import net.psforever.objects.Player
import net.psforever.objects.avatar.scoring.Kill
import net.psforever.objects.sourcing.UniquePlayer
+import net.psforever.packet.game.GenericObjectActionMessage
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SendResponse
import net.psforever.types.{PlanetSideEmpire, Vector3}
import scala.collection.mutable
@@ -106,16 +109,15 @@ trait FacilityHackParticipation extends ParticipationLogic {
if (building.virusId != 8) {
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.GlobalDefinitions
- import net.psforever.services.Service
- import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
val mainTerm = building.Amenities.filter(x => x.isInstanceOf[Terminal] && x.Definition == GlobalDefinitions.main_terminal).head.GUID
- val msg1 = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, mainTerm, 61)
- val msg2 = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, mainTerm, 58)
+ val pkts = SendResponse(
+ GenericObjectActionMessage(mainTerm, 61),
+ GenericObjectActionMessage(mainTerm, 58)
+ )
val events = building.Zone.AvatarEvents
- list.foreach { p =>
- events ! AvatarServiceMessage(p.Name, msg1)
- events ! AvatarServiceMessage(p.Name, msg2)
- }
+ events ! BundledEnvelope(list.map { p =>
+ MessageEnvelope(p.Name, pkts)
+ })
}
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/participation/MajorFacilityHackParticipation.scala b/src/main/scala/net/psforever/objects/serverobject/structures/participation/MajorFacilityHackParticipation.scala
index 29fd9a7c3..a30211873 100644
--- a/src/main/scala/net/psforever/objects/serverobject/structures/participation/MajorFacilityHackParticipation.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/structures/participation/MajorFacilityHackParticipation.scala
@@ -4,7 +4,7 @@ package net.psforever.objects.serverobject.structures.participation
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.sourcing.{PlayerSource, UniquePlayer}
import net.psforever.objects.zones.{HotSpotInfo, ZoneHotSpotProjector}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, Vector3}
import net.psforever.util.Config
import akka.pattern.ask
@@ -15,7 +15,8 @@ import net.psforever.objects.avatar.scoring.Kill
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.packet.game.ChatMsg
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SendResponse
import scala.collection.mutable
import scala.concurrent.duration._
@@ -303,17 +304,18 @@ final case class MajorFacilityHackParticipation(building: Building) extends Faci
finalCep,
expType = "cep"
)
- events ! AvatarServiceMessage(hacker.Name, AvatarAction.AwardCep(hackerId, finalCep))
+ events ! MessageEnvelope(hacker.Name, AvatarAction.AwardCep(hackerId, finalCep))
}*/
//bystanders (cep if squad leader, bep otherwise)
- contributingPlayers
+ events ! BundledEnvelope(contributingPlayers
//.filterNot { _.CharId == hackerId }
- .foreach { player =>
+ .map { player =>
val charId = player.CharId
val contributionMultiplier = contributionPerPlayerByTime.getOrElse(charId, 1f)
val outputValue = (finalCep * contributionMultiplier).toLong
- events ! AvatarServiceMessage(player.Name, AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, outputValue))
+ MessageEnvelope(player.Name, AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, outputValue))
}
+ )
//flag carrier (won't be in soi, but earns cep from capture)
flagCarrier.collect {
case player if !isResecured =>
@@ -337,7 +339,7 @@ final case class MajorFacilityHackParticipation(building: Building) extends Faci
finalModifiedCep,
expType = "llu"
)
- events ! AvatarServiceMessage(player.Name, AvatarAction.AwardCep(charId, finalModifiedCep))
+ events ! MessageEnvelope(player.Name, AvatarAction.AwardCep(charId, finalModifiedCep))
}
} else {
//no need to calculate a fancy score
@@ -438,9 +440,9 @@ object MajorFacilityHackParticipation {
msg: ChatMsg
): Unit = {
val events = building.Zone.LocalEvents
- val message = LocalAction.SendResponse(msg)
- targets.foreach { player =>
- events ! LocalServiceMessage(player.Name, message)
- }
+ val message = SendResponse(msg)
+ events ! BundledEnvelope(targets.map { player =>
+ MessageEnvelope(player.Name, message)
+ })
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/participation/TowerHackParticipation.scala b/src/main/scala/net/psforever/objects/serverobject/structures/participation/TowerHackParticipation.scala
index 505c401ae..08d2453da 100644
--- a/src/main/scala/net/psforever/objects/serverobject/structures/participation/TowerHackParticipation.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/structures/participation/TowerHackParticipation.scala
@@ -4,7 +4,8 @@ package net.psforever.objects.serverobject.structures.participation
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.zones.exp.ToDatabase
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.types.{PlanetSideEmpire, Vector3}
import net.psforever.util.Config
@@ -144,7 +145,7 @@ final case class TowerHackParticipation(building: Building) extends FacilityHack
//7. reward participants
//Classically, only players in the SOI are rewarded
//terminal hacker (always cep)
- events ! AvatarServiceMessage(hacker.Name, AvatarAction.AwardCep(hacker.CharId, finalCep))
+ events ! MessageEnvelope(hacker.Name, AvatarAction.AwardCep(hacker.CharId, finalCep))
ToDatabase.reportFacilityCapture(
hackerId,
zoneNumber,
@@ -153,18 +154,19 @@ final case class TowerHackParticipation(building: Building) extends FacilityHack
expType = "cep"
)
//bystanders (cep if squad leader, bep otherwise)
- soiPlayers
+ events ! BundledEnvelope(soiPlayers
.filterNot(_.CharId == hackerId)
- .foreach { player =>
+ .map { player =>
val charId = player.CharId
val contributionTimeMultiplier = contributionPerPlayerByTime.getOrElse(charId, 0.5f)
val contributionDistanceMultiplier = contributionPerPlayerByDistanceFromGoal.getOrElse(charId, 0.5f)
val outputValue = (finalCep * contributionTimeMultiplier * contributionDistanceMultiplier).toLong
- events ! AvatarServiceMessage(
+ MessageEnvelope(
player.Name,
AvatarAction.FacilityCaptureRewards(buildingId, zoneNumber, outputValue)
)
}
+ )
} else {
//no need to calculate a fancy score
ToDatabase.reportFacilityCaptureInBulk(
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala
index ad700fbbe..e4e33b2aa 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala
@@ -83,7 +83,7 @@ object ProximityTerminal {
if (obj.Actor == Default.Actor) {
obj.Actor =
context.actorOf(Props(classOf[ProximityTerminalControl], obj), PlanetSideServerObject.UniqueActorName(obj))
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
}
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala
index b26f1d617..c34eb6425 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala
@@ -6,6 +6,9 @@ import net.psforever.objects.serverobject.damage.Damageable
import net.psforever.objects.sourcing.AmenitySource
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.HackState1
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
+import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
import org.log4s.Logger
import scala.annotation.unused
@@ -24,10 +27,7 @@ import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityCo
import net.psforever.objects.vital.{HealFromTerminal, RepairFromTerminal, Vitality}
import net.psforever.objects.zones.ZoneAware
import net.psforever.packet.game.InventoryStateMessage
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.local.LocalAction
/**
* An `Actor` that handles messages being dispatched to a specific `ProximityTerminal`.
@@ -147,7 +147,7 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
tryAutoRepair()
if (term.HackedBy.nonEmpty) {
val zone = term.Zone
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, term))
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(term))
}
super.DestructionAwareness(target, cause)
}
@@ -181,7 +181,8 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
self,
ProximityTerminalControl.TerminalAction()
)
- TerminalObject.Zone.LocalEvents ! Terminal.StartProximityEffect(term)
+ val zone = TerminalObject.Zone
+ zone.LocalEvents ! MessageEnvelope(zone.id, LocalAction.ProximityTerminalEffect(TerminalObject.GUID, effectState = true))
}
} else {
log.warn(s"ProximityTerminal.Use: $target was rejected by unit ${term.Definition.Name}@${term.GUID.guid}")
@@ -201,7 +202,8 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
//de-activation (global / local)
if (term.NumberUsers == 0 && hadUsers) {
terminalAction.cancel()
- TerminalObject.Zone.LocalEvents ! Terminal.StopProximityEffect(term)
+ val zone = TerminalObject.Zone
+ zone.LocalEvents ! MessageEnvelope(zone.id, LocalAction.ProximityTerminalEffect(TerminalObject.GUID, effectState = false))
}
} else {
log.debug(
@@ -216,12 +218,13 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
terminalAction.cancel()
if (callbacks.nonEmpty) {
callbacks.clear()
- TerminalObject.Zone.LocalEvents ! Terminal.StopProximityEffect(term)
+ val zone = TerminalObject.Zone
+ zone.LocalEvents ! MessageEnvelope(zone.id, LocalAction.ProximityTerminalEffect(TerminalObject.GUID, effectState = true))
}
//clear hack state
if (term.HackedBy.nonEmpty) {
val zone = term.Zone
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, term))
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(term))
}
}
@@ -347,9 +350,9 @@ object ProximityTerminalControl {
if (oldMax < maxHealthCap) {
target.MaxHealth = newMax
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttributeToAll(target.GUID, 1, newMax)
+ PlanetsideAttribute(target.GUID, 1, newMax)
)
}
if (target.Health < newMax) {
@@ -362,17 +365,17 @@ object ProximityTerminalControl {
def PlayerHealthCallback(target: PlanetSideGameObject with Vitality with ZoneAware): Unit = {
val zone = target.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttributeToAll(target.GUID, 0, target.Health)
+ PlanetsideAttribute(target.GUID, 0, target.Health)
)
}
def VehicleHealthCallback(target: PlanetSideGameObject with Vitality with ZoneAware): Unit = {
val zone = target.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, 0, target.Health)
+ PlanetsideAttribute(target.GUID, 0, target.Health)
)
}
@@ -401,9 +404,9 @@ object ProximityTerminalControl {
target.Armor = armor + finalRepairAmount
target.LogActivity(RepairFromTerminal(AmenitySource(terminal), finalRepairAmount))
val zone = target.Zone
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.PlanetsideAttributeToAll(target.GUID, 4, target.Armor)
+ PlanetsideAttribute(target.GUID, 4, target.Armor)
)
target.Armor == maxArmor
} else {
@@ -429,12 +432,12 @@ object ProximityTerminalControl {
val events = unit.Zone.AvatarEvents
val channel = target.Name
ancient.foreach { case (weapon, slots) =>
- slots.foreach { slot =>
- events ! AvatarServiceMessage(
+ events ! BundledEnvelope(slots.map { slot =>
+ MessageEnvelope(
channel,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity))
+ SendResponse(InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity))
)
- }
+ })
}
!result.flatMap { _._2 }.exists { slot => slot.Magazine < slot.MaxMagazine() }
}
@@ -454,14 +457,14 @@ object ProximityTerminalControl {
)
val events = unit.Zone.VehicleEvents
val channel = target.Actor.toString
- result.foreach { case (weapon, slots) =>
- slots.foreach { slot =>
- events ! VehicleServiceMessage(
+ events ! BundledEnvelope(result.flatMap { case (weapon, slots) =>
+ slots.map { slot =>
+ MessageEnvelope(
channel,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity))
+ SendResponse(InventoryStateMessage(slot.Box.GUID, weapon.GUID, slot.Box.Capacity))
)
}
- }
+ })
!result.flatMap { _._2 }.exists { slot => slot.Magazine < slot.MaxMagazine() }
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
index b3a80776e..9b289caad 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/TerminalControl.scala
@@ -12,8 +12,7 @@ import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableA
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.HackState1
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
/**
* An `Actor` that handles messages being dispatched to a specific `Terminal`.
@@ -100,7 +99,7 @@ class TerminalControl(term: Terminal)
tryAutoRepair()
if (term.HackedBy.nonEmpty) {
val zone = term.Zone
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, term))
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(term))
}
super.DestructionAwareness(target, cause)
}
@@ -122,7 +121,7 @@ class TerminalControl(term: Terminal)
//clear hack state
if (term.HackedBy.nonEmpty) {
val zone = term.Zone
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, term))
+ zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(term))
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala
index 9f07bce14..d8cbe03f9 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/capture/CaptureTerminals.scala
@@ -6,8 +6,11 @@ import net.psforever.objects.serverobject.hackable.GenericHackables
import net.psforever.objects.serverobject.structures.{Building, StructureType, WarpGate}
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.sourcing.PlayerSource
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.local.LocalAction
+import net.psforever.services.local.support.HackCaptureActor
+import net.psforever.services.local.support.CaptureEnvelope
import net.psforever.types.PlanetSideEmpire
+import net.psforever.services.base.envelope.MessageEnvelope
import scala.concurrent.duration._
import scala.util.{Failure, Success}
@@ -39,22 +42,17 @@ object CaptureTerminals {
val zoneid = zone.id
val events = zone.LocalEvents
val isResecured = hackingPlayer.Faction == target.Faction
- events ! LocalServiceMessage(
+ events ! MessageEnvelope(
zoneid,
- LocalAction.TriggerSound(hackingPlayer.GUID, target.HackSound, hackingPlayer.Position, 30, 0.49803925f)
+ hackingPlayer.GUID,
+ LocalAction.TriggerSound(target.HackSound, hackingPlayer.Position, 30, 0.49803925f)
)
if (isResecured) {
// Resecure the CC
- events ! LocalServiceMessage(
- zoneid,
- LocalAction.ResecureCaptureTerminal(target, PlayerSource(hackingPlayer))
- )
+ events ! CaptureEnvelope(HackCaptureActor.ResecureCaptureTerminal(target, zone, PlayerSource(hackingPlayer)))
} else {
// Start the CC hack timer
- events ! LocalServiceMessage(
- zoneid,
- LocalAction.StartCaptureTerminalHack(target)
- )
+ events ! CaptureEnvelope(HackCaptureActor.StartCaptureTerminalHack(target, zone, 0, 8L))
}
case Failure(_) =>
log.warn(s"Hack message failed on target guid: ${target.GUID}")
diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala
index c03709e69..f35249851 100644
--- a/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/terminals/implant/ImplantTerminalMechControl.scala
@@ -16,8 +16,9 @@ import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
import net.psforever.packet.game.HackState1
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SetEmpire
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
import scala.annotation.unused
@@ -144,14 +145,14 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
val zone = mech.Zone
val zoneId = zone.id
val events = zone.VehicleEvents
- mech.Seats.values.foreach(seat =>
+ events ! BundledEnvelope(mech.Seats.values.flatMap(seat =>
seat.occupant.collect {
case player =>
seat.unmount(player)
player.VehicleSeated = None
- events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2=false, guid))
+ MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(4, unk2=false, guid))
}
- )
+ ))
}
def powerTurnOnCallback(): Unit = {
@@ -173,7 +174,7 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
if (player.Faction == localFaction) {
if (mech.Owner.asInstanceOf[Building].CaptureTerminalIsHacked) {
//this is actually futile, as a hacked base does not grant access to the terminal
- events ! LocalServiceMessage(localFaction.toString, LocalAction.SetEmpire(guid, localFaction))
+ events ! MessageEnvelope(localFaction.toString, SetEmpire(guid, localFaction))
}
kickAllOccupantsNotOfFaction(zone, guid, mech, localFaction)
} else {
@@ -224,9 +225,9 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
setToFaction: PlanetSideEmpire.Value
): Unit = {
val events = zone.LocalEvents
- opposingFactionsAre(setToFaction).foreach { faction =>
- events ! LocalServiceMessage(faction.toString, LocalAction.SetEmpire(guid, faction))
- }
+ events ! BundledEnvelope(opposingFactionsAre(setToFaction).toSeq.map { faction =>
+ MessageEnvelope(faction.toString, SetEmpire(guid, faction))
+ })
}
private def noAccessByOpposingFactions(
@@ -235,9 +236,9 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
setToFaction: PlanetSideEmpire.Value
): Unit = {
val events = zone.LocalEvents
- opposingFactionsAre(setToFaction).foreach { faction =>
- events ! LocalServiceMessage(faction.toString, LocalAction.SetEmpire(guid, setToFaction))
- }
+ events ! BundledEnvelope(opposingFactionsAre(setToFaction).toSeq.map { faction =>
+ MessageEnvelope(faction.toString, SetEmpire(guid, setToFaction))
+ })
}
private def opposingFactionsAre(faction: PlanetSideEmpire.Value): PlanetSideEmpire.ValueSet = {
@@ -272,13 +273,13 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
): Unit = {
val zoneId = zone.id
val events = zone.LocalEvents
- obj.Seats.values.foreach(seat =>
+ events ! BundledEnvelope(obj.Seats.values.flatMap(seat =>
seat.occupant.collect {
case player if test(player.Faction) =>
seat.unmount(player)
player.VehicleSeated = None
- events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, guid))
+ MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(4, unk2 = false, guid))
}
- )
+ ))
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala
index 24f1bdea4..eaf927db0 100644
--- a/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/turret/FacilityTurretControl.scala
@@ -13,9 +13,10 @@ import net.psforever.objects.serverobject.turret.auto.AutomatedTurret.Target
import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret, AutomatedTurretBehavior}
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.{ChangeFireModeMessage, HackState1}
-import net.psforever.services.Service
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SendResponse
import net.psforever.services.vehicle.support.TurretUpgrader
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, PlanetSideEmpire, PlanetSideGUID}
/**
@@ -179,7 +180,7 @@ class FacilityTurretControl(turret: FacilityTurret)
seat.unmount(player)
player.VehicleSeated = None
if (player.HasGUID) {
- events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2=false, guid))
+ events ! MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(4, unk2=false, guid))
}
case None => ()
}
@@ -237,9 +238,9 @@ class FacilityTurretControl(turret: FacilityTurret)
.flatMap(_.Equipment)
.collect { case weapon: Tool if weapon.FireModeIndex > 0 =>
weapon.FireModeIndex = 0
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
zoneid,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, ChangeFireModeMessage(weapon.GUID, 0))
+ SendResponse(ChangeFireModeMessage(weapon.GUID, 0))
)
}
}
@@ -335,15 +336,15 @@ class FacilityTurretControl(turret: FacilityTurret)
val zone = turret.Zone
val zoneId = zone.id
val events = zone.VehicleEvents
- turret.Seats.values.zipWithIndex.foreach {
+ events ! BundledEnvelope(turret.Seats.values.zipWithIndex.flatMap {
case (seat, seat_num) =>
seat.occupant.collect {
case player =>
seat.unmount(player)
player.VehicleSeated = None
- events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, seat_num, unk2=true, guid))
+ MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(seat_num, unk2=true, guid))
}
- }
+ })
captureTerminalChanges(terminal, super.captureTerminalIsHacked, actionDelays = 3000L)
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/TurretControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/TurretControl.scala
index 2212a67ea..9a6845e78 100644
--- a/src/main/scala/net/psforever/objects/serverobject/turret/TurretControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/turret/TurretControl.scala
@@ -8,7 +8,9 @@ import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
import net.psforever.objects.serverobject.damage.{Damageable, DamageableWeaponTurret}
import net.psforever.objects.serverobject.repair.RepairableWeaponTurret
import net.psforever.objects.vital.interaction.DamageResult
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.packet.game.PlanetsideAttributeMessage
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
trait TurretControl
extends Actor
@@ -39,8 +41,10 @@ trait TurretControl
val zoneId = zone.id
val events = zone.AvatarEvents
val tguid = TurretObject.GUID
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 0))
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 0))
+ events ! MessageEnvelope(
+ zoneId,
+ SendResponse(PlanetsideAttributeMessage(tguid, 50, 0), PlanetsideAttributeMessage(tguid, 51, 0))
+ )
}
/**
@@ -56,7 +60,9 @@ trait TurretControl
val tguid = target.GUID
CancelJammeredSound(target)
CancelJammeredStatus(target)
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 50, 1))
- events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 1))
+ events ! MessageEnvelope(
+ zoneId,
+ SendResponse(PlanetsideAttributeMessage(tguid, 50, 1), PlanetsideAttributeMessage(tguid, 51, 1))
+ )
}
}
diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/VanuSentryControl.scala b/src/main/scala/net/psforever/objects/serverobject/turret/VanuSentryControl.scala
index 4a6cb991c..38fbfb7ca 100644
--- a/src/main/scala/net/psforever/objects/serverobject/turret/VanuSentryControl.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/turret/VanuSentryControl.scala
@@ -4,7 +4,8 @@ package net.psforever.objects.serverobject.turret
import akka.actor.Cancellable
import net.psforever.objects.serverobject.ServerObjectControl
import net.psforever.objects.{Default, Player, Tool}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.local.LocalAction
import net.psforever.types.Vector3
import scala.concurrent.ExecutionContext.Implicits.global
@@ -49,13 +50,14 @@ class VanuSentryControl(turret: FacilityTurret)
if (weapon.Magazine < weapon.MaxMagazine && System.currentTimeMillis() - weapon.LastDischarge > 3000L) {
weapon.Magazine += 1
val seat = TurretObject.Seat(0).get
- seat.occupant.collect {
+ TurretObject.Zone.LocalEvents ! BundledEnvelope(seat.occupant.collect {
case player: Player =>
- TurretObject.Zone.LocalEvents ! LocalServiceMessage(
+ MessageEnvelope(
TurretObject.Zone.id,
- LocalAction.RechargeVehicleWeapon(player.GUID, TurretObject.GUID, weapon.GUID)
+ player.GUID,
+ LocalAction.RechargeVehicleWeapon(TurretObject.GUID, weapon.GUID)
)
- }
+ })
}
else if (weapon.Magazine == weapon.MaxMagazine && weaponAmmoRechargeTimer != Default.Cancellable) {
weaponAmmoRechargeTimer.cancel()
diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala b/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala
index 03b8925ae..742a8c67c 100644
--- a/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/turret/WeaponTurrets.scala
@@ -5,11 +5,11 @@ import net.psforever.objects.avatar.Certification
import net.psforever.objects.ce.Deployable
import net.psforever.objects.{Player, Tool, TurretDeployable}
import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, InventoryStateMessage}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
-import net.psforever.services.vehicle.support.TurretUpgrader
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.{SendResponse, SetEmpire}
+import net.psforever.services.local.LocalAction
+import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader}
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.PlanetSideGUID
object WeaponTurrets {
@@ -31,9 +31,9 @@ object WeaponTurrets {
upgrade: TurretUpgrade.Value
)(): Unit = {
tool.Magazine = 0
- target.Zone.AvatarEvents ! AvatarServiceMessage(
+ target.Zone.AvatarEvents ! MessageEnvelope(
user.Name,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, InventoryStateMessage(tool.AmmoSlot.Box.GUID, tool.GUID, 0))
+ SendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, tool.GUID, 0))
)
FinishUpgradingMannedTurret(target, upgrade)
}
@@ -45,7 +45,7 @@ object WeaponTurrets {
* @see `TurretUpgrade`
* @see `TurretUpgrader.AddTask`
* @see `TurretUpgrader.ClearSpecific`
- * @see `VehicleServiceMessage.TurretUpgrade`
+ * @see `TurretMessage`
* @param target the facility turret being upgraded
* @param upgrade the upgrade being applied to the turret (usually, it's weapon system)
*/
@@ -53,8 +53,8 @@ object WeaponTurrets {
log.info(s"Manned wall turret weapon being converted to $upgrade")
val zone = target.Zone
val events = zone.VehicleEvents
- events ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), zone))
- events ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, zone, upgrade))
+ events ! TurretEnvelope(TurretUpgrader.ClearSpecific(List(target), zone))
+ events ! TurretEnvelope(TurretUpgrader.AddTask(target, zone, upgrade))
}
/**
@@ -85,10 +85,9 @@ object WeaponTurrets {
turret.UpdateTurretUpgradeTime()
(HackState.Ongoing, progress.toInt)
}
- turret.Zone.AvatarEvents ! AvatarServiceMessage(
+ turret.Zone.AvatarEvents ! MessageEnvelope(
tplayer.Name,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
HackMessage(progressType, turret.GUID, tplayer.GUID, progressGrade, -1f, progressState, HackState7.Unk8)
)
)
@@ -101,28 +100,30 @@ object WeaponTurrets {
val certs = hacker.avatar.certifications
if (certs.contains(Certification.ExpertHacking) || certs.contains(Certification.ElectronicsExpert)) {
// Forcefully dismount all seated occupants from the turret
- target.Seats.values.foreach { seat =>
+ zone.VehicleEvents ! BundledEnvelope(target.Seats.values.flatMap { seat =>
seat.occupant.collect {
player: Player =>
seat.unmount(player)
player.VehicleSeated = None
- zone.VehicleEvents ! VehicleServiceMessage(
+ MessageEnvelope(
zone.id,
- VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, target.GUID)
+ player.GUID,
+ VehicleAction.KickPassenger(4, unk2 = false, target.GUID)
)
}
- }
+ })
//hacker owns the deployable now
target.OwnerGuid = None
target.Actor ! Deployable.Ownership(hacker)
//convert faction
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.SetEmpire(Service.defaultPlayerGUID, target.GUID, hacker.Faction)
+ SetEmpire(target.GUID, hacker.Faction)
)
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.TriggerSound(hacker.GUID, target.HackSound, target.Position, 30, 0.49803925f)
+ hacker.GUID,
+ LocalAction.TriggerSound(target.HackSound, target.Position, 30, 0.49803925f)
)
} else {
//deconstruct
diff --git a/src/main/scala/net/psforever/objects/serverobject/turret/auto/AutomatedTurretBehavior.scala b/src/main/scala/net/psforever/objects/serverobject/turret/auto/AutomatedTurretBehavior.scala
index b9ef525ac..0e3cd9add 100644
--- a/src/main/scala/net/psforever/objects/serverobject/turret/auto/AutomatedTurretBehavior.scala
+++ b/src/main/scala/net/psforever/objects/serverobject/turret/auto/AutomatedTurretBehavior.scala
@@ -17,8 +17,8 @@ import net.psforever.objects.zones.Zone
import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.objects.{Default, PlanetSideGameObject, Player}
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ObjectDetectedMessage}
-import net.psforever.services.Service
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import net.psforever.types.{PlanetSideGUID, Vector3}
import scala.concurrent.ExecutionContext.Implicits.global
@@ -879,7 +879,7 @@ object AutomatedTurretBehavior {
EffectTarget.Validation.AutoTurretBlankVehicleTarget
)
- private val noTargets: List[PlanetSideGUID] = List(Service.defaultPlayerGUID)
+ private val noTargets: List[PlanetSideGUID] = List(Default.GUID0)
/**
* Are we tracking a target entity?
@@ -889,9 +889,9 @@ object AutomatedTurretBehavior {
* @param list target's globally unique identifier, in list form
*/
def startTracking(zone: Zone, channel: String, turretGuid: PlanetSideGUID, list: List[PlanetSideGUID]): Unit = {
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
channel,
- LocalAction.SendResponse(ObjectDetectedMessage(turretGuid, turretGuid, 0, list))
+ SendResponse(ObjectDetectedMessage(turretGuid, turretGuid, 0, list))
)
}
@@ -902,9 +902,9 @@ object AutomatedTurretBehavior {
* @param turretGuid turret
*/
def stopTracking(zone: Zone, channel: String, turretGuid: PlanetSideGUID): Unit = {
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
channel,
- LocalAction.SendResponse(ObjectDetectedMessage(turretGuid, turretGuid, 0, noTargets))
+ SendResponse(ObjectDetectedMessage(turretGuid, turretGuid, 0, noTargets))
)
}
@@ -915,9 +915,9 @@ object AutomatedTurretBehavior {
* @param weaponGuid turret's weapon
*/
def startShooting(zone: Zone, channel: String, weaponGuid: PlanetSideGUID): Unit = {
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
channel,
- LocalAction.SendResponse(ChangeFireStateMessage_Start(weaponGuid))
+ SendResponse(ChangeFireStateMessage_Start(weaponGuid))
)
}
@@ -928,9 +928,9 @@ object AutomatedTurretBehavior {
* @param weaponGuid turret's weapon
*/
def stopShooting(zone: Zone, channel: String, weaponGuid: PlanetSideGUID): Unit = {
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
channel,
- LocalAction.SendResponse(ChangeFireStateMessage_Stop(weaponGuid))
+ SendResponse(ChangeFireStateMessage_Stop(weaponGuid))
)
}
diff --git a/src/main/scala/net/psforever/objects/vehicles/control/AmsControl.scala b/src/main/scala/net/psforever/objects/vehicles/control/AmsControl.scala
index ccb69f2fe..f30cddc14 100644
--- a/src/main/scala/net/psforever/objects/vehicles/control/AmsControl.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/AmsControl.scala
@@ -2,8 +2,9 @@
package net.psforever.objects.vehicles.control
import net.psforever.objects._
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.DriveState
/**
@@ -29,8 +30,8 @@ class AmsControl(vehicle: Vehicle)
case None => ""
}
val events = zone.VehicleEvents
- events ! VehicleServiceMessage.AMSDeploymentChange(zone)
- events ! VehicleServiceMessage(driverChannel, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vehicle.GUID, 81, 1))
+ events ! MessageEnvelope(zone.id, VehicleAction.AMSDeploymentChange(zone))
+ events ! MessageEnvelope(driverChannel, PlanetsideAttribute(vehicle.GUID, 81, 1))
case _ => ;
}
}
@@ -49,8 +50,8 @@ class AmsControl(vehicle: Vehicle)
case None => ""
}
val events = zone.VehicleEvents
- events ! VehicleServiceMessage.AMSDeploymentChange(zone)
- events ! VehicleServiceMessage(driverChannel, VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vehicle.GUID, 81, 0))
+ events ! MessageEnvelope(zone.id, VehicleAction.AMSDeploymentChange(zone))
+ events ! MessageEnvelope(driverChannel, PlanetsideAttribute(vehicle.GUID, 81, 0))
case _ => ;
}
}
diff --git a/src/main/scala/net/psforever/objects/vehicles/AntTransferBehavior.scala b/src/main/scala/net/psforever/objects/vehicles/control/AntTransferBehavior.scala
similarity index 80%
rename from src/main/scala/net/psforever/objects/vehicles/AntTransferBehavior.scala
rename to src/main/scala/net/psforever/objects/vehicles/control/AntTransferBehavior.scala
index 10efab816..edf37c040 100644
--- a/src/main/scala/net/psforever/objects/vehicles/AntTransferBehavior.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/AntTransferBehavior.scala
@@ -1,27 +1,28 @@
-// Copyright (c) 2020 PSForever
-package net.psforever.objects.vehicles
+package net.psforever.objects.vehicles.control
import akka.actor.{ActorRef, Cancellable}
+import akka.actor.typed.scaladsl.adapter._
+
import net.psforever.actors.commands.NtuCommand
import net.psforever.actors.zone.BuildingActor
import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.structures.WarpGate
import net.psforever.objects.serverobject.transfer.{TransferBehavior, TransferContainer}
-import net.psforever.objects.{NtuContainer, _}
+import net.psforever.objects._
import net.psforever.types.DriveState
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
-import akka.actor.typed.scaladsl.adapter._
import net.psforever.objects.serverobject.transfer.TransferContainer.TransferMaterial
+import net.psforever.packet.game.PlanetsideAttributeMessage
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
var panelAnimationFunc: () => Unit = NoCharge
- var ntuChargingTick: Cancellable = Default.Cancellable
- findChargeTargetFunc = Vehicles.FindANTChargingSource
+ var ntuChargingTick: Cancellable = Default.Cancellable
+ findChargeTargetFunc = Vehicles.FindANTChargingSource
findDischargeTargetFunc = Vehicles.FindANTDischargingTarget
def TransferMaterial: TransferMaterial = Ntu.Nanites
@@ -31,30 +32,30 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
def antBehavior: Receive = storageBehavior.orElse(transferBehavior)
def ActivatePanelsForChargingEvent(vehicle: NtuContainer): Unit = {
- val obj = ChargeTransferObject
+ val obj = ChargeTransferObject
val zone = obj.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vehicle.GUID, 52, 1L)
+ PlanetsideAttribute(vehicle.GUID, 52, 1L)
) // panel glow on
}
/** Charging */
def StartNtuChargingEvent(vehicle: NtuContainer): Unit = {
- val obj = ChargeTransferObject
+ val obj = ChargeTransferObject
val zone = obj.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vehicle.GUID, 49, 1L)
+ PlanetsideAttribute(vehicle.GUID, 49, 1L)
) // orb particle effect on
}
def UpdateNtuUI(vehicle: Vehicle with NtuContainer): Unit = {
if (vehicle.Seats.values.exists(_.isOccupied)) {
val display = vehicle.NtuCapacitorScaled.toLong
- vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
+ vehicle.Zone.VehicleEvents ! MessageEnvelope(
vehicle.Actor.toString,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vehicle.GUID, 45, display)
+ PlanetsideAttribute(vehicle.GUID, 45, display)
)
}
}
@@ -158,18 +159,16 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
val zoneId = zone.id
val events = zone.VehicleEvents
if (transferEvent == TransferBehavior.Event.Charging) {
- events ! VehicleServiceMessage(
+ //1. panel glow off
+ //2. orb particle effect off
+ events ! MessageEnvelope(
zoneId,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 52, 0L)
- ) // panel glow off
- events ! VehicleServiceMessage(
- zoneId,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 49, 0L)
- ) // orb particle effect off
+ SendResponse(PlanetsideAttributeMessage(vguid, 52, 0L), PlanetsideAttributeMessage(vguid, 49, 0L))
+ )
} else if (transferEvent == TransferBehavior.Event.Discharging) {
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
zoneId,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, 52, 0L)
+ PlanetsideAttribute(vguid, 52, 0L)
) // panel glow off
}
}
@@ -189,7 +188,8 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
transferTarget match {
case Some(silo: ResourceSilo) =>
scala.math.min(
- scala.math.min(silo.MaxNtuCapacitor / silo.Definition.ChargeTime.toSeconds.toFloat, chargeable.NtuCapacitor),
+ scala.math
+ .min(silo.MaxNtuCapacitor / silo.Definition.ChargeTime.toSeconds.toFloat, chargeable.NtuCapacitor),
max
)
case _ =>
@@ -209,9 +209,11 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit = {
val obj = ChargeTransferObject
- if (obj.DeploymentState == DriveState.Deployed &&
- transferEvent == TransferBehavior.Event.Charging &&
- ReceiveAndDepositUntilFull(obj, amount)) {
+ if (
+ obj.DeploymentState == DriveState.Deployed &&
+ transferEvent == TransferBehavior.Event.Charging &&
+ ReceiveAndDepositUntilFull(obj, amount)
+ ) {
panelAnimationFunc()
} else {
TryStopChargingEvent(obj)
diff --git a/src/main/scala/net/psforever/objects/vehicles/control/ApcControl.scala b/src/main/scala/net/psforever/objects/vehicles/control/ApcControl.scala
index c08b7a432..09236c8ae 100644
--- a/src/main/scala/net/psforever/objects/vehicles/control/ApcControl.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/ApcControl.scala
@@ -10,8 +10,8 @@ import net.psforever.objects.vital.projectile.MaxDistanceCutoff
import net.psforever.objects.vital.prop.DamageWithPosition
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{TriggerEffectMessage, TriggeredEffectLocation}
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import net.psforever.types.PlanetSideGUID
/**
@@ -46,23 +46,20 @@ class ApcControl(vehicle: Vehicle)
val zone = obj.Zone
val events = zone.VehicleEvents
val pos = obj.Position
- val GUID0 = Service.defaultPlayerGUID
+ val GUID0 = Default.GUID0
val emp = ApcControl.apc_emp
val faction = obj.Faction
//drain the capacitor
capacitorCharge(-vehicle.Capacitor)
//cause the emp
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
zone.id,
- VehicleAction.SendResponse(
- GUID0,
- TriggerEffectMessage(
+ SendResponse(TriggerEffectMessage(
GUID0,
s"apc_explosion_emp_${faction.toString.toLowerCase}",
None,
Some(TriggeredEffectLocation(pos, obj.Orientation))
- )
- )
+ ))
)
//resolve what targets are affected by the emp
Zone.serverSideDamage(
diff --git a/src/main/scala/net/psforever/objects/vehicles/control/BfrControl.scala b/src/main/scala/net/psforever/objects/vehicles/control/BfrControl.scala
index 4f956351b..af869a71f 100644
--- a/src/main/scala/net/psforever/objects/vehicles/control/BfrControl.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/BfrControl.scala
@@ -16,8 +16,8 @@ import net.psforever.objects.vital.ShieldCharge
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone
import net.psforever.packet.game._
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{GenericObjectAction, PlanetsideAttribute, SendResponse}
import net.psforever.types._
import scala.annotation.unused
@@ -269,9 +269,9 @@ class BfrControl(vehicle: Vehicle)
def disableShield(): Unit = {
val zone = vehicle.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
s"${zone.id}",
- VehicleAction.SendResponse(PlanetSideGUID(0), GenericObjectActionMessage(vehicle.GUID, 45))
+ SendResponse(GenericObjectActionMessage(vehicle.GUID, 45))
)
}
@@ -283,9 +283,9 @@ class BfrControl(vehicle: Vehicle)
def enableShield(): Unit = {
val zone = vehicle.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
s"${zone.id}",
- VehicleAction.SendResponse(PlanetSideGUID(0), GenericObjectActionMessage(vehicle.GUID, 44))
+ SendResponse(GenericObjectActionMessage(vehicle.GUID, 44))
)
}
@@ -334,9 +334,9 @@ class BfrControl(vehicle: Vehicle)
val vguid = vehicle.GUID
val zone = vehicle.Zone
val shields = vehicle.Shields
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, vguid, vehicle.Definition.shieldUiAttribute, shields)
+ PlanetsideAttribute(vguid, vehicle.Definition.shieldUiAttribute, shields)
)
}
@@ -399,7 +399,7 @@ class BfrControl(vehicle: Vehicle)
}) match {
case (slot, Some(_)) =>
armManagementFunc(slot)
- val guid0 = Service.defaultPlayerGUID
+ val guid0 = Default.GUID0
val doNotSendTo = other match {
case Some(pguid: PlanetSideGUID) => pguid
case _ => guid0
@@ -414,9 +414,10 @@ class BfrControl(vehicle: Vehicle)
}) match {
case Some(useThisGuid) =>
val zone = vehicle.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.GenericObjectAction(doNotSendTo, useThisGuid, action)
+ doNotSendTo,
+ GenericObjectAction(useThisGuid, action)
)
case _ => ()
}
@@ -546,7 +547,7 @@ class BfrControl(vehicle: Vehicle)
val obj = ChargeTransferObject
val zone = obj.Zone
val events = zone.VehicleEvents
- val GUID0 = Service.defaultPlayerGUID
+ val GUID0 = Default.GUID0
getNtuContainer() match {
case Some(siphon : NtuSiphon)
if GlobalDefinitions.isBattleFrameNTUSiphon(siphon.equipment.Definition) &&
@@ -563,17 +564,14 @@ class BfrControl(vehicle: Vehicle)
//cause the emp
siphon.equipment.lastDischarge = now
//TODO this is the apc emp effect; is there an ntu siphon emp effect?
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
zone.id,
- VehicleAction.SendResponse(
- GUID0,
- TriggerEffectMessage(
+ SendResponse(TriggerEffectMessage(
GUID0,
s"apc_explosion_emp_${faction.toString.toLowerCase}",
None,
Some(TriggeredEffectLocation(pos, obj.Orientation))
- )
- )
+ ))
)
//resolve what targets are affected by the emp
Zone.serverSideDamage(
@@ -588,12 +586,9 @@ class BfrControl(vehicle: Vehicle)
//the siphon is not ready to dispatch another emp; chat message borrowed from kit use logic
//the client actually enforces a hard limit of 30s before it will react to use of the siphon emp mode
//it does not even dispatch the packet before that, making it rare if this precautionary message is seen
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
obj.Seats(0).occupant.get.Name,
- VehicleAction.SendResponse(
- GUID0,
- ChatMsg(ChatMessageType.UNK_225, wideContents = false, "", s"@TimeUntilNextUse^${30000 - elapsedWait}", None)
- )
+ SendResponse(ChatMsg(ChatMessageType.UNK_225, wideContents = false, "", s"@TimeUntilNextUse^${30000 - elapsedWait}", None))
)
}
case _ => ()
diff --git a/src/main/scala/net/psforever/objects/vehicles/BfrTransferBehavior.scala b/src/main/scala/net/psforever/objects/vehicles/control/BfrTransferBehavior.scala
similarity index 96%
rename from src/main/scala/net/psforever/objects/vehicles/BfrTransferBehavior.scala
rename to src/main/scala/net/psforever/objects/vehicles/control/BfrTransferBehavior.scala
index 24aa6d9c2..db80c1c9a 100644
--- a/src/main/scala/net/psforever/objects/vehicles/BfrTransferBehavior.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/BfrTransferBehavior.scala
@@ -1,18 +1,20 @@
// Copyright (c) 2021 PSForever
-package net.psforever.objects.vehicles
+package net.psforever.objects.vehicles.control
import akka.actor.ActorRef
import akka.actor.typed.scaladsl.adapter._
import net.psforever.actors.commands.NtuCommand
import net.psforever.actors.zone.BuildingActor
-import net.psforever.objects.{NtuContainer, NtuContainerDefinition, _}
+import net.psforever.objects._
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.equipment.EquipmentSlot
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.structures.WarpGate
import net.psforever.objects.serverobject.transfer.{TransferBehavior, TransferContainer}
+import net.psforever.objects.vehicles.VehicleSubsystem
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -116,9 +118,9 @@ trait BfrTransferBehavior
def UpdateNtuUI(vehicle: Vehicle with NtuContainer, siphon: NtuContainer): Unit = {
siphon match {
case equip: NtuSiphon =>
- vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
+ vehicle.Zone.VehicleEvents ! MessageEnvelope(
vehicle.Actor.toString,
- VehicleAction.InventoryState2(PlanetSideGUID(0), equip.storageGUID, siphon.GUID, siphon.NtuCapacitor.toInt)
+ VehicleAction.InventoryState2(equip.storageGUID, siphon.GUID, siphon.NtuCapacitor.toInt)
)
case _ => ;
}
diff --git a/src/main/scala/net/psforever/objects/vehicles/CargoBehavior.scala b/src/main/scala/net/psforever/objects/vehicles/control/CargoBehavior.scala
similarity index 98%
rename from src/main/scala/net/psforever/objects/vehicles/CargoBehavior.scala
rename to src/main/scala/net/psforever/objects/vehicles/control/CargoBehavior.scala
index 2a9e9cd97..854adc71b 100644
--- a/src/main/scala/net/psforever/objects/vehicles/CargoBehavior.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/CargoBehavior.scala
@@ -1,5 +1,5 @@
// Copyright (c) 2020 PSForever
-package net.psforever.objects.vehicles
+package net.psforever.objects.vehicles.control
import akka.actor.Actor
import net.psforever.objects._
diff --git a/src/main/scala/net/psforever/objects/vehicles/control/CargoCarrierControl.scala b/src/main/scala/net/psforever/objects/vehicles/control/CargoCarrierControl.scala
index 5892d974f..3609f2775 100644
--- a/src/main/scala/net/psforever/objects/vehicles/control/CargoCarrierControl.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/CargoCarrierControl.scala
@@ -3,7 +3,7 @@ package net.psforever.objects.vehicles.control
import net.psforever.objects._
import net.psforever.objects.serverobject.damage.{Damageable, DamageableVehicle}
-import net.psforever.objects.vehicles.{Cargo, CarrierBehavior}
+import net.psforever.objects.vehicles.Cargo
import net.psforever.objects.vital.interaction.DamageResult
/**
diff --git a/src/main/scala/net/psforever/objects/vehicles/CarrierBehavior.scala b/src/main/scala/net/psforever/objects/vehicles/control/CarrierBehavior.scala
similarity index 90%
rename from src/main/scala/net/psforever/objects/vehicles/CarrierBehavior.scala
rename to src/main/scala/net/psforever/objects/vehicles/control/CarrierBehavior.scala
index 93d47cabb..bf3417ce9 100644
--- a/src/main/scala/net/psforever/objects/vehicles/CarrierBehavior.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/CarrierBehavior.scala
@@ -1,17 +1,18 @@
// Copyright (c) 2021 PSForever
-package net.psforever.objects.vehicles
+package net.psforever.objects.vehicles.control
import akka.actor.{Actor, Cancellable}
import net.psforever.actors.zone.ZoneActor
-import net.psforever.objects.zones.Zone
import net.psforever.objects._
import net.psforever.objects.sourcing.VehicleSource
+import net.psforever.objects.vehicles.Cargo
import net.psforever.objects.vital.VehicleCargoMountActivity
+import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{CargoMountPointStatusMessage, ObjectAttachMessage, ObjectDetachMessage, PlanetsideAttributeMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, CargoStatus, PlanetSideGUID, Vector3}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.concurrent.duration._
@@ -58,10 +59,9 @@ trait CarrierBehavior {
) {
if (iteration == 0) {
//open the cargo bay door
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id,
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
+ SendResponse(
CargoMountPointStatusMessage(
obj.GUID,
PlanetSideGUID(0),
@@ -206,14 +206,10 @@ object CarrierBehavior {
log.debug(s"HandleCheckCargoMounting: mounting cargo vehicle in carrier at distance of $distance")
CargoMountAction(carrier, cargo, hold, carrierGUID)
cargo.Velocity = None
- zone.VehicleEvents ! VehicleServiceMessage(
- s"${cargo.Actor}",
- VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health))
- )
- zone.VehicleEvents ! VehicleServiceMessage(
- s"${cargo.Actor}",
- VehicleAction.SendResponse(PlanetSideGUID(0), PlanetsideAttributeMessage(cargoGUID, cargo.Definition.shieldUiAttribute, cargo.Shields))
- )
+ zone.VehicleEvents ! MessageEnvelope(s"${cargo.Actor}", SendResponse(Seq(
+ PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health),
+ PlanetsideAttributeMessage(cargoGUID, cargo.Definition.shieldUiAttribute, cargo.Shields)
+ )))
CargoMountBehaviorForAll(carrier, cargo, mountPoint)
zone.actor ! ZoneActor.RemoveFromBlockMap(cargo)
false
@@ -224,11 +220,10 @@ object CarrierBehavior {
)
cargo.Actor ! CargoBehavior.EndCargoMounting(carrierGUID)
val cargoDriverGUID = cargo.Seats(0).occupant.get.GUID
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.SendResponse(
- cargoDriverGUID,
- CargoMountPointStatusMessage(
+ cargoDriverGUID,
+ SendResponse(CargoMountPointStatusMessage(
carrierGUID,
PlanetSideGUID(0),
PlanetSideGUID(0),
@@ -236,8 +231,7 @@ object CarrierBehavior {
mountPoint,
CargoStatus.Empty,
0
- )
- )
+ ))
)
false
//sending packet to the cargo vehicle's client results in player being lock in own vehicle
@@ -326,11 +320,10 @@ object CarrierBehavior {
)
cargo.Actor ! CargoBehavior.EndCargoDismounting(carrierGUID)
val cargoDriverGUID = cargo.Seats(0).occupant.get.GUID
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.SendResponse(
- cargoDriverGUID,
- CargoMountPointStatusMessage(
+ cargoDriverGUID,
+ SendResponse(CargoMountPointStatusMessage(
carrierGUID,
PlanetSideGUID(0),
PlanetSideGUID(0),
@@ -338,8 +331,7 @@ object CarrierBehavior {
mountPoint,
CargoStatus.Empty,
0
- )
- )
+ ))
)
false
//sending packet to the cargo vehicle's client results in player being lock in own vehicle
@@ -448,18 +440,14 @@ object CarrierBehavior {
//the lodestar's cargo hold is almost the center of the vehicle
carrier.Position
}
- val GUID0 = Service.defaultPlayerGUID
+ val GUID0 = Default.GUID0
val zoneId = zone.id
val events = zone.VehicleEvents
val cargoActor = cargo.Actor
- events ! VehicleServiceMessage(
- s"$cargoActor",
- VehicleAction.SendResponse(GUID0, PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health))
- )
- events ! VehicleServiceMessage(
- s"$cargoActor",
- VehicleAction.SendResponse(GUID0, PlanetsideAttributeMessage(cargoGUID, cargo.Definition.shieldUiAttribute, cargo.Shields))
- )
+ events ! MessageEnvelope(s"$cargoActor", SendResponse(Seq(
+ PlanetsideAttributeMessage(cargoGUID, 0, cargo.Health),
+ PlanetsideAttributeMessage(cargoGUID, cargo.Definition.shieldUiAttribute, cargo.Shields)
+ )))
zone.actor ! ZoneActor.AddToBlockMap(cargo, carrier.Position)
if (carrier.isFlying) {
//the carrier vehicle is flying; eject the cargo vehicle
@@ -468,9 +456,7 @@ object CarrierBehavior {
val detachCargoMsg = ObjectDetachMessage(carrierGUID, cargoGUID, cargoHoldPosition - Vector3.z(1), rotation)
val resetCargoMsg =
CargoMountPointStatusMessage(carrierGUID, GUID0, GUID0, cargoGUID, mountPoint, CargoStatus.Empty, 0)
- events ! VehicleServiceMessage(zoneId, VehicleAction.SendResponse(GUID0, ejectCargoMsg))
- events ! VehicleServiceMessage(zoneId, VehicleAction.SendResponse(GUID0, detachCargoMsg))
- events ! VehicleServiceMessage(zoneId, VehicleAction.SendResponse(GUID0, resetCargoMsg))
+ events ! MessageEnvelope(zoneId, SendResponse(Seq(ejectCargoMsg, detachCargoMsg, resetCargoMsg)))
log.debug(s"HandleVehicleCargoDismount: eject - $ejectCargoMsg, detach - $detachCargoMsg")
if (driverOpt.isEmpty) {
//TODO cargo should drop like a rock like normal; until then, deconstruct it
@@ -483,18 +469,17 @@ object CarrierBehavior {
CargoMountPointStatusMessage(carrierGUID, GUID0, cargoGUID, GUID0, mountPoint, CargoStatus.InProgress, 0)
val cargoDetachMessage =
ObjectDetachMessage(carrierGUID, cargoGUID, cargoHoldPosition + Vector3.z(1f), rotation)
- events ! VehicleServiceMessage(zoneId, VehicleAction.SendResponse(GUID0, cargoStatusMessage))
- events ! VehicleServiceMessage(zoneId, VehicleAction.SendResponse(GUID0, cargoDetachMessage))
+ events ! MessageEnvelope(zoneId, SendResponse(Seq(cargoStatusMessage, cargoDetachMessage)))
driverOpt match {
case Some(driver) =>
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
s"${driver.Name}",
- VehicleAction.KickCargo(GUID0, cargo, cargo.Definition.AutoPilotSpeed2, 2500)
+ VehicleAction.KickCargo(cargo, cargo.Definition.AutoPilotSpeed2, 2500)
)
case None =>
val resetCargoMsg =
CargoMountPointStatusMessage(carrierGUID, GUID0, GUID0, cargoGUID, mountPoint, CargoStatus.Empty, 0)
- events ! VehicleServiceMessage(zoneId, VehicleAction.SendResponse(GUID0, resetCargoMsg)) //lazy
+ events ! MessageEnvelope(zoneId, SendResponse(resetCargoMsg)) //lazy
//TODO cargo should back out like normal; until then, deconstruct it
cargoActor ! Vehicle.Deconstruct()
}
@@ -610,8 +595,7 @@ object CarrierBehavior {
attachMessage: ObjectAttachMessage,
mountPointStatusMessage: CargoMountPointStatusMessage
): Unit = {
- zone.VehicleEvents ! VehicleServiceMessage(zone.id, VehicleAction.SendResponse(exclude, attachMessage))
- zone.VehicleEvents ! VehicleServiceMessage(zone.id, VehicleAction.SendResponse(exclude, mountPointStatusMessage))
+ zone.VehicleEvents ! MessageEnvelope(zone.id, exclude, SendResponse(Seq(attachMessage, mountPointStatusMessage)))
}
/**
@@ -631,14 +615,7 @@ object CarrierBehavior {
val zone = carrier.Zone
val zoneId = zone.id
val msgs @ (attachMessage, mountPointStatusMessage) = CargoMountMessages(carrier, cargo, mountPoint)
- zone.VehicleEvents ! VehicleServiceMessage(
- zoneId,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, attachMessage)
- )
- zone.VehicleEvents ! VehicleServiceMessage(
- zoneId,
- VehicleAction.SendResponse(Service.defaultPlayerGUID, mountPointStatusMessage)
- )
+ zone.VehicleEvents ! MessageEnvelope(zoneId, SendResponse(Seq(attachMessage, mountPointStatusMessage)))
msgs
}
diff --git a/src/main/scala/net/psforever/objects/vehicles/control/VehicleCapacitance.scala b/src/main/scala/net/psforever/objects/vehicles/control/VehicleCapacitance.scala
index 2b84932a9..42bb8a01b 100644
--- a/src/main/scala/net/psforever/objects/vehicles/control/VehicleCapacitance.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/VehicleCapacitance.scala
@@ -3,8 +3,8 @@ package net.psforever.objects.vehicles.control
import akka.actor.{Actor, Cancellable}
import net.psforever.objects._
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -59,9 +59,9 @@ trait VehicleCapacitance {
protected def showCapacitorCharge(): Unit = {
val obj = CapacitanceObject
- obj.Zone.VehicleEvents ! VehicleServiceMessage(
+ obj.Zone.VehicleEvents ! MessageEnvelope(
self.toString(),
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 113, obj.Capacitor)
+ PlanetsideAttribute(obj.GUID, 113, obj.Capacitor)
)
}
diff --git a/src/main/scala/net/psforever/objects/vehicles/control/VehicleControl.scala b/src/main/scala/net/psforever/objects/vehicles/control/VehicleControl.scala
index adf02e282..6940e3c27 100644
--- a/src/main/scala/net/psforever/objects/vehicles/control/VehicleControl.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/control/VehicleControl.scala
@@ -36,9 +36,10 @@ import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game._
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.types._
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
+import net.psforever.services.vehicle.VehicleAction
import scala.annotation.unused
import scala.concurrent.ExecutionContext.Implicits.global
@@ -204,8 +205,7 @@ class VehicleControl(vehicle: Vehicle)
case Vehicle.UpdateSubsystemStates(toChannel, stateToResolve) =>
val events = vehicle.Zone.VehicleEvents
- val guid0 = Service.defaultPlayerGUID
- (stateToResolve match {
+ val pkts = (stateToResolve match {
case Some(state) =>
vehicle.Subsystems().filter { _.Enabled == state } //only subsystems that are enabled or are disabled
case None =>
@@ -213,7 +213,7 @@ class VehicleControl(vehicle: Vehicle)
})
.flatMap { _.getMessage(vehicle) }
.foreach { pkt =>
- events ! VehicleServiceMessage(toChannel, VehicleAction.SendResponse(guid0, pkt))
+ events ! MessageEnvelope(toChannel, SendResponse(pkt))
}
case FactionAffinity.ConvertFactionAffinity(faction) =>
@@ -244,11 +244,11 @@ class VehicleControl(vehicle: Vehicle)
log.info(s"changing vehicle equipment loadout to ${player.Name}'s option #${msg.unk1 + 1}")
val (oldWeapons, newWeapons, oldInventory, finalInventory) =
handleTerminalMessageVehicleLoadout(player, definition, weapons, inventory)
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
VehicleAction.ChangeLoadout(vehicle.GUID, oldWeapons, newWeapons, oldInventory, finalInventory)
)
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
player.Name,
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result = true)
)
@@ -256,7 +256,7 @@ class VehicleControl(vehicle: Vehicle)
case _ => ()
}
} else {
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
player.Name,
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result = false)
)
@@ -330,9 +330,9 @@ class VehicleControl(vehicle: Vehicle)
.orElse {
case VehicleControl.Deletion() =>
val zone = vehicle.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.UnloadVehicle(Service.defaultPlayerGUID, vehicle, vehicle.GUID)
+ VehicleAction.UnloadVehicle(vehicle, vehicle.GUID)
)
zone.Transport.tell(Zone.Vehicle.Despawn(vehicle), zone.Transport)
//notify target spawner that the vehicle has despawned if this is a VR Shooting Range zone
@@ -451,7 +451,7 @@ class VehicleControl(vehicle: Vehicle)
zone.actor ! ZoneActor.AddToBlockMap(player, vehicle.Position)
}
if (player.HasGUID) {
- events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = true, guid))
+ events ! MessageEnvelope(zoneId, player.GUID, VehicleAction.KickPassenger(4, unk2 = true, guid))
}
}
}
@@ -521,9 +521,9 @@ class VehicleControl(vehicle: Vehicle)
val obj = ContainerObject
obj.Find(item) match {
case Some(slot) =>
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
self.toString,
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectAttachMessage(obj.GUID, item.GUID, slot))
+ SendResponse(ObjectAttachMessage(obj.GUID, item.GUID, slot))
)
case None => ()
}
@@ -533,9 +533,9 @@ class VehicleControl(vehicle: Vehicle)
def RemoveItemFromSlotCallback(item: Equipment, slot: Int): Unit = {
val zone = ContainerObject.Zone
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
self.toString,
- VehicleAction.UnstowEquipment(Service.defaultPlayerGUID, item.GUID)
+ VehicleAction.UnstowEquipment(item.GUID)
)
}
@@ -547,25 +547,22 @@ class VehicleControl(vehicle: Vehicle)
val events = zone.VehicleEvents
val iguid = item.GUID
item.Faction = obj.Faction
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
//TODO when a new weapon, the equipment slot ui goes blank, but the weapon functions; remount vehicle to correct it
if (obj.VisibleSlots.contains(slot)) zone.id else channel,
- VehicleAction.SendResponse(
- Service.defaultPlayerGUID,
- OCM.detailed(item, ObjectCreateMessageParent(oguid, slot))
- )
+ SendResponse(OCM.detailed(item, ObjectCreateMessageParent(oguid, slot)))
)
item match {
case box: AmmoBox =>
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
channel,
- VehicleAction.InventoryState2(Service.defaultPlayerGUID, iguid, oguid, box.Capacity)
+ VehicleAction.InventoryState2(iguid, oguid, box.Capacity)
)
case weapon: Tool =>
weapon.AmmoSlots.map { slot => slot.Box }.foreach { box =>
- events ! VehicleServiceMessage(
+ events ! MessageEnvelope(
channel,
- VehicleAction.InventoryState2(Service.defaultPlayerGUID, box.GUID, iguid, box.Capacity)
+ VehicleAction.InventoryState2(box.GUID, iguid, box.Capacity)
)
}
case _ => ()
@@ -576,9 +573,9 @@ class VehicleControl(vehicle: Vehicle)
val obj = ContainerObject
val zone = obj.Zone
val toChannel = if (obj.VisibleSlots.contains(fromSlot)) zone.id else self.toString
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
toChannel,
- VehicleAction.ObjectDelete(item.GUID)
+ ObjectDelete(item.GUID)
)
}
@@ -639,9 +636,9 @@ class VehicleControl(vehicle: Vehicle)
if (canChargeShields) {
vehicle.LogActivity(ShieldCharge(amount, motivator))
vehicle.Shields = vehicle.Shields + amount
- vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
+ vehicle.Zone.VehicleEvents ! MessageEnvelope(
s"${vehicle.Actor}",
- VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), vehicle.GUID, vehicle.Definition.shieldUiAttribute, vehicle.Shields)
+ PlanetsideAttribute(vehicle.GUID, vehicle.Definition.shieldUiAttribute, vehicle.Shields)
)
}
}
@@ -694,9 +691,10 @@ class VehicleControl(vehicle: Vehicle)
case Some(allow) =>
val group = AccessPermissionGroup(attribute - 10)
log.info(s"$dname changed ${vehicle.Definition.Name}'s access permission $group to $allow")
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.SeatPermissions(dguid, vguid, attribute, value)
+ dguid,
+ VehicleAction.SeatPermissions(vguid, attribute, value)
)
//kick players who should not be seated in the vehicle due to permission changes
if (allow == VehicleLockState.Locked) { //TODO only important permission atm
@@ -707,9 +705,10 @@ class VehicleControl(vehicle: Vehicle)
if (vehicle.SeatPermissionGroup(seatIndex).contains(group) && !tplayer.Name.equals(dname)) { //can not kick self
seat.unmount(tplayer)
tplayer.VehicleSeated = None
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
zone.id,
- VehicleAction.KickPassenger(tplayer.GUID, 4, unk2 = false, vguid)
+ tplayer.GUID,
+ VehicleAction.KickPassenger(4, unk2 = false, vguid)
)
}
case _ => () // No player seated
@@ -755,15 +754,10 @@ class VehicleControl(vehicle: Vehicle)
def vehicleSubsystemMessages(messages: List[PlanetSideGamePacket]): Unit = {
val zone = vehicle.Zone
- val zoneid = zone.id
- val events = zone.VehicleEvents
- val guid0 = Service.defaultPlayerGUID
- messages.foreach { pkt =>
- events ! VehicleServiceMessage(
- zoneid,
- VehicleAction.SendResponse(guid0, pkt)
- )
- }
+ zone.VehicleEvents ! MessageEnvelope(
+ zone.id,
+ SendResponse(messages)
+ )
}
override protected def canChangeVulnerability(state: Damageable.PersonalVulnerability): Boolean = {
diff --git a/src/main/scala/net/psforever/objects/vehicles/interaction/WithEntranceInVehicle.scala b/src/main/scala/net/psforever/objects/vehicles/interaction/WithEntranceInVehicle.scala
index 41eed6d99..10009f7dd 100644
--- a/src/main/scala/net/psforever/objects/vehicles/interaction/WithEntranceInVehicle.scala
+++ b/src/main/scala/net/psforever/objects/vehicles/interaction/WithEntranceInVehicle.scala
@@ -6,6 +6,8 @@ import net.psforever.objects.avatar.interaction.WithEntrance
import net.psforever.objects.serverobject.doors.InteriorDoorPassage
import net.psforever.objects.serverobject.environment.PieceOfEnvironment
import net.psforever.objects.zones.interaction.InteractsWithZone
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
class WithEntranceInVehicle
extends WithEntrance() {
@@ -39,12 +41,10 @@ class WithEntranceInVehicle
private def warnAboutProximity(obj: InteractsWithZone, msg: String): Unit = {
import net.psforever.packet.game.ChatMsg
- import net.psforever.services.Service
- import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.types.ChatMessageType
- obj.Zone.AvatarEvents ! AvatarServiceMessage(
+ obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Actor.toString(),
- AvatarAction.SendResponse(Service.defaultPlayerGUID, ChatMsg(ChatMessageType.UNK_227, msg))
+ SendResponse(ChatMsg(ChatMessageType.UNK_227, msg))
)
}
}
diff --git a/src/main/scala/net/psforever/objects/zones/MapInfo.scala b/src/main/scala/net/psforever/objects/zones/MapInfo.scala
index 31e648aa3..2f85c696b 100644
--- a/src/main/scala/net/psforever/objects/zones/MapInfo.scala
+++ b/src/main/scala/net/psforever/objects/zones/MapInfo.scala
@@ -2,11 +2,10 @@ package net.psforever.objects.zones
import enumeratum.values.{StringEnum, StringEnumEntry}
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle}
-import net.psforever.objects.serverobject.environment.{Pool, _}
+import net.psforever.objects.serverobject.environment._
import net.psforever.packet.game.{ChatMsg, OffshoreVehicleMessage}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID, Vector3}
sealed abstract class MapInfo(
@@ -687,23 +686,17 @@ object MapEnvironment {
" will be executed for treason." //TODO for bops, eventually
}
val warning = s"Do not travel any further $trespass of the battlefield or you$punishment"
- p.Zone.AvatarEvents ! AvatarServiceMessage(
+ p.Zone.AvatarEvents ! MessageEnvelope(
p.Name,
- AvatarAction.SendResponseTargeted(
- Service.defaultPlayerGUID,
- ChatMsg(ChatMessageType.CMT_QUIT, warning)
- )
+ SendResponse(ChatMsg(ChatMessageType.CMT_QUIT, warning))
)
case _ => ;
}
obj match {
case v: Vehicle =>
- v.Zone.VehicleEvents ! VehicleServiceMessage(
+ v.Zone.VehicleEvents ! MessageEnvelope(
v.Actor.toString(),
- VehicleAction.SendResponse(
- Service.defaultPlayerGUID,
- OffshoreVehicleMessage(v.Seats(0).occupant.get.GUID, v.GUID, msg)
- )
+ SendResponse(OffshoreVehicleMessage(v.Seats(0).occupant.get.GUID, v.GUID, msg))
)
case _ => ;
}
diff --git a/src/main/scala/net/psforever/objects/zones/Zone.scala b/src/main/scala/net/psforever/objects/zones/Zone.scala
index c01c41f05..4e237f06f 100644
--- a/src/main/scala/net/psforever/objects/zones/Zone.scala
+++ b/src/main/scala/net/psforever/objects/zones/Zone.scala
@@ -1571,6 +1571,17 @@ object Zone {
}
}
+ def AmsSpawnPoints(zone: Zone): List[SpawnTube] = {
+ import net.psforever.objects.vehicles.UtilityType
+ import net.psforever.objects.GlobalDefinitions
+ zone.Vehicles
+ .filter(veh =>
+ veh.Health > 0 && veh.Definition == GlobalDefinitions.ams && veh.DeploymentState == DriveState.Deployed
+ )
+ .flatMap(veh => veh.Utilities.values.filter(util => util.UtilType == UtilityType.ams_respawn_tube))
+ .map(util => util().asInstanceOf[SpawnTube])
+ }
+
object Setup {
/* zone setup code */
@@ -1613,10 +1624,9 @@ object Zone {
if (zone.id.startsWith("tzsh")) {
zone.npcPopulation = context.actorOf(Props(classOf[ShootingRangeTargetSpawnerActor], zone), s"$id-npcs")
}
-
- zone.avatarEvents = context.actorOf(Props(classOf[AvatarService], zone), s"$id-avatar-events")
- zone.localEvents = context.actorOf(Props(classOf[LocalService], zone), s"$id-local-events")
- zone.vehicleEvents = context.actorOf(Props(classOf[VehicleService], zone), s"$id-vehicle-events")
+ zone.avatarEvents = context.actorOf(AvatarService(), s"$id-avatar-events")
+ zone.localEvents = context.actorOf(LocalService(zone), s"$id-local-events")
+ zone.vehicleEvents = context.actorOf(VehicleService(), s"$id-vehicle-events")
zone.timeOfDayOrigin = System.currentTimeMillis()
@@ -1707,14 +1717,14 @@ object Zone {
.flatMap(_.Amenities.filter(_.Definition == GlobalDefinitions.resource_silo))
.collect {
case silo: ResourceSilo =>
- silo.Actor ! Service.Startup()
+ silo.Actor ! Service.Startup
}
//some painfields need to look for their closest door
buildings.values
.flatMap(_.Amenities.filter(_.Definition.isInstanceOf[PainboxDefinition]))
.collect {
case painbox: Painbox =>
- painbox.Actor ! Service.Startup()
+ painbox.Actor ! Service.Startup
}
//the orbital_buildings in sanctuary zones have to establish their shuttle routes
map.shuttleBays
@@ -1722,7 +1732,7 @@ object Zone {
guid(_)
}
.collect { case Some(obj: OrbitalShuttlePad) =>
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
}
//allocate soi information
zone.soi ! SOI.Build()
diff --git a/src/main/scala/net/psforever/objects/zones/ZoneDeployableActor.scala b/src/main/scala/net/psforever/objects/zones/ZoneDeployableActor.scala
index f5c0197b7..431f67e14 100644
--- a/src/main/scala/net/psforever/objects/zones/ZoneDeployableActor.scala
+++ b/src/main/scala/net/psforever/objects/zones/ZoneDeployableActor.scala
@@ -10,7 +10,8 @@ import net.psforever.objects.sourcing.ObjectSource
import net.psforever.objects.vehicles.MountedWeapons
import net.psforever.objects.vital.SpawningActivity
import net.psforever.packet.game.ChatMsg
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import net.psforever.types.ChatMessageType
import scala.annotation.tailrec
@@ -107,9 +108,9 @@ object ZoneDeployableActor {
val position = obj.Position
deployableList.find(_ eq obj) match {
case _ if Interference.Test(zone, obj).nonEmpty =>
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
obj.OwnerName.getOrElse(""),
- LocalAction.SendResponse(ChatMsg(ChatMessageType.UNK_227, "@nomove_intersecting"))
+ SendResponse(ChatMsg(ChatMessageType.UNK_227, "@nomove_intersecting"))
) //may not be the correct message but is sufficient at explaining why the deployable can not be built
false
case None =>
diff --git a/src/main/scala/net/psforever/objects/zones/ZoneGroundActor.scala b/src/main/scala/net/psforever/objects/zones/ZoneGroundActor.scala
index cf41f29d7..84f44a3d0 100644
--- a/src/main/scala/net/psforever/objects/zones/ZoneGroundActor.scala
+++ b/src/main/scala/net/psforever/objects/zones/ZoneGroundActor.scala
@@ -4,9 +4,9 @@ package net.psforever.objects.zones
import akka.actor.Actor
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.equipment.Equipment
+import net.psforever.services.avatar.support.{DropItemEnvelope, PickupItemEnvelope}
import net.psforever.types.PlanetSideGUID
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer
@@ -31,10 +31,7 @@ class ZoneGroundActor(zone: Zone, equipmentOnGround: ListBuffer[Equipment]) exte
equipmentOnGround += item
item.Position = pos
item.Orientation = orient
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.DropItem(Service.defaultPlayerGUID, item)
- )
+ zone.AvatarEvents ! DropItemEnvelope(zone.id, AvatarAction.DropItem(item), zone)
zone.actor ! ZoneActor.AddToBlockMap(item, pos)
Zone.Ground.ItemOnGround(item, pos, orient)
})
@@ -42,7 +39,7 @@ class ZoneGroundActor(zone: Zone, equipmentOnGround: ListBuffer[Equipment]) exte
case Zone.Ground.PickupItem(item_guid) =>
sender() ! (FindItemOnGround(item_guid) match {
case Some(item) =>
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PickupItem(Service.defaultPlayerGUID, item, 0))
+ zone.AvatarEvents ! PickupItemEnvelope(zone.id, AvatarAction.PickupItem(item, 0), zone)
zone.actor ! ZoneActor.RemoveFromBlockMap(item)
Zone.Ground.ItemInHand(item)
case None =>
@@ -54,7 +51,7 @@ class ZoneGroundActor(zone: Zone, equipmentOnGround: ListBuffer[Equipment]) exte
FindItemOnGround(item_guid) match {
case Some(item) =>
zone.actor ! ZoneActor.RemoveFromBlockMap(item)
- zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PickupItem(Service.defaultPlayerGUID, item, 0))
+ zone.AvatarEvents ! PickupItemEnvelope(zone.id, AvatarAction.PickupItem(item, 0), zone)
case None => ;
}
diff --git a/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala b/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala
index a22b32314..eb4b69958 100644
--- a/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala
+++ b/src/main/scala/net/psforever/objects/zones/ZoneHotSpotProjector.scala
@@ -5,6 +5,9 @@ import akka.actor.{Actor, ActorRef, Cancellable, Props}
import net.psforever.objects.Default
import net.psforever.types.{PlanetSideEmpire, Vector3}
import net.psforever.services.ServiceManager
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.galaxy.GalaxyAction
+
import scala.collection.mutable.ListBuffer
import scala.concurrent.duration._
@@ -302,12 +305,13 @@ class ZoneHotSpotProjector(zone: Zone, hotspots: ListBuffer[HotSpotInfo], blanki
def UpdateHotSpots(affectedFactions: Iterable[PlanetSideEmpire.Value], hotSpotInfos: Iterable[HotSpotInfo]): Unit = {
val zoneNumber = zone.Number
val hotSpotInfoList = hotSpotInfos.toList
- affectedFactions.foreach(faction =>
- galaxy ! Zone.HotSpot.Update(
- faction,
- zoneNumber,
- 1,
- ZoneHotSpotProjector.SpecificHotSpotInfo(faction, hotSpotInfoList)
+ galaxy ! BundledEnvelope(
+ affectedFactions.map(faction =>
+ MessageEnvelope(faction.toString, GalaxyAction.HotSpotUpdate(
+ zoneNumber,
+ 1,
+ ZoneHotSpotProjector.SpecificHotSpotInfo(faction, hotSpotInfoList)
+ ))
)
)
}
diff --git a/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala b/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala
index e972808d6..c276cf0c3 100644
--- a/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala
+++ b/src/main/scala/net/psforever/objects/zones/ZonePopulationActor.scala
@@ -7,7 +7,9 @@ import net.psforever.objects.avatar.{AvatarBot, CorpseControl, PlayerControl}
import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.vital.{InGameHistory, SpawningActivity}
import net.psforever.objects.{Default, Player}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.ObjectDelete
import net.psforever.types.Vector3
import scala.collection.concurrent.TrieMap
@@ -88,9 +90,9 @@ class ZonePopulationActor(zone: Zone, playerMap: TrieMap[Int, Option[Player]], b
if (BotSpawn(bot, botList)) {
bot.Zone = zone
zone.actor ! ZoneActor.AddToBlockMap(bot, bot.Position)
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.LoadPlayer(bot.GUID, bot.Definition.ObjectId, bot.GUID, bot.Definition.Packet.ConstructorData(bot).get, None)
+ zone.AvatarEvents ! MessageEnvelope(
+ zone.id, bot.GUID,
+ AvatarAction.LoadPlayer(bot.Definition.ObjectId, bot.GUID, bot.Definition.Packet.ConstructorData(bot).get, None)
)
}
@@ -99,9 +101,9 @@ class ZonePopulationActor(zone: Zone, playerMap: TrieMap[Int, Option[Player]], b
if (bot.Actor != null) bot.Actor ! akka.actor.PoisonPill
bot.Actor = Default.Actor
zone.actor ! ZoneActor.RemoveFromBlockMap(bot)
- zone.AvatarEvents ! AvatarServiceMessage(
- zone.id,
- AvatarAction.ObjectDelete(bot.GUID, bot.GUID, unk=0)
+ zone.AvatarEvents ! MessageEnvelope(
+ zone.id, bot.GUID,
+ ObjectDelete(bot.GUID, unk=0)
)
}
diff --git a/src/main/scala/net/psforever/objects/zones/ZoneProjectileActor.scala b/src/main/scala/net/psforever/objects/zones/ZoneProjectileActor.scala
index 1fc6deb58..6d8e509e8 100644
--- a/src/main/scala/net/psforever/objects/zones/ZoneProjectileActor.scala
+++ b/src/main/scala/net/psforever/objects/zones/ZoneProjectileActor.scala
@@ -2,10 +2,12 @@
package net.psforever.objects.zones
import akka.actor.{Actor, Cancellable}
+import net.psforever.objects.Default
import net.psforever.objects.ballistics.Projectile
import net.psforever.objects.guid.{GUIDTask, StraightforwardTask, TaskBundle, TaskWorkflow}
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.ObjectDelete
import net.psforever.types.PlanetSideGUID
import scala.collection.mutable
@@ -110,7 +112,7 @@ class ZoneProjectileActor(
TaskBundle(
reg.mainTask,
TaskBundle(
- reg.subTasks(0).mainTask,
+ reg.subTasks.head.mainTask,
unregisterProjectile(obj)
)
)
@@ -142,11 +144,11 @@ class ZoneProjectileActor(
projectileList.addOne(projectile)
val (clarifiedFilterGuid, duration) = if (definition.radiation_cloud) {
zone.blockMap.addTo(projectile)
- (Service.defaultPlayerGUID, projectile.profile.Lifespan seconds)
+ (Default.GUID0, projectile.profile.Lifespan seconds)
} else if (definition.RemoteClientData == (0,0)) {
//remote projectiles that are not radiation clouds have lifespans controlled by the controller (user)
//this projectile has defaulted remote client data
- (Service.defaultPlayerGUID, projectile.profile.Lifespan * 1.5f seconds)
+ (Default.GUID0, projectile.profile.Lifespan * 1.5f seconds)
} else {
//remote projectiles that are not radiation clouds have lifespans controlled by the controller (user)
//if the controller fails, the projectile has a bit more than its normal lifespan before automatic clean up
@@ -156,10 +158,10 @@ class ZoneProjectileActor(
projectileGuid,
context.system.scheduler.scheduleOnce(duration, self, ZoneProjectile.Remove(projectileGuid))
)
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
+ clarifiedFilterGuid,
AvatarAction.LoadProjectile(
- clarifiedFilterGuid,
definition.ObjectId,
projectileGuid,
definition.Packet.ConstructorData(projectile).get
@@ -188,19 +190,19 @@ class ZoneProjectileActor(
projectileList.remove(projectileList.indexOf(projectile))
if (projectile.Definition.radiation_cloud) {
zone.blockMap.removeFrom(projectile)
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.ObjectDelete(PlanetSideGUID(0), projectile_guid, 2)
+ ObjectDelete(projectile_guid, 2)
)
} else if (projectile.Definition.RemoteClientData == (0,0)) {
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.ObjectDelete(PlanetSideGUID(0), projectile_guid, 2)
+ ObjectDelete(projectile_guid, 2)
)
} else {
- zone.AvatarEvents ! AvatarServiceMessage(
+ zone.AvatarEvents ! MessageEnvelope(
zone.id,
- AvatarAction.ProjectileExplodes(PlanetSideGUID(0), projectile_guid, projectile)
+ AvatarAction.ProjectileExplodes(projectile_guid, projectile)
)
}
}
diff --git a/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala b/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala
index 29dacff8d..eba37613a 100644
--- a/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala
+++ b/src/main/scala/net/psforever/objects/zones/ZoneVehicleActor.scala
@@ -9,8 +9,8 @@ import net.psforever.objects.serverobject.structures.WarpGate
import net.psforever.objects.vital.InGameHistory
import net.psforever.objects.{Default, GlobalDefinitions, Vehicle}
import net.psforever.packet.game.ChatMsg
-import net.psforever.services.Service
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
import net.psforever.types.{ChatMessageType, DriveState, PlanetSideEmpire, Vector3}
import scala.annotation.tailrec
@@ -204,9 +204,9 @@ object ZoneVehicleActor {
else None
}
msgOpt.foreach { msg =>
- zone.VehicleEvents ! VehicleServiceMessage(
+ zone.VehicleEvents ! MessageEnvelope(
vehicle.Seats.headOption.flatMap(_._2.occupant).map(_.Name).getOrElse(""),
- VehicleAction.SendResponse(Service.defaultPlayerGUID, ChatMsg(ChatMessageType.UNK_227, msg))
+ SendResponse(ChatMsg(ChatMessageType.UNK_227, msg))
)
}
msgOpt.isDefined
diff --git a/src/main/scala/net/psforever/objects/zones/exp/KillAssists.scala b/src/main/scala/net/psforever/objects/zones/exp/KillAssists.scala
index 91a4d3a67..55b1b17be 100644
--- a/src/main/scala/net/psforever/objects/zones/exp/KillAssists.scala
+++ b/src/main/scala/net/psforever/objects/zones/exp/KillAssists.scala
@@ -6,7 +6,8 @@ import net.psforever.objects.avatar.scoring.{Assist, Death, KDAStat, Kill}
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
import net.psforever.objects.vital.interaction.{Adversarial, DamageResult}
import net.psforever.objects.vital.{DamagingActivity, HealingActivity, InGameActivity, RepairingActivity, RevivingActivity, SpawningActivity}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.types.PlanetSideEmpire
import net.psforever.util.Config
@@ -42,7 +43,6 @@ object KillAssists {
* @param eventBus where to send the results of the experience determination(s)
* @see `ActorRef`
* @see `AvatarAction.UpdateKillsDeathsAssists`
- * @see `AvatarServiceMessage`
* @see `DamageResult`
* @see `rewardThisPlayerDeath`
*/
@@ -52,9 +52,9 @@ object KillAssists {
history: Iterable[InGameActivity],
eventBus: ActorRef
): Unit = {
- rewardThisPlayerDeath(victim, lastDamage, history).foreach { case (p, kda) =>
- eventBus ! AvatarServiceMessage(p.Name, AvatarAction.UpdateKillsDeathsAssists(p.CharId, kda))
- }
+ eventBus ! BundledEnvelope(rewardThisPlayerDeath(victim, lastDamage, history).map { case (p, kda) =>
+ MessageEnvelope(p.Name, AvatarAction.UpdateKillsDeathsAssists(p.CharId, kda))
+ })
}
/**
diff --git a/src/main/scala/net/psforever/objects/zones/exp/KillContributions.scala b/src/main/scala/net/psforever/objects/zones/exp/KillContributions.scala
index 441d28f8c..25e79e3bf 100644
--- a/src/main/scala/net/psforever/objects/zones/exp/KillContributions.scala
+++ b/src/main/scala/net/psforever/objects/zones/exp/KillContributions.scala
@@ -8,7 +8,8 @@ import net.psforever.objects.sourcing.{BuildingSource, MountableEntry, PlayerSou
import net.psforever.objects.vital.{Contribution, InGameActivity, RevivingActivity, TelepadUseActivity, TerminalUsedActivity, VehicleCargoDismountActivity, VehicleCargoMountActivity, DismountingActivity, MountingActivity}
import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.zones.exp.rec.{CombinedHealthAndArmorContributionProcess, MachineRecoveryExperienceContributionProcess}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{PlanetSideEmpire, Vector3}
import net.psforever.util.Config
@@ -73,7 +74,6 @@ object KillContributions {
* @param eventBus where to send the results of the experience determination(s)
* @see `ActorRef`
* @see `AvatarAction.UpdateKillsDeathsAssists`
- * @see `AvatarServiceMessage`
* @see `rewardTheseSupporters`
* @see `SupportActivity`
*/
@@ -88,7 +88,7 @@ object KillContributions {
//take the output and transform that into contribution distribution data
rewardTheseSupporters(target, history, kill, bep)
.foreach { case (charId, ContributionStatsOutput(player, weapons, exp)) =>
- eventBus ! AvatarServiceMessage(
+ eventBus ! MessageEnvelope(
player.Name,
AvatarAction.UpdateKillsDeathsAssists(charId, SupportActivity(victim, weapons, exp.toLong))
)
@@ -108,7 +108,6 @@ object KillContributions {
* @see `ActorRef`
* @see `additionalContributionSources`
* @see `AvatarAction.UpdateKillsDeathsAssists`
- * @see `AvatarServiceMessage`
* @see `CombinedHealthAndArmorContributionProcess`
* @see `composeContributionOutput`
* @see `initialScoring`
diff --git a/src/main/scala/net/psforever/packet/game/HackMessage.scala b/src/main/scala/net/psforever/packet/game/HackMessage.scala
index b5d0c7e7b..7a5ee8f38 100644
--- a/src/main/scala/net/psforever/packet/game/HackMessage.scala
+++ b/src/main/scala/net/psforever/packet/game/HackMessage.scala
@@ -129,18 +129,6 @@ final case class HackMessage(
}
object HackMessage extends Marshallable[HackMessage] {
- def apply(
- unk1: HackState1,
- target_guid: PlanetSideGUID,
- player_guid: PlanetSideGUID,
- progress: Int,
- unk5: Int,
- hack_state: HackState,
- unk7: HackState7
- ): HackMessage = {
- new HackMessage(unk1, target_guid, player_guid, progress, unk5.toFloat, hack_state, unk7)
- }
-
implicit val codec: Codec[HackMessage] = (
("unk1" | HackState1.codec) ::
("object_guid" | PlanetSideGUID.codec) ::
diff --git a/src/main/scala/net/psforever/services/CavernRotationService.scala b/src/main/scala/net/psforever/services/CavernRotationService.scala
index 824a817b1..ef3c83d3b 100644
--- a/src/main/scala/net/psforever/services/CavernRotationService.scala
+++ b/src/main/scala/net/psforever/services/CavernRotationService.scala
@@ -12,7 +12,9 @@ import net.psforever.objects.Default
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.ChatMsg
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage, GalaxyServiceResponse}
+import net.psforever.services.base.envelope.{BundledEnvelope, GenericResponseEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.galaxy.{GalaxyAction, GalaxyStamp}
import net.psforever.types.ChatMessageType
import net.psforever.util.Config
import net.psforever.zones.Zones
@@ -89,7 +91,7 @@ object CavernRotationService {
*/
private def closedCavernWarning(zone: ZoneMonitor, counter: Int, galaxyService: ActorRef): Boolean = {
if (!zone.locked) {
- galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(
+ galaxyService ! MessageEnvelope("", SendResponse(
ChatMsg(ChatMessageType.UNK_229, s"@cavern_closing_warning^@${zone.zone.id}~^@$counter~")
))
true
@@ -557,36 +559,35 @@ class CavernRotationService(
val (lockedZones, unlockedZones) = managedZones.partition(_.locked)
//borrow GalaxyService response structure, but send to the specific endpoint math.max(0, monitor.start + monitor.duration - curr)
unlockedZones.foreach { monitor =>
- sendToSession ! GalaxyServiceResponse("", GalaxyResponse.UnlockedZoneUpdate(monitor.zone))
+ val resp = GalaxyAction.UnlockedZoneUpdate(monitor.zone)
+ sendToSession ! GenericResponseEnvelope(GalaxyStamp, "", Default.GUID0, resp)
}
val sortedLocked = lockedZones.sortBy(z => z.start)
sortedLocked.take(2).foreach { monitor =>
- sendToSession ! GalaxyServiceResponse(
- "",
- GalaxyResponse.LockedZoneUpdate(monitor.zone, math.max(0, monitor.start + monitor.duration - curr))
- )
+ val resp = GalaxyAction.LockedZoneUpdate(monitor.zone, math.max(0, monitor.start + monitor.duration - curr))
+ sendToSession ! GenericResponseEnvelope(GalaxyStamp, "", Default.GUID0, resp)
}
sortedLocked.takeRight(2).foreach { monitor =>
- sendToSession ! GalaxyServiceResponse(
- "",
- GalaxyResponse.LockedZoneUpdate(monitor.zone, 0L)
- )
+ val resp = GalaxyAction.LockedZoneUpdate(monitor.zone, 0L)
+ sendToSession ! GenericResponseEnvelope(GalaxyStamp, "", Default.GUID0, resp)
}
}
def sendCavernRotationUpdatesToAll(galaxyService: ActorRef): Unit = {
val curr = System.currentTimeMillis()
val (lockedZones, unlockedZones) = managedZones.partition(_.locked)
- unlockedZones.foreach { z =>
- galaxyService ! GalaxyServiceMessage(GalaxyAction.UnlockedZoneUpdate(z.zone))
- }
val sortedLocked = lockedZones.sortBy(z => z.start)
- sortedLocked.take(2).foreach { z =>
- galaxyService ! GalaxyServiceMessage(GalaxyAction.LockedZoneUpdate(z.zone, z.start + z.duration - curr))
- }
- sortedLocked.takeRight(2).foreach { z =>
- galaxyService ! GalaxyServiceMessage(GalaxyAction.LockedZoneUpdate(z.zone, 0L))
- }
+ galaxyService ! BundledEnvelope(
+ unlockedZones.map { z =>
+ MessageEnvelope("", GalaxyAction.UnlockedZoneUpdate(z.zone))
+ } ++
+ sortedLocked.take(2).map { z =>
+ MessageEnvelope("", GalaxyAction.LockedZoneUpdate(z.zone, z.start + z.duration - curr))
+ } ++
+ sortedLocked.takeRight(2).map { z =>
+ MessageEnvelope("", GalaxyAction.LockedZoneUpdate(z.zone, 0L))
+ }
+ )
}
/**
@@ -654,8 +655,8 @@ class CavernRotationService(
val unlocking = managedZones(nextToUnlock)
val lockingZone = locking.zone
val unlockingZone = unlocking.zone
- val fullHoursBetweenRotationsAsHours = timeToCompleteAllRotationsHours.hours
- val fullHoursBetweenRotationsAsMillis = fullHoursBetweenRotationsAsHours.toMillis
+ //val fullHoursBetweenRotationsAsHours = timeToCompleteAllRotationsHours.hours
+ //val fullHoursBetweenRotationsAsMillis = fullHoursBetweenRotationsAsHours.toMillis
val hoursBetweenRotationsAsHours = timeBetweenRotationsHours.hours
val prevToLock = nextToLock
nextToLock = (nextToLock + 1) % managedZones.size
@@ -670,7 +671,7 @@ class CavernRotationService(
lockTimerToDisplayWarning(hoursBetweenRotationsAsHours - firstClosingWarningAtMinutes.minutes)
//alert clients to change
if (lockingZone ne unlockingZone) {
- galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(
+ galaxyService ! MessageEnvelope("", SendResponse(
ChatMsg(ChatMessageType.UNK_229, s"@cavern_switched^@${lockingZone.id}~^@${unlockingZone.id}")
))
//change warp gate statuses to reflect zone lock state
@@ -729,7 +730,7 @@ class CavernRotationService(
advanceTimeBy: FiniteDuration,
galaxyService: ActorRef
) : Unit = {
- val curr = System.currentTimeMillis()
+ //val curr = System.currentTimeMillis()
val advanceByTimeAsMillis = advanceTimeBy.toMillis
managedZones.foreach { zone =>
zone.start = zone.start - advanceByTimeAsMillis
diff --git a/src/main/scala/net/psforever/services/Service.scala b/src/main/scala/net/psforever/services/Service.scala
index 48d7a2f53..68e5779ea 100644
--- a/src/main/scala/net/psforever/services/Service.scala
+++ b/src/main/scala/net/psforever/services/Service.scala
@@ -1,37 +1,20 @@
// Copyright (c) 2017 PSForever
package net.psforever.services
-import akka.event.{ActorEventBus, SubchannelClassification}
-import akka.util.Subclassification
-import net.psforever.types.PlanetSideGUID
+import akka.actor.ActorRef
object Service {
- final val defaultPlayerGUID: PlanetSideGUID = PlanetSideGUID(0)
+ case object Startup
- final case class Startup()
+ final case class Join(channel: String, sendJoinConfirmation: Boolean)
- final case class Join(channel: String)
- final case class Leave(channel: Option[String] = None)
- final case class LeaveAll()
-}
-
-trait GenericEventBusMsg {
- def channel: String
-}
-
-class GenericEventBus[A <: GenericEventBusMsg] extends ActorEventBus with SubchannelClassification {
- type Event = A
- type Classifier = String
-
- protected def classify(event: Event): Classifier = event.channel
-
- protected def subclassification =
- new Subclassification[Classifier] {
- def isEqual(x: Classifier, y: Classifier) = x == y
- def isSubclass(x: Classifier, y: Classifier) = x.startsWith(y)
- }
-
- protected def publish(event: Event, subscriber: Subscriber): Unit = {
- subscriber ! event
+ object Join {
+ def apply(channel: String): Join = Join(channel, sendJoinConfirmation = false)
}
+
+ final case class JoinConfirmation(eventSystem: ActorRef, channel: String)
+
+ final case class Leave(channel: String)
+
+ case object LeaveAll
}
diff --git a/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala b/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala
index 3ff3206af..6c452e91d 100644
--- a/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala
+++ b/src/main/scala/net/psforever/services/account/AccountPersistenceService.scala
@@ -15,8 +15,10 @@ import net.psforever.objects.zones.Zone
import net.psforever.persistence
import net.psforever.types.Vector3
import net.psforever.services.{Service, ServiceManager}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.ObjectDelete
+import net.psforever.services.galaxy.GalaxyAction
import net.psforever.zones.Zones
import scala.util.Success
@@ -367,7 +369,7 @@ class PersistenceMonitor(
(inZone.Players.find(p => p.name == name), inZone.AllPlayers.find(p => p.Name == name)) match {
case (Some(avatar), Some(player)) if player.VehicleSeated.nonEmpty =>
//in case the player is holding the llu and disconnects
- player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.DropSpecialItem())
+ player.Zone.AvatarEvents ! MessageEnvelope(player.Name, AvatarAction.DropSpecialItem())
//alive or dead in a vehicle
//if the avatar is dead while in a vehicle, they haven't released yet
AvatarActor.saveAvatarData(avatar)
@@ -385,7 +387,7 @@ class PersistenceMonitor(
case (Some(avatar), Some(player)) =>
//in case the player is holding the llu and disconnects
- player.Zone.AvatarEvents ! AvatarServiceMessage(player.Name, AvatarAction.DropSpecialItem())
+ player.Zone.AvatarEvents ! MessageEnvelope(player.Name, AvatarAction.DropSpecialItem())
//alive or dead, as standard Infantry
AvatarActor.saveAvatarData(avatar)
AvatarActor.finalSavePlayerData(player)
@@ -414,8 +416,7 @@ class PersistenceMonitor(
* As this persistence monitor is about to become invalid,
* any messages sent in response to what we are sending are received by the monitor's parent.
* @see `Avatar`
- * @see `AvatarAction.ObjectDelete`
- * @see `AvatarServiceMessage`
+ * @see `ObjectDelete`
* @see `GUIDTask.UnregisterPlayer`
* @see `Player`
* @see `Zone.AvatarEvents`
@@ -434,7 +435,7 @@ class PersistenceMonitor(
case _ => ;
}
inZone.Population.tell(Zone.Population.Release(avatar), parent)
- inZone.AvatarEvents.tell(AvatarServiceMessage(inZone.id, AvatarAction.ObjectDelete(pguid, pguid)), parent)
+ inZone.AvatarEvents.tell(MessageEnvelope(inZone.id, pguid, ObjectDelete(pguid)), parent)
TaskWorkflow.execute(GUIDTask.unregisterPlayer(inZone.GUID, player))
//inZone.tasks.tell(GUIDTask.UnregisterPlayer(player)(inZone.GUID), parent)
AvatarLogout(avatar)
@@ -452,8 +453,8 @@ class PersistenceMonitor(
*/
def AvatarLogout(avatar: Avatar): Unit = {
LivePlayerList.Remove(avatar.id)
- squadService.tell(Service.Leave(Some(avatar.id.toString)), context.parent)
- galaxyService.tell(GalaxyServiceMessage(GalaxyAction.LogStatusChange(avatar.name)), context.parent)
+ squadService.tell(Service.Leave(avatar.id.toString), context.parent)
+ galaxyService.tell(MessageEnvelope(GalaxyAction.LogStatusChange(avatar.name)), context.parent)
Deployables.Disown(inZone, avatar, context.parent)
inZone.Population.tell(Zone.Population.Leave(avatar), context.parent)
TaskWorkflow.execute(GUIDTask.unregisterObject(inZone.GUID, avatar.locker))
diff --git a/src/main/scala/net/psforever/services/avatar/AvatarAction.scala b/src/main/scala/net/psforever/services/avatar/AvatarAction.scala
new file mode 100644
index 000000000..593fd920d
--- /dev/null
+++ b/src/main/scala/net/psforever/services/avatar/AvatarAction.scala
@@ -0,0 +1,205 @@
+// Copyright (c) 2017-2026 PSForever
+package net.psforever.services.avatar
+
+import net.psforever.objects.{Player, Vehicle}
+import net.psforever.objects.avatar.scoring.KDAStat
+import net.psforever.objects.ballistics.Projectile
+import net.psforever.objects.equipment.Equipment
+import net.psforever.objects.inventory.InventoryItem
+import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
+import net.psforever.objects.sourcing.{SourceEntry, UniquePlayer}
+import net.psforever.objects.vital.interaction.DamageResult
+import net.psforever.objects.zones.Zone
+import net.psforever.packet.game.{ImplantAction, ObjectCreateMessage}
+import net.psforever.packet.game.objectcreate.{ConstructorData, DroppedItemData, ObjectCreateMessageParent, PlacementData}
+import net.psforever.services.base.message.{EventMessage, EventResponse, ObjectDelete, SelfRespondingEvent}
+import net.psforever.types.{ExoSuitType, ExperienceType, PlanetSideGUID, TransactionType, Vector3}
+
+import scala.concurrent.duration.FiniteDuration
+
+object AvatarAction {
+ final case class ArmorChanged(suit: ExoSuitType.Value, subtype: Int) extends SelfRespondingEvent
+
+ final case class AvatarImplant(action: ImplantAction.Value, implantSlot: Int, status: Int) extends SelfRespondingEvent
+
+ final case class ChangeFireMode(item_guid: PlanetSideGUID, mode: Int) extends SelfRespondingEvent
+
+ final case class EnvironmentalDamage(player_guid: PlanetSideGUID, source_guid: PlanetSideGUID, amount: Int) extends SelfRespondingEvent
+
+ final case class DeactivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends SelfRespondingEvent
+
+ final case class ActivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends SelfRespondingEvent
+
+ final case class Destroy(victim: PlanetSideGUID, killer: PlanetSideGUID, weapon: PlanetSideGUID, pos: Vector3) extends SelfRespondingEvent
+
+ final case class DestroyDisplay(killer: SourceEntry, victim: SourceEntry, method: Int, unk: Int = 121) extends SelfRespondingEvent
+
+ final case class DropCreatedItem(packet: ObjectCreateMessage) extends EventResponse
+
+ final case class DropItem(item: Equipment) extends EventMessage {
+ def response(): EventResponse = {
+ val definition = item.Definition
+ val objectData = DroppedItemData(
+ PlacementData(item.Position, item.Orientation),
+ definition.Packet.ConstructorData(item).get
+ )
+ AvatarAction.DropCreatedItem(ObjectCreateMessage(definition.ObjectId, item.GUID, objectData))
+ }
+ }
+
+ final case class EquipmentCreatedInHand(packet: ObjectCreateMessage) extends EventResponse
+
+ final case class EquipmentInHand(target_guid: PlanetSideGUID, slot: Int, item: Equipment) extends EventMessage {
+ def response(): EventResponse = {
+ val definition = item.Definition
+ val containerData = ObjectCreateMessageParent(target_guid, slot)
+ val objectData = definition.Packet.ConstructorData(item).get
+ AvatarAction.EquipmentCreatedInHand(
+ ObjectCreateMessage(definition.ObjectId, item.GUID, containerData, objectData)
+ )
+ }
+ }
+
+ final case class Killed(cause: DamageResult, mount_guid: Option[PlanetSideGUID]) extends SelfRespondingEvent
+
+ final case class LoadCreatedPlayer(pkt: ObjectCreateMessage) extends EventResponse
+
+ final case class LoadPlayer(
+ object_id: Int,
+ target_guid: PlanetSideGUID,
+ cdata: ConstructorData,
+ pdata: Option[ObjectCreateMessageParent]
+ ) extends EventMessage {
+ def response(): EventResponse = {
+ val pkt = pdata match {
+ case Some(data) =>
+ ObjectCreateMessage(object_id, target_guid, data, cdata)
+ case None =>
+ ObjectCreateMessage(object_id, target_guid, cdata)
+ }
+ LoadCreatedPlayer(pkt)
+ }
+ }
+
+ final case class LoadCreatedProjectile(pkt: ObjectCreateMessage) extends EventResponse
+
+ final case class LoadProjectile(
+ object_id: Int,
+ projectile_guid: PlanetSideGUID,
+ cdata: ConstructorData
+ ) extends EventMessage {
+ def response(): EventResponse = {
+ LoadCreatedProjectile(ObjectCreateMessage(object_id, projectile_guid, cdata))
+ }
+ }
+
+ final case class ObjectHeld(slot: Int, previousSLot: Int) extends SelfRespondingEvent
+
+ final case class OxygenState(player: OxygenStateTarget, vehicle: Option[OxygenStateTarget]) extends SelfRespondingEvent
+
+ final case class PlanetsideStringAttribute(attribute_type: Int, attribute_value: String) extends SelfRespondingEvent
+
+ final case class PlayerState(
+ pos: Vector3,
+ vel: Option[Vector3],
+ facingYaw: Float,
+ facingPitch: Float,
+ facingYawUpper: Float,
+ timestamp: Int,
+ is_crouching: Boolean,
+ is_jumping: Boolean,
+ jump_thrust: Boolean,
+ is_cloaked: Boolean,
+ spectator: Boolean,
+ weaponInHand: Boolean
+ ) extends SelfRespondingEvent
+
+ final case class PickupItem(item: Equipment, unk: Int = 0) extends EventMessage {
+ def response(): EventResponse = {
+ ObjectDelete(item.GUID, unk)
+ }
+ }
+
+ final case class ProjectileAutoLockAwareness(mode: Int) extends SelfRespondingEvent
+
+ final case class ProjectileExplodes(projectile_guid: PlanetSideGUID, projectile: Projectile) extends SelfRespondingEvent
+
+ final case class ProjectileState(
+ projectile_guid: PlanetSideGUID,
+ shot_pos: Vector3,
+ shot_vel: Vector3,
+ shot_orient: Vector3,
+ sequence: Int,
+ end: Boolean,
+ hit_target: PlanetSideGUID
+ ) extends SelfRespondingEvent
+
+ final case class PutDownFDU(player_guid: PlanetSideGUID) extends SelfRespondingEvent
+
+ final case class ReleasePlayer(player: Player) extends EventResponse
+
+ final case class Release(player: Player, zone: Zone, time: Option[FiniteDuration] = None) extends EventMessage {
+ def response(): EventResponse = {
+ ReleasePlayer(player)
+ }
+ }
+
+ final case class Revive(target_guid: PlanetSideGUID) extends SelfRespondingEvent
+
+ final case class StowEquipment(target_guid: PlanetSideGUID, slot: Int, item: Equipment)
+ extends SelfRespondingEvent
+
+ final case class TerminalOrderResult(terminal_guid: PlanetSideGUID, action: TransactionType.Value, result: Boolean)
+ extends SelfRespondingEvent
+
+ final case class ChangeExosuit(
+ target_guid: PlanetSideGUID,
+ armor: Int,
+ exosuit: ExoSuitType.Value,
+ subtype: Int,
+ last_drawn_slot: Int,
+ new_max_hand: Boolean,
+ old_holsters: List[(Equipment, PlanetSideGUID)],
+ holsters: List[InventoryItem],
+ old_inventory: List[(Equipment, PlanetSideGUID)],
+ inventory: List[InventoryItem],
+ drop: List[InventoryItem],
+ delete: List[(Equipment, PlanetSideGUID)]
+ ) extends SelfRespondingEvent
+
+ final case class ChangeLoadout(
+ target_guid: PlanetSideGUID,
+ armor: Int,
+ exosuit: ExoSuitType.Value,
+ subtype: Int,
+ last_drawn_slot: Int,
+ new_max_hand: Boolean,
+ old_holsters: List[(Equipment, PlanetSideGUID)],
+ holsters: List[InventoryItem],
+ old_inventory: List[(Equipment, PlanetSideGUID)],
+ inventory: List[InventoryItem],
+ drop: List[InventoryItem]
+ ) extends SelfRespondingEvent
+
+ final case class DropSpecialItem() extends SelfRespondingEvent
+
+ final case class UseKit(kit_guid: PlanetSideGUID, kit_objid: Int) extends SelfRespondingEvent
+
+ final case class KitNotUsed(kit_guid: PlanetSideGUID, msg: String) extends SelfRespondingEvent
+
+ final case class UpdateKillsDeathsAssists(charId: Long, kda: KDAStat) extends SelfRespondingEvent
+
+ final case class AwardBep(charId: Long, bep: Long, expType: ExperienceType) extends SelfRespondingEvent
+
+ final case class AwardCep(charId: Long, bep: Long) extends SelfRespondingEvent
+
+ final case class FacilityCaptureRewards(building_id: Int, zone_number: Int, exp: Long) extends SelfRespondingEvent
+
+ final case class ShareKillExperienceWithSquad(killer: Player, exp: Long) extends SelfRespondingEvent
+
+ final case class ShareAntExperienceWithSquad(owner: UniquePlayer, exp: Long, vehicle: Vehicle) extends SelfRespondingEvent
+
+ final case class RemoveFromOutfitChat(outfit_id: Long) extends SelfRespondingEvent
+
+ final case object TeardownConnection extends SelfRespondingEvent
+}
diff --git a/src/main/scala/net/psforever/services/avatar/AvatarService.scala b/src/main/scala/net/psforever/services/avatar/AvatarService.scala
index bbdf1f99a..9c56bf9c0 100644
--- a/src/main/scala/net/psforever/services/avatar/AvatarService.scala
+++ b/src/main/scala/net/psforever/services/avatar/AvatarService.scala
@@ -1,521 +1,18 @@
// Copyright (c) 2017 PSForever
package net.psforever.services.avatar
-import akka.actor.{Actor, ActorRef, Props}
-import net.psforever.objects.zones.Zone
-import net.psforever.packet.game.ObjectCreateMessage
-import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectCreateMessageParent, PlacementData}
-import net.psforever.types.PlanetSideGUID
-import net.psforever.services.avatar.support.{CorpseRemovalActor, DroppedItemRemover}
-import net.psforever.services.{GenericEventBus, RemoverActor, Service}
+import akka.actor.Props
+import net.psforever.services.avatar.support.{CorpseRemovalSupport, LitterRemovalSupport}
+import net.psforever.services.base.{EventSystemStamp, GenericEventServiceWithCacheAndSupport}
-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")
+case object AvatarStamp extends EventSystemStamp
- private[this] val log = org.log4s.getLogger
-
- val AvatarEvents = new GenericEventBus[AvatarServiceResponse] //AvatarEventBus
-
- def receive: Receive = {
- case Service.Join(channel) =>
- val path = s"/$channel/Avatar"
- val who = sender()
- AvatarEvents.subscribe(who, path)
-
- case Service.Leave(None) =>
- AvatarEvents.unsubscribe(sender())
-
- case Service.Leave(Some(channel)) =>
- val path = s"/$channel/Avatar"
- AvatarEvents.unsubscribe(sender(), path)
-
- case Service.LeaveAll() =>
- AvatarEvents.unsubscribe(sender())
-
- case AvatarServiceMessage(forChannel, action) =>
- action match {
- case AvatarAction.ArmorChanged(player_guid, suit, subtype) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ArmorChanged(suit, subtype))
- )
- case AvatarAction.AvatarImplant(player_guid, action, implantSlot, status) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.AvatarImplant(action, implantSlot, status))
- )
- case AvatarAction.ChangeAmmo(
- player_guid,
- weapon_guid,
- weapon_slot,
- old_ammo_guid,
- ammo_id,
- ammo_guid,
- ammo_data
- ) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, old_ammo_guid, ammo_id, ammo_guid, ammo_data)
- )
- )
- case AvatarAction.ChangeFireMode(player_guid, item_guid, mode) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ChangeFireMode(item_guid, mode))
- )
- case AvatarAction.ChangeFireState_Start(player_guid, weapon_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.ChangeFireState_Start(weapon_guid)
- )
- )
- case AvatarAction.ChangeFireState_Stop(player_guid, weapon_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ChangeFireState_Stop(weapon_guid))
- )
- case AvatarAction.ConcealPlayer(player_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ConcealPlayer())
- )
- case AvatarAction.EnvironmentalDamage(player_guid, source_guid, amount) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.EnvironmentalDamage(player_guid, source_guid, amount)
- )
- )
- case AvatarAction.Destroy(victim, killer, weapon, pos) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", victim, AvatarResponse.Destroy(victim, killer, weapon, pos))
- )
- case AvatarAction.DestroyDisplay(killer, victim, method, unk) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.DestroyDisplay(killer, victim, method, unk)
- )
- )
- case AvatarAction.DropItem(player_guid, item) =>
- val definition = item.Definition
- val objectData = DroppedItemData(
- PlacementData(item.Position, item.Orientation),
- definition.Packet.ConstructorData(item).get
- )
- janitor forward RemoverActor.AddTask(item, zone)
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.DropItem(ObjectCreateMessage(definition.ObjectId, item.GUID, objectData))
- )
- )
- case AvatarAction.EquipmentInHand(player_guid, target_guid, slot, item) =>
- val definition = item.Definition
- val containerData = ObjectCreateMessageParent(target_guid, slot)
- val objectData = definition.Packet.ConstructorData(item).get
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.EquipmentInHand(
- ObjectCreateMessage(definition.ObjectId, item.GUID, containerData, objectData)
- )
- )
- )
- case AvatarAction.GenericObjectAction(player_guid, object_guid, action_code) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.GenericObjectAction(object_guid, action_code)
- )
- )
- case AvatarAction.HitHint(source_guid, player_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.HitHint(source_guid))
- )
- case AvatarAction.Killed(player_guid, cause, mount_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.Killed(cause, mount_guid))
- )
- case AvatarAction.LoadPlayer(player_guid, object_id, target_guid, cdata, pdata) =>
- val pkt = pdata match {
- case Some(data) =>
- ObjectCreateMessage(object_id, target_guid, data, cdata)
- case None =>
- ObjectCreateMessage(object_id, target_guid, cdata)
- }
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.LoadPlayer(pkt))
- )
- case AvatarAction.LoadProjectile(player_guid, object_id, object_guid, cdata) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.LoadProjectile(
- ObjectCreateMessage(object_id, object_guid, cdata)
- )
- )
- )
- case AvatarAction.ObjectDelete(player_guid, item_guid, unk) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ObjectDelete(item_guid, unk))
- )
- case AvatarAction.ObjectHeld(player_guid, slot, previousSlot) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ObjectHeld(slot, previousSlot))
- )
- case AvatarAction.OxygenState(player, vehicle) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player.guid, AvatarResponse.OxygenState(player, vehicle))
- )
- case AvatarAction.PlanetsideAttribute(guid, attribute_type, attribute_value) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- guid,
- AvatarResponse.PlanetsideAttribute(attribute_type, attribute_value)
- )
- )
- case AvatarAction.PlanetsideAttributeToAll(guid, attribute_type, attribute_value) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- guid,
- AvatarResponse.PlanetsideAttributeToAll(attribute_type, attribute_value)
- )
- )
- case AvatarAction.PlanetsideAttributeSelf(guid, attribute_type, attribute_value) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- guid,
- AvatarResponse.PlanetsideAttributeSelf(attribute_type, attribute_value)
- )
- )
- case AvatarAction.PlanetsideStringAttribute(guid, attribute_type, attribute_value) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- guid,
- AvatarResponse.PlanetsideStringAttribute(attribute_type, attribute_value)
- )
- )
- case AvatarAction.PlayerState(
- guid,
- pos,
- vel,
- yaw,
- pitch,
- yaw_upper,
- seq_time,
- is_crouching,
- is_jumping,
- jump_thrust,
- is_cloaking,
- spectating,
- weaponInHand
- ) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- guid,
- AvatarResponse.PlayerState(
- pos,
- vel,
- yaw,
- pitch,
- yaw_upper,
- seq_time,
- is_crouching,
- is_jumping,
- jump_thrust,
- is_cloaking,
- spectating,
- weaponInHand
- )
- )
- )
- case AvatarAction.ProjectileAutoLockAwareness(mode) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- PlanetSideGUID(0),
- AvatarResponse.ProjectileAutoLockAwareness(mode)
- )
- )
- case AvatarAction.ProjectileExplodes(player_guid, projectile_guid, projectile) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.ProjectileExplodes(projectile_guid, projectile)
- )
- )
- case AvatarAction.ProjectileState(
- player_guid,
- projectile_guid,
- shot_pos,
- shot_vel,
- shot_orient,
- sequence,
- end,
- target
- ) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.ProjectileState(projectile_guid, shot_pos, shot_vel, shot_orient, sequence, end, target)
- )
- )
- case AvatarAction.PickupItem(player_guid, item, unk) =>
- janitor forward RemoverActor.ClearSpecific(List(item), zone)
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ObjectDelete(item.GUID, unk))
- )
- case AvatarAction.PutDownFDU(player_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", Service.defaultPlayerGUID, AvatarResponse.PutDownFDU(player_guid))
- )
- case AvatarAction.Release(player, _, time) =>
- undertaker forward RemoverActor.AddTask(player, zone, time)
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player.GUID, AvatarResponse.Release(player))
- )
- case AvatarAction.Reload(player_guid, weapon_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.Reload(weapon_guid))
- )
- case AvatarAction.SetEmpire(player_guid, target_guid, faction) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.SetEmpire(target_guid, faction))
- )
- case AvatarAction.StowEquipment(player_guid, target_guid, slot, obj) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- player_guid,
- AvatarResponse.StowEquipment(target_guid, slot, obj)
- )
- )
- case AvatarAction.WeaponDryFire(player_guid, weapon_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.WeaponDryFire(weapon_guid))
- )
- case AvatarAction.SendResponse(player_guid, msg) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.SendResponse(msg))
- )
- case AvatarAction.SendResponseTargeted(target_guid, msg) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- target_guid,
- AvatarResponse.SendResponseTargeted(target_guid, msg)
- )
- )
- case AvatarAction.Revive(target_guid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", target_guid, AvatarResponse.Revive(target_guid))
- )
-
- case AvatarAction.TeardownConnection() =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.TeardownConnection()
- )
- )
-
- case AvatarAction.TerminalOrderResult(terminal, term_action, result) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.TerminalOrderResult(terminal, term_action, result)
- )
- )
- case AvatarAction.ChangeExosuit(
- target,
- armor,
- exosuit,
- subtype,
- slot,
- maxhand,
- old_holsters,
- holsters,
- old_inventory,
- inventory,
- drop,
- delete
- ) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.ChangeExosuit(
- target,
- armor,
- exosuit,
- subtype,
- slot,
- maxhand,
- old_holsters,
- holsters,
- old_inventory,
- inventory,
- drop,
- delete
- )
- )
- )
- case AvatarAction.ChangeLoadout(
- target,
- armor,
- exosuit,
- subtype,
- slot,
- maxhand,
- old_holsters,
- holsters,
- old_inventory,
- inventory,
- drop
- ) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.ChangeLoadout(
- target,
- armor,
- exosuit,
- subtype,
- slot,
- maxhand,
- old_holsters,
- holsters,
- old_inventory,
- inventory,
- drop
- )
- )
- )
-
- case AvatarAction.DropSpecialItem() =>
- AvatarEvents.publish(AvatarServiceResponse(s"/$forChannel/Avatar", Service.defaultPlayerGUID, AvatarResponse.DropSpecialItem()))
-
- case AvatarAction.UseKit(kit_guid, kit_objid) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.UseKit(kit_guid, kit_objid)
- )
- )
-
- case AvatarAction.KitNotUsed(kit_guid, msg) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.KitNotUsed(kit_guid, msg)
- )
- )
-
- case AvatarAction.UpdateKillsDeathsAssists(charId, stat) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.UpdateKillsDeathsAssists(charId, stat)
- )
- )
-
- case AvatarAction.AwardBep(charId, bep, expType) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.AwardBep(charId, bep, expType)
- )
- )
-
- case AvatarAction.AwardCep(charId, bep) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.AwardCep(charId, bep)
- )
- )
-
- case AvatarAction.FacilityCaptureRewards(building_id, zone_number, exp) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.FacilityCaptureRewards(building_id, zone_number, exp)
- )
- )
-
- case AvatarAction.ShareKillExperienceWithSquad(killer, exp) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.ShareKillExperienceWithSquad(killer, exp)
- )
- )
-
- case AvatarAction.ShareAntExperienceWithSquad(owner, exp, vehicle) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.ShareAntExperienceWithSquad(owner, exp, vehicle)
- )
- )
-
- case AvatarAction.RemoveFromOutfitChat(outfit_id) =>
- AvatarEvents.publish(
- AvatarServiceResponse(
- s"/$forChannel/Avatar",
- Service.defaultPlayerGUID,
- AvatarResponse.RemoveFromOutfitChat(outfit_id)
- )
- )
-
- case _ => ()
- }
-
- //message to Undertaker
- case AvatarServiceMessage.Corpse(msg) =>
- undertaker forward msg
-
- //message to Janitor
- case AvatarServiceMessage.Ground(msg) =>
- janitor forward msg
-
- /*
- case AvatarService.PlayerStateShift(killer, guid) =>
- val playerOpt: Option[PlayerAvatar] = PlayerMasterList.getPlayer(guid)
- if (playerOpt.isDefined) {
- val player: PlayerAvatar = playerOpt.get
- AvatarEvents.publish(AvatarMessage("/Avatar/" + player.continent, guid,
- AvatarServiceReply.PlayerStateShift(killer)
- ))
- }
- */
-
- case msg =>
- log.warn(s"Unhandled message $msg from ${sender()}")
+object AvatarService {
+ def apply(): Props = {
+ Props(
+ classOf[GenericEventServiceWithCacheAndSupport],
+ AvatarStamp,
+ List(CorpseRemovalSupport, LitterRemovalSupport)
+ )
}
}
diff --git a/src/main/scala/net/psforever/services/avatar/AvatarServiceMessage.scala b/src/main/scala/net/psforever/services/avatar/AvatarServiceMessage.scala
deleted file mode 100644
index e17cfe0aa..000000000
--- a/src/main/scala/net/psforever/services/avatar/AvatarServiceMessage.scala
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (c) 2017 PSForever
-package net.psforever.services.avatar
-
-import net.psforever.objects.{Player, Vehicle}
-import net.psforever.objects.avatar.scoring.KDAStat
-import net.psforever.objects.ballistics.Projectile
-import net.psforever.objects.equipment.Equipment
-import net.psforever.objects.inventory.InventoryItem
-import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
-import net.psforever.objects.sourcing.{SourceEntry, UniquePlayer}
-import net.psforever.objects.vital.interaction.DamageResult
-import net.psforever.objects.zones.Zone
-import net.psforever.packet.PlanetSideGamePacket
-import net.psforever.packet.game.ImplantAction
-import net.psforever.packet.game.objectcreate.{ConstructorData, ObjectCreateMessageParent}
-import net.psforever.types.{ExoSuitType, ExperienceType, PlanetSideEmpire, PlanetSideGUID, TransactionType, Vector3}
-
-import scala.concurrent.duration.FiniteDuration
-
-final case class AvatarServiceMessage(forChannel: String, actionMessage: AvatarAction.Action)
-
-object AvatarServiceMessage {
- final case class Corpse(msg: Any)
- final case class Ground(msg: Any)
-}
-
-object AvatarAction {
- sealed trait Action
-
- final case class ArmorChanged(player_guid: PlanetSideGUID, suit: ExoSuitType.Value, subtype: Int) extends Action
- final case class AvatarImplant(player_guid: PlanetSideGUID, action: ImplantAction.Value, implantSlot: Int, status: Int) extends Action
- final case class ChangeAmmo(
- player_guid: PlanetSideGUID,
- weapon_guid: PlanetSideGUID,
- weapon_slot: Int,
- old_ammo_guid: PlanetSideGUID,
- ammo_id: Int,
- ammo_guid: PlanetSideGUID,
- ammo_data: ConstructorData
- ) extends Action
- final case class ChangeFireMode(player_guid: PlanetSideGUID, item_guid: PlanetSideGUID, mode: Int) extends Action
- final case class ChangeFireState_Start(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
- final case class ChangeFireState_Stop(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
- final case class ConcealPlayer(player_guid: PlanetSideGUID) extends Action
- final case class EnvironmentalDamage(player_guid: PlanetSideGUID, source_guid: PlanetSideGUID, amount: Int)
- extends Action
- final case class DeactivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends Action
- final case class ActivateImplantSlot(player_guid: PlanetSideGUID, slot: Int) extends Action
- final case class Destroy(victim: PlanetSideGUID, killer: PlanetSideGUID, weapon: PlanetSideGUID, pos: Vector3)
- extends Action
- final case class DestroyDisplay(killer: SourceEntry, victim: SourceEntry, method: Int, unk: Int = 121) extends Action
- final case class DropItem(player_guid: PlanetSideGUID, item: Equipment) extends Action
- final case class EquipmentInHand(player_guid: PlanetSideGUID, target_guid: PlanetSideGUID, slot: Int, item: Equipment)
- extends Action
- final case class GenericObjectAction(player_guid: PlanetSideGUID, object_guid: PlanetSideGUID, action_code: Int)
- extends Action
- final case class HitHint(source_guid: PlanetSideGUID, player_guid: PlanetSideGUID) extends Action
- final case class Killed(player_guid: PlanetSideGUID, cause: DamageResult, mount_guid: Option[PlanetSideGUID]) extends Action
- final case class LoadPlayer(
- player_guid: PlanetSideGUID,
- object_id: Int,
- target_guid: PlanetSideGUID,
- cdata: ConstructorData,
- pdata: Option[ObjectCreateMessageParent]
- ) extends Action
- final case class LoadProjectile(
- player_guid: PlanetSideGUID,
- object_id: Int,
- projectile_guid: PlanetSideGUID,
- cdata: ConstructorData
- ) extends Action
- final case class ObjectDelete(player_guid: PlanetSideGUID, item_guid: PlanetSideGUID, unk: Int = 0) extends Action
- final case class ObjectHeld(player_guid: PlanetSideGUID, slot: Int, previousSLot: Int) extends Action
- final case class OxygenState(player: OxygenStateTarget, vehicle: Option[OxygenStateTarget]) extends Action
- final case class PlanetsideAttribute(player_guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
- extends Action
- final case class PlanetsideAttributeToAll(player_guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
- extends Action
- final case class PlanetsideAttributeSelf(player_guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
- extends Action
- final case class PlanetsideStringAttribute(player_guid: PlanetSideGUID, attribute_type: Int, attribute_value: String)
- extends Action
- final case class PlayerState(
- player_guid: PlanetSideGUID,
- pos: Vector3,
- vel: Option[Vector3],
- facingYaw: Float,
- facingPitch: Float,
- facingYawUpper: Float,
- timestamp: Int,
- is_crouching: Boolean,
- is_jumping: Boolean,
- jump_thrust: Boolean,
- is_cloaked: Boolean,
- spectator: Boolean,
- weaponInHand: Boolean
- ) extends Action
- final case class PickupItem(player_guid: PlanetSideGUID, item: Equipment, unk: Int = 0) extends Action
- final case class ProjectileAutoLockAwareness(mode: Int) extends Action
- final case class ProjectileExplodes(
- player_guid: PlanetSideGUID,
- projectile_guid: PlanetSideGUID,
- projectile: Projectile
- ) extends Action
- final case class ProjectileState(
- player_guid: PlanetSideGUID,
- projectile_guid: PlanetSideGUID,
- shot_pos: Vector3,
- shot_vel: Vector3,
- shot_orient: Vector3,
- sequence: Int,
- end: Boolean,
- hit_target: PlanetSideGUID
- ) extends Action
- final case class PutDownFDU(player_guid: PlanetSideGUID) extends Action
- final case class Release(player: Player, zone: Zone, time: Option[FiniteDuration] = None) extends Action
- final case class Revive(target_guid: PlanetSideGUID) extends Action
- final case class Reload(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
- final case class SetEmpire(player_guid: PlanetSideGUID, object_guid: PlanetSideGUID, faction: PlanetSideEmpire.Value)
- extends Action
- final case class StowEquipment(player_guid: PlanetSideGUID, target_guid: PlanetSideGUID, slot: Int, item: Equipment)
- extends Action
- final case class WeaponDryFire(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
-
- final case class SendResponse(player_guid: PlanetSideGUID, msg: PlanetSideGamePacket) extends Action
- final case class SendResponseTargeted(target_guid: PlanetSideGUID, msg: PlanetSideGamePacket) extends Action
-
- final case class TerminalOrderResult(terminal_guid: PlanetSideGUID, action: TransactionType.Value, result: Boolean)
- extends Action
- final case class ChangeExosuit(
- target_guid: PlanetSideGUID,
- armor: Int,
- exosuit: ExoSuitType.Value,
- subtype: Int,
- last_drawn_slot: Int,
- new_max_hand: Boolean,
- old_holsters: List[(Equipment, PlanetSideGUID)],
- holsters: List[InventoryItem],
- old_inventory: List[(Equipment, PlanetSideGUID)],
- inventory: List[InventoryItem],
- drop: List[InventoryItem],
- delete: List[(Equipment, PlanetSideGUID)]
- ) extends Action
- final case class ChangeLoadout(
- target_guid: PlanetSideGUID,
- armor: Int,
- exosuit: ExoSuitType.Value,
- subtype: Int,
- last_drawn_slot: Int,
- new_max_hand: Boolean,
- old_holsters: List[(Equipment, PlanetSideGUID)],
- holsters: List[InventoryItem],
- old_inventory: List[(Equipment, PlanetSideGUID)],
- inventory: List[InventoryItem],
- drop: List[InventoryItem]
- ) extends Action
- final case class DropSpecialItem() extends Action
- final case class UseKit(kit_guid: PlanetSideGUID, kit_objid: Int) extends Action
- final case class KitNotUsed(kit_guid: PlanetSideGUID, msg: String) extends Action
-
- final case class UpdateKillsDeathsAssists(charId: Long, kda: KDAStat) extends Action
- final case class AwardBep(charId: Long, bep: Long, expType: ExperienceType) extends Action
- final case class AwardCep(charId: Long, bep: Long) extends Action
- final case class FacilityCaptureRewards(building_id: Int, zone_number: Int, exp: Long) extends Action
- final case class ShareKillExperienceWithSquad(killer: Player, exp: Long) extends Action
- final case class ShareAntExperienceWithSquad(owner: UniquePlayer, exp: Long, vehicle: Vehicle) extends Action
- final case class RemoveFromOutfitChat(outfit_id: Long) extends Action
-
- final case class TeardownConnection() extends Action
- // final case class PlayerStateShift(killer : PlanetSideGUID, victim : PlanetSideGUID) extends Action
- // final case class DestroyDisplay(killer : PlanetSideGUID, victim : PlanetSideGUID) extends Action
-}
diff --git a/src/main/scala/net/psforever/services/avatar/AvatarServiceResponse.scala b/src/main/scala/net/psforever/services/avatar/AvatarServiceResponse.scala
deleted file mode 100644
index 87560d293..000000000
--- a/src/main/scala/net/psforever/services/avatar/AvatarServiceResponse.scala
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright (c) 2017 PSForever
-package net.psforever.services.avatar
-
-import net.psforever.objects.{Player, Vehicle}
-import net.psforever.objects.avatar.scoring.KDAStat
-import net.psforever.objects.ballistics.Projectile
-import net.psforever.objects.equipment.Equipment
-import net.psforever.objects.inventory.InventoryItem
-import net.psforever.objects.serverobject.environment.interaction.common.Watery.OxygenStateTarget
-import net.psforever.objects.sourcing.{SourceEntry, UniquePlayer}
-import net.psforever.objects.vital.interaction.DamageResult
-import net.psforever.packet.PlanetSideGamePacket
-import net.psforever.packet.game.objectcreate.ConstructorData
-import net.psforever.packet.game.{ImplantAction, ObjectCreateMessage}
-import net.psforever.types.{ExoSuitType, ExperienceType, PlanetSideEmpire, PlanetSideGUID, TransactionType, Vector3}
-import net.psforever.services.GenericEventBusMsg
-
-final case class AvatarServiceResponse(
- channel: String,
- avatar_guid: PlanetSideGUID,
- replyMessage: AvatarResponse.Response
-) extends GenericEventBusMsg
-
-object AvatarResponse {
- sealed trait Response
-
- final case class ArmorChanged(suit: ExoSuitType.Value, subtype: Int) extends Response
- final case class AvatarImplant(action: ImplantAction.Value, implantSlot: Int, status: Int) extends Response
- final case class ChangeAmmo(
- weapon_guid: PlanetSideGUID,
- weapon_slot: Int,
- old_ammo_guid: PlanetSideGUID,
- ammo_id: Int,
- ammo_guid: PlanetSideGUID,
- ammo_data: ConstructorData
- ) extends Response
- final case class ChangeFireMode(item_guid: PlanetSideGUID, mode: Int) extends Response
- final case class ChangeFireState_Start(weapon_guid: PlanetSideGUID) extends Response
- final case class ChangeFireState_Stop(weapon_guid: PlanetSideGUID) extends Response
- final case class ConcealPlayer() extends Response
- final case class EnvironmentalDamage(target: PlanetSideGUID, source_guid: PlanetSideGUID, amount: Int)
- extends Response
- final case class Destroy(victim: PlanetSideGUID, killer: PlanetSideGUID, weapon: PlanetSideGUID, pos: Vector3)
- extends Response
- final case class DestroyDisplay(killer: SourceEntry, victim: SourceEntry, method: Int, unk: Int) extends Response
- final case class DropItem(pkt: ObjectCreateMessage) extends Response
- final case class EquipmentInHand(pkt: ObjectCreateMessage) extends Response
- final case class GenericObjectAction(object_guid: PlanetSideGUID, action_code: Int) extends Response
- final case class HitHint(source_guid: PlanetSideGUID) extends Response
- final case class Killed(cause: DamageResult, mount_guid: Option[PlanetSideGUID]) extends Response
- final case class LoadPlayer(pkt: ObjectCreateMessage) extends Response
- final case class LoadProjectile(pkt: ObjectCreateMessage) extends Response
- final case class ObjectDelete(item_guid: PlanetSideGUID, unk: Int) extends Response
- final case class ObjectHeld(slot: Int, previousSLot: Int) extends Response
- final case class OxygenState(player: OxygenStateTarget, vehicle: Option[OxygenStateTarget]) extends Response
- final case class PlanetsideAttribute(attribute_type: Int, attribute_value: Long) extends Response
- final case class PlanetsideAttributeToAll(attribute_type: Int, attribute_value: Long) extends Response
- final case class PlanetsideAttributeSelf(attribute_type: Int, attribute_value: Long) extends Response
- final case class PlanetsideStringAttribute(attribute_type: Int, attribute_value: String) extends Response
- final case class PlayerState(
- pos: Vector3,
- vel: Option[Vector3],
- facingYaw: Float,
- facingPitch: Float,
- facingYawUpper: Float,
- timestamp: Int,
- is_crouching: Boolean,
- is_jumping: Boolean,
- jump_thrust: Boolean,
- is_cloaked: Boolean,
- spectator: Boolean,
- weaponInHand: Boolean
- ) extends Response
- final case class ProjectileAutoLockAwareness(mode: Int) extends Response
- final case class ProjectileExplodes(projectile_guid: PlanetSideGUID, projectile: Projectile) extends Response
- final case class ProjectileState(
- projectile_guid: PlanetSideGUID,
- shot_pos: Vector3,
- shot_vel: Vector3,
- shot_orient: Vector3,
- sequence: Int,
- end: Boolean,
- hit_target: PlanetSideGUID
- ) extends Response
- final case class PutDownFDU(target_guid: PlanetSideGUID) extends Response
- final case class Release(player: Player) extends Response
- final case class Reload(weapon_guid: PlanetSideGUID) extends Response
- final case class Revive(target_guid: PlanetSideGUID) extends Response
- final case class SetEmpire(object_guid: PlanetSideGUID, faction: PlanetSideEmpire.Value) extends Response
- final case class StowEquipment(target_guid: PlanetSideGUID, slot: Int, item: Equipment) extends Response
- final case class WeaponDryFire(weapon_guid: PlanetSideGUID) extends Response
-
- final case class SendResponse(msg: PlanetSideGamePacket) extends Response
- final case class SendResponseTargeted(target_guid: PlanetSideGUID, msg: PlanetSideGamePacket) extends Response
-
- final case class TerminalOrderResult(terminal_guid: PlanetSideGUID, action: TransactionType.Value, result: Boolean)
- extends Response
- final case class ChangeExosuit(
- target_guid: PlanetSideGUID,
- armor: Int,
- exosuit: ExoSuitType.Value,
- subtype: Int,
- last_drawn_slot: Int,
- new_max_hand: Boolean,
- old_holsters: List[(Equipment, PlanetSideGUID)],
- holsters: List[InventoryItem],
- old_inventory: List[(Equipment, PlanetSideGUID)],
- inventory: List[InventoryItem],
- drop: List[InventoryItem],
- delete: List[(Equipment, PlanetSideGUID)]
- ) extends Response
- final case class ChangeLoadout(
- target_guid: PlanetSideGUID,
- armor: Int,
- exosuit: ExoSuitType.Value,
- subtype: Int,
- last_drawn_slot: Int,
- new_max_hand: Boolean,
- old_holsters: List[(Equipment, PlanetSideGUID)],
- holsters: List[InventoryItem],
- old_inventory: List[(Equipment, PlanetSideGUID)],
- inventory: List[InventoryItem],
- drop: List[InventoryItem]
- ) extends Response
- final case class DropSpecialItem() extends Response
-
- final case class TeardownConnection() extends Response
- // final case class PlayerStateShift(itemID : PlanetSideGUID) extends Response
- final case class UseKit(kit_guid: PlanetSideGUID, kit_objid: Int) extends Response
- final case class KitNotUsed(kit_guid: PlanetSideGUID, msg: String) extends Response
-
- final case class UpdateKillsDeathsAssists(charId: Long, kda: KDAStat) extends Response
- final case class AwardBep(charId: Long, bep: Long, expType: ExperienceType) extends Response
- final case class AwardCep(charId: Long, bep: Long) extends Response
- final case class FacilityCaptureRewards(building_id: Int, zone_number: Int, exp: Long) extends Response
- final case class ShareKillExperienceWithSquad(killer: Player, exp: Long) extends Response
- final case class ShareAntExperienceWithSquad(owner: UniquePlayer, exp: Long, vehicle: Vehicle) extends Response
- final case class RemoveFromOutfitChat(outfit_id: Long) extends Response
-}
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 974f0b687..1f23e6022 100644
--- a/src/main/scala/net/psforever/services/avatar/support/CorpseRemovalActor.scala
+++ b/src/main/scala/net/psforever/services/avatar/support/CorpseRemovalActor.scala
@@ -1,14 +1,49 @@
// Copyright (c) 2017 PSForever
package net.psforever.services.avatar.support
+import akka.actor.{ActorContext, ActorRef, Props}
import net.psforever.objects.guid.{GUIDTask, TaskBundle}
import net.psforever.objects.Player
-import net.psforever.types.ExoSuitType
-import net.psforever.services.{RemoverActor, Service}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.types.{ExoSuitType, PlanetSideGUID}
+import net.psforever.services.avatar.AvatarAction.Release
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelope, GenericSupportEnvelopeOnly}
+import net.psforever.services.base.message.ObjectDelete
+import net.psforever.services.base.support.RemoverActor
import scala.concurrent.duration._
+case object CorpseRemovalSupport
+ extends EventServiceSupport {
+ def label: String = "undertaker"
+ def constructor(context: ActorContext): ActorRef = {
+ context.actorOf(Props[CorpseRemovalActor](), name = "CorpseRemoval")
+ }
+}
+
+final case class ReleaseEnvelope(
+ channel: String,
+ filter: PlanetSideGUID,
+ msg: Release
+ )
+ extends GenericSupportEnvelope {
+ def supportLabel: String = "undertaker"
+ def supportMessage: Any = {
+ val Release(player, zone, time) = msg
+ RemoverActor.AddTask(player, zone, time)
+ }
+}
+
+object ReleaseEnvelope {
+ def apply(channel: String, actionMessage: Release): ReleaseEnvelope =
+ ReleaseEnvelope(channel, actionMessage.player.GUID, actionMessage)
+}
+
+final case class CorpseEnvelope(supportMessage: Any)
+ extends GenericSupportEnvelopeOnly {
+ def supportLabel: String = "undertaker"
+}
+
class CorpseRemovalActor extends RemoverActor() {
final val FirstStandardDuration: FiniteDuration = 1 minute
@@ -23,9 +58,9 @@ class CorpseRemovalActor extends RemoverActor() {
def FirstJob(entry: RemoverActor.Entry): Unit = {
import net.psforever.objects.zones.Zone
entry.zone.Population ! Zone.Corpse.Remove(entry.obj.asInstanceOf[Player])
- context.parent ! AvatarServiceMessage(
+ context.parent ! MessageEnvelope(
entry.zone.id,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, entry.obj.GUID, unk=1)
+ ObjectDelete(entry.obj.GUID, unk=1)
)
}
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 80a0ce879..32d12bd55 100644
--- a/src/main/scala/net/psforever/services/avatar/support/DroppedItemRemover.scala
+++ b/src/main/scala/net/psforever/services/avatar/support/DroppedItemRemover.scala
@@ -1,13 +1,71 @@
// Copyright (c) 2017 PSForever
package net.psforever.services.avatar.support
+import akka.actor.{ActorContext, ActorRef, Props}
+import net.psforever.objects.Default
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.guid.{GUIDTask, TaskBundle}
-import net.psforever.services.{RemoverActor, Service}
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.objects.zones.Zone
+import net.psforever.services.avatar.AvatarAction.{DropItem, PickupItem}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelope, GenericSupportEnvelopeOnly}
+import net.psforever.services.base.message.ObjectDelete
+import net.psforever.services.base.support.RemoverActor
+import net.psforever.types.PlanetSideGUID
import scala.concurrent.duration._
+case object LitterRemovalSupport
+ extends EventServiceSupport {
+ def label: String = "janitor"
+ def constructor(context: ActorContext): ActorRef = {
+ context.actorOf(Props[DroppedItemRemover](), name = "DroppedItemRemover")
+ }
+}
+
+final case class PickupItemEnvelope(
+ channel: String,
+ filter: PlanetSideGUID,
+ msg: PickupItem,
+ zone: Zone
+ )
+ extends GenericSupportEnvelope {
+ def supportLabel: String = "janitor"
+ def supportMessage: Any = {
+ val PickupItem(item, _) = msg
+ RemoverActor.ClearSpecific(List(item), zone)
+ }
+}
+
+object PickupItemEnvelope {
+ def apply(channel: String, actionMessage: PickupItem, zone: Zone): PickupItemEnvelope =
+ PickupItemEnvelope(channel, Default.GUID0, actionMessage, zone)
+}
+
+final case class DropItemEnvelope(
+ channel: String,
+ filter: PlanetSideGUID,
+ msg: DropItem,
+ zone: Zone
+ )
+ extends GenericSupportEnvelope {
+ def supportLabel: String = "janitor"
+ def supportMessage: Any = {
+ val DropItem(item) = msg
+ RemoverActor.AddTask(item, zone)
+ }
+}
+
+object DropItemEnvelope {
+ def apply(channel: String, actionMessage: DropItem, zone: Zone): DropItemEnvelope =
+ DropItemEnvelope(channel, Default.GUID0, actionMessage, zone)
+}
+
+final case class GroundEnvelope(supportMessage: Any)
+ extends GenericSupportEnvelopeOnly {
+ def supportLabel: String = "janitor"
+}
+
class DroppedItemRemover extends RemoverActor() {
final val FirstStandardDuration: FiniteDuration = 3 minutes
@@ -22,9 +80,9 @@ class DroppedItemRemover extends RemoverActor() {
def FirstJob(entry: RemoverActor.Entry): Unit = {
import net.psforever.objects.zones.Zone
entry.zone.Ground ! Zone.Ground.RemoveItem(entry.obj.GUID)
- context.parent ! AvatarServiceMessage(
+ context.parent ! MessageEnvelope(
entry.zone.id,
- AvatarAction.ObjectDelete(Service.defaultPlayerGUID, entry.obj.GUID)
+ ObjectDelete(entry.obj.GUID)
)
}
diff --git a/src/main/scala/net/psforever/services/base/GenericEventService.scala b/src/main/scala/net/psforever/services/base/GenericEventService.scala
new file mode 100644
index 000000000..ac098ca68
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/GenericEventService.scala
@@ -0,0 +1,104 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base
+
+import akka.actor.Actor
+import net.psforever.services.Service
+import net.psforever.services.base.bus.GenericEventBus
+import net.psforever.services.base.envelope.{BundledEnvelope, GenericMessageEnvelope}
+import org.log4s.Logger
+
+/**
+ * A distinct tag associated with an event system.
+ * The stamp is intended to demonstrate that the input message has been interpreted into an output response
+ * through actual use of an event system
+ * and that the response has not been fabricated and is not fraudulent.
+ * While the word "stamp" more probably calls to mind the concept of a postage stamp,
+ * the purpose of this artifact is closer to that of the routing information
+ * stamped onto an envelope over the postage stamp area of a letter.
+ */
+trait EventSystemStamp {
+ /*
+ Example:
+ The channels are "foo", "foo.fizz", and "foo.buzz"
+ In general, Classifier channels will perform left-pattern matching
+ Publishing to channel "foo" will allocate Classifiers "foo", "foo.fizz", and "foo.buzz"
+ To isolate "foo", one must distinguish it with a right-pattern such as "out"
+ Publishing to channel "foo.out" no longer publishes to "foo.fizz.out" or to "foo.buzz.out"
+ */
+ /**
+ * Take an input channel and produce the publishing output channel.
+ * @param channel publishing channel
+ * @return appended publishing channel
+ */
+ def routing(channel: String): String = s"/$channel/out"
+}
+
+/**
+ * Basic opt-in event response relay system.
+ * Remembers "subscribers" (`ActorRef`) to "channels" (`String`);
+ * accepts "messages" (`GenericMessageEnvelope`) and interprets the message as a response (`GenericResponseEnvelope`);
+ * and, dispatches the response to all subscribers associated with the channel provided in the message.
+ * @param stamp distinct tag associated with an event system
+ */
+class GenericEventService(stamp: EventSystemStamp)
+ extends Actor {
+ protected lazy val log: Logger = org.log4s.getLogger(getClass.getSimpleName)
+
+ protected val eventBus: GenericEventBus = new GenericEventBus
+
+ /**
+ * Add subscription handling.
+ */
+ private def commonJoinBehavior: Receive = {
+ case Service.Join(channel, true) =>
+ val path = stamp.routing(channel)
+ val who = sender()
+ eventBus.subscribe(who, path)
+ who ! Service.JoinConfirmation(self, channel)
+
+ case Service.Join(channel, _) =>
+ val path = stamp.routing(channel)
+ val who = sender()
+ eventBus.subscribe(who, path)
+ }
+
+ /**
+ * Remove subscription handling.
+ */
+ private def commonLeaveBehavior: Receive = {
+ case Service.LeaveAll =>
+ eventBus.unsubscribe(sender())
+
+ case Service.Leave(channel) =>
+ val path = stamp.routing(channel)
+ eventBus.unsubscribe(sender(), path)
+ }
+
+ /**
+ * Accept and handle designated messages.
+ */
+ protected def commonBehavior: Receive = {
+ case bundle: BundledEnvelope =>
+ bundle.msgs.foreach(commonBehavior.apply)
+
+ case msg: GenericMessageEnvelope =>
+ handleMessage(msg)
+ }
+
+ def receive: Receive = commonJoinBehavior
+ .orElse(commonLeaveBehavior)
+ .orElse(commonBehavior)
+ .orElse {
+ case msg =>
+ log.warn(s"Unhandled message $msg from ${sender()}")
+ }
+
+ /**
+ * Handle designated messages.
+ * Interpret the input message as an output response and publish that response.
+ * @param event event system message
+ */
+ protected def handleMessage(event: GenericMessageEnvelope): Unit = {
+ eventBus.publish(event.response(stamp))
+ }
+}
diff --git a/src/main/scala/net/psforever/services/base/GenericEventServiceWithCacheAndSupport.scala b/src/main/scala/net/psforever/services/base/GenericEventServiceWithCacheAndSupport.scala
new file mode 100644
index 000000000..1f284af76
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/GenericEventServiceWithCacheAndSupport.scala
@@ -0,0 +1,245 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base
+
+import akka.actor.Cancellable
+import net.psforever.objects.Default
+import net.psforever.services.base.envelope.{BundledEnvelope, GenericMessageEnvelope, GenericResponseEnvelope, MessageEnvelope, MessageTransformationBehavior}
+import net.psforever.services.base.message.EventMessage
+import net.psforever.types.PlanetSideGUID
+import net.psforever.util.Config
+
+import scala.collection.concurrent.{Map => CMap}
+import scala.jdk.CollectionConverters._
+import java.util.concurrent.ConcurrentHashMap
+import scala.concurrent.ExecutionContext.Implicits.global
+import scala.concurrent.duration.DurationLong
+
+/*
+Adapted from the rating limiting code in PSForever fork https://github.com/Pinapse/giant with permission
+ */
+
+/**
+ * A framework for flagged messages to be cached
+ * based on designation of a target globally unique identifier.
+ * Suggestion: this identifier be associated with the source.
+ */
+trait CachedGenericEventEnvelope
+ extends MessageTransformationBehavior {
+ /** cache designator */
+ def guid: PlanetSideGUID
+}
+
+final case class CachedEnvelope(
+ guid: PlanetSideGUID,
+ channel: String,
+ filter: PlanetSideGUID,
+ msg: EventMessage
+ ) extends CachedGenericEventEnvelope {
+ assert(guid != Default.GUID0, "can not cache message under default GUID")
+}
+
+object CachedEnvelope {
+ /**
+ * If the filter is specified, but not the cache target, treat the filter like the cache target.
+ * Treat invalid values as a reason to downgrade from a cached message envelope to a traditional message envelope.
+ * Warn of this downgrade.e
+ * @param channel set of subscribers on an event system bus the envelope should reach
+ * @param filter specific subscriber endpoint to be excluded (the subscriber should filter themselves)
+ * @param msg input payload transported by this envelope
+ * @return either a `CacheEnvelope` or a `MessageEnvelope`, depending on cache-readiness of the `filter` value
+ */
+ def apply(channel: String, filter: PlanetSideGUID, msg: EventMessage): GenericMessageEnvelope = {
+ if (filter == Default.GUID0) {
+ org.log4s.getLogger("CachedEnvelope").warn("(1) cached message envelope downgraded to normal message envelope")
+ MessageEnvelope(channel, filter, msg)
+ } else {
+ CachedEnvelope(filter, channel, filter, msg)
+ }
+ }
+
+ /**
+ * If the cache target is specified, but is not valid,
+ * downgrade from a cached message envelope to a traditional message envelope.
+ * Warn of this downgrade.
+ * If valid, the filter becomes its defaulted value in the corresponding message
+ * @param guid cache designator
+ * @param channel set of subscribers on an event system bus the envelope should reach
+ * @param msg input payload transported by this envelope
+ * @return either a `CacheEnvelope` or a `MessageEnvelope`, depending on cache-readiness of the target
+ */
+ def apply(guid: PlanetSideGUID, channel: String, msg: EventMessage): GenericMessageEnvelope = {
+ if (guid == Default.GUID0) {
+ org.log4s.getLogger("CachedEnvelope").warn("(2) cached message envelope downgraded to normal message envelope")
+ MessageEnvelope(channel, guid, msg)
+ } else {
+ CachedEnvelope(guid, channel, Default.GUID0, msg)
+ }
+ }
+}
+
+/**
+ * An internal message for the purpose of forcing cached messages to be flushed.
+ * All of it's fields default to harmless values because it is not intended to be processed by an event system
+ * but it must maintain the trappings of a message envelope to be processed.
+ * @see `NoMessage`
+ * @see `NoResponseEnvelope`
+ */
+private case object FlushCachedMessages extends GenericMessageEnvelope {
+ def originalChannel: String = ""
+ def msg: EventMessage = NoMessage
+ def response(stamp: EventSystemStamp): GenericResponseEnvelope = NoResponseEnvelope
+ def channel: String = ""
+ def filter: PlanetSideGUID = Default.GUID0
+}
+
+class GenericEventServiceWithCacheAndSupport
+(
+ stamp: EventSystemStamp,
+ eventSupportServices: List[EventServiceSupport]
+) extends GenericEventServiceWithSupport(stamp, eventSupportServices) {
+ private val flushCacheDelay: Long = Config.app.network.eventCaching.flushCacheDelay
+ private val flushCacheMaxDelay: Long = Config.app.network.eventCaching.flushCacheMaxDelay
+ private var hasCachedMessages: Int = 0
+ private var lastCachedMessages: Int = 0
+ private val messageThreshold: Long = Config.app.network.eventCaching.messageTrafficThreshold
+ private var nextTimeToFlushCache: Long = 0L
+ private var emergencyFlush: Cancellable = Default.Cancellable
+
+ private val cache: CMap[String, CMap[String, CMap[PlanetSideGUID, GenericMessageEnvelope]]] =
+ new ConcurrentHashMap[String, CMap[String, CMap[PlanetSideGUID, GenericMessageEnvelope]]]().asScala
+
+ override def postStop(): Unit = {
+ flushCache()
+ super.postStop()
+ }
+
+ private def adjustedFlushDelay(): Long = {
+ // flushCacheWait <= t <= emergencyFlushMaxDelay
+ math.min(
+ flushCacheDelay + math.max(0, lastCachedMessages - messageThreshold),
+ flushCacheMaxDelay
+ )
+ }
+
+ /**
+ * If there were previously no messages in the cache,
+ * prepare to flush the cache after the intended interval passes,
+ * whether the passing of that interval is detected by a new incoming message and the cache gets flushed naturally,
+ * or if a safety timer expires and the cache is flushed in precaution.
+ */
+ private def tryRetimeFlushCache(): Unit = {
+ hasCachedMessages += 1
+ if (hasCachedMessages == 1) {
+ val flushDelay = adjustedFlushDelay()
+ nextTimeToFlushCache = System.currentTimeMillis() + flushDelay
+ emergencyFlush = context.system.scheduler.scheduleOnce(delay = (1.25f * flushDelay).toLong milliseconds, self, FlushCachedMessages)
+ }
+ }
+
+ /**
+ * Add messages to the cache.
+ * @param event event system message
+ */
+ private def pushToCache(event: CachedGenericEventEnvelope): Unit = {
+ pushToCache(event, event.msg.getClass.getName, event.guid)
+ }
+ /**
+ * Add messages to the cache.
+ * @param event event system message
+ * @param eventGuid event system message filter
+ */
+ private def pushToCache(event: GenericMessageEnvelope, eventGuid: PlanetSideGUID): Unit = {
+ pushToCache(event, event.msg.getClass.getName, eventGuid)
+ }
+ /**
+ * Add messages to the cache
+ * based on their channel, then their type, then their cache target identifier.
+ * Messages that arrive with the same cache profile as a previous message,
+ * but before that previous message was dispatched,
+ * will overwrite the previous message without fanfare or warning.
+ * @param event event system message
+ * @param eventClassName event system message identifier
+ * @param eventGuid event system message filter
+ */
+ private def pushToCache(event: GenericMessageEnvelope, eventClassName: String, eventGuid: PlanetSideGUID): Unit = {
+ val updateBranch = cache
+ .getOrElseUpdate(event.channel, new ConcurrentHashMap[String, CMap[PlanetSideGUID, GenericMessageEnvelope]]().asScala)
+ .getOrElseUpdate(eventClassName, new ConcurrentHashMap[PlanetSideGUID, GenericMessageEnvelope]().asScala)
+ updateBranch.updateWith(eventGuid) { _ => Some(event) }
+ tryRetimeFlushCache()
+ }
+
+ /**
+ * If the cache has messages and the current time exceeds the anticipated flush time,
+ * flush the cache messages to the normal event system bus.
+ */
+ private def tryFlushCache(): Boolean = {
+ val willFlush = hasCachedMessages > 0 && nextTimeToFlushCache < System.currentTimeMillis()
+ if (willFlush) {
+ flushCache()
+ }
+ willFlush
+ }
+
+ /**
+ * Flush the cache messages to the normal event system bus.
+ * Clear old messages then reset all flags that would force the messages to be flushed.
+ */
+ private def flushCache(): Unit = {
+ cache.foreachEntry { (_, map) =>
+ map.foreachEntry { (_, map) =>
+ map.foreachEntry { (_, event) =>
+ super.handleMessage(event)
+ }
+ map.clear()
+ }
+ }
+ lastCachedMessages = hasCachedMessages
+ hasCachedMessages = 0
+ emergencyFlush.cancel()
+ emergencyFlush = Default.Cancellable
+ }
+
+ /**
+ * If the cache will be flushed after this message, flush the cache and then pass the message for processing.
+ * If the cache will not be flushed, add the message to the cache.
+ * In any case, procedure should always be ready to flush the cache when a message is received.
+ * If there is a support actor involved with a cached message, it is resolved when the message is flushed.
+ * @param event event system message that may be cached
+ */
+ override protected def handleMessage(event: GenericMessageEnvelope): Unit = {
+ event match {
+ case FlushCachedMessages =>
+ flushCache()
+ case bundle: BundledEnvelope =>
+ handleMessageBundled(bundle)
+ case _: CachedGenericEventEnvelope if tryFlushCache() =>
+ super.handleMessage(event)
+ case envelope: CachedGenericEventEnvelope =>
+ pushToCache(envelope)
+ case _ =>
+ tryFlushCache()
+ super.handleMessage(event)
+ }
+ }
+
+ /**
+ * If even one message in a bundle is to be cached, the contents of the whole bundle should be cached.
+ * Otherwise, just handle things normally.
+ * @param bundle event system message that may be cached
+ */
+ private def handleMessageBundled(bundle: BundledEnvelope): Unit = {
+ val messages = bundle.msgs
+ messages.find(_.isInstanceOf[CachedGenericEventEnvelope]) match {
+ case Some(cache: CachedGenericEventEnvelope) if messages.size == 1 =>
+ pushToCache(messages.head, cache.guid)
+ tryFlushCache()
+ case Some(cache: CachedGenericEventEnvelope) =>
+ val guid = cache.guid
+ messages.foreach(msg => pushToCache(msg, guid))
+ tryFlushCache()
+ case _ =>
+ messages.foreach(handleMessage)
+ }
+ }
+}
diff --git a/src/main/scala/net/psforever/services/base/GenericEventServiceWithSupport.scala b/src/main/scala/net/psforever/services/base/GenericEventServiceWithSupport.scala
new file mode 100644
index 000000000..e10b152f1
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/GenericEventServiceWithSupport.scala
@@ -0,0 +1,128 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base
+
+import akka.actor.{ActorContext, ActorRef}
+import net.psforever.objects.Default
+import net.psforever.services.base.envelope.{GenericMessageEnvelope, GenericResponseEnvelope, MessageTransformationBehavior, NoReply, Undelivered}
+import net.psforever.services.base.message.{EventMessage, EventResponse, SelfRespondingEvent}
+import net.psforever.types.PlanetSideGUID
+
+import scala.annotation.unused
+
+/**
+ * A message when there should be none, but a message is required to be defined anyway.
+ * @see `GenericSupportEnvelopeOnly`
+ */
+case object NoMessage extends SelfRespondingEvent
+
+/**
+ * A response when there should be none, but a response is required to be defined anyway.
+ * @see `GenericSupportEnvelopeOnly`
+ * @see `NoReply`
+ * @see `Undelivered`
+ */
+case object NoResponseEnvelope extends GenericResponseEnvelope {
+ def reply: EventResponse = NoReply
+ def stamp: EventSystemStamp = Undelivered
+ def channel: String = ""
+ def filter: PlanetSideGUID = Default.GUID0
+}
+
+/**
+ * A framework for how support actors are to be submitted to an event system.
+ * The bare bones are a label by which the support actor is identified for message routing,
+ * and a function that constructs the support actor within the context of the event system.
+ * @see `ActorContext`
+ */
+trait EventServiceSupport {
+ def label: String
+ def constructor(@unused context: ActorContext): ActorRef
+}
+
+/**
+ * A framework for communicating messages to support actors within an event system.
+ * The bare bones are a label by which the support actor is identified for message routing,
+ * and the message payload for the support actor to process.
+ * @see `ActorContext`
+ */
+trait GenericMessageToSupport {
+ def supportLabel: String
+ def supportMessage: Any
+}
+
+/**
+ * An envelope framework for communicating messages to support actors within an event system
+ * and also interacting with the event system directly.
+ */
+trait GenericSupportEnvelope
+ extends GenericMessageToSupport
+ with MessageTransformationBehavior
+
+/**
+ * An envelope framework for communicating messages to support actors within an event system only.
+ */
+trait GenericSupportEnvelopeOnly
+ extends GenericMessageToSupport
+ with GenericMessageEnvelope {
+ def originalChannel: String = ""
+ def channel: String = ""
+ def filter: PlanetSideGUID = Default.GUID0
+ def msg: EventMessage = NoMessage
+
+ def response(@unused stamp: EventSystemStamp): GenericResponseEnvelope = NoResponseEnvelope
+}
+
+/**
+ * Advanced opt-in event response relay system.
+ * Includes a system of specialized child actors that serve specific repeatable operations
+ * whose behaviors are intentionally synchronized on this event pipeline
+ * or whose collective operational overhead can be streamlined by reliance on a singular pipeline.
+ * @param stamp distinct tag associated with an event system
+ * @param eventSupportServices list of support actors to initialize
+ */
+class GenericEventServiceWithSupport
+(
+ stamp: EventSystemStamp,
+ eventSupportServices: List[EventServiceSupport]
+) extends GenericEventService(stamp) {
+
+ private val supportServices: Map[String, ActorRef] =
+ eventSupportServices
+ .map { supportService => (supportService.label, supportService.constructor(context)) }
+ .toMap[String, ActorRef]
+
+ /**
+ * Use the label assigned to a support actor
+ * to locate that support actor on this event system
+ * and forward to it a payload message.
+ * @param msg event system message carrying an additional message for a support actor
+ */
+ private def forwardToSupport(msg: GenericMessageToSupport): Unit = {
+ supportServices
+ .get(msg.supportLabel)
+ .map { support =>
+ support.forward(msg.supportMessage)
+ msg
+ }
+ .getOrElse {
+ log.error(s"support service ${msg.supportLabel} was not found - check message routing or service params")
+ }
+ }
+
+ /**
+ * If the message involves the support actor subsystem, forward the message to it for additional processing.
+ * Afterwards, or if not, merely call up to previously-established message handling if warranted.
+ * @param event event system message that may be carrying an additional message for a support actor
+ */
+ override protected def handleMessage(event: GenericMessageEnvelope): Unit = {
+ event match {
+ case msg: GenericSupportEnvelopeOnly =>
+ forwardToSupport(msg)
+ case msg: GenericSupportEnvelope =>
+ forwardToSupport(msg)
+ super.handleMessage(event)
+ case event =>
+ super.handleMessage(event)
+ }
+ }
+}
diff --git a/src/main/scala/net/psforever/services/base/bus/GenericEventBus.scala b/src/main/scala/net/psforever/services/base/bus/GenericEventBus.scala
new file mode 100644
index 000000000..57454399d
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/bus/GenericEventBus.scala
@@ -0,0 +1,45 @@
+// Copyright (c) 2017 PSForever
+package net.psforever.services.base.bus
+
+import akka.event.{ActorEventBus, SubchannelClassification}
+import akka.util.Subclassification
+import net.psforever.services.base.envelope.GenericResponseEnvelope
+
+/**
+ * Maintain a list of endpoints that have subscribed to a specific perspective
+ * internally called a `Classifier` and externally referred to as a "channel".
+ * When an `Event` - externally referred colloquially as a "message" - is received,
+ * to be published,
+ * match the "channel" to a list of known `Classifier` endpoints.
+ * Each of these `Subscribers` should receive the message.
+ * @see `GenericResponseEnvelope`
+ * @see `ActorEventBus.Subscriber`
+ */
+class GenericEventBus
+ extends ActorEventBus with SubchannelClassification {
+ type Event = GenericResponseEnvelope
+ type Classifier = String
+
+ protected def classify(event: Event): Classifier = event.outChannel
+
+ /*
+ Example:
+ The channels are "foo", "foo.fizz", and "foo.buzz"
+ In general, Classifier channels will perform left-pattern matching
+ Publishing to channel "foo" will allocate Classifiers "foo", "foo.fizz", and "foo.buzz"
+ See `GenericResponseEnvelope.outChannel` to determine how this is applied
+ */
+ protected def subclassification: Subclassification[String] = new Subclassification[Classifier] {
+ def isEqual(x: Classifier, y: Classifier): Boolean = x.equals(y)
+
+ def isSubclass(x: Classifier, y: Classifier): Boolean = x.startsWith(y)
+ }
+
+ override def publish(event: Event): Unit = {
+ super[SubchannelClassification].publish(event)
+ }
+
+ protected def publish(event: Event, subscriber: Subscriber): Unit = {
+ subscriber ! event
+ }
+}
diff --git a/src/main/scala/net/psforever/services/base/envelope/AllEnvelopes.scala b/src/main/scala/net/psforever/services/base/envelope/AllEnvelopes.scala
new file mode 100644
index 000000000..d60860743
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/envelope/AllEnvelopes.scala
@@ -0,0 +1,17 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.envelope
+
+import net.psforever.types.PlanetSideGUID
+
+/**
+ * Base of all envelope classes.
+ * Defines a channel and a filter, both of which server the purpose of routing the message to its destination.
+ */
+trait AllEnvelopes {
+ /** set of subscribers on an event system bus that the envelope should reach */
+ def channel: String
+ /** specific subscriber endpoint to be excluded (the subscriber should filter themselves upon receipt) */
+ def filter: PlanetSideGUID
+
+ val time: Long = System.currentTimeMillis()
+}
diff --git a/src/main/scala/net/psforever/services/base/envelope/BundledEnvelope.scala b/src/main/scala/net/psforever/services/base/envelope/BundledEnvelope.scala
new file mode 100644
index 000000000..9c831b014
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/envelope/BundledEnvelope.scala
@@ -0,0 +1,82 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.envelope
+
+import net.psforever.objects.Default
+import net.psforever.services.base.EventSystemStamp
+import net.psforever.services.base.message.{EventMessage, EventResponse}
+import net.psforever.types.PlanetSideGUID
+
+import scala.annotation.tailrec
+
+/**
+ * A message when there should be none, but a message is required to be defined anyway.
+ */
+case object NoMessage extends EventMessage {
+ override def response(): EventResponse = NoReply
+}
+
+/**
+ * A response envelope when there should be none, but an envelope for messaging product is required to be defined anyway.
+ */
+case object NoResponse extends GenericResponseEnvelope {
+ override def reply: EventResponse = NoReply
+ override def stamp: EventSystemStamp = Undelivered
+ override def channel: String = ""
+ override def filter: PlanetSideGUID = Default.GUID0
+}
+
+/**
+ * A collection of messaging envelopes to be dispatched to an event system at the same time
+ * within the conditions of event system synchronization between different messages.
+ * All messages contained within the bundling are to be processed at the time of processing by the bundling.
+ * The order of the bundled message envelopes should be considered important.
+ * @see `SendResponse(Seq[PlanetSideGamePacket])`
+ * @param msgs list of message envelopes
+ */
+final case class BundledEnvelope(msgs: Iterable[GenericMessageEnvelope])
+ extends GenericMessageEnvelope {
+ assert(msgs.size == BundledEnvelope.unwind(msgs).size, "do not nest bundled event system envelopes")
+
+ override def msg: EventMessage = NoMessage
+ override def response(stamp: EventSystemStamp): GenericResponseEnvelope = NoResponse
+ override def channel: String = ""
+ override def filter: PlanetSideGUID = Default.GUID0
+}
+
+object BundledEnvelope {
+ /**
+ * Overloaded constructor for `BundledEnvelope` objects.
+ * The entities are separated between "the first" and "any others" to distinguish from
+ * the `case class` constructor that accepts any number of message envelopes
+ * including no message envelopes at all.
+ * @param first single, required `GenericMessageEnvelope` entity for bundling
+ * @param msgs any other `GenericMessageEnvelope` entity for bundling
+ * @return a `BundledEnvelope` object
+ */
+ def apply(first: GenericMessageEnvelope, msgs: GenericMessageEnvelope*): BundledEnvelope = {
+ new BundledEnvelope(unwind(first +: msgs))
+ }
+
+ /**
+ * Input sanitization method that unpacks `BundledEnvelope` message envelopes
+ * producing a single-dimensional list of `GenericMessageEnvelope` entities.
+ * An assertion in the constructor of `BundledEnvelope` aborts object creation
+ * if a `BundledEnvelope` entity is within that `BundledEnvelope` entity.
+ * @param in list of `GenericMessageEnvelope` entities to be processed
+ * @param out list of `GenericMessageEnvelope` entities that have been processed
+ * @return list of `GenericMessageEnvelope` entities that have been processed
+ */
+ @tailrec
+ private def unwind(in: Iterable[GenericMessageEnvelope], out: List[GenericMessageEnvelope] = Nil): List[GenericMessageEnvelope] = {
+ if (in.isEmpty) {
+ out
+ } else {
+ in.head match {
+ case bundle: BundledEnvelope =>
+ unwind(bundle.msgs ++ in.tail, out)
+ case first =>
+ unwind(in.tail, out :+ first)
+ }
+ }
+ }
+}
diff --git a/src/main/scala/net/psforever/services/base/envelope/GenericMessageEnvelope.scala b/src/main/scala/net/psforever/services/base/envelope/GenericMessageEnvelope.scala
new file mode 100644
index 000000000..ae4c411e4
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/envelope/GenericMessageEnvelope.scala
@@ -0,0 +1,28 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.envelope
+
+import net.psforever.services.base.EventSystemStamp
+import net.psforever.services.base.message.EventMessage
+import net.psforever.types.PlanetSideGUID
+
+trait GenericMessageEnvelope
+ extends AllEnvelopes {
+ /** input payload transported by this envelope */
+ def msg: EventMessage
+ /** method that counts as "processing" the envelope by an event system;
+ * the event system supplies their stamp and converts the message envelope into a response envelope;
+ * the input message is converted into a response message */
+ def response(stamp: EventSystemStamp): GenericResponseEnvelope
+}
+
+object GenericMessageEnvelope {
+ /**
+ * The extracted data from a message envelope resembles the data from,
+ * including the filter and the original channel information.
+ * @param obj response envelope
+ * @return a tuple containing the channel, filter, and reply message
+ */
+ def unapply(obj: GenericMessageEnvelope): Option[(String, PlanetSideGUID, EventMessage)] = {
+ Some((obj.channel, obj.filter, obj.msg))
+ }
+}
diff --git a/src/main/scala/net/psforever/services/base/envelope/GenericResponseEnvelope.scala b/src/main/scala/net/psforever/services/base/envelope/GenericResponseEnvelope.scala
new file mode 100644
index 000000000..5f5a39420
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/envelope/GenericResponseEnvelope.scala
@@ -0,0 +1,72 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.envelope
+
+import net.psforever.services.base.EventSystemStamp
+import net.psforever.services.base.message.{EventMessage, EventResponse, SelfRespondingEvent}
+import net.psforever.types.PlanetSideGUID
+
+/**
+ * The framework of an event system envelope that is treated as the processed complement of a message envelope.
+ */
+trait GenericResponseEnvelope
+ extends AllEnvelopes {
+ /** result of converting the message envelope input payload into output payload */
+ def reply: EventResponse
+ /** marker indicating the routing through which the original message was processed */
+ def stamp: EventSystemStamp
+ /** channel information tailored to the event system */
+ final def outChannel: String = stamp.routing(channel)
+}
+
+object GenericResponseEnvelope {
+ /**
+ * Fake a response envelope, as if processed by a specific event system.
+ * @param stamp marker indicating the routing through which the original message was processed
+ * @param channel set of subscribers on an event system bus the envelope should reach
+ * @param filter a specific subscriber endpoint to be excluded
+ * @param msg output payload transported by this envelope
+ * @return a faked but typically acceptable response envelope
+ */
+ def apply(stamp: EventSystemStamp, channel: String, filter: PlanetSideGUID, msg: EventMessage): GenericResponseEnvelope = {
+ val envelope = MessageEnvelope(channel, filter, msg)
+ envelope.response(stamp)
+ }
+
+ /**
+ * Fake a response envelope, as if processed by a specific event system.
+ * @param _stamp marker indicating the routing through which the original message was processed
+ * @param _channel set of subscribers on an event system bus the envelope should reach
+ * @param _filter a specific subscriber endpoint to be excluded
+ * @param _reply input payload transported by this envelope
+ * @return a faked but typically acceptable response envelope
+ */
+ def apply(_stamp: EventSystemStamp, _channel: String, _filter: PlanetSideGUID, _reply: SelfRespondingEvent): GenericResponseEnvelope = {
+ apply(_stamp, _channel, _filter, _reply.asInstanceOf[EventResponse])
+ }
+
+ /**
+ * Fake a response envelope, as if processed by a specific event system.
+ * @param _stamp marker indicating the routing through which the original message was processed
+ * @param _channel set of subscribers on an event system bus the envelope should reach
+ * @param _filter a specific subscriber endpoint to be excluded
+ * @param _reply input payload transported by this envelope
+ * @return a faked but typically acceptable response envelope
+ */
+ def apply(_stamp: EventSystemStamp, _channel: String, _filter: PlanetSideGUID, _reply: EventResponse): GenericResponseEnvelope = {
+ new GenericResponseEnvelope {
+ def channel: String = _channel
+ def filter: PlanetSideGUID = _filter
+ def reply: EventResponse = _reply
+ def stamp: EventSystemStamp = _stamp
+ }
+ }
+
+ /**
+ * The `unapply`ed data from a response envelope resembles the data from includes the filter and the channel information.
+ * @param obj response envelope
+ * @return a tuple containing the channel, filter, and reply message
+ */
+ def unapply(obj: GenericResponseEnvelope): Option[(String, PlanetSideGUID, EventResponse)] = {
+ Some((obj.channel, obj.filter, obj.reply))
+ }
+}
diff --git a/src/main/scala/net/psforever/services/base/envelope/MessageEnvelope.scala b/src/main/scala/net/psforever/services/base/envelope/MessageEnvelope.scala
new file mode 100644
index 000000000..58373b521
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/envelope/MessageEnvelope.scala
@@ -0,0 +1,65 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.envelope
+
+import net.psforever.objects.Default
+import net.psforever.services.base.EventSystemStamp
+import net.psforever.services.base.message.{EventMessage, EventResponse}
+import net.psforever.types.PlanetSideGUID
+
+/**
+ * A response when there should be none, but a reply is required to be defined anyway.
+ */
+case object NoReply extends EventResponse
+
+/**
+ * A stamp that represents not having been processed by an event system.
+ * Should never been given out to an event system.
+ */
+case object Undelivered extends EventSystemStamp {
+ override def routing(channel: String): String = ""
+}
+
+/**
+ * The mechanics of a proper event system envelope.
+ * The envelope has two forms: the input message envelope and the output response envelope.
+ * The event system uses its stamp to mark that the message form converts into the response form when being processed.
+ * In terms of proper metaphor,
+ * it makes no sense for a post office take a letter out of its original envelope,
+ * write a completely different envelope,
+ * write a completely different letter,
+ * package the new letter in the new envelope,
+ * and deliver it is place of the originals.
+ * That would be considered fraud.
+ */
+trait MessageTransformationBehavior
+ extends GenericMessageEnvelope
+ with GenericResponseEnvelope {
+ private var outputStamp: EventSystemStamp = Undelivered
+ private var outputReply: EventResponse = NoReply
+
+ // satisfies GenericMessageEnvelope
+ def response(stamp: EventSystemStamp): GenericResponseEnvelope = {
+ outputStamp = stamp
+ outputReply = msg.response()
+ this
+ }
+
+ // satisfies GenericResponseEnvelope
+ def stamp: EventSystemStamp = outputStamp
+
+ def reply: EventResponse = outputReply
+}
+
+object MessageEnvelope {
+ def apply(msg: EventMessage): MessageEnvelope =
+ MessageEnvelope("", Default.GUID0, msg)
+
+ def apply(channel: String, msg: EventMessage): MessageEnvelope =
+ MessageEnvelope(channel, Default.GUID0, msg)
+}
+
+/**
+ * A proper event system envelope.
+ */
+case class MessageEnvelope(channel: String, filter: PlanetSideGUID, msg: EventMessage)
+ extends MessageTransformationBehavior
diff --git a/src/main/scala/net/psforever/services/base/message/ChangeAmmo.scala b/src/main/scala/net/psforever/services/base/message/ChangeAmmo.scala
new file mode 100644
index 000000000..101a37cc7
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/ChangeAmmo.scala
@@ -0,0 +1,14 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.packet.game.objectcreate.ConstructorData
+import net.psforever.types.PlanetSideGUID
+
+final case class ChangeAmmo(
+ weapon_guid: PlanetSideGUID,
+ weapon_slot: Int,
+ old_ammo_guid: PlanetSideGUID,
+ ammo_id: Int,
+ ammo_guid: PlanetSideGUID,
+ ammo_data: ConstructorData
+ ) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/ChangeFireState_Start.scala b/src/main/scala/net/psforever/services/base/message/ChangeFireState_Start.scala
new file mode 100644
index 000000000..59d1bb142
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/ChangeFireState_Start.scala
@@ -0,0 +1,6 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+final case class ChangeFireState_Start(weapon_guid: PlanetSideGUID) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/ChangeFireState_Stop.scala b/src/main/scala/net/psforever/services/base/message/ChangeFireState_Stop.scala
new file mode 100644
index 000000000..5aeb30c11
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/ChangeFireState_Stop.scala
@@ -0,0 +1,6 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+final case class ChangeFireState_Stop(weapon_guid: PlanetSideGUID) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/ConcealPlayer.scala b/src/main/scala/net/psforever/services/base/message/ConcealPlayer.scala
new file mode 100644
index 000000000..1a642c72c
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/ConcealPlayer.scala
@@ -0,0 +1,6 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+final case class ConcealPlayer(player_guid: PlanetSideGUID) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/EventExchange.scala b/src/main/scala/net/psforever/services/base/message/EventExchange.scala
new file mode 100644
index 000000000..3331927cb
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/EventExchange.scala
@@ -0,0 +1,14 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+trait EventResponse
+
+trait EventMessage {
+ def response(): EventResponse
+}
+
+trait SelfRespondingEvent
+ extends EventMessage
+ with EventResponse {
+ def response(): EventResponse = this
+}
diff --git a/src/main/scala/net/psforever/services/base/message/GenericObjectAction.scala b/src/main/scala/net/psforever/services/base/message/GenericObjectAction.scala
new file mode 100644
index 000000000..a62a467f6
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/GenericObjectAction.scala
@@ -0,0 +1,6 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+final case class GenericObjectAction(object_guid: PlanetSideGUID, action_code: Int) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/HintsAtAttacker.scala b/src/main/scala/net/psforever/services/base/message/HintsAtAttacker.scala
new file mode 100644
index 000000000..dbb835448
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/HintsAtAttacker.scala
@@ -0,0 +1,7 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+//analogue for HitHint
+final case class HintsAtAttacker(source_guid: PlanetSideGUID) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/ObjectDelete.scala b/src/main/scala/net/psforever/services/base/message/ObjectDelete.scala
new file mode 100644
index 000000000..43fb1949e
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/ObjectDelete.scala
@@ -0,0 +1,6 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+final case class ObjectDelete(obj_guid: PlanetSideGUID, unk: Int = 0) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/PlanetsideAttribute.scala b/src/main/scala/net/psforever/services/base/message/PlanetsideAttribute.scala
new file mode 100644
index 000000000..6bf3af0b4
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/PlanetsideAttribute.scala
@@ -0,0 +1,10 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+final case class PlanetsideAttribute(
+ target_guid: PlanetSideGUID,
+ attribute_type: Int,
+ attribute_value: Long
+ ) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/ReloadTool.scala b/src/main/scala/net/psforever/services/base/message/ReloadTool.scala
new file mode 100644
index 000000000..e4b8aee48
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/ReloadTool.scala
@@ -0,0 +1,6 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+final case class ReloadTool(weapon_guid: PlanetSideGUID) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/SendResponse.scala b/src/main/scala/net/psforever/services/base/message/SendResponse.scala
new file mode 100644
index 000000000..cb3f452a5
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/SendResponse.scala
@@ -0,0 +1,12 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.packet.PlanetSideGamePacket
+
+final case class SendResponse(pkts: Seq[PlanetSideGamePacket]) extends SelfRespondingEvent
+
+object SendResponse {
+ def apply(pkt: PlanetSideGamePacket): SendResponse = SendResponse(Seq(pkt))
+
+ def apply(first: PlanetSideGamePacket, msgs: PlanetSideGamePacket*): SendResponse = SendResponse(first +: msgs)
+}
diff --git a/src/main/scala/net/psforever/services/base/message/SetEmpire.scala b/src/main/scala/net/psforever/services/base/message/SetEmpire.scala
new file mode 100644
index 000000000..7e2315372
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/SetEmpire.scala
@@ -0,0 +1,6 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
+
+final case class SetEmpire(object_guid: PlanetSideGUID, faction: PlanetSideEmpire.Value) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/base/message/WeaponDryFire.scala b/src/main/scala/net/psforever/services/base/message/WeaponDryFire.scala
new file mode 100644
index 000000000..a011bb209
--- /dev/null
+++ b/src/main/scala/net/psforever/services/base/message/WeaponDryFire.scala
@@ -0,0 +1,6 @@
+// Copyright (c) 2026 PSForever
+package net.psforever.services.base.message
+
+import net.psforever.types.PlanetSideGUID
+
+final case class WeaponDryFire(weapon_guid: PlanetSideGUID) extends SelfRespondingEvent
diff --git a/src/main/scala/net/psforever/services/RemoverActor.scala b/src/main/scala/net/psforever/services/base/support/RemoverActor.scala
similarity index 99%
rename from src/main/scala/net/psforever/services/RemoverActor.scala
rename to src/main/scala/net/psforever/services/base/support/RemoverActor.scala
index d6118dccc..2de317768 100644
--- a/src/main/scala/net/psforever/services/RemoverActor.scala
+++ b/src/main/scala/net/psforever/services/base/support/RemoverActor.scala
@@ -1,12 +1,11 @@
// Copyright (c) 2017 PSForever
-package net.psforever.services
+package net.psforever.services.base.support
import akka.actor.Cancellable
import net.psforever.objects.guid.{StraightforwardTask, TaskBundle, TaskWorkflow}
import net.psforever.objects.zones.Zone
import net.psforever.objects.{Default, PlanetSideGameObject}
import net.psforever.types.Vector3
-import net.psforever.services.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions}
import scala.concurrent.Future
import scala.concurrent.duration._
diff --git a/src/main/scala/net/psforever/services/support/SimilarityComparator.scala b/src/main/scala/net/psforever/services/base/support/SimilarityComparator.scala
similarity index 87%
rename from src/main/scala/net/psforever/services/support/SimilarityComparator.scala
rename to src/main/scala/net/psforever/services/base/support/SimilarityComparator.scala
index d9ea16a1b..f840500cb 100644
--- a/src/main/scala/net/psforever/services/support/SimilarityComparator.scala
+++ b/src/main/scala/net/psforever/services/base/support/SimilarityComparator.scala
@@ -1,5 +1,5 @@
// Copyright (c) 2017 PSForever
-package net.psforever.services.support
+package net.psforever.services.base.support
abstract class SimilarityComparator[A <: SupportActor.Entry] {
diff --git a/src/main/scala/net/psforever/services/support/SupportActor.scala b/src/main/scala/net/psforever/services/base/support/SupportActor.scala
similarity index 99%
rename from src/main/scala/net/psforever/services/support/SupportActor.scala
rename to src/main/scala/net/psforever/services/base/support/SupportActor.scala
index bb52e1f0b..07503ad17 100644
--- a/src/main/scala/net/psforever/services/support/SupportActor.scala
+++ b/src/main/scala/net/psforever/services/base/support/SupportActor.scala
@@ -1,5 +1,5 @@
// Copyright (c) 2017 PSForever
-package net.psforever.services.support
+package net.psforever.services.base.support
import akka.actor.Actor
import net.psforever.objects.PlanetSideGameObject
diff --git a/src/main/scala/net/psforever/services/support/SupportActorCaseConversions.scala b/src/main/scala/net/psforever/services/base/support/SupportActorCaseConversions.scala
similarity index 96%
rename from src/main/scala/net/psforever/services/support/SupportActorCaseConversions.scala
rename to src/main/scala/net/psforever/services/base/support/SupportActorCaseConversions.scala
index 4a1fedd77..3640cceff 100644
--- a/src/main/scala/net/psforever/services/support/SupportActorCaseConversions.scala
+++ b/src/main/scala/net/psforever/services/base/support/SupportActorCaseConversions.scala
@@ -1,5 +1,5 @@
// Copyright (c) 2017 PSForever
-package net.psforever.services.support
+package net.psforever.services.base.support
import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.zones.Zone
diff --git a/src/main/scala/net/psforever/services/chat/ChatService.scala b/src/main/scala/net/psforever/services/chat/ChatService.scala
index 68fc0edbb..5d72ebf71 100644
--- a/src/main/scala/net/psforever/services/chat/ChatService.scala
+++ b/src/main/scala/net/psforever/services/chat/ChatService.scala
@@ -6,6 +6,7 @@ import akka.actor.typed.{ActorRef, Behavior}
import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors}
import net.psforever.objects.{Session, SessionSource}
import net.psforever.packet.game.ChatMsg
+import net.psforever.services.base.message.{EventMessage, EventResponse}
import net.psforever.types.{ChatMessageType, PlanetSideEmpire}
object ChatService {
@@ -17,14 +18,16 @@ object ChatService {
new ChatService(context)
}
- sealed trait Command
+ sealed trait Command extends EventMessage {
+ def response(): EventResponse = null
+ }
final case class JoinChannel(actor: ActorRef[MessageResponse], sessionSource: SessionSource, channel: ChatChannel) extends Command
final case class LeaveChannel(actor: ActorRef[MessageResponse], channel: ChatChannel) extends Command
final case class LeaveAllChannels(actor: ActorRef[MessageResponse]) extends Command
final case class Message(session: Session, message: ChatMsg, channel: ChatChannel) extends Command
- final case class MessageResponse(session: Session, message: ChatMsg, channel: ChatChannel)
+ final case class MessageResponse(session: Session, message: ChatMsg, channel: ChatChannel) extends EventResponse
}
class ChatService(context: ActorContext[ChatService.Command]) extends AbstractBehavior[ChatService.Command](context) {
diff --git a/src/main/scala/net/psforever/services/galaxy/GalaxyAction.scala b/src/main/scala/net/psforever/services/galaxy/GalaxyAction.scala
new file mode 100644
index 000000000..96015b6ad
--- /dev/null
+++ b/src/main/scala/net/psforever/services/galaxy/GalaxyAction.scala
@@ -0,0 +1,38 @@
+// Copyright (c) 2017-2026 PSForever
+package net.psforever.services.galaxy
+
+import net.psforever.objects.Vehicle
+import net.psforever.objects.vehicles.VehicleManifest
+import net.psforever.objects.zones.{HotSpotInfo, Zone}
+import net.psforever.packet.game.{BuildingInfoUpdateMessage, CaptureFlagUpdateMessage}
+import net.psforever.services.base.message.SelfRespondingEvent
+import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
+
+object GalaxyAction {
+ final case class HotSpotUpdate(zone_id: Int, priority: Int, host_spot_info: List[HotSpotInfo]) extends SelfRespondingEvent
+
+ final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends SelfRespondingEvent
+
+ final case class FlagMapUpdate(msg: CaptureFlagUpdateMessage) extends SelfRespondingEvent
+
+ final case class TransferPassenger(
+ player_guid: PlanetSideGUID,
+ temp_channel: String,
+ vehicle: Vehicle,
+ vehicle_to_delete: PlanetSideGUID,
+ manifest: VehicleManifest
+ ) extends SelfRespondingEvent
+
+ final case class UpdateBroadcastPrivileges(
+ zoneId: Int,
+ gateMapId: Int,
+ fromFactions: Set[PlanetSideEmpire.Value],
+ toFactions: Set[PlanetSideEmpire.Value]
+ ) extends SelfRespondingEvent
+
+ final case class LockedZoneUpdate(zone: Zone, timeUntilUnlock: Long) extends SelfRespondingEvent
+
+ final case class UnlockedZoneUpdate(zone: Zone) extends SelfRespondingEvent
+
+ final case class LogStatusChange(name: String) extends SelfRespondingEvent
+}
diff --git a/src/main/scala/net/psforever/services/galaxy/GalaxyService.scala b/src/main/scala/net/psforever/services/galaxy/GalaxyService.scala
index a526db02e..79569a4e0 100644
--- a/src/main/scala/net/psforever/services/galaxy/GalaxyService.scala
+++ b/src/main/scala/net/psforever/services/galaxy/GalaxyService.scala
@@ -1,107 +1,21 @@
-// Copyright (c) 2017 PSForever
+// Copyright (c) 2017-2026 PSForever
package net.psforever.services.galaxy
-import akka.actor.Actor
-import net.psforever.objects.zones.Zone
-import net.psforever.packet.game.BuildingInfoUpdateMessage
-import net.psforever.services.{GenericEventBus, Service}
+import akka.actor.Props
+import net.psforever.services.base.{EventSystemStamp, GenericEventService}
-class GalaxyService extends Actor {
- private[this] val log = org.log4s.getLogger
-
- val GalaxyEvents = new GenericEventBus[GalaxyServiceResponse]
-
- def receive: Receive = {
- case Service.Join(faction) if "TRNCVS".containsSlice(faction) =>
- val path = s"/$faction/Galaxy"
- GalaxyEvents.subscribe(sender(), path)
-
- case Service.Join("galaxy") =>
- val path = s"/Galaxy"
- GalaxyEvents.subscribe(sender(), path)
-
- case Service.Join(channel) =>
- val path = s"/$channel/Galaxy"
- GalaxyEvents.subscribe(sender(), path)
-
- case Service.Leave(None) =>
- GalaxyEvents.unsubscribe(sender())
-
- case Service.Leave(Some(channel)) =>
- val path = s"/$channel/Galaxy"
- GalaxyEvents.unsubscribe(sender(), path)
-
- case Service.LeaveAll() =>
- GalaxyEvents.unsubscribe(sender())
-
- case GalaxyServiceMessage(forChannel, action) =>
- action match {
- case GalaxyAction.MapUpdate(msg: BuildingInfoUpdateMessage) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(s"/Galaxy", GalaxyResponse.MapUpdate(msg))
- )
-
- case GalaxyAction.UpdateBroadcastPrivileges(zoneId, gateMapId, fromFactions, toFactions) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(
- s"/$forChannel/Galaxy",
- GalaxyResponse.UpdateBroadcastPrivileges(zoneId, gateMapId, fromFactions, toFactions)
- )
- )
-
- case GalaxyAction.FlagMapUpdate(msg) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(s"/Galaxy", GalaxyResponse.FlagMapUpdate(msg))
- )
-
- case GalaxyAction.TransferPassenger(_, temp_channel, vehicle, vehicle_to_delete, manifest) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(
- s"/$forChannel/Galaxy",
- GalaxyResponse.TransferPassenger(temp_channel, vehicle, vehicle_to_delete, manifest)
- )
- )
-
- case GalaxyAction.LockedZoneUpdate(zone, time) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(
- s"/Galaxy",
- GalaxyResponse.LockedZoneUpdate(zone, time)
- )
- )
-
- case GalaxyAction.UnlockedZoneUpdate(zone) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(
- s"/Galaxy",
- GalaxyResponse.UnlockedZoneUpdate(zone)
- )
- )
-
- case GalaxyAction.LogStatusChange(name) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(
- s"/Galaxy",
- GalaxyResponse.LogStatusChange(name)
- )
- )
-
- case GalaxyAction.SendResponse(msg) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(
- s"/Galaxy",
- GalaxyResponse.SendResponse(msg)
- )
- )
- case _ => ;
- }
-
- case Zone.HotSpot.Update(faction, zone_num, priority, info) =>
- GalaxyEvents.publish(
- GalaxyServiceResponse(s"/$faction/Galaxy", GalaxyResponse.HotSpotUpdate(zone_num, priority, info))
- )
-
- case msg =>
- log.warn(s"Unhandled message $msg from ${sender()}")
+case object GalaxyStamp extends EventSystemStamp {
+ override def routing(channel: String): String = {
+ if (channel.trim.isEmpty) {
+ "/out"
+ } else {
+ super.routing(channel)
+ }
+ }
+}
+
+object GalaxyService {
+ def apply(): Props = {
+ Props(classOf[GenericEventService], GalaxyStamp)
}
}
diff --git a/src/main/scala/net/psforever/services/galaxy/GalaxyServiceMessage.scala b/src/main/scala/net/psforever/services/galaxy/GalaxyServiceMessage.scala
deleted file mode 100644
index dcdaebfc2..000000000
--- a/src/main/scala/net/psforever/services/galaxy/GalaxyServiceMessage.scala
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2017 PSForever
-package net.psforever.services.galaxy
-
-import net.psforever.objects.Vehicle
-import net.psforever.objects.vehicles.VehicleManifest
-import net.psforever.objects.zones.Zone
-import net.psforever.packet.PlanetSideGamePacket
-import net.psforever.packet.game.{BuildingInfoUpdateMessage, CaptureFlagUpdateMessage}
-import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
-
-final case class GalaxyServiceMessage(forChannel: String, actionMessage: GalaxyAction.Action)
-
-object GalaxyServiceMessage {
- def apply(actionMessage: GalaxyAction.Action): GalaxyServiceMessage = GalaxyServiceMessage("", actionMessage)
-}
-
-object GalaxyAction {
- trait Action
-
- final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends Action
- final case class FlagMapUpdate(msg: CaptureFlagUpdateMessage) extends Action
-
- final case class TransferPassenger(
- player_guid: PlanetSideGUID,
- temp_channel: String,
- vehicle: Vehicle,
- vehicle_to_delete: PlanetSideGUID,
- manifest: VehicleManifest
- ) extends Action
-
- final case class UpdateBroadcastPrivileges(
- zoneId: Int,
- gateMapId: Int,
- fromFactions: Set[PlanetSideEmpire.Value],
- toFactions: Set[PlanetSideEmpire.Value]
- ) extends Action
-
- final case class LockedZoneUpdate(zone: Zone, timeUntilUnlock: Long) extends Action
-
- final case class UnlockedZoneUpdate(zone: Zone) extends Action
-
- final case class LogStatusChange(name: String) extends Action
-
- final case class SendResponse(msg: PlanetSideGamePacket) extends Action
-}
diff --git a/src/main/scala/net/psforever/services/galaxy/GalaxyServiceResponse.scala b/src/main/scala/net/psforever/services/galaxy/GalaxyServiceResponse.scala
deleted file mode 100644
index dcaf93817..000000000
--- a/src/main/scala/net/psforever/services/galaxy/GalaxyServiceResponse.scala
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2017 PSForever
-package net.psforever.services.galaxy
-
-import net.psforever.objects.Vehicle
-import net.psforever.objects.vehicles.VehicleManifest
-import net.psforever.objects.zones.{HotSpotInfo, Zone}
-import net.psforever.packet.PlanetSideGamePacket
-import net.psforever.packet.game.{BuildingInfoUpdateMessage, CaptureFlagUpdateMessage}
-import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
-import net.psforever.services.GenericEventBusMsg
-
-final case class GalaxyServiceResponse(channel: String, replyMessage: GalaxyResponse.Response)
- extends GenericEventBusMsg
-
-object GalaxyResponse {
- trait Response
-
- final case class HotSpotUpdate(zone_id: Int, priority: Int, host_spot_info: List[HotSpotInfo]) extends Response
- final case class MapUpdate(msg: BuildingInfoUpdateMessage) extends Response
- final case class FlagMapUpdate(msg: CaptureFlagUpdateMessage) extends Response
-
-
- final case class TransferPassenger(
- temp_channel: String,
- vehicle: Vehicle,
- vehicle_to_delete: PlanetSideGUID,
- manifest: VehicleManifest
- ) extends Response
-
- final case class UpdateBroadcastPrivileges(
- zoneId: Int,
- gateMapId: Int,
- fromFactions: Set[PlanetSideEmpire.Value],
- toFactions: Set[PlanetSideEmpire.Value]
- ) extends Response
-
- final case class LockedZoneUpdate(zone: Zone, timeUntilUnlock: Long) extends Response
-
- final case class UnlockedZoneUpdate(zone: Zone) extends Response
-
- final case class LogStatusChange(name: String) extends Response
-
- final case class SendResponse(msg: PlanetSideGamePacket) extends Response
-}
diff --git a/src/main/scala/net/psforever/services/hart/HartTimer.scala b/src/main/scala/net/psforever/services/hart/HartTimer.scala
index 3de884fe0..576eadcfe 100644
--- a/src/main/scala/net/psforever/services/hart/HartTimer.scala
+++ b/src/main/scala/net/psforever/services/hart/HartTimer.scala
@@ -4,8 +4,11 @@ package net.psforever.services.hart
import akka.actor.{Actor, ActorRef, Cancellable}
import net.psforever.objects.Default
import net.psforever.objects.zones.Zone
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.services.{GenericEventBus, GenericEventBusMsg}
+import net.psforever.services.base.EventSystemStamp
+import net.psforever.services.base.bus.GenericEventBus
+import net.psforever.services.base.envelope.{GenericResponseEnvelope, MessageEnvelope, NoReply}
+import net.psforever.services.base.message.EventResponse
+import net.psforever.services.local.LocalAction
import net.psforever.types.{HartSequence, PlanetSideGUID}
import scala.concurrent.duration._
@@ -20,7 +23,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
*/
class HartTimer(zone: Zone) extends Actor {
/** since the system is zone-locked, caching this value is fine */
- val zoneId = zone.id
+ val zoneId: String = zone.id
/** all of the paired HART facility amenities and the shuttle housed in that facility (in that order) */
var padAndShuttlePairs: List[(PlanetSideGUID, PlanetSideGUID)] = List()
@@ -43,10 +46,10 @@ class HartTimer(zone: Zone) extends Actor {
var timer: Cancellable = Default.Cancellable
/** a message bus to which all associated orbital shuttle pads are subscribed */
- val padEvents = new GenericEventBus[HartTimer.Command]
+ val padEvents = new GenericEventBus
/** cache common messages */
- val shuttleDockedInThisZone = HartTimer.ShuttleDocked(zoneId)
- val shuttleFreeFromDockInThisZone = HartTimer.ShuttleFreeFromDock(zoneId)
+ val shuttleDockedInThisZone: HartTimer.ShuttleDocked = HartTimer.ShuttleDocked(zoneId)
+ val shuttleFreeFromDockInThisZone: HartTimer.ShuttleFreeFromDock = HartTimer.ShuttleFreeFromDock(zoneId)
/** the behaviors common to both the inert and active operations of the hart */
val commonBehavior: Receive = {
@@ -105,7 +108,7 @@ class HartTimer(zone: Zone) extends Actor {
event.prerequisiteUpdate match {
case Some(fields) =>
val times = event.timeFields(time)
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
forChannel,
LocalAction.ShuttleEvent(HartTimer.OrbitalShuttleEvent(
fields.u1, fields.u2, times.t1, times.t2, times.t3, padAndShuttlePairs zip Seq(20, 20, 20)
@@ -113,7 +116,7 @@ class HartTimer(zone: Zone) extends Actor {
)
case None => ;
}
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
forChannel,
LocalAction.ShuttleEvent(
HartTimer.analyzeEvent(event, padAndShuttlePairs, time)
@@ -153,17 +156,17 @@ class HartTimer(zone: Zone) extends Actor {
val evt = HartTimer.analyzeEvent(event, padAndShuttlePairs)
event.docked match {
case Some(true) if currEvent.docked.isEmpty =>
- zone.LocalEvents ! LocalServiceMessage(zoneId, LocalAction.ShuttleEvent(evt))
+ zone.LocalEvents ! MessageEnvelope(zoneId, LocalAction.ShuttleEvent(evt))
padEvents.publish( shuttleDockedInThisZone )
case Some(false) if currEvent.docked.contains(true) =>
padEvents.publish( shuttleFreeFromDockInThisZone )
context.system.scheduler.scheduleOnce(
delay = 10 milliseconds,
zone.LocalEvents,
- LocalServiceMessage(zoneId, LocalAction.ShuttleEvent(evt))
+ MessageEnvelope(zoneId, LocalAction.ShuttleEvent(evt))
)
case _ =>
- zone.LocalEvents ! LocalServiceMessage(zoneId, LocalAction.ShuttleEvent(evt))
+ zone.LocalEvents ! MessageEnvelope(zoneId, LocalAction.ShuttleEvent(evt))
}
if (currEvent.lockedDoors != event.lockedDoors) {
padEvents.publish( if(event.lockedDoors) HartTimer.LockDoors else HartTimer.UnlockDoors )
@@ -254,14 +257,22 @@ object HartTimer {
pairs: List[((PlanetSideGUID, PlanetSideGUID), Int)]
)
+ case object HartStamp extends EventSystemStamp
+
/**
* Design for the envelop for the message bus
* to relay instructions back to the individual facility amenity portions of this HART system.
* The channel is blank because it does not need special designation.
*/
- trait Command extends GenericEventBusMsg { def channel: String = "" }
+ trait Command extends GenericResponseEnvelope {
+ def originalChannel: String = ""
+ def channel: String = ""
+ def filter: PlanetSideGUID = Default.GUID0
+ def stamp: EventSystemStamp = HartStamp
+ def reply: EventResponse = NoReply
+ }
/**
- * Forbid entry through the boartding gantry doors.
+ * Forbid entry through the boarding gantry doors.
*/
case object LockDoors extends Command
/**
diff --git a/src/main/scala/net/psforever/services/hart/HartTimerActions.scala b/src/main/scala/net/psforever/services/hart/HartTimerActions.scala
index 291c4bbc3..442f60c4b 100644
--- a/src/main/scala/net/psforever/services/hart/HartTimerActions.scala
+++ b/src/main/scala/net/psforever/services/hart/HartTimerActions.scala
@@ -3,7 +3,8 @@ package net.psforever.services.hart
import net.psforever.objects.Vehicle
import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.local.LocalAction
object HartTimerActions {
/**
@@ -17,7 +18,7 @@ object HartTimerActions {
if(toChannel.equals(zone.id)) {
shuttle.MountedIn = pad.GUID
}
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
toChannel,
LocalAction.ShuttleDock(pad.GUID, shuttle.GUID, 3)
)
@@ -34,7 +35,7 @@ object HartTimerActions {
if(toChannel.equals(zone.id)) {
shuttle.MountedIn = None
}
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
toChannel,
LocalAction.ShuttleUndock(pad.GUID, shuttle.GUID, shuttle.Position, shuttle.Orientation)
)
@@ -51,7 +52,7 @@ object HartTimerActions {
if(toChannel.equals(zone.id)) {
shuttle.Flying = state
}
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
toChannel,
LocalAction.ShuttleState(shuttle.GUID, shuttle.Position, shuttle.Orientation, state)
)
diff --git a/src/main/scala/net/psforever/services/local/LocalAction.scala b/src/main/scala/net/psforever/services/local/LocalAction.scala
new file mode 100644
index 000000000..4e42bca59
--- /dev/null
+++ b/src/main/scala/net/psforever/services/local/LocalAction.scala
@@ -0,0 +1,151 @@
+// Copyright (c) 2017-2026 PSForever
+package net.psforever.services.local
+
+import net.psforever.objects.{Default, PlanetSideGameObject, TelepadDeployable, Vehicle}
+import net.psforever.objects.ce.{Deployable, DeployedItem}
+import net.psforever.objects.serverobject.doors.Door
+import net.psforever.objects.serverobject.llu.CaptureFlag
+import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
+import net.psforever.objects.vehicles.Utility
+import net.psforever.objects.zones.Zone
+import net.psforever.packet.game.{DeployableInfo, DeploymentAction, GenericAction, HackState7, ObjectCreateMessage, TriggeredEffect, TriggeredEffectLocation, TriggeredSound}
+import net.psforever.services.base.message.{EventMessage, EventResponse, SelfRespondingEvent, SendResponse}
+import net.psforever.services.hart.HartTimer.OrbitalShuttleEvent
+import net.psforever.types.{PlanetSideGUID, Vector3}
+
+object LocalAction {
+ sealed trait IsADoorMessage extends SelfRespondingEvent
+
+ sealed trait IsAHackMessage extends SelfRespondingEvent
+
+ final case class DeployItem(item: Deployable) extends EventMessage {
+ def response(): EventResponse = {
+ val definition = item.Definition
+ val objectData = definition.Packet.ConstructorData(item).get
+ SendResponse(ObjectCreateMessage(definition.ObjectId, item.GUID, objectData))
+ }
+ }
+
+ final case class DeployableMapIcon(behavior: DeploymentAction.Value, deployInfo: DeployableInfo) extends SelfRespondingEvent
+
+ final case class DeployableUIFor(obj: DeployedItem.Value) extends SelfRespondingEvent
+
+ final case class Detonate(guid: PlanetSideGUID, obj: PlanetSideGameObject) extends SelfRespondingEvent
+
+ final case class DoorOpens(continent: Zone, door: Door) extends IsADoorMessage
+
+ final case class DoorCloses(door_guid: PlanetSideGUID) extends IsADoorMessage
+
+ final case class EliminateDeployable(
+ obj: Deployable,
+ object_guid: PlanetSideGUID,
+ pos: Vector3,
+ deletionEffect: Int
+ ) extends SelfRespondingEvent
+
+ final case class HackClear(
+ target_guid: PlanetSideGUID,
+ unk1: Long,
+ unk2: HackState7 = HackState7.Unk8
+ ) extends IsAHackMessage
+
+ final case class HackObject(target_guid: PlanetSideGUID, unk1: Long, unk2: HackState7) extends IsAHackMessage
+
+ final case class LluSpawned(llu: CaptureFlag) extends SelfRespondingEvent
+
+ final case class LluDespawned(
+ guid: PlanetSideGUID,
+ position: Vector3
+ ) extends SelfRespondingEvent
+
+ final case class GenericActionMessage(action_num: GenericAction) extends SelfRespondingEvent
+
+ final case class ProximityTerminalAction(
+ terminal: Terminal with ProximityUnit,
+ target: PlanetSideGameObject
+ ) extends EventResponse
+
+ final case class ProximityTerminalEffect(
+ object_guid: PlanetSideGUID,
+ effectState: Boolean
+ ) extends SelfRespondingEvent
+
+ final case class RouterTelepadMessage(msg: String) extends SelfRespondingEvent
+
+ final case class RouterTelepadTransport(
+ passenger_guid: PlanetSideGUID,
+ src_guid: PlanetSideGUID,
+ dest_guid: PlanetSideGUID
+ ) extends SelfRespondingEvent
+
+ final case class ShuttleDock(pad_guid: PlanetSideGUID, shuttle_guid: PlanetSideGUID, toSlot: Int) extends SelfRespondingEvent
+
+ final case class ShuttleUndock(
+ pad_guid: PlanetSideGUID,
+ shuttle_guid: PlanetSideGUID,
+ pos: Vector3, orient: Vector3
+ ) extends SelfRespondingEvent
+
+ final case class ShuttleEvent(ev: OrbitalShuttleEvent) extends SelfRespondingEvent
+
+ final case class ShuttleState(guid: PlanetSideGUID, pos: Vector3, orientation: Vector3, state: Int) extends SelfRespondingEvent
+
+ final case class StartRouterInternalTelepad(
+ router_guid: PlanetSideGUID,
+ obj_guid: PlanetSideGUID,
+ obj: Utility.InternalTelepad
+ ) extends SelfRespondingEvent
+
+ final case class ToggleTeleportSystem(
+ router: Vehicle,
+ systemPlan: Option[(Utility.InternalTelepad, TelepadDeployable)]
+ ) extends SelfRespondingEvent
+
+ final case class TriggerEffectAtLocation(
+ target: PlanetSideGUID,
+ effect: String,
+ effectInfo: Option[TriggeredEffect] = None,
+ triggeredLocation: Option[TriggeredEffectLocation] = None
+ ) extends EventResponse
+
+ final case class TriggerEffect(effect: String, target: PlanetSideGUID) extends EventMessage {
+ def response(): EventResponse = {
+ TriggerEffectAtLocation(target, effect)
+ }
+ }
+
+ final case class TriggerEffectInfo(target: PlanetSideGUID, effect: String, unk1: Boolean, unk2: Long) extends EventMessage {
+ def response(): EventResponse = {
+ TriggerEffectAtLocation(target, effect, Some(TriggeredEffect(unk1, unk2)))
+ }
+ }
+
+ final case class TriggerEffectLocation(
+ effect: String,
+ pos: Vector3,
+ orient: Vector3
+ ) extends EventMessage {
+ def response(): EventResponse = {
+ TriggerEffectAtLocation(Default.GUID0, effect, None, Some(TriggeredEffectLocation(pos, orient)))
+ }
+ }
+
+ final case class TriggerSound(
+ sound: TriggeredSound.Value,
+ pos: Vector3,
+ unk: Int,
+ volume: Float
+ ) extends SelfRespondingEvent
+
+ final case class UpdateForceDomeStatus(
+ building_guid: PlanetSideGUID,
+ activated: Boolean
+ ) extends SelfRespondingEvent
+
+ final case class RechargeVehicleWeapon(
+ mountable_guid: PlanetSideGUID,
+ weapon_guid: PlanetSideGUID
+ ) extends SelfRespondingEvent
+
+ final case class ForceZoneChange(zone: Zone) extends SelfRespondingEvent
+}
diff --git a/src/main/scala/net/psforever/services/local/LocalService.scala b/src/main/scala/net/psforever/services/local/LocalService.scala
index 751dce97b..e6aad046f 100644
--- a/src/main/scala/net/psforever/services/local/LocalService.scala
+++ b/src/main/scala/net/psforever/services/local/LocalService.scala
@@ -1,362 +1,19 @@
// Copyright (c) 2017 PSForever
package net.psforever.services.local
-import akka.actor.{Actor, Props}
-import net.psforever.objects.serverobject.terminals.Terminal
+import akka.actor.Props
import net.psforever.objects.zones.Zone
-import net.psforever.packet.game.{ObjectCreateMessage, TriggeredEffect, TriggeredEffectLocation}
-import net.psforever.services.local.support.CaptureFlagManager
-import net.psforever.types.PlanetSideGUID
import net.psforever.services.local.support._
-import net.psforever.services.{GenericEventBus, Service}
-import net.psforever.services.support.SupportActor
+import net.psforever.services.base.{EventSystemStamp, GenericEventServiceWithSupport}
-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 captureFlagManager = context.actorOf(
- Props(classOf[CaptureFlagManager], zone), s"${zone.id}-local-capture-flag-manager"
- )
- private[this] val log = org.log4s.getLogger
+case object LocalStamp extends EventSystemStamp
- val LocalEvents = new GenericEventBus[LocalServiceResponse]
-
- def receive: Receive = {
- case Service.Join(channel) =>
- val path = s"/$channel/Local"
- LocalEvents.subscribe(sender(), path)
-
- case Service.Leave(None) =>
- LocalEvents.unsubscribe(sender())
-
- case Service.Leave(Some(channel)) =>
- val path = s"/$channel/Local"
- LocalEvents.unsubscribe(sender(), path)
-
- case Service.LeaveAll() =>
- LocalEvents.unsubscribe(sender())
-
- case LocalServiceMessage(forChannel, action) =>
- action match {
- case LocalAction.DeployItem(item) =>
- val definition = item.Definition
- val objectData = definition.Packet.ConstructorData(item).get
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.SendResponse(ObjectCreateMessage(definition.ObjectId, item.GUID, objectData))
- )
- )
- case LocalAction.DeployableMapIcon(player_guid, behavior, deployInfo) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.DeployableMapIcon(behavior, deployInfo)
- )
- )
- case LocalAction.DeployableUIFor(item) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.DeployableUIFor(item)
- )
- )
- case LocalAction.Detonate(guid, obj) =>
- LocalEvents.publish(
- LocalServiceResponse(s"/$forChannel/Local", Service.defaultPlayerGUID, LocalResponse.Detonate(guid, obj))
- )
- case LocalAction.DoorOpens(player_guid, _, door) =>
- doorCloser ! DoorCloseActor.DoorIsOpen(door, zone)
- LocalEvents.publish(
- LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.DoorOpens(door.GUID))
- )
- case LocalAction.DoorCloses(player_guid, door_guid) =>
- LocalEvents.publish(
- LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.DoorCloses(door_guid))
- )
- case LocalAction.DoorSlamsShut(door) =>
- val door_guid = door.GUID
- doorCloser ! SupportActor.HurrySpecific(List(door), zone)
- LocalEvents.publish(
- LocalServiceResponse(s"/$forChannel/Local", Service.defaultPlayerGUID, LocalResponse.DoorCloses(door_guid))
- )
- case LocalAction.EliminateDeployable(obj, guid, pos, effect) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.EliminateDeployable(obj, guid, pos, effect)
- )
- )
- case LocalAction.HackClear(player_guid, target, unk1, unk2) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.SendHackMessageHackCleared(target.GUID, unk1, unk2)
- )
- )
- case LocalAction.HackTemporarily(player_guid, _, target, hackValue, hackClear, duration, unk2) =>
- hackClearer ! HackClearActor.ObjectIsHacked(target, zone, hackClear, unk2, duration)
- LocalEvents.publish(
- LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.HackObject(target.GUID, hackValue, unk2))
- )
- case LocalAction.ClearTemporaryHack(_, target) =>
- hackClearer ! HackClearActor.ObjectIsResecured(target)
-
- case LocalAction.ResecureCaptureTerminal(target, hacker) =>
- hackCapturer ! HackCaptureActor.ResecureCaptureTerminal(target, zone, hacker)
- case LocalAction.StartCaptureTerminalHack(target) =>
- hackCapturer ! HackCaptureActor.StartCaptureTerminalHack(target, zone, 0, 8L)
- case LocalAction.LluCaptured(llu) =>
- hackCapturer ! HackCaptureActor.FlagCaptured(llu)
- case LocalAction.LluLost(llu) =>
- hackCapturer ! HackCaptureActor.FlagLost(llu)
-
- case LocalAction.LluSpawned(player_guid, llu) =>
- // Forward to all clients to create object locally
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.LluSpawned(llu)
- )
- )
-
- case LocalAction.LluDespawned(player_guid, guid, position) =>
- // Forward to all clients to destroy object locally
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.LluDespawned(guid, position)
- )
- )
-
- case LocalAction.SendPacket(packet) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- PlanetSideGUID(-1),
- LocalResponse.SendPacket(packet)
- )
- )
-
- case LocalAction.SendPlanetsideAttributeMessage(player_guid, target_guid, attribute_number, attribute_value) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.PlanetsideAttribute(target_guid, attribute_number, attribute_value)
- )
- )
- case LocalAction.SendGenericObjectActionMessage(player_guid, target_guid, action_number) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.GenericObjectAction(target_guid, action_number)
- )
- )
-
- case LocalAction.SendChatMsg(player_guid, msg) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.ChatMessage(msg)
- )
- )
-
- case LocalAction.SendGenericActionMessage(player_guid, action_number) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.GenericActionMessage(action_number)
- )
- )
- case LocalAction.RouterTelepadMessage(msg) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.RouterTelepadMessage(msg)
- )
- )
- case LocalAction.RouterTelepadTransport(player_guid, passenger_guid, src_guid, dest_guid) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.RouterTelepadTransport(passenger_guid, src_guid, dest_guid)
- )
- )
- case LocalAction.SendResponse(pkt) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.SendResponse(pkt)
- )
- )
- case LocalAction.SetEmpire(object_guid, empire) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.SetEmpire(object_guid, empire)
- )
- )
- case LocalAction.ShuttleDock(pad, shuttle, slot) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.ShuttleDock(pad, shuttle, slot)
- )
- )
- case LocalAction.ShuttleUndock(pad, shuttle, pos, orient) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.ShuttleUndock(pad, shuttle, pos, orient)
- )
- )
- case LocalAction.ShuttleEvent(ev) =>
- LocalEvents.publish(
- LocalServiceResponse(s"/$forChannel/Local", Service.defaultPlayerGUID, LocalResponse.ShuttleEvent(ev))
- )
- case LocalAction.ShuttleState(guid, pos, orient, state) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.ShuttleState(guid, pos, orient, state)
- )
- )
- case LocalAction.StartRouterInternalTelepad(router_guid, obj_guid, obj) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.StartRouterInternalTelepad(router_guid, obj_guid, obj)
- )
- )
- case LocalAction.ToggleTeleportSystem(player_guid, router, system_plan) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.ToggleTeleportSystem(router, system_plan)
- )
- )
- case LocalAction.TriggerEffect(player_guid, effect, target) =>
- LocalEvents.publish(
- LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.TriggerEffect(target, effect))
- )
- case LocalAction.TriggerEffectLocation(player_guid, effect, pos, orient) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.TriggerEffect(PlanetSideGUID(0), effect, None, Some(TriggeredEffectLocation(pos, orient)))
- )
- )
- case LocalAction.TriggerEffectInfo(player_guid, effect, target, unk1, unk2) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.TriggerEffect(target, effect, Some(TriggeredEffect(unk1, unk2)))
- )
- )
- case LocalAction.TriggerSound(player_guid, sound, pos, unk, volume) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.TriggerSound(sound, pos, unk, volume)
- )
- )
- case LocalAction.UpdateForceDomeStatus(player_guid, building_guid, activated) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.UpdateForceDomeStatus(building_guid, activated)
- )
- )
- case LocalAction.RechargeVehicleWeapon(player_guid, vehicle_guid, weapon_guid) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- player_guid,
- LocalResponse.RechargeVehicleWeapon(vehicle_guid, weapon_guid)
- )
- )
- case LocalAction.ForceZoneChange(zone) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/$forChannel/Local",
- Service.defaultPlayerGUID,
- LocalResponse.ForceZoneChange(zone)
- )
- )
- case _ => ;
- }
-
- //response from DoorCloseActor
- case DoorCloseActor.CloseTheDoor(door_guid, _) =>
- LocalEvents.publish(
- LocalServiceResponse(s"/${zone.id}/Local", Service.defaultPlayerGUID, LocalResponse.DoorCloses(door_guid))
- )
-
- //response from HackClearActor
- case HackClearActor.SendHackMessageHackCleared(target_guid, _, unk1, unk2) =>
- log.info(s"Clearing hack for $target_guid")
- LocalEvents.publish(
- LocalServiceResponse(
- s"/${zone.id}/Local",
- Service.defaultPlayerGUID,
- LocalResponse.SendHackMessageHackCleared(target_guid, unk1, unk2)
- )
- )
-
- //message from ProximityTerminalControl
- case Terminal.StartProximityEffect(terminal) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/${zone.id}/Local",
- PlanetSideGUID(0),
- LocalResponse.ProximityTerminalEffect(terminal.GUID, effectState = true)
- )
- )
- case Terminal.StopProximityEffect(terminal) =>
- LocalEvents.publish(
- LocalServiceResponse(
- s"/${zone.id}/Local",
- PlanetSideGUID(0),
- LocalResponse.ProximityTerminalEffect(terminal.GUID, effectState = false)
- )
- )
-
- // Forward all CaptureFlagManager messages
- case msg: CaptureFlagManager.Command =>
- captureFlagManager.forward(msg)
-
- case msg =>
- log.warn(s"Unhandled message $msg from ${sender()}")
+object LocalService {
+ def apply(zone: Zone): Props = {
+ Props(
+ classOf[GenericEventServiceWithSupport],
+ LocalStamp,
+ List(DoorCloserSupport, HackClearSupport, HackCaptureSupport, CaptureFlagSupport(zone))
+ )
}
}
diff --git a/src/main/scala/net/psforever/services/local/LocalServiceMessage.scala b/src/main/scala/net/psforever/services/local/LocalServiceMessage.scala
deleted file mode 100644
index ced629458..000000000
--- a/src/main/scala/net/psforever/services/local/LocalServiceMessage.scala
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2017 PSForever
-package net.psforever.services.local
-
-import net.psforever.objects.ce.{Deployable, DeployedItem}
-import net.psforever.objects.serverobject.PlanetSideServerObject
-import net.psforever.objects.serverobject.doors.Door
-import net.psforever.objects.serverobject.hackable.Hackable
-import net.psforever.objects.serverobject.llu.CaptureFlag
-import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
-import net.psforever.objects.sourcing.PlayerSource
-import net.psforever.objects.vehicles.Utility
-import net.psforever.objects.zones.Zone
-import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle}
-import net.psforever.packet.PlanetSideGamePacket
-import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum
-import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
-import net.psforever.packet.game.{ChatMsg, DeployableInfo, DeploymentAction, GenericAction, HackState7, TriggeredSound}
-import net.psforever.services.hart.HartTimer.OrbitalShuttleEvent
-import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
-
-final case class LocalServiceMessage(forChannel: String, actionMessage: LocalAction.Action)
-
-object LocalServiceMessage {
- final case class Deployables(msg: Any)
-}
-
-object LocalAction {
- trait Action
-
- final case class DeployItem(item: Deployable) extends Action
- final case class DeployableMapIcon(
- player_guid: PlanetSideGUID,
- behavior: DeploymentAction.Value,
- deployInfo: DeployableInfo
- ) extends Action
- final case class DeployableUIFor(obj: DeployedItem.Value) extends Action
- final case class Detonate(guid: PlanetSideGUID, obj: PlanetSideGameObject) extends Action
- final case class DoorOpens(player_guid: PlanetSideGUID, continent: Zone, door: Door) extends Action
- final case class DoorCloses(player_guid: PlanetSideGUID, door_guid: PlanetSideGUID) extends Action
- final case class DoorSlamsShut(door: Door) extends Action
- final case class EliminateDeployable(
- obj: Deployable,
- object_guid: PlanetSideGUID,
- pos: Vector3,
- deletionEffect: Int
- ) extends Action
- final case class HackClear(player_guid: PlanetSideGUID, target: PlanetSideServerObject, unk1: Long, unk2: HackState7 = HackState7.Unk8)
- extends Action
- final case class HackTemporarily(
- player_guid: PlanetSideGUID,
- continent: Zone,
- target: PlanetSideServerObject,
- hackValue: Long,
- hackClearValue: Long,
- duration: Int,
- unk2: HackState7 = HackState7.Unk8
- ) extends Action
- final case class ClearTemporaryHack(player_guid: PlanetSideGUID, target: PlanetSideServerObject with Hackable)
- extends Action
-
- final case class ResecureCaptureTerminal(target: CaptureTerminal, hacker: PlayerSource) extends Action
- final case class StartCaptureTerminalHack(target: CaptureTerminal) extends Action
- final case class LluCaptured(llu: CaptureFlag) extends Action
- final case class LluLost(llu: CaptureFlag) extends Action
- final case class LluSpawned(player_guid: PlanetSideGUID, llu: CaptureFlag) extends Action
- final case class LluDespawned(player_guid: PlanetSideGUID, guid: PlanetSideGUID, position: Vector3) extends Action
-
- final case class SendPacket(packet: PlanetSideGamePacket) extends Action
- final case class SendPlanetsideAttributeMessage(
- player_guid: PlanetSideGUID,
- target: PlanetSideGUID,
- attribute_number: PlanetsideAttributeEnum,
- attribute_value: Long
- ) extends Action
- final case class SendGenericObjectActionMessage(
- player_guid: PlanetSideGUID,
- target: PlanetSideGUID,
- action_number: GenericObjectActionEnum
- ) extends Action
-
- final case class SendChatMsg(
- player_guid: PlanetSideGUID,
- msg: ChatMsg
- ) extends Action
-
- final case class SendGenericActionMessage(
- player_guid: PlanetSideGUID,
- action_number: GenericAction
- ) extends Action
- final case class RouterTelepadMessage(msg: String) extends Action
- final case class RouterTelepadTransport(
- player_guid: PlanetSideGUID,
- passenger_guid: PlanetSideGUID,
- src_guid: PlanetSideGUID,
- dest_guid: PlanetSideGUID
- ) extends Action
- final case class SendResponse(pkt: PlanetSideGamePacket) extends Action
- final case class SetEmpire(object_guid: PlanetSideGUID, empire: PlanetSideEmpire.Value) extends Action
- final case class ShuttleDock(pad_guid: PlanetSideGUID, shuttle_guid: PlanetSideGUID, toSlot: Int) extends Action
- final case class ShuttleUndock(
- pad_guid: PlanetSideGUID,
- shuttle_guid: PlanetSideGUID,
- pos: Vector3, orient: Vector3
- ) extends Action
- final case class ShuttleEvent(ev: OrbitalShuttleEvent) extends Action
- final case class ShuttleState(guid: PlanetSideGUID, pos: Vector3, orientation: Vector3, state: Int) extends Action
- final case class StartRouterInternalTelepad(
- router_guid: PlanetSideGUID,
- obj_guid: PlanetSideGUID,
- obj: Utility.InternalTelepad
- ) extends Action
- final case class ToggleTeleportSystem(
- player_guid: PlanetSideGUID,
- router: Vehicle,
- systemPlan: Option[(Utility.InternalTelepad, TelepadDeployable)]
- ) extends Action
- final case class TriggerEffect(player_guid: PlanetSideGUID, effect: String, target: PlanetSideGUID) extends Action
- final case class TriggerEffectInfo(
- player_guid: PlanetSideGUID,
- effect: String,
- target: PlanetSideGUID,
- unk1: Boolean,
- unk2: Long
- ) extends Action
- final case class TriggerEffectLocation(player_guid: PlanetSideGUID, effect: String, pos: Vector3, orient: Vector3)
- extends Action
- final case class TriggerSound(
- player_guid: PlanetSideGUID,
- sound: TriggeredSound.Value,
- pos: Vector3,
- unk: Int,
- volume: Float
- ) extends Action
- final case class UpdateForceDomeStatus(player_guid: PlanetSideGUID, building_guid: PlanetSideGUID, activated: Boolean)
- extends Action
- final case class RechargeVehicleWeapon(
- player_guid: PlanetSideGUID,
- mountable_guid: PlanetSideGUID,
- weapon_guid: PlanetSideGUID
- ) extends Action
- final case class ForceZoneChange(zone: Zone) extends Action
-}
diff --git a/src/main/scala/net/psforever/services/local/LocalServiceResponse.scala b/src/main/scala/net/psforever/services/local/LocalServiceResponse.scala
deleted file mode 100644
index 8834ab197..000000000
--- a/src/main/scala/net/psforever/services/local/LocalServiceResponse.scala
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2017 PSForever
-package net.psforever.services.local
-
-import net.psforever.objects.serverobject.llu.CaptureFlag
-import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle}
-import net.psforever.objects.ce.{Deployable, DeployedItem}
-import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
-import net.psforever.objects.vehicles.Utility
-import net.psforever.objects.zones.Zone
-import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum
-import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
-import net.psforever.packet.PlanetSideGamePacket
-import net.psforever.packet.game._
-import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
-import net.psforever.services.GenericEventBusMsg
-import net.psforever.services.hart.HartTimer.OrbitalShuttleEvent
-
-final case class LocalServiceResponse(
- channel: String,
- avatar_guid: PlanetSideGUID,
- replyMessage: LocalResponse.Response
-) extends GenericEventBusMsg
-
-object LocalResponse {
- trait Response
-
- final case class DeployableMapIcon(action: DeploymentAction.Value, deployInfo: DeployableInfo) extends Response
- final case class DeployableUIFor(obj: DeployedItem.Value) extends Response
- final case class Detonate(guid: PlanetSideGUID, obj: PlanetSideGameObject) extends Response
- final case class DoorOpens(door_guid: PlanetSideGUID) extends Response
- final case class DoorCloses(door_guid: PlanetSideGUID) extends Response
- final case class EliminateDeployable(
- obj: Deployable,
- object_guid: PlanetSideGUID,
- pos: Vector3,
- deletionEffect: Int
- ) extends Response
- final case class SendHackMessageHackCleared(target_guid: PlanetSideGUID, unk1: Long, unk2: HackState7) extends Response
- final case class HackObject(target_guid: PlanetSideGUID, unk1: Long, unk2: HackState7) extends Response
-
- final case class SendPacket(packet: PlanetSideGamePacket) extends Response
- final case class PlanetsideAttribute(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long)
- extends Response
- final case class GenericObjectAction(target_guid: PlanetSideGUID, action_number: GenericObjectActionEnum)
- extends Response
- final case class ChatMessage(msg: ChatMsg) extends Response
- final case class GenericActionMessage(action_num: GenericAction) extends Response
-
- final case class LluSpawned(llu: CaptureFlag) extends Response
- final case class LluDespawned(guid: PlanetSideGUID, position: Vector3) extends Response
-
- final case class ObjectDelete(item_guid: PlanetSideGUID, unk: Int) extends Response
- final case class ProximityTerminalAction(terminal: Terminal with ProximityUnit, target: PlanetSideGameObject)
- extends Response
- final case class ProximityTerminalEffect(object_guid: PlanetSideGUID, effectState: Boolean) extends Response
- final case class RouterTelepadMessage(msg: String) extends Response
- final case class RouterTelepadTransport(
- passenger_guid: PlanetSideGUID,
- src_guid: PlanetSideGUID,
- dest_guid: PlanetSideGUID
- ) extends Response
- final case class SendResponse(pkt: PlanetSideGamePacket) extends Response
- final case class SetEmpire(object_guid: PlanetSideGUID, empire: PlanetSideEmpire.Value) extends Response
- final case class ShuttleDock(pad_guid: PlanetSideGUID, shuttle_guid: PlanetSideGUID, toSlot: Int) extends Response
- final case class ShuttleUndock(
- pad_guid: PlanetSideGUID,
- shuttle_guid: PlanetSideGUID,
- pos: Vector3, orient: Vector3
- ) extends Response
- final case class ShuttleEvent(ev: OrbitalShuttleEvent) extends Response
- final case class ShuttleState(guid: PlanetSideGUID, pos: Vector3, orientation: Vector3, state: Int) extends Response
- final case class StartRouterInternalTelepad(
- router_guid: PlanetSideGUID,
- obj_guid: PlanetSideGUID,
- obj: Utility.InternalTelepad
- ) extends Response
- final case class ToggleTeleportSystem(
- router: Vehicle,
- systemPlan: Option[(Utility.InternalTelepad, TelepadDeployable)]
- ) extends Response
- final case class TriggerEffect(
- target: PlanetSideGUID,
- effect: String,
- effectInfo: Option[TriggeredEffect] = None,
- triggeredLocation: Option[TriggeredEffectLocation] = None
- ) extends Response
- final case class TriggerSound(sound: TriggeredSound.Value, pos: Vector3, unk: Int, volume: Float) extends Response
- final case class UpdateForceDomeStatus(building_guid: PlanetSideGUID, activated: Boolean) extends Response
- final case class RechargeVehicleWeapon(mountable_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Response
- final case class ForceZoneChange(zone: Zone) extends Response
-}
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 980a0f756..38616a0ea 100644
--- a/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala
+++ b/src/main/scala/net/psforever/services/local/support/CaptureFlagManager.scala
@@ -1,7 +1,7 @@
// Copyright (c) 2021 PSForever
package net.psforever.services.local.support
-import akka.actor.{Actor, ActorRef, Cancellable}
+import akka.actor.{Actor, ActorContext, ActorRef, Cancellable, Props}
import net.psforever.login.WorldSession
import net.psforever.objects.{Default, PlanetSideGameObject, Player}
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
@@ -13,14 +13,30 @@ import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
import net.psforever.objects.zones.Zone
import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game._
-import net.psforever.services.{Service, ServiceManager}
+import net.psforever.services.ServiceManager
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
-import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelopeOnly}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{GenericObjectAction, SendResponse}
+import net.psforever.services.galaxy.GalaxyAction
+import net.psforever.services.local.LocalAction
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID, Vector3}
import scala.concurrent.duration.DurationInt
+case class CaptureFlagSupport(zone: Zone)
+ extends EventServiceSupport {
+ def label: String = "captureFlagManager"
+ def constructor(context: ActorContext): ActorRef = {
+ context.actorOf(Props(classOf[CaptureFlagManager], zone), name = "CaptureFlagManager")
+ }
+}
+
+final case class FlagEnvelope(supportMessage: CaptureFlagManager.Command)
+ extends GenericSupportEnvelopeOnly {
+ def supportLabel: String = "captureFlagManager"
+}
+
/**
* Responsible for handling capture flag related lifecycles
*/
@@ -45,12 +61,11 @@ class CaptureFlagManager(zone: Zone) extends Actor {
case CaptureFlagManager.SpawnCaptureFlag(capture_terminal, target, hackingFaction) =>
val socket = capture_terminal.Owner.asInstanceOf[Building].GetFlagSocket.get
// Override CC message when looked at
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendGenericObjectActionMessage(
- PlanetSideGUID(-1),
+ GenericObjectAction(
capture_terminal.GUID,
- GenericObjectActionEnum.FlagSpawned
+ GenericObjectActionEnum.FlagSpawned.id
)
)
// Register LLU object create task and callback to create on clients
@@ -67,9 +82,9 @@ class CaptureFlagManager(zone: Zone) extends Actor {
TaskWorkflow.execute(WorldSession.CallBackForTask(
GUIDTask.registerObject(zone.GUID, flag),
zone.LocalEvents,
- LocalServiceMessage(
+ MessageEnvelope(
zone.id,
- LocalAction.LluSpawned(Service.defaultPlayerGUID, flag)
+ LocalAction.LluSpawned(flag)
)
))
// Broadcast chat message for LLU spawn
@@ -82,7 +97,11 @@ class CaptureFlagManager(zone: Zone) extends Actor {
case None => "A soldier"
}
// Trigger Install sound
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUInstall, flag.Target.CaptureTerminal.get.Position, 20, 0.8000001f))
+ zone.LocalEvents ! MessageEnvelope(
+ zone.id,
+ PlanetSideGUID(-1),
+ LocalAction.TriggerSound(TriggeredSound.LLUInstall, flag.Target.CaptureTerminal.get.Position, 20, 0.8000001f)
+ )
// Broadcast capture chat message
CaptureFlagManager.ChatBroadcast(zone, CaptureFlagChatMessageStrings.CTF_Success(name, flag.Faction, flag.Owner.asInstanceOf[Building].Name))
// Despawn flag
@@ -115,8 +134,16 @@ class CaptureFlagManager(zone: Zone) extends Actor {
case CaptureFlagManager.PickupFlag(flag: CaptureFlag, player: Player) =>
flag.Carrier = Some(player)
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendPacket(ObjectAttachMessage(player.GUID, flag.GUID, 252)))
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.TriggerSound(PlanetSideGUID(-1), TriggeredSound.LLUPickup, player.Position, 15, volume = 0.8f))
+ zone.LocalEvents ! MessageEnvelope(
+ zone.id,
+ PlanetSideGUID(-1),
+ SendResponse(ObjectAttachMessage(player.GUID, flag.GUID, 252))
+ )
+ zone.LocalEvents ! MessageEnvelope(
+ zone.id,
+ PlanetSideGUID(-1),
+ LocalAction.TriggerSound(TriggeredSound.LLUPickup, player.Position, 15, volume = 0.8f)
+ )
CaptureFlagManager.ChatBroadcast(
zone,
CaptureFlagChatMessageStrings.CTF_FlagPickedUp(player.Name, player.Faction, flag.Owner.asInstanceOf[Building].Name),
@@ -132,7 +159,11 @@ class CaptureFlagManager(zone: Zone) extends Actor {
// Remove attached player from flag
flag.Carrier = None
// Send drop packet
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.SendPacket(ObjectDetachMessage(player.GUID, flag.GUID, player.Position, 0, 0, 0)))
+ zone.LocalEvents ! MessageEnvelope(
+ zone.id,
+ PlanetSideGUID(-1),
+ SendResponse(ObjectDetachMessage(player.GUID, flag.GUID, player.Position, 0, 0, 0))
+ )
// Send dropped chat message
CaptureFlagManager.ChatBroadcast(
zone,
@@ -155,9 +186,9 @@ class CaptureFlagManager(zone: Zone) extends Actor {
TaskWorkflow.execute(WorldSession.CallBackForTask(
GUIDTask.registerObject(zone.GUID, replacementLlu),
zone.LocalEvents,
- LocalServiceMessage(
+ MessageEnvelope(
zone.id,
- LocalAction.LluSpawned(Service.defaultPlayerGUID, replacementLlu)
+ LocalAction.LluSpawned(replacementLlu)
)
))
case _ =>
@@ -189,7 +220,7 @@ class CaptureFlagManager(zone: Zone) extends Actor {
is_monolith_unit = false
)
}
- galaxyService ! GalaxyServiceMessage(GalaxyAction.FlagMapUpdate(CaptureFlagUpdateMessage(zone.Number, flagInfo)))
+ galaxyService ! MessageEnvelope("", GalaxyAction.FlagMapUpdate(CaptureFlagUpdateMessage(zone.Number, flagInfo)))
}
private def TrackFlag(flag: CaptureFlag): Unit = {
@@ -216,7 +247,7 @@ class CaptureFlagManager(zone: Zone) extends Actor {
flag.Owner.asInstanceOf[Building].GetFlagSocket.get.captureFlag = None
UntrackFlag(flag)
// Unregister LLU from clients,
- zone.LocalEvents ! LocalServiceMessage(zone.id, LocalAction.LluDespawned(PlanetSideGUID(-1), flag.GUID, flag.Position))
+ zone.LocalEvents ! MessageEnvelope(zone.id, PlanetSideGUID(-1), LocalAction.LluDespawned(flag.GUID, flag.Position))
// Then unregister it from the GUID pool
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, flag))
}
@@ -246,12 +277,10 @@ object CaptureFlagManager {
} else {
ChatMessageType.UNK_229
}
- zone.LocalEvents ! LocalServiceMessage(
+ zone.LocalEvents ! MessageEnvelope(
zone.id,
- LocalAction.SendChatMsg(
- PlanetSideGUID(-1),
- ChatMsg(messageType, wideContents = true, "", message, None)
- )
+ PlanetSideGUID(-1),
+ SendResponse(ChatMsg(messageType, wideContents = true, "", message, None))
)
}
@@ -288,7 +317,7 @@ object CaptureFlagManager {
if LoseFlagViolentlyToEnvironment(target, Set(EnvironmentAttribute.Water, EnvironmentAttribute.Lava, EnvironmentAttribute.Death)) /*||
LoseFlagViolentlyToWarpGateEnvelope(zone, target)*/ =>
flag.Destroyed = true
- zone.LocalEvents ! LocalServiceMessage("", LocalAction.LluLost(flag))
+ zone.LocalEvents ! CaptureEnvelope(HackCaptureActor.FlagLost(flag))
true
}
.getOrElse(false)
diff --git a/src/main/scala/net/psforever/services/local/support/DoorCloseActor.scala b/src/main/scala/net/psforever/services/local/support/DoorCloseActor.scala
index 115924267..e3ca9a6e4 100644
--- a/src/main/scala/net/psforever/services/local/support/DoorCloseActor.scala
+++ b/src/main/scala/net/psforever/services/local/support/DoorCloseActor.scala
@@ -1,15 +1,36 @@
// Copyright (c) 2017 PSForever
package net.psforever.services.local.support
-import akka.actor.{Actor, Cancellable}
+import akka.actor.{Actor, ActorContext, ActorRef, Cancellable, Props}
import net.psforever.objects.{Default, Doors}
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.zones.Zone
+import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelope}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.local.LocalAction.IsADoorMessage
+import net.psforever.services.local.LocalAction
import net.psforever.types.PlanetSideGUID
import scala.annotation.tailrec
import scala.concurrent.duration._
+case object DoorCloserSupport
+ extends EventServiceSupport {
+ def label: String = "doorCloser"
+ def constructor(context: ActorContext): ActorRef = {
+ context.actorOf(Props[DoorCloseActor](), name = "DoorCloser")
+ }
+}
+
+final case class DoorMessage(
+ channel: String,
+ msg: IsADoorMessage,
+ supportMessage: Any
+ ) extends GenericSupportEnvelope {
+ def filter: PlanetSideGUID = Default.GUID0
+ def supportLabel: String = "doorCloser"
+}
+
/**
* Close an opened door after a certain amount of time has passed.
* This `Actor` is intended to sit on top of the event system that handles broadcast messaging regarding doors opening.
@@ -43,11 +64,13 @@ class DoorCloseActor() extends Actor {
doorsLeftOpen1 ++
doorsLeftOpen2.map(entry => DoorCloseActor.DoorEntry(entry.door, entry.zone, now))
).sortBy(_.time)
- doorsToClose2.foreach(entry => {
- entry.door.Open = None //permissible break from synchronization
- context.parent ! DoorCloseActor.CloseTheDoor(entry.door.GUID, entry.zone.id) //call up to the main event system
- })
-
+ doorsToClose2
+ .map { case DoorCloseActor.DoorEntry(door, zone, _) =>
+ door.Open = None //permissible break from synchronization
+ (zone, MessageEnvelope(zone.id, LocalAction.DoorCloses(door.GUID))) //call up to the main event system
+ }
+ .groupBy(_._1)
+ .foreach { case (zone, list) => zone.LocalEvents ! BundledEnvelope(list.map(_._2)) }
if (openDoors.nonEmpty) {
val short_timeout: FiniteDuration = math.max(1, DoorCloseActor.timeout_time - (now - openDoors.head.time)).milliseconds
import scala.concurrent.ExecutionContext.Implicits.global
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 ffe816566..dc579b915 100644
--- a/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala
+++ b/src/main/scala/net/psforever/services/local/support/HackCaptureActor.scala
@@ -1,7 +1,7 @@
// Copyright (c) 2021 PSForever
package net.psforever.services.local.support
-import akka.actor.{Actor, Cancellable}
+import akka.actor.{Actor, ActorContext, ActorRef, Cancellable, Props}
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.hackable.Hackable
@@ -13,16 +13,32 @@ import net.psforever.objects.Default
import net.psforever.objects.serverobject.structures.participation.MajorFacilityHackParticipation
import net.psforever.packet.game.{ChatMsg, GenericAction, HackState7, PlanetsideAttributeEnum}
import net.psforever.objects.sourcing.PlayerSource
-import net.psforever.services.Service
+import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelopeOnly}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.local.support.HackCaptureActor.GetHackingFaction
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
-import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGUID}
+import net.psforever.services.local.LocalAction
+import net.psforever.types.{ChatMessageType, PlanetSideEmpire}
import java.util.concurrent.{Executors, TimeUnit}
import scala.collection.Seq
+import scala.collection.mutable.ArrayBuffer
import scala.concurrent.duration.{FiniteDuration, _}
import scala.util.Random
+case object HackCaptureSupport
+ extends EventServiceSupport {
+ def label: String = "hackCapturer"
+ def constructor(context: ActorContext): ActorRef = {
+ context.actorOf(Props[HackCaptureActor](), name = "HackCapturer")
+ }
+}
+
+final case class CaptureEnvelope(supportMessage: Any)
+ extends GenericSupportEnvelopeOnly {
+ def supportLabel: String = "hackCapturer"
+}
+
/**
* Responsible for handling the aspects related to hacking control consoles and capturing bases.
*/
@@ -156,24 +172,19 @@ class HackCaptureActor extends Actor {
case HackCaptureActor.FlagLost(flag) =>
val owner = flag.Owner.asInstanceOf[Building]
val guid = owner.GUID
- val terminalOpt = owner.CaptureTerminal
- hackedObjects
- .find(entry => guid == entry.target.Owner.GUID)
- .collect { entry =>
- val terminal = terminalOpt.get
- 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")
- None
- }
- context.parent ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.FlagLost)
+ val (found, remaining) = hackedObjects.partition(_.target.Owner.GUID == guid)
+ hackedObjects = remaining
+ found.collectFirst { _ =>
+ val terminal = owner.CaptureTerminal.get
+ 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)
+ RestartTimer() // If there's hacked objects left in the list restart the timer with the shortest hack time left
+ }
+ if (found.isEmpty) {
+ log.warn(s"FlagLost: flag data does not match to an entry in the hacked objects list")
+ }
+ owner.Zone.LocalEvents ! FlagEnvelope(CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.FlagLost))
case _ => ()
}
@@ -195,7 +206,7 @@ class HackCaptureActor extends Actor {
true
case Some((owner, Some(flag), Some(neighbours))) if neighbours.nonEmpty && hackingFaction != flag.Faction =>
log.info(s"$hackingFaction is overriding the ongoing LLU hack of facility ${owner.Name} by ${flag.Faction}")
- terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.Ended)
+ terminal.Zone.LocalEvents ! FlagEnvelope(CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.Ended))
NotifyHackStateChange(terminal, isResecured = false)
RestartTimer()
spawnCaptureFlag(neighbours, terminal, hackingFaction)
@@ -209,7 +220,7 @@ class HackCaptureActor extends Actor {
case Some((owner, Some(flag), _)) =>
log.warn(s"TrySpawnCaptureFlag: couldn't find any neighbouring $hackingFaction facilities of ${owner.Name} for LLU hack")
owner.GetFlagSocket.foreach { _.clearOldFlagData() }
- terminal.Zone.LocalEvents ! CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.Ended)
+ terminal.Zone.LocalEvents ! FlagEnvelope(CaptureFlagManager.Lost(flag, CaptureFlagLostReasonEnum.Ended))
false
case _ =>
log.error(s"TrySpawnCaptureFlag: expecting a terminal ${terminal.GUID.guid} with the ctf owning facility")
@@ -225,7 +236,7 @@ class HackCaptureActor extends Actor {
// Find a random neighbouring base matching the hacking faction
val targetBase = neighbours.toVector((new Random).nextInt(neighbours.size))
// Request LLU is created by CaptureFlagActor via LocalService
- terminal.Zone.LocalEvents ! CaptureFlagManager.SpawnCaptureFlag(terminal, targetBase, hackingFaction)
+ terminal.Zone.LocalEvents ! FlagEnvelope(CaptureFlagManager.SpawnCaptureFlag(terminal, targetBase, hackingFaction))
}
private def NotifyHackStateChange(
@@ -234,12 +245,11 @@ class HackCaptureActor extends Actor {
): Unit = {
val attributeValue = HackCaptureActor.GetHackUpdateAttributeValue(terminal, isResecured)
// Notify all clients that CC has had its hack state changed
- terminal.Zone.LocalEvents ! LocalServiceMessage(
+ terminal.Zone.LocalEvents ! MessageEnvelope(
terminal.Zone.id,
- LocalAction.SendPlanetsideAttributeMessage(
- PlanetSideGUID(-1),
+ PlanetsideAttribute(
terminal.GUID,
- PlanetsideAttributeEnum.ControlConsoleHackUpdate,
+ PlanetsideAttributeEnum.ControlConsoleHackUpdate.id,
attributeValue
)
)
@@ -267,18 +277,18 @@ class HackCaptureActor extends Actor {
private def HackCompleted(terminal: CaptureTerminal with Hackable, hackedByFaction: PlanetSideEmpire.Value): Unit = {
val building = terminal.Owner.asInstanceOf[Building]
+ val zone = building.Zone
+ val events = zone.LocalEvents
+ val messages: ArrayBuffer[MessageEnvelope] = ArrayBuffer()
if (building.NtuLevel > 0) {
building.virusId = 8
building.virusInstalledBy = None
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
//dispatch to players aligned with the capturing faction within the SOI
- val events = building.Zone.LocalEvents
- val msg = LocalAction.SendGenericActionMessage(Service.defaultPlayerGUID, GenericAction.FacilityCaptureFanfare)
- building
- .PlayersInSOI
- .collect { case p if p.Faction == hackedByFaction =>
- events ! LocalServiceMessage(p.Name, msg)
- }
+ val msg = LocalAction.GenericActionMessage(GenericAction.FacilityCaptureFanfare)
+ messages.appendAll(building.PlayersInSOI.collect { case p if p.Faction == hackedByFaction =>
+ MessageEnvelope(p.Name, msg)
+ })
val buildings = building.Zone.Buildings.values
val hackedBaseId = building.GUID
val facilities = if (building.Zone.id.startsWith("c")) {
@@ -312,7 +322,8 @@ class HackCaptureActor extends Actor {
}
NotifyHackStateChange(terminal, isResecured = true)
// todo: this appears to be the way to reset the base warning lights after the hack finishes but it doesn't seem to work.
- context.parent ! HackClearActor.SendHackMessageHackCleared(building.GUID, terminal.Zone.id, 3212836864L, HackState7.Unk8) //call up
+ messages.append(MessageEnvelope(zone.id, LocalAction.HackClear(building.GUID, 3212836864L, HackState7.Unk8)))
+ events ! BundledEnvelope(messages)
}
private def RestartTimer(): Unit = {
diff --git a/src/main/scala/net/psforever/services/local/support/HackClearActor.scala b/src/main/scala/net/psforever/services/local/support/HackClearActor.scala
index c93ae2696..429cb59c3 100644
--- a/src/main/scala/net/psforever/services/local/support/HackClearActor.scala
+++ b/src/main/scala/net/psforever/services/local/support/HackClearActor.scala
@@ -2,17 +2,44 @@
package net.psforever.services.local.support
import java.util.concurrent.TimeUnit
-import akka.actor.{Actor, Cancellable}
+import akka.actor.{Actor, ActorContext, ActorRef, Cancellable, Props}
import net.psforever.objects.{Default, GlobalDefinitions}
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.HackState7
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
+import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelope, GenericSupportEnvelopeOnly}
+import net.psforever.services.base.message.GenericObjectAction
+import net.psforever.services.local.LocalAction.IsAHackMessage
+import net.psforever.services.local.LocalAction
import net.psforever.types.PlanetSideGUID
import scala.annotation.tailrec
import scala.concurrent.duration._
+case object HackClearSupport
+ extends EventServiceSupport {
+ def label: String = "hackClearer"
+ def constructor(context: ActorContext): ActorRef = {
+ context.actorOf(Props[HackClearActor](), name = "HackClearer")
+ }
+}
+
+final case class HackEntityEnvelope(
+ channel: String,
+ filter: PlanetSideGUID,
+ msg: IsAHackMessage,
+ supportMessage: Any
+ ) extends GenericSupportEnvelope {
+ def supportLabel: String = "hackClearer"
+}
+
+final case class HackClearEnvelope(supportMessage: Any)
+ extends GenericSupportEnvelopeOnly {
+ def supportLabel: String = "hackClearer"
+}
+
/**
* Restore original functionality to an object that has been hacked after a certain amount of time has passed.
* This `Actor` is intended to sit on top of the event system that handles broadcast messaging regarding hacking events.
@@ -45,32 +72,27 @@ class HackClearActor() extends Actor {
//TODO we can just walk across the list of doors and extract only the first few entries
val (unhackObjects, stillHackedObjects) = PartitionEntries(hackedObjects, now)
hackedObjects = stillHackedObjects
- unhackObjects.foreach(entry => {
- entry.target.Actor ! CommonMessages.ClearHack()
- context.parent ! HackClearActor.SendHackMessageHackCleared(
- entry.target.GUID,
- entry.zone.id,
- entry.unk1,
- entry.unk2
- ) //call up to the main event system
- if (entry.target.Definition == GlobalDefinitions.main_terminal) {
- ClearVirusFromBuilding(entry.target)
+ unhackObjects
+ .map { case HackClearActor.HackEntry(target, zone, unk1, unk2, _, _) =>
+ target.Actor ! CommonMessages.ClearHack()
+ if (target.Definition == GlobalDefinitions.main_terminal) {
+ ClearVirusFromBuilding(target)
+ }
+ (zone, MessageEnvelope(zone.id, LocalAction.HackClear(target.GUID, unk1, unk2)))
+ }
+ .groupBy(_._1)
+ .foreach { case (zone, list) =>
+ zone.LocalEvents ! BundledEnvelope(list.map(_._2))
}
- })
RestartTimer()
case HackClearActor.ObjectIsResecured(target) =>
hackedObjects.find { _.target == target } match {
- case Some(entry: HackClearActor.HackEntry) =>
+ case Some(HackClearActor.HackEntry(target, zone, unk1, unk2, _, _)) =>
hackedObjects = hackedObjects.filterNot(x => x.target == target)
- entry.target.Actor ! CommonMessages.ClearHack()
- context.parent ! HackClearActor.SendHackMessageHackCleared(
- entry.target.GUID,
- entry.zone.id,
- entry.unk1,
- entry.unk2
- ) //call up to the main event system
+ target.Actor ! CommonMessages.ClearHack()
+ zone.LocalEvents ! MessageEnvelope(zone.id, LocalAction.HackClear(target.GUID, 3212836864L, HackState7.Unk8))
// Restart the timer in case the object we just removed was the next one scheduled
RestartTimer()
@@ -109,17 +131,13 @@ class HackClearActor() extends Actor {
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.actors.zone.BuildingActor
- import net.psforever.services.Service
- import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
val building = target.asInstanceOf[Terminal].Owner.asInstanceOf[Building]
building.virusId = 8
building.virusInstalledBy = None
- val msg = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, target.GUID, 60)
+ val msg = GenericObjectAction(target.GUID, 60)
val events = building.Zone.AvatarEvents
- building.PlayersInSOI.foreach { player =>
- events ! AvatarServiceMessage(player.Name, msg)
- }
+ events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) })
building.Actor ! BuildingActor.MapUpdate()
}
diff --git a/src/main/scala/net/psforever/services/properties/PropertyOverrideManager.scala b/src/main/scala/net/psforever/services/properties/PropertyOverrideManager.scala
index 9af42b969..0a7888ae4 100644
--- a/src/main/scala/net/psforever/services/properties/PropertyOverrideManager.scala
+++ b/src/main/scala/net/psforever/services/properties/PropertyOverrideManager.scala
@@ -5,6 +5,7 @@ import net.psforever.packet.game.{GamePropertyTarget, PropertyOverrideMessage}
import net.psforever.packet.game.PropertyOverrideMessage.GamePropertyScope
import net.psforever.packet.game.objectcreate.ObjectClass
import net.psforever.zones.Zones
+
import scala.collection.mutable.ListBuffer
class PropertyOverrideManager extends Actor {
@@ -12,11 +13,10 @@ class PropertyOverrideManager extends Actor {
private var overrides: Map[Int, Map[String, List[(String, String)]]] = Map()
private var gamePropertyScopes: List[PropertyOverrideMessage.GamePropertyScope] = List()
- lazy private val zoneIds: Iterable[Int] = Zones.zones.map(_.Number)
override def preStart(): Unit = {
LoadOverridesFromFile(zoneId = 0) // Global overrides
- for (zoneId <- zoneIds) {
+ for (zoneId <- Zones.zones.map(_.Number)) {
LoadOverridesFromFile(zoneId)
}
ProcessGamePropertyScopes()
@@ -26,7 +26,7 @@ class PropertyOverrideManager extends Actor {
case PropertyOverrideManager.GetOverridesMessage =>
sender() ! gamePropertyScopes
- case _ => ;
+ case _ => ()
}
private def LoadOverridesFromFile(zoneId: Int): Unit = {
@@ -37,11 +37,11 @@ class PropertyOverrideManager extends Actor {
}
if (zoneOverrides == null) {
log.debug(s"PropertyOverride: no overrides found for zone $zoneId using filename game_objects$zoneId.adb.lst")
- return
+ } else {
+ val grouped = zoneOverrides.groupBy(_._1).view.mapValues(_.map(x => (x._2, x._3)).toList).toMap
+ log.debug(s"PropertyOverride: loaded property overrides for zone $zoneId: ${grouped.toString}")
+ overrides += (zoneId -> grouped)
}
- val grouped = zoneOverrides.groupBy(_._1).view.mapValues(_.map(x => (x._2, x._3)).toList).toMap
- log.debug(s"PropertyOverride: loaded property overrides for zone $zoneId: ${grouped.toString}")
- overrides += (zoneId -> grouped)
}
private def ProcessGamePropertyScopes(): Unit = {
@@ -61,28 +61,26 @@ class PropertyOverrideManager extends Actor {
gamePropertyScopes = scopesBuffer.toList
}
- def LoadFile(path: String): ListBuffer[(String, String, String)] = {
+ def LoadFile(path: String): List[(String, String, String)] = {
val stream = getClass.getClassLoader.getResourceAsStream(path)
if (stream == null) {
- return null
- }
- val content = scala.io.Source.fromInputStream(stream).getLines().filter(x => x.startsWith("add_property"))
- val data: ListBuffer[(String, String, String)] = ListBuffer()
- for (line <- content) {
- val splitLine = line.split(" ")
- if (splitLine.length >= 3) {
- val objectName = splitLine(1)
- val property = splitLine(2)
- var propertyValue = ""
- for (i <- 3 until splitLine.length) {
- propertyValue += splitLine(i) + " "
+ List.empty[(String, String, String)]
+ } else {
+ val content = scala.io.Source.fromInputStream(stream).getLines()
+ val data = content
+ .filter(_.startsWith("add_property"))
+ .map { line => (line, line.split("\\s+")) }
+ .filter(_._2.length > 2) //n >= 3
+ .map { case (line, tokens) =>
+ val objectName = tokens(1)
+ val property = tokens(2)
+ val propertyValue = line.drop(objectName.length + property.length + 15) //"add_property" (12) + spaces (3)
+ (objectName, property, propertyValue)
}
- propertyValue = propertyValue.trim
- data += ((objectName, property, propertyValue))
- }
+ .toList
+ stream.close()
+ data
}
- stream.close()
- data
}
}
diff --git a/src/main/scala/net/psforever/services/teamwork/SquadService.scala b/src/main/scala/net/psforever/services/teamwork/SquadService.scala
index 926dba54e..fcac21e2c 100644
--- a/src/main/scala/net/psforever/services/teamwork/SquadService.scala
+++ b/src/main/scala/net/psforever/services/teamwork/SquadService.scala
@@ -176,20 +176,20 @@ class SquadService extends Actor {
def receive: Receive = {
//subscribe to a faction's channel - necessary to receive updates about listed squads
- case Service.Join(faction) if SquadService.FactionWordSalad.indexOf(faction) > -1 =>
+ case Service.Join(faction, _) if SquadService.FactionWordSalad.indexOf(faction) > -1 =>
JoinByFaction(faction, sender())
//subscribe to the player's personal channel - necessary for future and previous squad information
- case Service.Join(char_id) =>
+ case Service.Join(char_id, _) =>
JoinByCharacterId(char_id, sender())
- case Service.Leave(Some(faction)) if SquadService.FactionWordSalad.indexOf(faction) > -1 =>
+ case Service.Leave(faction) if SquadService.FactionWordSalad.indexOf(faction) > -1 =>
LeaveByFaction(faction, sender())
- case Service.Leave(Some(char_id)) =>
+ case Service.Leave(char_id) =>
LeaveByCharacterId(char_id, sender())
- case Service.Leave(None) | Service.LeaveAll() =>
+ case Service.LeaveAll =>
LeaveInGeneral(sender())
case Terminated(actorRef) =>
diff --git a/src/main/scala/net/psforever/services/teamwork/SquadServiceMessage.scala b/src/main/scala/net/psforever/services/teamwork/SquadServiceMessage.scala
index f99942df6..8cda11648 100644
--- a/src/main/scala/net/psforever/services/teamwork/SquadServiceMessage.scala
+++ b/src/main/scala/net/psforever/services/teamwork/SquadServiceMessage.scala
@@ -5,6 +5,7 @@ import net.psforever.objects.Player
import net.psforever.objects.avatar.Certification
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{WaypointEventAction, WaypointInfo, SquadAction => PacketSquadAction}
+import net.psforever.services.base.message.{EventMessage, EventResponse}
import net.psforever.types.{PlanetSideGUID, SquadRequestType, SquadWaypoint, Vector3}
final case class SquadServiceMessage(tplayer: Player, zone: Zone, actionMessage: Any)
@@ -15,7 +16,9 @@ object SquadServiceMessage {
}
object SquadAction {
- sealed trait Action
+ sealed trait Action extends EventMessage {
+ def response(): EventResponse = null
+ }
final case class InitSquadList() extends Action
final case class InitCharId() extends Action
diff --git a/src/main/scala/net/psforever/services/teamwork/SquadServiceResponse.scala b/src/main/scala/net/psforever/services/teamwork/SquadServiceResponse.scala
index bd2753292..a5281453c 100644
--- a/src/main/scala/net/psforever/services/teamwork/SquadServiceResponse.scala
+++ b/src/main/scala/net/psforever/services/teamwork/SquadServiceResponse.scala
@@ -2,14 +2,23 @@
package net.psforever.services.teamwork
import akka.actor.ActorRef
+import net.psforever.objects.Default
import net.psforever.objects.avatar.Certification
import net.psforever.objects.teamwork.Squad
import net.psforever.packet.game.{SquadDetail, SquadInfo, WaypointEventAction, WaypointInfo}
+import net.psforever.services.base.message.EventResponse
import net.psforever.types.{ChatMessageType, PlanetSideGUID, SquadResponseType, SquadWaypoint}
-import net.psforever.services.GenericEventBusMsg
+import net.psforever.services.base.EventSystemStamp
+import net.psforever.services.base.envelope.GenericResponseEnvelope
-final case class SquadServiceResponse(channel: String, exclude: Iterable[Long], response: SquadResponse.Response)
- extends GenericEventBusMsg
+case object SquadStamp extends EventSystemStamp
+
+final case class SquadServiceResponse(channel: String, exclude: Iterable[Long], reply: SquadResponse.Response)
+ extends EventResponse with GenericResponseEnvelope {
+ def filter: PlanetSideGUID = Default.GUID0
+
+ def stamp: EventSystemStamp = SquadStamp
+}
object SquadServiceResponse {
def apply(toChannel: String, response: SquadResponse.Response): SquadServiceResponse =
@@ -20,7 +29,7 @@ object SquadServiceResponse {
}
object SquadResponse {
- sealed trait Response
+ sealed trait Response extends EventResponse
final case class ListSquadFavorite(line: Int, task: String) extends Response
diff --git a/src/main/scala/net/psforever/services/teamwork/SquadSubscriptionEntity.scala b/src/main/scala/net/psforever/services/teamwork/SquadSubscriptionEntity.scala
index 104bd5320..fe0537992 100644
--- a/src/main/scala/net/psforever/services/teamwork/SquadSubscriptionEntity.scala
+++ b/src/main/scala/net/psforever/services/teamwork/SquadSubscriptionEntity.scala
@@ -2,11 +2,11 @@
package net.psforever.services.teamwork
import akka.actor.ActorRef
-import scala.collection.mutable
+import scala.collection.mutable
import net.psforever.objects.teamwork.{Squad, SquadFeatures}
import net.psforever.packet.game.SquadDetail
-import net.psforever.services.GenericEventBus
+import net.psforever.services.base.bus.GenericEventBus
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
class SquadSubscriptionEntity {
@@ -28,7 +28,7 @@ class SquadSubscriptionEntity {
* @see `Service.Join`
* @see `Service.Leave`
*/
- val SquadEvents = new GenericEventBus[SquadServiceResponse]
+ val SquadEvents = new GenericEventBus
/**
* This collection contains the message-sending contact reference for individuals.
diff --git a/src/main/scala/net/psforever/services/vehicle/VehicleAction.scala b/src/main/scala/net/psforever/services/vehicle/VehicleAction.scala
new file mode 100644
index 000000000..dad025f86
--- /dev/null
+++ b/src/main/scala/net/psforever/services/vehicle/VehicleAction.scala
@@ -0,0 +1,143 @@
+// Copyright (c) 2017-2026 PSForever
+package net.psforever.services.vehicle
+
+import net.psforever.objects.{PlanetSideGameObject, Vehicle}
+import net.psforever.objects.equipment.Equipment
+import net.psforever.objects.inventory.InventoryItem
+import net.psforever.objects.serverobject.tube.SpawnTube
+import net.psforever.objects.zones.Zone
+import net.psforever.packet.game.ObjectCreateMessage
+import net.psforever.packet.game.objectcreate.{ConstructorData, ObjectCreateMessageParent}
+import net.psforever.services.base.message.{EventMessage, EventResponse, SelfRespondingEvent}
+import net.psforever.types.{BailType, DriveState, PlanetSideGUID, Vector3}
+
+object VehicleAction {
+ final case class ChildObjectState(object_guid: PlanetSideGUID, pitch: Float, yaw: Float) extends SelfRespondingEvent
+
+ final case class DeployRequest(
+ object_guid: PlanetSideGUID,
+ state: DriveState.Value,
+ unk1: Int,
+ unk2: Boolean,
+ pos: Vector3
+ ) extends SelfRespondingEvent
+
+ final case class DismountVehicle(bailType: BailType.Value, unk2: Boolean) extends SelfRespondingEvent
+
+ final case class EquipmentCreatedInSlot(pkt: ObjectCreateMessage) extends EventResponse
+
+ final case class EquipmentInSlot(target_guid: PlanetSideGUID, slot: Int, equipment: Equipment) extends EventMessage {
+ override def response(): EventResponse = {
+ val definition = equipment.Definition
+ val pkt = ObjectCreateMessage(
+ definition.ObjectId,
+ equipment.GUID,
+ ObjectCreateMessageParent(target_guid, slot),
+ definition.Packet.ConstructorData(equipment).get
+ )
+ VehicleAction.EquipmentCreatedInSlot(pkt)
+ }
+ }
+
+ final case class FrameVehicleState(
+ vehicle_guid: PlanetSideGUID,
+ unk1: Int,
+ pos: Vector3,
+ orient: Vector3,
+ vel: Option[Vector3],
+ unk2: Boolean,
+ unk3: Int,
+ unk4: Int,
+ is_crouched: Boolean,
+ unk6: Boolean,
+ unk7: Boolean,
+ unk8: Int,
+ unk9: Long,
+ unkA: Long
+ ) extends SelfRespondingEvent
+
+ final case class InventoryState(
+ obj: PlanetSideGameObject,
+ parent_guid: PlanetSideGUID,
+ start: Int,
+ con_data: ConstructorData
+ ) extends SelfRespondingEvent
+
+ final case class InventoryState2(obj_guid: PlanetSideGUID, parent_guid: PlanetSideGUID, value: Int) extends SelfRespondingEvent
+
+ final case class KickPassenger(unk1: Int, unk2: Boolean, vehicle_guid: PlanetSideGUID) extends SelfRespondingEvent
+
+ final case class LoadVehicle(
+ vehicle: Vehicle,
+ vtype: Int,
+ vguid: PlanetSideGUID,
+ vdata: ConstructorData
+ ) extends SelfRespondingEvent
+
+ final case class MountVehicle(object_guid: PlanetSideGUID, seat: Int) extends SelfRespondingEvent
+
+ final case class Ownership(vehicle_guid: PlanetSideGUID) extends SelfRespondingEvent
+
+ final case class LoseOwnership(owner_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID) extends SelfRespondingEvent
+
+ final case class SeatPermissions(vehicle_guid: PlanetSideGUID, seat_group: Int, permission: Long) extends SelfRespondingEvent
+
+ final case class StowCreatedEquipment(
+ vehicle_guid: PlanetSideGUID,
+ slot: Int,
+ itype: Int,
+ iguid: PlanetSideGUID,
+ idata: ConstructorData
+ ) extends EventResponse
+
+ final case class StowEquipment(vehicle_guid: PlanetSideGUID, slot: Int, item: Equipment) extends SelfRespondingEvent
+
+ final case class UnloadVehicle(vehicle: Vehicle, vehicle_guid: PlanetSideGUID) extends SelfRespondingEvent
+
+ final case class UnstowEquipment(item_guid: PlanetSideGUID) extends SelfRespondingEvent
+
+ final case class VehicleState(
+ vehicle_guid: PlanetSideGUID,
+ unk1: Int,
+ pos: Vector3,
+ ang: Vector3,
+ vel: Option[Vector3],
+ unk2: Option[Int],
+ unk3: Int,
+ unk4: Int,
+ wheel_direction: Int,
+ unk5: Boolean,
+ unk6: Boolean
+ ) extends SelfRespondingEvent
+
+ final case class UpdateAmsSpawnList(list: List[SpawnTube]) extends EventResponse
+
+ final case class UpdateAmsSpawnPoint(zone: Zone) extends EventMessage {
+ override def response(): EventResponse = {
+ VehicleAction.UpdateAmsSpawnList(Zone.AmsSpawnPoints(zone))
+ }
+ }
+
+ final case class AMSDeploymentChange(zone: Zone) extends EventMessage {
+ override def response(): EventResponse = {
+ VehicleAction.UpdateAmsSpawnList(Zone.AmsSpawnPoints(zone))
+ }
+ }
+
+ final case class TransferPassengerChannel(
+ temp_channel: String,
+ new_channel: String,
+ vehicle: Vehicle,
+ vehicle_to_delete: PlanetSideGUID
+ ) extends SelfRespondingEvent
+
+ final case class KickCargo(cargo: Vehicle, speed: Int, delay: Long) extends SelfRespondingEvent
+
+ final case class ChangeLoadout(
+ target_guid: PlanetSideGUID,
+ removed_weapons: List[(Equipment, PlanetSideGUID)],
+ new_weapons: List[InventoryItem],
+ old_inventory: List[(Equipment, PlanetSideGUID)],
+ new_inventory: List[InventoryItem]
+ ) extends SelfRespondingEvent
+}
diff --git a/src/main/scala/net/psforever/services/vehicle/VehicleService.scala b/src/main/scala/net/psforever/services/vehicle/VehicleService.scala
index 72168faa0..26f130f43 100644
--- a/src/main/scala/net/psforever/services/vehicle/VehicleService.scala
+++ b/src/main/scala/net/psforever/services/vehicle/VehicleService.scala
@@ -1,442 +1,18 @@
-// Copyright (c) 2017 PSForever
+// Copyright (c) 2017-2026 PSForever
package net.psforever.services.vehicle
-import akka.actor.{Actor, ActorRef, Props}
-import net.psforever.objects.serverobject.pad.VehicleSpawnPad
-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
-import net.psforever.types.DriveState
-import net.psforever.services.{GenericEventBus, Service}
+import akka.actor.Props
+import net.psforever.services.base.{EventSystemStamp, GenericEventServiceWithCacheAndSupport}
+import net.psforever.services.vehicle.support.TurretUpgradeSupport
-class VehicleService(zone: Zone) extends Actor {
- private val turretUpgrade: ActorRef = context.actorOf(Props[TurretUpgrader](), s"${zone.id}-turret-upgrade-agent")
- private[this] val log = org.log4s.getLogger
+case object VehicleStamp extends EventSystemStamp
- val VehicleEvents = new GenericEventBus[VehicleServiceResponse]
-
- def receive: Receive = {
- case Service.Join(channel) =>
- val path = s"/$channel/Vehicle"
- VehicleEvents.subscribe(sender(), path)
-
- case Service.Leave(None) =>
- VehicleEvents.unsubscribe(sender())
-
- case Service.Leave(Some(channel)) =>
- val path = s"/$channel/Vehicle"
- VehicleEvents.unsubscribe(sender(), path)
-
- case Service.LeaveAll() =>
- VehicleEvents.unsubscribe(sender())
-
- case VehicleServiceMessage(forChannel, action) =>
- action match {
- case VehicleAction.ChangeAmmo(player_guid, weapon_guid, weapon_slot, old_ammo_guid, ammo_id, ammo_guid, ammo_data) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.ChangeAmmo(weapon_guid, weapon_slot, old_ammo_guid, ammo_id, ammo_guid, ammo_data)
- )
- )
- case VehicleAction.ChangeFireState_Start(player_guid, weapon_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.ChangeFireState_Start(weapon_guid)
- )
- )
- case VehicleAction.ChangeFireState_Stop(player_guid, weapon_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.ChangeFireState_Stop(weapon_guid))
- )
- case VehicleAction.ChildObjectState(player_guid, object_guid, pitch, yaw) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.ChildObjectState(object_guid, pitch, yaw)
- )
- )
- case VehicleAction.DeployRequest(player_guid, object_guid, state, unk1, unk2, pos) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.DeployRequest(object_guid, state, unk1, unk2, pos)
- )
- )
- case VehicleAction.DismountVehicle(player_guid, bailType, unk2) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.DismountVehicle(bailType, unk2)
- )
- )
- case VehicleAction.EquipmentInSlot(player_guid, target_guid, slot, equipment) =>
- val definition = equipment.Definition
- val pkt = ObjectCreateMessage(
- definition.ObjectId,
- equipment.GUID,
- ObjectCreateMessageParent(target_guid, slot),
- definition.Packet.ConstructorData(equipment).get
- )
- ObjectCreateMessageParent(target_guid, slot)
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.EquipmentInSlot(pkt))
- )
- case VehicleAction.FrameVehicleState(
- player_guid,
- vehicle_guid,
- unk1,
- pos,
- orient,
- vel,
- unk2,
- unk3,
- unk4,
- is_crouched,
- unk6,
- unk7,
- unk8,
- unk9,
- unkA
- ) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.FrameVehicleState(
- vehicle_guid,
- unk1,
- pos,
- orient,
- vel,
- unk2,
- unk3,
- unk4,
- is_crouched,
- unk6,
- unk7,
- unk8,
- unk9,
- unkA
- )
- )
- )
- case VehicleAction.GenericObjectAction(player_guid, guid, code) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.GenericObjectAction(guid, code)
- )
- )
- case VehicleAction.InventoryState(player_guid, obj, parent_guid, start, con_data) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.InventoryState(obj, parent_guid, start, con_data)
- )
- )
- case VehicleAction.InventoryState2(player_guid, obj_guid, parent_guid, value) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.InventoryState2(obj_guid, parent_guid, value)
- )
- )
- case VehicleAction.KickPassenger(player_guid, seat_num, kickedByDriver, vehicle_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.KickPassenger(seat_num, kickedByDriver, vehicle_guid)
- )
- )
- case VehicleAction.ObjectDelete(guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.ObjectDelete(guid)
- )
- )
- case VehicleAction.LoadVehicle(player_guid, vehicle, vtype, vguid, vdata) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.LoadVehicle(vehicle, vtype, vguid, vdata)
- )
- )
- case VehicleAction.MountVehicle(player_guid, vehicle_guid, seat) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.MountVehicle(vehicle_guid, seat)
- )
- )
- case VehicleAction.LoseOwnership(owner_guid, vehicle_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", Service.defaultPlayerGUID, VehicleResponse.LoseOwnership(owner_guid, vehicle_guid))
- )
- case VehicleAction.Ownership(player_guid, vehicle_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.Ownership(vehicle_guid))
- )
- case VehicleAction.PlanetsideAttribute(exclude_guid, target_guid, attribute_type, attribute_value) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- exclude_guid,
- VehicleResponse.PlanetsideAttribute(target_guid, attribute_type, attribute_value)
- )
- )
-
- case VehicleAction.Reload(player_guid, weapon_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.Reload(weapon_guid))
- )
- case VehicleAction.SeatPermissions(player_guid, vehicle_guid, seat_group, permission) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.SeatPermissions(vehicle_guid, seat_group, permission)
- )
- )
- case VehicleAction.StowEquipment(player_guid, vehicle_guid, slot, item) =>
- val definition = item.Definition
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.StowEquipment(
- vehicle_guid,
- slot,
- definition.ObjectId,
- item.GUID,
- definition.Packet.DetailedConstructorData(item).get
- )
- )
- )
- case VehicleAction.WeaponDryFire(player_guid, weapon_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.WeaponDryFire(weapon_guid))
- )
- case VehicleAction.UnloadVehicle(player_guid, vehicle, vehicle_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.UnloadVehicle(vehicle, vehicle_guid)
- )
- )
- case VehicleAction.UnstowEquipment(player_guid, item_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.UnstowEquipment(item_guid))
- )
- case VehicleAction.VehicleState(
- player_guid,
- vehicle_guid,
- unk1,
- pos,
- ang,
- vel,
- unk2,
- unk3,
- unk4,
- wheel_direction,
- unk5,
- unk6
- ) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.VehicleState(
- vehicle_guid,
- unk1,
- pos,
- ang,
- vel,
- unk2,
- unk3,
- unk4,
- wheel_direction,
- unk5,
- unk6
- )
- )
- )
- case VehicleAction.SendResponse(player_guid, msg) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.SendResponse(msg))
- )
-
- //unlike other messages, just return to sender, don't publish
- case VehicleAction.UpdateAmsSpawnPoint(zone: Zone) =>
- sender() ! VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.UpdateAmsSpawnPoint(AmsSpawnPoints(zone))
- )
-
- case VehicleAction.TransferPassengerChannel(
- player_guid,
- old_channel,
- temp_channel,
- vehicle,
- vehicle_to_delete
- ) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- player_guid,
- VehicleResponse.TransferPassengerChannel(old_channel, temp_channel, vehicle, vehicle_to_delete)
- )
- )
- case VehicleAction.KickCargo(player_guid, cargo, speed, delay) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.KickCargo(cargo, speed, delay))
- )
-
- case VehicleAction.ChangeLoadout(target_guid, removed_weapons, new_weapons, old_inventory, new_inventory) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$forChannel/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.ChangeLoadout(target_guid, removed_weapons, new_weapons, old_inventory, new_inventory)
- )
- )
- case _ => ;
- }
-
- //message to TurretUpgrader
- case VehicleServiceMessage.TurretUpgrade(msg) =>
- turretUpgrade forward msg
-
- //from VehicleSpawnControl, etc.
- case VehicleSpawnPad.ConcealPlayer(player_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/${zone.id}/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.ConcealPlayer(player_guid)
- )
- )
-
- case VehicleSpawnPad.AttachToRails(vehicle, pad) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/${zone.id}/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.AttachToRails(vehicle.GUID, pad.GUID)
- )
- )
-
- case VehicleSpawnPad.StartPlayerSeatedInVehicle(driver_name, vehicle, pad) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$driver_name/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.StartPlayerSeatedInVehicle(vehicle, pad)
- )
- )
-
- case VehicleSpawnPad.PlayerSeatedInVehicle(driver_name, vehicle, pad) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$driver_name/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.PlayerSeatedInVehicle(vehicle, pad)
- )
- )
-
- case VehicleSpawnPad.ServerVehicleOverrideStart(driver_name, vehicle, pad) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$driver_name/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.ServerVehicleOverrideStart(vehicle, pad)
- )
- )
-
- case VehicleSpawnPad.ServerVehicleOverrideEnd(driver_name, vehicle, pad) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$driver_name/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.ServerVehicleOverrideEnd(vehicle, pad)
- )
- )
-
- case VehicleSpawnPad.DetachFromRails(vehicle, pad) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/${zone.id}/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.DetachFromRails(vehicle.GUID, pad.GUID, pad.Position, pad.Orientation.z)
- )
- )
- case VehicleSpawnPad.ResetSpawnPad(pad) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/${zone.id}/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.ResetSpawnPad(pad.GUID)
- )
- )
-
- case VehicleSpawnPad.RevealPlayer(player_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/${zone.id}/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.RevealPlayer(player_guid)
- )
- )
-
- case VehicleSpawnPad.PeriodicReminder(to, reason, data) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/$to/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.PeriodicReminder(reason, data)
- )
- )
-
- //correspondence from WorldSessionActor
- case VehicleServiceMessage.AMSDeploymentChange(_) =>
- VehicleEvents.publish(
- VehicleServiceResponse(
- s"/${zone.id}/Vehicle",
- Service.defaultPlayerGUID,
- VehicleResponse.UpdateAmsSpawnPoint(AmsSpawnPoints(zone))
- )
- )
-
- case msg =>
- log.warn(s"Unhandled message $msg from ${sender()}")
- }
-
- import net.psforever.objects.serverobject.tube.SpawnTube
- def AmsSpawnPoints(zone: Zone): List[SpawnTube] = {
- import net.psforever.objects.vehicles.UtilityType
- import net.psforever.objects.GlobalDefinitions
- zone.Vehicles
- .filter(veh =>
- veh.Health > 0 && veh.Definition == GlobalDefinitions.ams && veh.DeploymentState == DriveState.Deployed
- )
- .flatMap(veh => veh.Utilities.values.filter(util => util.UtilType == UtilityType.ams_respawn_tube))
- .map(util => util().asInstanceOf[SpawnTube])
+object VehicleService {
+ def apply(): Props = {
+ Props(
+ classOf[GenericEventServiceWithCacheAndSupport],
+ VehicleStamp,
+ List(TurretUpgradeSupport)
+ )
}
}
diff --git a/src/main/scala/net/psforever/services/vehicle/VehicleServiceMessage.scala b/src/main/scala/net/psforever/services/vehicle/VehicleServiceMessage.scala
deleted file mode 100644
index 07bb29769..000000000
--- a/src/main/scala/net/psforever/services/vehicle/VehicleServiceMessage.scala
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright (c) 2017 PSForever
-package net.psforever.services.vehicle
-
-import net.psforever.objects.{PlanetSideGameObject, Vehicle}
-import net.psforever.objects.equipment.Equipment
-import net.psforever.objects.inventory.InventoryItem
-import net.psforever.objects.zones.Zone
-import net.psforever.packet.PlanetSideGamePacket
-import net.psforever.packet.game.objectcreate.ConstructorData
-import net.psforever.types.{BailType, DriveState, PlanetSideGUID, Vector3}
-
-final case class VehicleServiceMessage(forChannel: String, actionMessage: VehicleAction.Action)
-
-object VehicleServiceMessage {
- final case class GiveActorControl(vehicle: Vehicle, actorName: String)
- final case class RevokeActorControl(vehicle: Vehicle)
-
- final case class TurretUpgrade(msg: Any)
-
- final case class AMSDeploymentChange(zone: Zone)
-}
-
-object VehicleAction {
- trait Action
-
- final case class ChangeAmmo(
- player_guid: PlanetSideGUID,
- weapon_guid: PlanetSideGUID,
- weapon_slot: Int,
- old_ammo_guid: PlanetSideGUID,
- ammo_id: Int,
- ammo_guid: PlanetSideGUID,
- ammo_data: ConstructorData
- ) extends Action
- final case class ChangeFireState_Start(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
- final case class ChangeFireState_Stop(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
- final case class ChildObjectState(player_guid: PlanetSideGUID, object_guid: PlanetSideGUID, pitch: Float, yaw: Float)
- extends Action
- final case class DeployRequest(
- player_guid: PlanetSideGUID,
- object_guid: PlanetSideGUID,
- state: DriveState.Value,
- unk1: Int,
- unk2: Boolean,
- pos: Vector3
- ) extends Action
- final case class DismountVehicle(player_guid: PlanetSideGUID, bailType: BailType.Value, unk2: Boolean) extends Action
- final case class EquipmentInSlot(
- player_guid: PlanetSideGUID,
- target_guid: PlanetSideGUID,
- slot: Int,
- equipment: Equipment
- ) extends Action
- final case class FrameVehicleState(
- player_guid: PlanetSideGUID,
- vehicle_guid: PlanetSideGUID,
- unk1: Int,
- pos: Vector3,
- orient: Vector3,
- vel: Option[Vector3],
- unk2: Boolean,
- unk3: Int,
- unk4: Int,
- is_crouched: Boolean,
- unk6: Boolean,
- unk7: Boolean,
- unk8: Int,
- unk9: Long,
- unkA: Long
- ) extends Action
- final case class GenericObjectAction(player_guid: PlanetSideGUID, guid: PlanetSideGUID, action: Int) extends Action
- final case class InventoryState(
- player_guid: PlanetSideGUID,
- obj: PlanetSideGameObject,
- parent_guid: PlanetSideGUID,
- start: Int,
- con_data: ConstructorData
- ) extends Action
- final case class InventoryState2(
- player_guid: PlanetSideGUID,
- obj_guid: PlanetSideGUID,
- parent_guid: PlanetSideGUID,
- value: Int
- ) extends Action
- final case class KickPassenger(player_guid: PlanetSideGUID, unk1: Int, unk2: Boolean, vehicle_guid: PlanetSideGUID)
- extends Action
- final case class LoadVehicle(
- player_guid: PlanetSideGUID,
- vehicle: Vehicle,
- vtype: Int,
- vguid: PlanetSideGUID,
- vdata: ConstructorData
- ) extends Action
- final case class MountVehicle(player_guid: PlanetSideGUID, object_guid: PlanetSideGUID, seat: Int) extends Action
- final case class ObjectDelete(guid: PlanetSideGUID) extends Action
- final case class LoseOwnership(owner_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID) extends Action
- final case class Ownership(player_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID) extends Action
- final case class PlanetsideAttribute(
- player_guid: PlanetSideGUID,
- target_guid: PlanetSideGUID,
- attribute_type: Int,
- attribute_value: Long
- ) extends Action
- final case class Reload(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
- final case class SeatPermissions(
- player_guid: PlanetSideGUID,
- vehicle_guid: PlanetSideGUID,
- seat_group: Int,
- permission: Long
- ) extends Action
- final case class StowEquipment(player_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID, slot: Int, item: Equipment)
- extends Action
- final case class UnloadVehicle(
- player_guid: PlanetSideGUID,
- vehicle: Vehicle,
- vehicle_guid: PlanetSideGUID
- ) extends Action
- final case class UnstowEquipment(player_guid: PlanetSideGUID, item_guid: PlanetSideGUID) extends Action
- final case class VehicleState(
- player_guid: PlanetSideGUID,
- vehicle_guid: PlanetSideGUID,
- unk1: Int,
- pos: Vector3,
- ang: Vector3,
- vel: Option[Vector3],
- unk2: Option[Int],
- unk3: Int,
- unk4: Int,
- wheel_direction: Int,
- unk5: Boolean,
- unk6: Boolean
- ) extends Action
- final case class SendResponse(player_guid: PlanetSideGUID, msg: PlanetSideGamePacket) extends Action
- final case class WeaponDryFire(player_guid: PlanetSideGUID, weapon_guid: PlanetSideGUID) extends Action
- final case class UpdateAmsSpawnPoint(zone: Zone) extends Action
-
- final case class TransferPassengerChannel(
- player_guid: PlanetSideGUID,
- temp_channel: String,
- new_channel: String,
- vehicle: Vehicle,
- vehicle_to_delete: PlanetSideGUID
- ) extends Action
-
- final case class KickCargo(player_guid: PlanetSideGUID, cargo: Vehicle, speed: Int, delay: Long) extends Action
-
- final case class ChangeLoadout(
- target_guid: PlanetSideGUID,
- removed_weapons: List[(Equipment, PlanetSideGUID)],
- new_weapons: List[InventoryItem],
- old_inventory: List[(Equipment, PlanetSideGUID)],
- new_inventory: List[InventoryItem]
- ) extends Action
-}
diff --git a/src/main/scala/net/psforever/services/vehicle/VehicleServiceResponse.scala b/src/main/scala/net/psforever/services/vehicle/VehicleServiceResponse.scala
deleted file mode 100644
index 22e2ed94f..000000000
--- a/src/main/scala/net/psforever/services/vehicle/VehicleServiceResponse.scala
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) 2017 PSForever
-package net.psforever.services.vehicle
-
-import net.psforever.objects.equipment.Equipment
-import net.psforever.objects.inventory.InventoryItem
-import net.psforever.objects.serverobject.pad.VehicleSpawnPad
-import net.psforever.objects.serverobject.pad.VehicleSpawnPad.Reminders
-import net.psforever.objects.{PlanetSideGameObject, Vehicle}
-import net.psforever.objects.serverobject.tube.SpawnTube
-import net.psforever.packet.PlanetSideGamePacket
-import net.psforever.packet.game.objectcreate.ConstructorData
-import net.psforever.packet.game.ObjectCreateMessage
-import net.psforever.types.{BailType, DriveState, PlanetSideGUID, Vector3}
-import net.psforever.services.GenericEventBusMsg
-
-final case class VehicleServiceResponse(
- channel: String,
- avatar_guid: PlanetSideGUID,
- replyMessage: VehicleResponse.Response
-) extends GenericEventBusMsg
-
-object VehicleResponse {
- trait Response
-
- final case class ChangeAmmo(
- weapon_guid: PlanetSideGUID,
- weapon_slot: Int,
- old_ammo_guid: PlanetSideGUID,
- ammo_id: Int,
- ammo_guid: PlanetSideGUID,
- ammo_data: ConstructorData
- ) extends Response
- final case class ChangeFireState_Start(weapon_guid: PlanetSideGUID) extends Response
- final case class ChangeFireState_Stop(weapon_guid: PlanetSideGUID) extends Response
- final case class ChildObjectState(object_guid: PlanetSideGUID, pitch: Float, yaw: Float) extends Response
- final case class ConcealPlayer(player_guid: PlanetSideGUID) extends Response
- final case class DeployRequest(
- object_guid: PlanetSideGUID,
- state: DriveState.Value,
- unk1: Int,
- unk2: Boolean,
- pos: Vector3
- ) extends Response
- final case class DismountVehicle(bailType: BailType.Value, unk2: Boolean) extends Response
- final case class EquipmentInSlot(pkt: ObjectCreateMessage) extends Response
- final case class FrameVehicleState(
- vehicle_guid: PlanetSideGUID,
- unk1: Int,
- pos: Vector3,
- orient: Vector3,
- vel: Option[Vector3],
- unk2: Boolean,
- unk3: Int,
- unk4: Int,
- is_crouched: Boolean,
- unk6: Boolean,
- unk7: Boolean,
- unk8: Int,
- unk9: Long,
- unkA: Long
- ) extends Response
- final case class GenericObjectAction(guid: PlanetSideGUID, action: Int) extends Response
- final case class HitHint(source_guid: PlanetSideGUID) extends Response
- final case class InventoryState(
- obj: PlanetSideGameObject,
- parent_guid: PlanetSideGUID,
- start: Int,
- con_data: ConstructorData
- ) extends Response
- final case class InventoryState2(obj_guid: PlanetSideGUID, parent_guid: PlanetSideGUID, value: Int) extends Response
- final case class KickPassenger(seat_num: Int, kickedByDriver: Boolean, vehicle_guid: PlanetSideGUID) extends Response
- final case class LoadVehicle(vehicle: Vehicle, vtype: Int, vguid: PlanetSideGUID, vdata: ConstructorData)
- extends Response
- final case class MountVehicle(object_guid: PlanetSideGUID, seat: Int) extends Response
- final case class ObjectDelete(guid: PlanetSideGUID) extends Response
- final case class Ownership(vehicle_guid: PlanetSideGUID) extends Response
- final case class LoseOwnership(owner_guid: PlanetSideGUID, vehicle_guid: PlanetSideGUID)
- extends Response
- final case class PlanetsideAttribute(vehicle_guid: PlanetSideGUID, attribute_type: Int, attribute_value: Long)
- extends Response
- final case class Reload(weapon_guid: PlanetSideGUID) extends Response
- final case class RevealPlayer(player_guid: PlanetSideGUID) extends Response
- final case class SeatPermissions(vehicle_guid: PlanetSideGUID, seat_group: Int, permission: Long) extends Response
- final case class StowEquipment(
- vehicle_guid: PlanetSideGUID,
- slot: Int,
- itype: Int,
- iguid: PlanetSideGUID,
- idata: ConstructorData
- ) extends Response
- final case class WeaponDryFire(weapon_guid: PlanetSideGUID) extends Response
- final case class UnloadVehicle(vehicle: Vehicle, vehicle_guid: PlanetSideGUID) extends Response
- final case class UnstowEquipment(item_guid: PlanetSideGUID) extends Response
- final case class VehicleState(
- vehicle_guid: PlanetSideGUID,
- unk1: Int,
- pos: Vector3,
- ang: Vector3,
- vel: Option[Vector3],
- unk2: Option[Int],
- unk3: Int,
- unk4: Int,
- wheel_direction: Int,
- unk5: Boolean,
- unk6: Boolean
- ) extends Response
- final case class SendResponse(msg: PlanetSideGamePacket) extends Response
- final case class UpdateAmsSpawnPoint(list: List[SpawnTube]) extends Response
-
- final case class AttachToRails(vehicle_guid: PlanetSideGUID, rails_guid: PlanetSideGUID) extends Response
- final case class StartPlayerSeatedInVehicle(vehicle: Vehicle, pad: VehicleSpawnPad) extends Response
- final case class PlayerSeatedInVehicle(vehicle: Vehicle, pad: VehicleSpawnPad) extends Response
- final case class DetachFromRails(
- vehicle_guid: PlanetSideGUID,
- rails_guid: PlanetSideGUID,
- rails_pos: Vector3,
- rails_rot: Float
- ) extends Response
- final case class ServerVehicleOverrideStart(vehicle: Vehicle, pad: VehicleSpawnPad) extends Response
- final case class ServerVehicleOverrideEnd(vehicle: Vehicle, pad: VehicleSpawnPad) extends Response
- final case class ResetSpawnPad(pad_guid: PlanetSideGUID) extends Response
- final case class PeriodicReminder(reason: Reminders.Value, data: Option[Any] = None) extends Response
-
- final case class TransferPassengerChannel(
- old_channel: String,
- temp_channel: String,
- vehicle: Vehicle,
- vehicle_to_delete: PlanetSideGUID
- ) extends Response
-
- final case class KickCargo(cargo: Vehicle, speed: Int, delay: Long) extends Response
-
- final case class ChangeLoadout(
- target_guid: PlanetSideGUID,
- removed_weapons: List[(Equipment, PlanetSideGUID)],
- new_weapons: List[InventoryItem],
- old_inventory: List[(Equipment, PlanetSideGUID)],
- new_inventory: List[InventoryItem]
- ) extends Response
-}
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 bd6e02866..ae2ce9d51 100644
--- a/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala
+++ b/src/main/scala/net/psforever/services/vehicle/support/TurretUpgrader.scala
@@ -1,7 +1,7 @@
// Copyright (c) 2017 PSForever
package net.psforever.services.vehicle.support
-import akka.actor.Cancellable
+import akka.actor.{ActorContext, ActorRef, Cancellable, Props}
import net.psforever.objects.equipment.EquipmentSlot
import net.psforever.objects.{AmmoBox, Default, PlanetSideGameObject, Tool}
import net.psforever.objects.guid._
@@ -9,14 +9,29 @@ import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.turret.{FacilityTurret, TurretUpgrade, WeaponTurret}
import net.psforever.objects.vehicles.MountedWeapons
import net.psforever.objects.zones.Zone
+import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelopeOnly}
+import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.types.PlanetSideGUID
-import net.psforever.services.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions}
+import net.psforever.services.vehicle.VehicleAction
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
+case object TurretUpgradeSupport
+ extends EventServiceSupport {
+ def label: String = "turretUpgrader"
+ def constructor(context: ActorContext): ActorRef = {
+ context.actorOf(Props[TurretUpgrader](), name = "TurretUpgrader")
+ }
+}
+
+final case class TurretEnvelope(supportMessage: Any)
+ extends GenericSupportEnvelopeOnly {
+ def supportLabel: String = "turretUpgrader"
+}
+
class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] {
var task: Cancellable = Default.Cancellable
@@ -159,9 +174,10 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] {
seat.unmount(tplayer)
tplayer.VehicleSeated = None
if (tplayer.HasGUID) {
- context.parent ! VehicleServiceMessage(
+ context.parent ! MessageEnvelope(
zoneId,
- VehicleAction.KickPassenger(tplayer.GUID, 4, unk2=false, turretGUID)
+ tplayer.GUID,
+ VehicleAction.KickPassenger(4, unk2=false, turretGUID)
)
}
})
@@ -229,15 +245,16 @@ class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] {
trace(s"Wall turret finished ${target.Upgrade} upgrade")
val targetGUID = target.GUID
if (target.Health > 0) {
- target.Weapons
+ context.parent ! BundledEnvelope(target.Weapons
.map { case (index: Int, slot: EquipmentSlot) => (index, slot.Equipment) }
.collect {
case (index, Some(tool: Tool)) =>
- context.parent ! VehicleServiceMessage(
+ MessageEnvelope(
zone.id,
- VehicleAction.EquipmentInSlot(PlanetSideGUID(0), targetGUID, index, tool)
+ VehicleAction.EquipmentInSlot(targetGUID, index, tool)
)
}
+ )
}
Finalize(target, entry.upgrade)
}
diff --git a/src/main/scala/net/psforever/util/Config.scala b/src/main/scala/net/psforever/util/Config.scala
index c814904b6..f32c2adaf 100644
--- a/src/main/scala/net/psforever/util/Config.scala
+++ b/src/main/scala/net/psforever/util/Config.scala
@@ -131,7 +131,8 @@ case class AntiCheatConfig(
case class NetworkConfig(
session: SessionConfig,
- middleware: MiddlewareConfig
+ middleware: MiddlewareConfig,
+ eventCaching: CachedMessagesConfig
)
case class MiddlewareConfig(
@@ -147,6 +148,12 @@ case class SessionConfig(
outboundGraceTime: FiniteDuration
)
+case class CachedMessagesConfig(
+ flushCacheDelay: Long, //milliseconds
+ flushCacheMaxDelay: Long, //milliseconds
+ messageTrafficThreshold: Long
+)
+
case class GameConfig(
instantAction: InstantActionConfig,
amenityAutorepairRate: Float,
diff --git a/src/test/scala/objects/DamageModelTests.scala b/src/test/scala/objects/DamageModelTests.scala
index b19467e75..1dcd9757b 100644
--- a/src/test/scala/objects/DamageModelTests.scala
+++ b/src/test/scala/objects/DamageModelTests.scala
@@ -31,6 +31,9 @@ class DamageCalculationsTests extends Specification {
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
val target = Vehicle(GlobalDefinitions.fury)
target.Position = Vector3(10, 0, 0)
+ player.GUID = PlanetSideGUID(1)
+ projectile.GUID = PlanetSideGUID(2)
+ target.GUID = PlanetSideGUID(3)
val resprojectile = DamageInteraction(
SourceEntry(target),
ProjectileReason(
@@ -271,6 +274,7 @@ class DamageCalculationsTests extends Specification {
)
val minDamageBase = charge_weapon.Projectile.Charging.get.min.Damage0
val chargeBaseDamage = charge_weapon.Projectile.Damage0
+ charge_projectile.GUID = PlanetSideGUID(1)
"charge (none)" in {
val cprojectile = charge_projectile.quality(ProjectileQuality.Modified(0))
@@ -329,6 +333,7 @@ class DamageCalculationsTests extends Specification {
Vector3(2, 2, 0),
Vector3.Zero
)
+ flak_projectile.GUID = PlanetSideGUID(1)
"flak hit (resolution is splash, no degrade)" in {
val resfprojectile = DamageInteraction(
diff --git a/src/test/scala/objects/DamageableTest.scala b/src/test/scala/objects/DamageableTest.scala
index bd2381fb9..8c3357fe4 100644
--- a/src/test/scala/objects/DamageableTest.scala
+++ b/src/test/scala/objects/DamageableTest.scala
@@ -22,11 +22,9 @@ import net.psforever.objects.vital.{SpawningActivity, Vitality}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.types._
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.support.SupportActor
-import net.psforever.services.vehicle.support.TurretUpgrader
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.support.SupportActor
+import net.psforever.services.vehicle.support.TurretEnvelope
import org.specs2.mutable.Specification
import scala.concurrent.duration._
@@ -38,6 +36,9 @@ import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.base.DamageResolution
import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.vital.resolution.ResolutionCalculations.Output
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
+import net.psforever.services.vehicle.support.TurretUpgrader
class DamageableTest extends Specification {
val player1: Player = Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
@@ -328,7 +329,7 @@ class DamageableEntityDamageTest extends ActorTest {
val msg1 = avatarProbe.receiveOne(5000 milliseconds)
val msg2 = activityProbe.receiveOne(5000 milliseconds)
msg1 match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(ValidPlanetSideGUID(2), 0, 3600)) => ()
+ case MessageEnvelope("test", _, PlanetsideAttribute(ValidPlanetSideGUID(2), 0, 3600)) => ()
case _ => assert(false, "DamageableEntity:handle taking damage - player not messaged")
}
msg2 match {
@@ -402,13 +403,13 @@ class DamageableEntityDestroyedTest extends ActorTest {
val msg1_2 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg1_2.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg1_2(1) match {
- case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
+ case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
case _ => false
}
)
@@ -553,19 +554,19 @@ class DamageableAmenityTest extends ActorTest {
term.Actor ! Vitality.Damage(applyDamageTo)
val msg1234 = avatarProbe.receiveN(4, 3000 milliseconds)
msg1234.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => ()
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => ()
case _ => assert(false)
}
msg1234(1) match {
- case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => ()
+ case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => ()
case _ => assert(false)
}
msg1234(2) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 50, 1)) => ()
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 50, 1)) => ()
case _ => assert(false)
}
msg1234(3) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 51, 1)) => ()
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 51, 1)) => ()
case _ => assert(false)
}
assert(term.Health <= term.Definition.DamageDestroysAt)
@@ -641,7 +642,7 @@ class DamageableMountableDamageTest extends ActorTest {
val msg2 = activityProbe.receiveOne(5000 milliseconds)
assert(
msg1_3.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
@@ -656,9 +657,10 @@ class DamageableMountableDamageTest extends ActorTest {
)
assert(
msg1_3(1) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter2",
- AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(_, Vector3(2, 2, 2)))
+ _,
+ SendResponse(Seq(DamageWithPositionMessage(_, Vector3(2, 2, 2))))
) =>
true
case _ => false
@@ -744,11 +746,11 @@ class DamageableMountableDestroyTest extends ActorTest {
val msg3 = player2Probe.receiveOne(200 milliseconds)
msg12.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => ()
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => ()
case _ => assert(false)
}
msg12(1) match {
- case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => ()
+ case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => ()
case _ => assert(false)
}
msg3 match {
@@ -831,7 +833,7 @@ class DamageableWeaponTurretDamageTest extends ActorTest {
val msg4 = avatarProbe.receiveOne(500 milliseconds)
assert(
msg12 match {
- case VehicleServiceMessage("test", VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
@@ -846,9 +848,10 @@ class DamageableWeaponTurretDamageTest extends ActorTest {
)
assert(
msg4 match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter2",
- AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(_, Vector3(2, 2, 2)))
+ _,
+ SendResponse(Seq(DamageWithPositionMessage(_, Vector3(2, 2, 2))))
) =>
true
case _ => false
@@ -931,9 +934,10 @@ class DamageableWeaponTurretJammerTest extends ActorTest {
val msg12 = vehicleProbe.receiveN(2, 500 milliseconds)
assert(
msg12.head match {
- case VehicleServiceMessage(
+ case MessageEnvelope(
"test",
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, PlanetSideGUID(2), 27, 1)
+ _,
+ PlanetsideAttribute(PlanetSideGUID(2), 27, 1)
) =>
true
case _ => false
@@ -941,9 +945,10 @@ class DamageableWeaponTurretJammerTest extends ActorTest {
)
assert(
msg12(1) match {
- case VehicleServiceMessage(
+ case MessageEnvelope(
"test",
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, PlanetSideGUID(5), 27, 1)
+ _,
+ PlanetsideAttribute(PlanetSideGUID(5), 27, 1)
) =>
true
case _ => false
@@ -1070,12 +1075,12 @@ class DamageableWeaponTurretDestructionTest extends ActorTest {
val msg3 = player2Probe.receiveOne(200 milliseconds)
val msg56 = vehicleProbe.receiveN(2, 200 milliseconds)
msg12_4.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => ;
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => ;
case _ =>
assert(false, s"DamageableWeaponTurretDestructionTest-1: ${msg12_4.head}")
}
msg12_4(1) match {
- case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => ;
+ case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => ;
case _ =>
assert(false, s"DamageableWeaponTurretDestructionTest-2: ${msg12_4(1)}")
}
@@ -1085,17 +1090,17 @@ class DamageableWeaponTurretDestructionTest extends ActorTest {
assert(false, s"DamageableWeaponTurretDestructionTest-3: player not dead - $msg3")
}
msg12_4(2) match {
- case AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(0), PlanetSideGUID(5), _)) => ;
+ case MessageEnvelope("test", _, ObjectDelete(PlanetSideGUID(5), _)) => ;
case _ =>
assert(false, s"DamageableWeaponTurretDestructionTest-4: ${msg12_4(2)}")
}
msg56.head match {
- case VehicleServiceMessage.TurretUpgrade(SupportActor.ClearSpecific(List(t), _)) if turret eq t => ;
+ case TurretEnvelope(SupportActor.ClearSpecific(List(t), _)) if turret eq t => ;
case _ =>
assert(false, s"DamageableWeaponTurretDestructionTest-5: ${msg56.head}")
}
msg56(1) match {
- case VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(t, _, TurretUpgrade.None, _)) if t eq turret => ()
+ case TurretEnvelope(TurretUpgrader.AddTask(t, _, TurretUpgrade.None, _)) if t eq turret => ()
case _ => assert(false, s"DamageableWeaponTurretDestructionTest-6: ${msg56(1)}")
}
assert(turret.Health <= turret.Definition.DamageDestroysAt)
@@ -1180,13 +1185,13 @@ class DamageableVehicleDamageTest extends ActorTest {
val msg4 = avatarProbe.receiveOne(200 milliseconds)
assert(
msg12.head match {
- case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), PlanetSideGUID(1), 68, _)) => true
+ case MessageEnvelope(_, _, PlanetsideAttribute(PlanetSideGUID(1), 68, _)) => true
case _ => false
}
)
assert(
msg12(1) match {
- case VehicleServiceMessage("test", VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), PlanetSideGUID(1), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 0, _)) => true
case _ => false
}
)
@@ -1201,9 +1206,10 @@ class DamageableVehicleDamageTest extends ActorTest {
)
assert(
msg4 match {
- case AvatarServiceMessage(
- "TestCharacter2",
- AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(9, Vector3(2, 0, 0)))
+ case MessageEnvelope(
+ "TestCharacter2",
+ _,
+ SendResponse(Seq(DamageWithPositionMessage(9, Vector3(2, 0, 0))))
) =>
true
case _ => false
@@ -1316,11 +1322,11 @@ class DamageableVehicleDamageMountedTest extends FreedContextActorTest {
val msg3 = activityProbe.receiveOne(500 milliseconds)
val msg45 = avatarProbe.receiveN(2,500 milliseconds)
msg12.head match {
- case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), PlanetSideGUID(1), 68, _)) => ;
+ case MessageEnvelope(_, _, PlanetsideAttribute(PlanetSideGUID(1), 68, _)) => ;
case _ => assert(false)
}
msg12(1) match {
- case VehicleServiceMessage("test", VehicleAction.PlanetsideAttribute(PlanetSideGUID(0), PlanetSideGUID(1), 0, _)) => ;
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 0, _)) => ;
case _ => assert(false)
}
msg3 match {
@@ -1331,16 +1337,18 @@ class DamageableVehicleDamageMountedTest extends FreedContextActorTest {
case _ => assert(false)
}
msg45.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter2",
- AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(400, Vector3(2, 0, 0)))
+ _,
+ SendResponse(Seq(DamageWithPositionMessage(400, Vector3(2, 0, 0))))
) => ;
case _ => assert(false)
}
msg45(1) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter3",
- AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(0, Vector3(2, 0, 0)))
+ _,
+ SendResponse(Seq(DamageWithPositionMessage(0, Vector3(2, 0, 0))))
) => ;
case _ => assert(false)
}
@@ -1451,9 +1459,10 @@ class DamageableVehicleJammeringMountedTest extends FreedContextActorTest {
player3Probe.expectNoMessage(200 milliseconds)
assert(
msg12 match {
- case VehicleServiceMessage(
+ case MessageEnvelope(
"test",
- VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, PlanetSideGUID(4), 27, 1)
+ _,
+ PlanetsideAttribute(PlanetSideGUID(4), 27, 1)
) =>
true
case _ => false
@@ -1545,11 +1554,11 @@ class DamageableVehicleDestroyTest extends ActorTest {
val msg124 = avatarProbe.receiveN(2, 3000 milliseconds)
val msg3 = player2Probe.receiveOne(3000 milliseconds)
msg124.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => ()
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 0, _)) => ()
case _ => assert(false)
}
msg124(1) match {
- case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(1), _, _, Vector3(1, 0, 0))) => ()
+ case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(1), _, _, Vector3(1, 0, 0))) => ()
case _ => assert(false)
}
msg3 match {
@@ -1710,31 +1719,31 @@ class DamageableVehicleDestroyTest extends ActorTest {
// vehicleProbe.expectNoMessage(10 milliseconds)
// assert(
// msg_avatar.exists({
-// case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(4), 0, _)) => true
+// case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(4), 0, _)) => true
// case _ => false
// })
// )
// assert(
// msg_avatar.exists({
-// case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(4), _, _, Vector3(1, 0, 0))) => true
+// case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(4), _, _, Vector3(1, 0, 0))) => true
// case _ => false
// })
// )
// assert(
// msg_avatar.exists({
-// case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => true
+// case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 0, _)) => true
// case _ => false
// })
// )
// assert(
// msg_avatar.exists({
-// case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(1), _, _, Vector3(1, 0, 0))) => true
+// case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(1), _, _, Vector3(1, 0, 0))) => true
// case _ => false
// })
// )
// assert(
// msg_avatar.exists({
-// case AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(0), PlanetSideGUID(2), _)) => true
+// case MessageEnvelope("test", _, ObjectDelete(PlanetSideGUID(0), PlanetSideGUID(2), _)) => true
// case _ => false
// })
// )
@@ -1752,9 +1761,10 @@ class DamageableVehicleDestroyTest extends ActorTest {
// )
// assert(
// msg_vehicle.exists({
-// case VehicleServiceMessage(
+// case MessageEnvelope(
// "test",
-// VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, PlanetSideGUID(4), 27, 0)
+// _,
+// PlanetsideAttribute(PlanetSideGUID(4), 27, 0)
// ) =>
// true
// case _ => false
@@ -1762,9 +1772,10 @@ class DamageableVehicleDestroyTest extends ActorTest {
// )
// assert(
// msg_vehicle.exists({
-// case VehicleServiceMessage(
+// case MessageEnvelope(
// "test",
-// VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, PlanetSideGUID(1), 68, 0)
+// _,
+// PlanetsideAttribute(PlanetSideGUID(1), 68, 0)
// ) =>
// true
// case _ => false
diff --git a/src/test/scala/objects/DeployableBehaviorTest.scala b/src/test/scala/objects/DeployableBehaviorTest.scala
index e9ac7df88..77b74fc18 100644
--- a/src/test/scala/objects/DeployableBehaviorTest.scala
+++ b/src/test/scala/objects/DeployableBehaviorTest.scala
@@ -13,9 +13,9 @@ import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.MaxNumberSource
import net.psforever.objects.zones.{Zone, ZoneDeployableActor, ZoneMap}
import net.psforever.packet.game._
-import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{ObjectDelete, SendResponse}
+import net.psforever.services.local.LocalAction
import net.psforever.types._
import scala.collection.mutable
@@ -50,16 +50,14 @@ class DeployableBehaviorSetupTest extends ActorTest {
val eventsMsgs = eventsProbe.receiveN(2, 10.seconds)
eventsMsgs.head match {
- case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
+ case MessageEnvelope("test", _, LocalAction.DeployItem(obj)) =>
assert(obj eq jmine, "self-setup test - not same mine")
case _ =>
assert( false, "self-setup test - wrong deploy message")
}
eventsMsgs(1) match {
- case LocalServiceMessage(
- "TR",
+ case MessageEnvelope("TR", _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Build,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.DisruptorMine, Vector3(1,2,3), PlanetSideGUID(0))
)
@@ -160,39 +158,36 @@ class DeployableBehaviorSetupOwnedP2Test extends FreedContextActorTest {
//assert(false, "test needs to be fixed")
val eventsMsgs = eventsProbe.receiveN(7, 10.seconds)
eventsMsgs.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(
- Service.defaultPlayerGUID,
- ObjectDeployedMessage(0, "jammer_mine", DeployOutcome.Success, 1, 20)
- )
+ _,
+ SendResponse(Seq(ObjectDeployedMessage(0, "jammer_mine", DeployOutcome.Success, 1, 20)))
) => ;
case _ =>
assert(false, "owned setup test, 2 - did not receive build confirmation")
}
eventsMsgs(1) match {
- case LocalServiceMessage("TestCharacter1", LocalAction.DeployableUIFor(DeployedItem.jammer_mine)) => ;
+ case MessageEnvelope("TestCharacter1", _, LocalAction.DeployableUIFor(DeployedItem.jammer_mine)) => ;
case _ => assert(false, "owned setup test, 2 - did not receive ui update")
}
eventsMsgs(2) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"test",
- LocalAction.TriggerEffectLocation(PlanetSideGUID(3), "spawn_object_effect", Vector3(1,2,3), Vector3(4,5,6))
+ PlanetSideGUID(3),
+ LocalAction.TriggerEffectLocation("spawn_object_effect", Vector3(1,2,3), Vector3(4,5,6))
) => ;
case _ => assert(false, "owned setup test, 2 - no spawn fx")
}
eventsMsgs(3) match {
- case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
+ case MessageEnvelope("test", _, LocalAction.DeployItem(obj)) =>
assert(obj eq jmine, "owned setup test, 2 - not same mine")
case _ =>
assert( false, "owned setup test, 2 - wrong deploy message")
}
//the message order can be jumbled from here-on
eventsMsgs(4) match {
- case LocalServiceMessage(
- "TR",
+ case MessageEnvelope("TR", _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Build,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.DisruptorMine, Vector3(1,2,3), PlanetSideGUID(3))
)
@@ -201,15 +196,16 @@ class DeployableBehaviorSetupOwnedP2Test extends FreedContextActorTest {
assert(false, "owned setup test, 2 - no icon or wrong icon")
}
eventsMsgs(5) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(Service.defaultPlayerGUID, GenericObjectActionMessage(PlanetSideGUID(1), 21))
+ _,
+ SendResponse(Seq(GenericObjectActionMessage(PlanetSideGUID(1), 21)))
) => ;
case _ =>
assert(false, "owned setup test, 2 - build action not reset (GOAM21)")
}
eventsMsgs(6) match {
- case AvatarServiceMessage("test", AvatarAction.ObjectDelete(Service.defaultPlayerGUID, PlanetSideGUID(2), 0)) => ;
+ case MessageEnvelope("test", _, ObjectDelete(PlanetSideGUID(2), 0)) => ;
case _ =>
assert(false, "owned setup test, 2 - construction tool not deleted")
}
@@ -250,14 +246,13 @@ class DeployableBehaviorDeconstructTest extends ActorTest {
jmine.Actor ! Deployable.Deconstruct()
val eventsMsgs = eventsProbe.receiveN(2, 10.seconds)
eventsMsgs.head match {
- case LocalServiceMessage("test", LocalAction.EliminateDeployable(_, PlanetSideGUID(1), Vector3(1,2,3), 2)) => ;
+ case MessageEnvelope("test", _, LocalAction.EliminateDeployable(_, PlanetSideGUID(1), Vector3(1,2,3), 2)) => ;
case _ => assert(false, "deconstruct test - not eliminating deployable")
}
eventsMsgs(1) match {
- case LocalServiceMessage(
- "TR",
+ case MessageEnvelope(
+ "TR", _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.DisruptorMine, Vector3(1, 2, 3), PlanetSideGUID(0))
)
@@ -313,15 +308,14 @@ class DeployableBehaviorDeconstructOwnedTest extends FreedContextActorTest {
jmine.Actor ! Deployable.Deconstruct()
val eventsMsgs = eventsProbe.receiveN(3, 10.seconds)
eventsMsgs.head match {
- case LocalServiceMessage("test",LocalAction.EliminateDeployable(mine, ValidPlanetSideGUID(1), Vector3(1.0,2.0,3.0),2))
+ case MessageEnvelope("test", _, LocalAction.EliminateDeployable(mine, ValidPlanetSideGUID(1), Vector3(1.0,2.0,3.0),2))
if mine eq jmine => ;
case _ => assert(false, "owned deconstruct test - not eliminating deployable")
}
eventsMsgs(1) match {
- case LocalServiceMessage(
- "TR",
+ case MessageEnvelope(
+ "TR", _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.DisruptorMine, Vector3(1, 2, 3), PlanetSideGUID(0))
)
@@ -329,7 +323,7 @@ class DeployableBehaviorDeconstructOwnedTest extends FreedContextActorTest {
case _ => assert(false, "owned deconstruct test - not removing icon")
}
eventsMsgs(2) match {
- case LocalServiceMessage("TestCharacter1", LocalAction.DeployableUIFor(DeployedItem.jammer_mine)) => ;
+ case MessageEnvelope("TestCharacter1", _, LocalAction.DeployableUIFor(DeployedItem.jammer_mine)) => ;
case _ => assert(false, "")
}
diff --git a/src/test/scala/objects/DeployableTest.scala b/src/test/scala/objects/DeployableTest.scala
index b02c1ed21..88536ee18 100644
--- a/src/test/scala/objects/DeployableTest.scala
+++ b/src/test/scala/objects/DeployableTest.scala
@@ -12,19 +12,20 @@ import net.psforever.objects.guid.source.MaxNumberSource
import net.psforever.objects.serverobject.mount.{MountInfo, Mountable, SeatDefinition}
import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.{Zone, ZoneDeployableActor, ZoneMap}
-import net.psforever.objects.{TurretDeployable, _}
+import net.psforever.objects._
import net.psforever.packet.game.{DeployableIcon, DeployableInfo, DeploymentAction}
import net.psforever.types._
import org.specs2.mutable.Specification
import net.psforever.services.Service
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.local.LocalAction
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.vital.base.DamageResolution
import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.projectile.ProjectileReason
import akka.actor.typed.scaladsl.adapter._
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
+import net.psforever.services.base.envelope.MessageEnvelope
import scala.collection.mutable
import scala.concurrent.duration._
@@ -370,8 +371,9 @@ class ExplosiveDeployableJammerTest extends ActorTest {
case _ => assert(false, "")
}
// eventMsgs.head match {
-// case LocalServiceMessage(
+// case MessageEnvelope(
// "NC",
+// _,
// LocalAction.DeployableMapIcon(
// ValidPlanetSideGUID(0),
// DeploymentAction.Dismiss,
@@ -381,14 +383,14 @@ class ExplosiveDeployableJammerTest extends ActorTest {
// case _ => assert(false, "")
// }
eventMsgs(1) match {
- case LocalServiceMessage("test", LocalAction.Detonate(PlanetSideGUID(1), _)) => ;
+ case MessageEnvelope("test", _, LocalAction.Detonate(PlanetSideGUID(1), _)) => ;
case _ => assert(false, "")
}
eventMsgs(2) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NC",
+ _,
LocalAction.DeployableMapIcon(
- ValidPlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(ValidPlanetSideGUID(1), DeployableIcon.HEMine, Vector3.Zero, ValidPlanetSideGUID(0))
)
@@ -396,10 +398,11 @@ class ExplosiveDeployableJammerTest extends ActorTest {
case _ => assert(false, "")
}
eventMsgs(3) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"test",
+ _,
AvatarAction.Destroy(
- ValidPlanetSideGUID(1),
+ ValidPlanetSideGUID(1),
ValidPlanetSideGUID(3),
ValidPlanetSideGUID(0),
Vector3.Zero
@@ -484,15 +487,15 @@ class ExplosiveDeployableJammerExplodeTest extends ActorTest {
case _ => assert(false, "")
}
eventMsgs(1) match {
- case LocalServiceMessage("test", LocalAction.Detonate(PlanetSideGUID(2), target))
+ case MessageEnvelope("test", _, LocalAction.Detonate(PlanetSideGUID(2), target))
if target eq h_mine => ()
case _ => assert(false, "")
}
eventMsgs(2) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NC",
+ _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(2), DeployableIcon.HEMine, _, PlanetSideGUID(0))
)
@@ -577,10 +580,10 @@ class ExplosiveDeployableDestructionTest extends ActorTest {
player1Probe.expectNoMessage(200 milliseconds)
val p2Msgs = player2Probe.receiveN(1, 200 milliseconds)
eventMsgs.head match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NC",
+ _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(2), DeployableIcon.HEMine, _, PlanetSideGUID(0))
)
@@ -588,14 +591,14 @@ class ExplosiveDeployableDestructionTest extends ActorTest {
case _ => assert(false, "")
}
eventMsgs(1) match {
- case AvatarServiceMessage(
- "test",
- AvatarAction.Destroy(PlanetSideGUID(2), PlanetSideGUID(3), Service.defaultPlayerGUID, Vector3.Zero)
+ case MessageEnvelope(
+ "test", _,
+ AvatarAction.Destroy(PlanetSideGUID(2), PlanetSideGUID(3), Default.GUID0, Vector3.Zero)
) => ;
case _ => assert(false, "")
}
eventMsgs(2) match {
- case LocalServiceMessage("test", LocalAction.TriggerEffect(_, "detonate_damaged_mine", PlanetSideGUID(2))) => ;
+ case MessageEnvelope("test", _, LocalAction.TriggerEffect("detonate_damaged_mine", PlanetSideGUID(2))) => ;
case _ => assert(false, "")
}
p2Msgs.head match {
diff --git a/src/test/scala/objects/DeploymentTest.scala b/src/test/scala/objects/DeploymentTest.scala
index 0b86da3f9..685479768 100644
--- a/src/test/scala/objects/DeploymentTest.scala
+++ b/src/test/scala/objects/DeploymentTest.scala
@@ -8,9 +8,10 @@ import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.{GlobalDefinitions, Vehicle}
import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior}
import net.psforever.objects.zones.{Zone, ZoneMap}
+import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{DriveState, PlanetSideEmpire, PlanetSideGUID, Vector3}
import org.specs2.mutable.Specification
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.vehicle.VehicleAction
import scala.concurrent.duration.Duration
@@ -72,9 +73,10 @@ class DeploymentBehavior2Test extends ActorTest {
case _ => assert(false, "")
}
reply2.head match {
- case VehicleServiceMessage(
+ case MessageEnvelope(
"test",
- VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
+ _,
+ VehicleAction.DeployRequest(PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
) => ()
case _ => assert(false, "")
}
@@ -84,9 +86,10 @@ class DeploymentBehavior2Test extends ActorTest {
case _ => assert(false, "")
}
reply2(1) match {
- case VehicleServiceMessage(
+ case MessageEnvelope(
"test",
- VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
+ _,
+ VehicleAction.DeployRequest(PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
) => ()
case _ => assert(false, "")
}
@@ -100,9 +103,10 @@ class DeploymentBehavior2Test extends ActorTest {
case _ => assert(false, "")
}
reply4.head match {
- case VehicleServiceMessage(
+ case MessageEnvelope(
"test",
- VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
+ _,
+ VehicleAction.DeployRequest(PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
) => ()
case _ => assert(false, "")
}
@@ -112,9 +116,10 @@ class DeploymentBehavior2Test extends ActorTest {
case _ => assert(false, "")
}
reply4(1) match {
- case VehicleServiceMessage(
+ case MessageEnvelope(
"test",
- VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
+ _,
+ VehicleAction.DeployRequest(PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
) => ()
case _ => assert(false, "")
}
@@ -140,9 +145,10 @@ class DeploymentBehavior3Test extends ActorTest {
case _ => assert(false, "")
}
reply2.head match {
- case VehicleServiceMessage(
- "test",
- VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
+ case MessageEnvelope(
+ "test",
+ _,
+ VehicleAction.DeployRequest(PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
) => ()
case _ => assert(false, "")
}
@@ -152,9 +158,10 @@ class DeploymentBehavior3Test extends ActorTest {
case _ => assert(false, "")
}
reply2(1) match {
- case VehicleServiceMessage(
- "test",
- VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
+ case MessageEnvelope(
+ "test",
+ _,
+ VehicleAction.DeployRequest(PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
) => ()
case _ => assert(false, "")
}
@@ -168,9 +175,10 @@ class DeploymentBehavior3Test extends ActorTest {
case _ => assert(false, "")
}
reply4.head match {
- case VehicleServiceMessage(
- "test",
- VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
+ case MessageEnvelope(
+ "test",
+ _,
+ VehicleAction.DeployRequest(PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
) => ()
case _ => assert(false, "")
}
@@ -180,9 +188,10 @@ class DeploymentBehavior3Test extends ActorTest {
case _ => assert(false, "")
}
reply4(1) match {
- case VehicleServiceMessage(
- "test",
- VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
+ case MessageEnvelope(
+ "test",
+ _,
+ VehicleAction.DeployRequest(PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
) => ()
case _ => assert(false, "")
}
diff --git a/src/test/scala/objects/DoorTest.scala b/src/test/scala/objects/DoorTest.scala
index 15d9db03b..48191ec59 100644
--- a/src/test/scala/objects/DoorTest.scala
+++ b/src/test/scala/objects/DoorTest.scala
@@ -12,7 +12,9 @@ import net.psforever.objects.{Default, GlobalDefinitions, Player}
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.zones.{Zone, ZoneMap}
-import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse}
+import net.psforever.services.base.envelope.GenericResponseEnvelope
+import net.psforever.services.local.support.DoorMessage
+import net.psforever.services.local.LocalAction
import net.psforever.types._
import org.specs2.mutable.Specification
@@ -77,7 +79,7 @@ class DoorControlOpenTest extends ActorTest {
door.Actor ! CommonMessages.Use(player)
val reply = probe.receiveOne(1000 milliseconds)
assert(reply match {
- case LocalServiceMessage("test", LocalAction.DoorOpens(PlanetSideGUID(0), _, d)) => d eq door
+ case DoorMessage("test", LocalAction.DoorOpens(_, thisDoor), _) => thisDoor eq door
case _ => false
})
assert(door.Open.isDefined)
@@ -105,7 +107,7 @@ class DoorControlAlreadyOpenTest extends ActorTest {
door.Actor.tell(CommonMessages.Use(player), probe.ref)
val reply = probe.receiveOne(1000 milliseconds)
assert(reply match {
- case LocalServiceResponse("test", _, LocalResponse.DoorOpens(guid)) => guid == door.GUID
+ case GenericResponseEnvelope("test", _, LocalAction.DoorOpens(_, thisDoor)) => thisDoor eq door
case _ => false
})
}
diff --git a/src/test/scala/objects/FacilityTurretTest.scala b/src/test/scala/objects/FacilityTurretTest.scala
index 4fcc4f218..105652f08 100644
--- a/src/test/scala/objects/FacilityTurretTest.scala
+++ b/src/test/scala/objects/FacilityTurretTest.scala
@@ -19,8 +19,9 @@ import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.{InventoryStateMessage, RepairMessage}
import net.psforever.types._
import org.specs2.mutable.Specification
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
+import net.psforever.services.vehicle.VehicleAction
import scala.collection.mutable
import scala.concurrent.duration._
@@ -259,10 +260,10 @@ class FacilityTurretControlRestorationTest extends ActorTest {
val msg4 = vehicleProbe.receiveOne(500 milliseconds)
assert(
msg12345.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction
- .SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(8), _, PlanetSideGUID(7), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(8), _, PlanetSideGUID(7), _)))
) =>
true
case _ => false
@@ -270,27 +271,28 @@ class FacilityTurretControlRestorationTest extends ActorTest {
)
assert(
msg12345(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg12345(2) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 50, 0)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 50, 0)) => true
case _ => false
}
)
assert(
msg12345(3) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 51, 0)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 51, 0)) => true
case _ => false
}
)
assert(
msg12345(4) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(2), _))
+ _,
+ SendResponse(Seq(RepairMessage(PlanetSideGUID(2), _)))
) =>
true
case _ => false
@@ -298,7 +300,7 @@ class FacilityTurretControlRestorationTest extends ActorTest {
)
assert(
msg4 match {
- case VehicleServiceMessage("test", VehicleAction.EquipmentInSlot(_, PlanetSideGUID(2), 1, t))
+ case MessageEnvelope("test", _, VehicleAction.EquipmentInSlot(PlanetSideGUID(2), 1, t))
if t eq turretWeapon =>
true
case _ => false
diff --git a/src/test/scala/objects/GeneratorTest.scala b/src/test/scala/objects/GeneratorTest.scala
index ef2c175e4..feeea8c2e 100644
--- a/src/test/scala/objects/GeneratorTest.scala
+++ b/src/test/scala/objects/GeneratorTest.scala
@@ -24,7 +24,9 @@ import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.{InventoryStateMessage, RepairMessage, TriggerEffectMessage}
import net.psforever.types._
import org.specs2.mutable.Specification
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import scala.concurrent.duration._
@@ -118,7 +120,7 @@ class GeneratorControlDamageTest extends ActorTest {
val msg_building = buildingProbe.receiveOne(500 milliseconds)
assert(
msg_avatar match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
@@ -203,7 +205,7 @@ class GeneratorControlCriticalTest extends ActorTest {
val msg_building = buildingProbe.receiveOne(500 milliseconds)
assert(
msg_avatar match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
@@ -312,21 +314,22 @@ class GeneratorControlDestroyedTest extends ActorTest {
)
assert(
msg_avatar2.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar2(1) match {
- case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
+ case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
case _ => false
}
)
assert(
msg_avatar2(2) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"test",
- AvatarAction.SendResponse(_, TriggerEffectMessage(PlanetSideGUID(2), "explosion_generator", None, None))
+ _,
+ SendResponse(Seq(TriggerEffectMessage(PlanetSideGUID(2), "explosion_generator", None, None)))
) =>
true
case _ => false
@@ -440,21 +443,22 @@ class GeneratorControlKillsTest extends ActorTest {
)
assert(
msg_avatar2.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar2(1) match {
- case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
+ case MessageEnvelope("test", _, AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
case _ => false
}
)
assert(
msg_avatar2(2) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"test",
- AvatarAction.SendResponse(_, TriggerEffectMessage(PlanetSideGUID(2), "explosion_generator", None, None))
+ _,
+ SendResponse(Seq(TriggerEffectMessage(PlanetSideGUID(2), "explosion_generator", None, None)))
) =>
true
case _ => false
@@ -818,10 +822,10 @@ class GeneratorControlRepairPastRestorePoint extends ActorTest {
val msg_building = buildingProbe.receiveOne(200 milliseconds)
assert(
msg_avatar.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction
- .SendResponse(_, InventoryStateMessage(ValidPlanetSideGUID(5), _, ValidPlanetSideGUID(4), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(ValidPlanetSideGUID(5), _, ValidPlanetSideGUID(4), _)))
) =>
true
case _ => false
@@ -829,15 +833,16 @@ class GeneratorControlRepairPastRestorePoint extends ActorTest {
)
assert(
msg_avatar(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, RepairMessage(ValidPlanetSideGUID(2), _))
+ _,
+ SendResponse(Seq(RepairMessage(ValidPlanetSideGUID(2), _)))
) =>
true
case _ => false
diff --git a/src/test/scala/objects/OrbitalShuttlePadTest.scala b/src/test/scala/objects/OrbitalShuttlePadTest.scala
index 04eb3f252..170316a62 100644
--- a/src/test/scala/objects/OrbitalShuttlePadTest.scala
+++ b/src/test/scala/objects/OrbitalShuttlePadTest.scala
@@ -24,7 +24,7 @@ import scala.concurrent.duration._
class OrbitalShuttlePadControlTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._
val services: ActorRef = ServiceManager.boot(system)
- services ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
+ services ! ServiceManager.Register(GalaxyService(), "galaxy")
services ! ServiceManager.Register(Props[HartService](), "hart")
expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]()
@@ -82,7 +82,7 @@ class OrbitalShuttlePadControlTest extends FreedContextActorTest {
"startup and create the shuttle" in {
assert(building.Amenities.size == 9)
assert(vehicles.isEmpty)
- pad.Actor ! Service.Startup()
+ pad.Actor ! Service.Startup
expectNoMessage(max = 5 seconds)
assert(building.Amenities.size == 10)
assert(vehicles.size == 1)
diff --git a/src/test/scala/objects/PlayerControlTest.scala b/src/test/scala/objects/PlayerControlTest.scala
index 3c343b439..eeee7f3b5 100644
--- a/src/test/scala/objects/PlayerControlTest.scala
+++ b/src/test/scala/objects/PlayerControlTest.scala
@@ -24,7 +24,9 @@ import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.vital.resolution.ResolutionCalculations.Output
import net.psforever.packet.game._
import net.psforever.types._
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{HintsAtAttacker, PlanetsideAttribute, SendResponse}
import scala.concurrent.duration._
@@ -68,9 +70,10 @@ class PlayerControlHealTest extends ActorTest {
val msg_avatar = avatarProbe.receiveN(4, 500 milliseconds)
assert(
msg_avatar.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _)))
) =>
true
case _ => false
@@ -78,25 +81,27 @@ class PlayerControlHealTest extends ActorTest {
)
assert(
msg_avatar(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
- case AvatarServiceMessage(
- "TestCharacter2",
- AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 55, 1)
- ) =>
+ case MessageEnvelope(
+ "TestCharacter2",
+ _,
+ PlanetsideAttribute(PlanetSideGUID(2), 55, 1)
+ ) =>
true
case _ => false
}
)
assert(
msg_avatar(3) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, RepairMessage(PlanetSideGUID(2), _))
+ _,
+ SendResponse(Seq(RepairMessage(PlanetSideGUID(2), _)))
) =>
true
case _ => false
@@ -146,9 +151,10 @@ class PlayerControlHealSelfTest extends ActorTest {
val msg_avatar1 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg_avatar1.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _)))
) =>
true
case _ => false
@@ -156,7 +162,7 @@ class PlayerControlHealSelfTest extends ActorTest {
)
assert(
msg_avatar1(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 0, _)) => true
case _ => false
}
)
@@ -169,9 +175,10 @@ class PlayerControlHealSelfTest extends ActorTest {
val msg_avatar2 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg_avatar2.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _)))
) =>
true
case _ => false
@@ -179,7 +186,7 @@ class PlayerControlHealSelfTest extends ActorTest {
)
assert(
msg_avatar2(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 0, _)) => true
case _ => false
}
)
@@ -229,9 +236,10 @@ class PlayerControlRepairTest extends ActorTest {
val msg_avatar = avatarProbe.receiveN(5, 1000 milliseconds)
assert(
msg_avatar.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _)))
) =>
true
case _ => false
@@ -239,25 +247,27 @@ class PlayerControlRepairTest extends ActorTest {
)
assert(
msg_avatar(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 4, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 4, _)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
- case AvatarServiceMessage(
- "TestCharacter2",
- AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 56, 1)
- ) =>
+ case MessageEnvelope(
+ "TestCharacter2",
+ _,
+ PlanetsideAttribute(PlanetSideGUID(2), 56, 1)
+ ) =>
true
case _ => false
}
)
assert(
msg_avatar(3) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, RepairMessage(PlanetSideGUID(2), _))
+ _,
+ SendResponse(Seq(RepairMessage(PlanetSideGUID(2), _)))
) =>
true
case _ => false
@@ -265,9 +275,10 @@ class PlayerControlRepairTest extends ActorTest {
)
assert(
msg_avatar(4) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter2",
- AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 56, 1)
+ _,
+ PlanetsideAttribute(PlanetSideGUID(2), 56, 1)
) =>
true
case _ => false
@@ -319,9 +330,10 @@ class PlayerControlRepairSelfTest extends ActorTest {
val msg_avatar1 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg_avatar1.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _)))
) =>
true
case _ => false
@@ -329,7 +341,7 @@ class PlayerControlRepairSelfTest extends ActorTest {
)
assert(
msg_avatar1(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 4, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 4, _)) => true
case _ => false
}
)
@@ -342,9 +354,10 @@ class PlayerControlRepairSelfTest extends ActorTest {
val msg_avatar2 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg_avatar2.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _)))
) =>
true
case _ => false
@@ -352,7 +365,7 @@ class PlayerControlRepairSelfTest extends ActorTest {
)
assert(
msg_avatar2(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 4, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 4, _)) => true
case _ => false
}
)
@@ -425,7 +438,7 @@ class PlayerControlDamageTest extends ActorTest {
val msg_activity = activityProbe.receiveOne(200 milliseconds)
assert(
msg_avatar.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 4, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 4, _)) => true
case _ => false
}
)
@@ -437,7 +450,7 @@ class PlayerControlDamageTest extends ActorTest {
)
assert(
msg_avatar(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
@@ -452,9 +465,10 @@ class PlayerControlDamageTest extends ActorTest {
)
assert(
msg_avatar(2) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter2",
- AvatarAction.HitHint(PlanetSideGUID(1), PlanetSideGUID(2))
+ PlanetSideGUID(1),
+ HintsAtAttacker(PlanetSideGUID(2))
) =>
true
case _ => false
@@ -537,7 +551,7 @@ class PlayerControlDeathStandingTest extends ActorTest {
activityProbe.expectNoMessage(200 milliseconds)
assert(
msg_avatar.head match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 4, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 4, _)) => true
case _ => false
}
)
@@ -549,28 +563,29 @@ class PlayerControlDeathStandingTest extends ActorTest {
)
assert(
msg_avatar(1) match {
- case AvatarServiceMessage("TestCharacter2", AvatarAction.Killed(PlanetSideGUID(2), _, None)) => true
+ case MessageEnvelope("TestCharacter2", _, AvatarAction.Killed(_, None)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(3) match {
- case AvatarServiceMessage("TestCharacter2", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 7, _)) =>
+ case MessageEnvelope("TestCharacter2", _, PlanetsideAttribute(PlanetSideGUID(2), 7, _)) =>
true
case _ => false
}
)
assert(
msg_avatar(4) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter2",
- AvatarAction.SendResponse(_, DestroyMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _))
+ _,
+ SendResponse(Seq(DestroyMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _)))
) =>
true
case _ => false
@@ -663,8 +678,9 @@ class PlayerControlDeathStandingTest extends ActorTest {
// )
// assert(
// msg_avatar.head match {
-// case AvatarServiceMessage(
+// case MessageEnvelope(
// "TestCharacter2",
+// _,
// AvatarAction.Killed(PlanetSideGUID(2), _, Some(PlanetSideGUID(7)))
// ) =>
// true
@@ -673,15 +689,16 @@ class PlayerControlDeathStandingTest extends ActorTest {
// )
// assert(
// msg_avatar(1) match {
-// case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+// case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
// case _ => false
// }
// )
// assert(
// msg_avatar(2) match {
-// case AvatarServiceMessage(
+// case MessageEnvelope(
// "TestCharacter2",
-// AvatarAction.SendResponse(_, DestroyMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _))
+// _,
+// SendResponse(DestroyMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _))
// ) =>
// true
// case _ => false
@@ -731,8 +748,9 @@ class PlayerControlDeathStandingTest extends ActorTest {
// val msg_drown = avatarProbe.receiveOne(250 milliseconds)
// assert(
// msg_drown match {
-// case AvatarServiceMessage(
+// case MessageEnvelope(
// "TestCharacter1",
+// _,
// AvatarAction.OxygenState(OxygenStateTarget(PlanetSideGUID(1), _, OxygenState.Suffocation, 100f), _)
// ) => true
// case _ => false
@@ -785,8 +803,9 @@ class PlayerControlDeathStandingTest extends ActorTest {
// val msg_drown = avatarProbe.receiveOne(250 milliseconds)
// assert(
// msg_drown match {
-// case AvatarServiceMessage(
+// case MessageEnvelope(
// "TestCharacter1",
+// _,
// AvatarAction.OxygenState(OxygenStateTarget(PlanetSideGUID(1), _, OxygenState.Suffocation, 100f), _)
// ) => true
// case _ => false
@@ -798,8 +817,9 @@ class PlayerControlDeathStandingTest extends ActorTest {
// val msg_recover = avatarProbe.receiveOne(250 milliseconds)
// assert(
// msg_recover match {
-// case AvatarServiceMessage(
+// case MessageEnvelope(
// "TestCharacter1",
+// _,
// AvatarAction.OxygenState(OxygenStateTarget(PlanetSideGUID(1), _, OxygenState.Recovery, _), _)
// ) => true
// case _ => false
@@ -851,19 +871,19 @@ class PlayerControlInteractWithLavaTest extends ActorTest {
val msg_burn = avatarProbe.receiveN(3, 1 seconds)
assert(
msg_burn.head match {
- case AvatarServiceMessage("test-map", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => true
+ case MessageEnvelope("test-map", _, PlanetsideAttribute(PlanetSideGUID(1), 0, _)) => true
case _ => false
}
)
assert(
msg_burn(1) match {
- case AvatarServiceMessage("TestCharacter1", AvatarAction.EnvironmentalDamage(PlanetSideGUID(1), _, _)) => true
+ case MessageEnvelope("TestCharacter1", _, AvatarAction.EnvironmentalDamage(PlanetSideGUID(1), _, _)) => true
case _ => false
}
)
assert(
msg_burn(2) match {
- case AvatarServiceMessage("test-map", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 54, _)) => true
+ case MessageEnvelope("test-map", _, PlanetsideAttribute(PlanetSideGUID(1), 54, _)) => true
case _ => false
}
)
diff --git a/src/test/scala/objects/RepairableTest.scala b/src/test/scala/objects/RepairableTest.scala
index 3d2c6fc38..20d49812f 100644
--- a/src/test/scala/objects/RepairableTest.scala
+++ b/src/test/scala/objects/RepairableTest.scala
@@ -17,8 +17,9 @@ import net.psforever.objects.vehicles.control.VehicleControl
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.{InventoryStateMessage, RepairMessage}
import net.psforever.types._
-import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
+import net.psforever.services.vehicle.VehicleAction
import scala.concurrent.duration._
@@ -70,10 +71,10 @@ class RepairableEntityRepairTest extends ActorTest {
val msg123 = avatarProbe.receiveN(3, 500 milliseconds)
assert(
msg123.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction
- .SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(5), _, PlanetSideGUID(4), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(5), _, PlanetSideGUID(4), _)))
) =>
true
case _ => false
@@ -81,15 +82,16 @@ class RepairableEntityRepairTest extends ActorTest {
)
assert(
msg123(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg123(2) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(2), _))
+ _,
+ SendResponse(Seq(RepairMessage(PlanetSideGUID(2), _)))
) =>
true
case _ => false
@@ -187,10 +189,10 @@ class RepairableAmenityTest extends ActorTest {
val msg12345 = avatarProbe.receiveN(5, 500 milliseconds)
assert(
msg12345.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction
- .SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(5), _, PlanetSideGUID(4), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(5), _, PlanetSideGUID(4), _)))
) =>
true
case _ => false
@@ -198,27 +200,28 @@ class RepairableAmenityTest extends ActorTest {
)
assert(
msg12345(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg12345(2) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 50, 0)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 50, 0)) => true
case _ => false
}
)
assert(
msg12345(3) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 51, 0)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 51, 0)) => true
case _ => false
}
)
assert(
msg12345(4) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(2), _))
+ _,
+ SendResponse(Seq(RepairMessage(PlanetSideGUID(2), _)))
) =>
true
case _ => false
@@ -285,10 +288,10 @@ class RepairableTurretWeapon extends ActorTest {
val msg4 = vehicleProbe.receiveOne(500 milliseconds)
assert(
msg12345.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction
- .SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(8), _, PlanetSideGUID(7), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(8), _, PlanetSideGUID(7), _)))
) =>
true
case _ => false
@@ -296,16 +299,17 @@ class RepairableTurretWeapon extends ActorTest {
)
assert(
msg12345(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
//msg12345(2) and msg12345(3) are related to RepairableAmenity
assert(
msg12345(4) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(2), _))
+ _,
+ SendResponse(Seq(RepairMessage(PlanetSideGUID(2), _)))
) =>
true
case _ => false
@@ -313,7 +317,7 @@ class RepairableTurretWeapon extends ActorTest {
)
assert(
msg4 match {
- case VehicleServiceMessage("test", VehicleAction.EquipmentInSlot(_, PlanetSideGUID(2), 1, t))
+ case MessageEnvelope("test", _, VehicleAction.EquipmentInSlot(PlanetSideGUID(2), 1, t))
if t eq turretWeapon =>
true
case _ => false
@@ -366,10 +370,10 @@ class RepairableVehicleRepair extends ActorTest {
val msg123 = avatarProbe.receiveN(3, 500 milliseconds)
assert(
msg123.head match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction
- .SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(6), _, PlanetSideGUID(5), _))
+ _,
+ SendResponse(Seq(InventoryStateMessage(PlanetSideGUID(6), _, PlanetSideGUID(5), _)))
) =>
true
case _ => false
@@ -377,15 +381,16 @@ class RepairableVehicleRepair extends ActorTest {
)
assert(
msg123(1) match {
- case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => true
+ case MessageEnvelope("test", _, PlanetsideAttribute(PlanetSideGUID(1), 0, _)) => true
case _ => false
}
)
assert(
msg123(2) match {
- case AvatarServiceMessage(
+ case MessageEnvelope(
"TestCharacter1",
- AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(1), _))
+ _,
+ SendResponse(Seq(RepairMessage(PlanetSideGUID(1), _)))
) =>
true
case _ => false
diff --git a/src/test/scala/objects/ResourceSiloTest.scala b/src/test/scala/objects/ResourceSiloTest.scala
index aa56739af..ef6683df6 100644
--- a/src/test/scala/objects/ResourceSiloTest.scala
+++ b/src/test/scala/objects/ResourceSiloTest.scala
@@ -16,8 +16,9 @@ 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.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.objects.avatar.Avatar
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.{InterstellarClusterService, Service, ServiceManager}
import net.psforever.services.galaxy.GalaxyService
@@ -90,7 +91,7 @@ class ResourceSiloControlStartupTest extends ActorTest {
"Resource silo" should {
"startup properly" in {
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
expectNoMessage(max = 1000 milliseconds)
}
}
@@ -112,7 +113,7 @@ class ResourceSiloControlStartupMessageNoneTest extends ActorTest {
"report if it has no NTU on startup" in {
obj.NtuCapacitor = 0
assert(obj.NtuCapacitor == 0)
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
val ownerMsg = buildingEvents.receiveOne(200 milliseconds)
assert(ownerMsg match {
case BuildingActor.NtuDepleted() => true
@@ -138,7 +139,7 @@ class ResourceSiloControlStartupMessageSomeTest extends ActorTest {
"report if it has any NTU on startup" in {
obj.NtuCapacitor = 1
assert(obj.NtuCapacitor == 1)
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
val ownerMsg = buildingEvents.receiveOne(200 milliseconds)
assert(ownerMsg match {
case BuildingActor.SuppliedWithNtu() => true
@@ -150,7 +151,7 @@ class ResourceSiloControlStartupMessageSomeTest extends ActorTest {
class ResourceSiloControlUseTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._
- ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
+ ServiceManager.boot(system) ! ServiceManager.Register(GalaxyService(), "galaxy")
expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]()
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
@@ -196,7 +197,7 @@ class ResourceSiloControlUseTest extends FreedContextActorTest {
ant.DeploymentState = DriveState.Deployed
building.Amenities = silo
silo.Actor = system.actorOf(Props(classOf[ResourceSiloControl], silo), "test-silo")
- silo.Actor ! Service.Startup()
+ silo.Actor ! Service.Startup
"Resource silo" should {
"respond when being used" in {
@@ -224,7 +225,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
val zoneEvents: TestProbe = TestProbe("zone-events")
zone.AvatarEvents = zoneEvents.ref
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
obj.Actor ! ResourceSilo.UpdateChargeLevel(-obj.NtuCapacitor)
zoneEvents.receiveN(3, 500.milliseconds) //events from setup
@@ -235,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 MessageEnvelope("nowhere", _, PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
case _ => assert(ResourceSiloTest.fail, s"$reply is wrong")
}
assert(!obj.LowNtuWarningOn)
@@ -256,7 +257,7 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
val buildingEvents: TestProbe = TestProbe("building-events")
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
buildingEvents.receiveOne(500 milliseconds) //message caused by "startup"
obj.Actor ! ResourceSilo.UpdateChargeLevel(-obj.NtuCapacitor)
zoneEvents.receiveN(3, 500.milliseconds) //events from setup
@@ -274,12 +275,12 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
assert(obj.NtuCapacitor == 305)
assert(obj.CapacitorDisplay == 3)
reply1.head match {
- case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 3)) => ;
+ case MessageEnvelope("nowhere", _, PlanetsideAttribute(PlanetSideGUID(1), 45, 3)) => ;
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 MessageEnvelope("nowhere", _, PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
case _ => assert(ResourceSiloTest.fail, s"${reply1(1)} is wrong")
}
assert(!obj.LowNtuWarningOn)
@@ -300,7 +301,7 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
val buildingEvents: TestProbe = TestProbe("building-events")
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
buildingEvents.receiveOne(500 milliseconds) //message caused by "startup"
obj.Actor ! ResourceSilo.UpdateChargeLevel(-obj.NtuCapacitor + 100)
zoneEvents.receiveN(3, 500.milliseconds) //events from setup
@@ -318,12 +319,12 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
assert(obj.NtuCapacitor == 205)
assert(obj.CapacitorDisplay == 2)
reply1.head match {
- case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 2)) => ;
+ case MessageEnvelope("nowhere", _, PlanetsideAttribute(PlanetSideGUID(1), 45, 2)) => ;
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 MessageEnvelope("nowhere", _, PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => ;
case _ => assert(ResourceSiloTest.fail, s"${reply1(1)} is wrong")
}
assert(!obj.LowNtuWarningOn)
@@ -344,7 +345,7 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
val buildingEvents: TestProbe = TestProbe("building-events")
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
- obj.Actor ! Service.Startup()
+ obj.Actor ! Service.Startup
obj.NtuCapacitor = 0
"Resource silo" should {
diff --git a/src/test/scala/objects/TelepadRouterTest.scala b/src/test/scala/objects/TelepadRouterTest.scala
index 7eff27c37..bc43ef10d 100644
--- a/src/test/scala/objects/TelepadRouterTest.scala
+++ b/src/test/scala/objects/TelepadRouterTest.scala
@@ -15,7 +15,9 @@ import net.psforever.objects.vehicles.{Utility, UtilityType}
import net.psforever.objects.zones.{Zone, ZoneDeployableActor, ZoneMap}
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.packet.game._
-import net.psforever.services.local.{LocalAction, LocalServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.local.LocalAction
import net.psforever.types.{DriveState, PlanetSideGUID, Vector3}
import scala.collection.mutable
@@ -47,16 +49,16 @@ class TelepadDeployableNoRouterTest extends ActorTest {
val eventsMsgs = eventsProbe.receiveN(4, 10.seconds)
eventsMsgs.head match {
- case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
+ case MessageEnvelope("test", _, LocalAction.DeployItem(obj)) =>
assert(obj eq telepad, "no-router telepad deployable testt - not same telepad")
case _ =>
assert( false, "no-router telepad deployable test - wrong deploy message")
}
eventsMsgs(1) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NEUTRAL",
+ _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Build,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.RouterTelepad, Vector3.Zero, PlanetSideGUID(0))
)
@@ -64,14 +66,14 @@ class TelepadDeployableNoRouterTest extends ActorTest {
case _ => assert(false, "no-router telepad deployable test - no icon or wrong icon")
}
eventsMsgs(2) match {
- case LocalServiceMessage("test", LocalAction.EliminateDeployable(`telepad`, PlanetSideGUID(1), Vector3.Zero, 2)) => ;
+ case MessageEnvelope("test", _, LocalAction.EliminateDeployable(`telepad`, PlanetSideGUID(1), Vector3.Zero, 2)) => ;
case _ => assert(false, "no-router telepad deployable test - not eliminating deployable")
}
eventsMsgs(3) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NEUTRAL",
+ _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.RouterTelepad, Vector3.Zero, PlanetSideGUID(0))
)
@@ -116,16 +118,16 @@ class TelepadDeployableNoActivationTest extends ActorTest {
val eventsMsgs = eventsProbe.receiveN(4, 10.seconds)
eventsMsgs.head match {
- case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
+ case MessageEnvelope("test", _, LocalAction.DeployItem(obj)) =>
assert(obj eq telepad, "no-activate telepad deployable testt - not same telepad")
case _ =>
assert( false, "no-activate telepad deployable test - wrong deploy message")
}
eventsMsgs(1) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NEUTRAL",
+ _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Build,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.RouterTelepad, Vector3.Zero, PlanetSideGUID(0))
)
@@ -134,14 +136,14 @@ class TelepadDeployableNoActivationTest extends ActorTest {
assert( false, "no-activate telepad deployable test - no icon or wrong icon")
}
eventsMsgs(2) match {
- case LocalServiceMessage("test", LocalAction.EliminateDeployable(`telepad`, PlanetSideGUID(1), Vector3.Zero, 2)) => ;
+ case MessageEnvelope("test", _, LocalAction.EliminateDeployable(`telepad`, PlanetSideGUID(1), Vector3.Zero, 2)) => ;
case _ => assert(false, "no-activate telepad deployable test - not eliminating deployable")
}
eventsMsgs(3) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NEUTRAL",
+ _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.RouterTelepad, Vector3.Zero, PlanetSideGUID(0))
)
@@ -189,16 +191,16 @@ class TelepadDeployableAttemptTest extends ActorTest {
val eventsMsgs = eventsProbe.receiveN(2, 10.seconds)
val routerMsgs = routerProbe.receiveN(1, 10.seconds)
eventsMsgs.head match {
- case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
+ case MessageEnvelope("test", _, LocalAction.DeployItem(obj)) =>
assert(obj eq telepad, "link attempt telepad deployable testt - not same telepad")
case _ =>
assert( false, "link attempt telepad deployable test - wrong deploy message")
}
eventsMsgs(1) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NEUTRAL",
+ _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Build,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.RouterTelepad, Vector3.Zero, PlanetSideGUID(0))
)
@@ -262,16 +264,16 @@ class TelepadDeployableResponseFromRouterTest extends FreedContextActorTest {
val eventsMsgs = eventsProbe.receiveN(9, 10.seconds)
eventsMsgs.head match {
- case LocalServiceMessage("test", LocalAction.DeployItem(obj)) =>
+ case MessageEnvelope("test", _, LocalAction.DeployItem(obj)) =>
assert(obj eq telepad, "link to router test - not same telepad")
case _ =>
assert( false, "link to router test - wrong deploy message")
}
eventsMsgs(1) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"NEUTRAL",
+ _,
LocalAction.DeployableMapIcon(
- PlanetSideGUID(0),
DeploymentAction.Build,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.RouterTelepad, Vector3.Zero, PlanetSideGUID(0))
)
@@ -279,53 +281,60 @@ class TelepadDeployableResponseFromRouterTest extends FreedContextActorTest {
case _ => assert(false, "link to router test - no icon or wrong icon")
}
eventsMsgs(2) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"test",
- LocalAction.SendResponse(
+ _,
+ SendResponse(Seq(
ObjectCreateMessage(_, 744, PlanetSideGUID(3), Some(ObjectCreateMessageParent(PlanetSideGUID(2), 2)), _)
- )
+ ))
) => ;
case _ => assert(false, "link to router test - did not create the internal router telepad (1)")
}
eventsMsgs(3) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"test",
- LocalAction.SendResponse(GenericObjectActionMessage(PlanetSideGUID(3), 27))
+ _,
+ SendResponse(Seq(GenericObjectActionMessage(PlanetSideGUID(3), 27)))
) => ;
case _ => assert(false, "link to router test - did not create the internal router telepad (2)")
}
eventsMsgs(4) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"test",
- LocalAction.SendResponse(GenericObjectActionMessage(PlanetSideGUID(3), 30))
+ _,
+ SendResponse(Seq(GenericObjectActionMessage(PlanetSideGUID(3), 30)))
) => ;
case _ => assert(false, "link to router test - did not create the internal router telepad (3)")
}
eventsMsgs(5) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"test",
- LocalAction.SendResponse(GenericObjectActionMessage(PlanetSideGUID(3), 27))
+ _,
+ SendResponse(Seq(GenericObjectActionMessage(PlanetSideGUID(3), 27)))
) => ;
case _ => assert(false, "link to router test - did not link the internal telepad (1)")
}
eventsMsgs(6) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"test",
- LocalAction.SendResponse(GenericObjectActionMessage(PlanetSideGUID(3), 28))
+ _,
+ SendResponse(Seq(GenericObjectActionMessage(PlanetSideGUID(3), 28)))
) => ;
case _ => assert(false, "link to router test - did not link the internal telepad (2)")
}
eventsMsgs(7) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"test",
- LocalAction.SendResponse(GenericObjectActionMessage(PlanetSideGUID(1), 27))
+ _,
+ SendResponse(Seq(GenericObjectActionMessage(PlanetSideGUID(1), 27)))
) => ;
case _ => assert(false, "link to router test - did not link the telepad (1)")
}
eventsMsgs(8) match {
- case LocalServiceMessage(
+ case MessageEnvelope(
"test",
- LocalAction.SendResponse(GenericObjectActionMessage(PlanetSideGUID(1), 28))
+ _,
+ SendResponse(Seq(GenericObjectActionMessage(PlanetSideGUID(1), 28)))
) => ;
case _ => assert(false, "link to router test - did not link the telepad (2)")
}
diff --git a/src/test/scala/objects/VehicleControlTest.scala b/src/test/scala/objects/VehicleControlTest.scala
index 9b9b7ca79..e57ed428f 100644
--- a/src/test/scala/objects/VehicleControlTest.scala
+++ b/src/test/scala/objects/VehicleControlTest.scala
@@ -25,7 +25,9 @@ import net.psforever.objects.vital.{ShieldCharge, SpawningActivity, Vitality}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game._
import net.psforever.services.ServiceManager
-import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
+import net.psforever.services.base.envelope.MessageEnvelope
+import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
+import net.psforever.services.vehicle.VehicleAction
import net.psforever.types._
import scala.concurrent.duration._
@@ -72,7 +74,7 @@ class VehicleControlPrepareForDeletionPassengerTest extends ActorTest {
val vehicle_msg = vehicleProbe.receiveN(1, 500 milliseconds)
vehicle_msg.head match {
- case VehicleServiceMessage("test", VehicleAction.KickPassenger(PlanetSideGUID(2), 4, true, PlanetSideGUID(1))) => ;
+ case MessageEnvelope("test", _, VehicleAction.KickPassenger(4, true, PlanetSideGUID(1))) => ;
case _ =>
assert(false, s"VehicleControlPrepareForDeletionPassengerTest: ${vehicle_msg.head}")
}
@@ -136,32 +138,32 @@ class VehicleControlPrepareForDeletionPassengerTest extends ActorTest {
// val vehicle_msg = vehicleProbe.receiveN(6, 1 minute)
// //dismounting as cargo messages
// vehicle_msg.head match {
-// case VehicleServiceMessage("test", VehicleAction.KickPassenger(PlanetSideGUID(3), 4, true, PlanetSideGUID(1))) => ;
+// case MessageEnvelope("test", _, VehicleAction.KickPassenger(PlanetSideGUID(3), 4, true, PlanetSideGUID(1))) => ;
// case _ =>
// assert(false, s"VehicleControlPrepareForDeletionMountedInTest-1: ${vehicle_msg.head}")
// }
// vehicle_msg(1) match {
-// case VehicleServiceMessage(_, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 0, _))) => ;
+// case MessageEnvelope(_, _, SendResponse(PlanetsideAttributeMessage(PlanetSideGUID(1), 0, _))) => ;
// case _ =>
// assert(false, s"VehicleControlPrepareForDeletionMountedInTest-2: ${vehicle_msg(1)}")
// }
// vehicle_msg(2) match {
-// case VehicleServiceMessage(_, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 68, _))) => ;
+// case MessageEnvelope(_, _, SendResponse(PlanetsideAttributeMessage(PlanetSideGUID(1), 68, _))) => ;
// case _ =>
// assert(false, s"VehicleControlPrepareForDeletionMountedInTest-3: ${vehicle_msg(2)}")
// }
// vehicle_msg(3) match {
-// case VehicleServiceMessage("test", VehicleAction.SendResponse(_, CargoMountPointStatusMessage(PlanetSideGUID(2), _, PlanetSideGUID(1), _, 1, CargoStatus.InProgress, 0))) => ;
+// case MessageEnvelope("test", _, SendResponse(CargoMountPointStatusMessage(PlanetSideGUID(2), _, PlanetSideGUID(1), _, 1, CargoStatus.InProgress, 0))) => ;
// case _ =>
// assert(false, s"VehicleControlPrepareForDeletionMountedInTest-4: ${vehicle_msg(3)}")
// }
// vehicle_msg(4) match {
-// case VehicleServiceMessage("test", VehicleAction.SendResponse(_, ObjectDetachMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _, _, _))) => ;
+// case MessageEnvelope("test", _, SendResponse(ObjectDetachMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _, _, _))) => ;
// case _ =>
// assert(false, s"VehicleControlPrepareForDeletionMountedInTest-5: ${vehicle_msg(4)}")
// }
// vehicle_msg(5) match {
-// case VehicleServiceMessage("test", VehicleAction.SendResponse(_, CargoMountPointStatusMessage(PlanetSideGUID(2), _, _, PlanetSideGUID(1), 1, CargoStatus.Empty, 0))) => ;
+// case MessageEnvelope("test", _, SendResponse(CargoMountPointStatusMessage(PlanetSideGUID(2), _, _, PlanetSideGUID(1), 1, CargoStatus.Empty, 0))) => ;
// case _ =>
// assert(false, s"VehicleControlPrepareForDeletionMountedInTest-6: ${vehicle_msg(5)}")
// }
@@ -224,7 +226,7 @@ class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActor
val vehicleMsgs = eventsProbe.receiveN(6, 10.seconds)
val cargoMsgs = cargoProbe.receiveN(1, 1.seconds)
vehicleMsgs.head match {
- case VehicleServiceMessage("test", VehicleAction.KickPassenger(PlanetSideGUID(4), 4, true, PlanetSideGUID(2))) => ()
+ case MessageEnvelope("test", _, VehicleAction.KickPassenger(4, true, PlanetSideGUID(2))) => ()
case _ =>
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-1: ${vehicleMsgs.head}")
}
@@ -232,27 +234,27 @@ class VehicleControlPrepareForDeletionMountedCargoTest extends FreedContextActor
assert(lodestar.Seats(0).occupant.isEmpty)
//cargo dismounting messages
vehicleMsgs(1) match {
- case VehicleServiceMessage(_, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 0, _))) => ()
+ case MessageEnvelope(_, _, SendResponse(Seq(PlanetsideAttributeMessage(PlanetSideGUID(1), 0, _)))) => ()
case _ =>
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-2: ${vehicleMsgs(1)}")
}
vehicleMsgs(2) match {
- case VehicleServiceMessage(_, VehicleAction.SendResponse(_, PlanetsideAttributeMessage(PlanetSideGUID(1), 68, _))) => ()
+ case MessageEnvelope(_, _, SendResponse(Seq(PlanetsideAttributeMessage(PlanetSideGUID(1), 68, _)))) => ()
case _ =>
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-3: ${vehicleMsgs(2)}")
}
vehicleMsgs(3) match {
- case VehicleServiceMessage("test", VehicleAction.SendResponse(_, CargoMountPointStatusMessage(PlanetSideGUID(2), _, PlanetSideGUID(1), _, 1, CargoStatus.InProgress, 0))) => ;
+ case MessageEnvelope("test", _, SendResponse(Seq(CargoMountPointStatusMessage(PlanetSideGUID(2), _, PlanetSideGUID(1), _, 1, CargoStatus.InProgress, 0)))) => ;
case _ =>
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-4: ${vehicleMsgs(3)}")
}
vehicleMsgs(4) match {
- case VehicleServiceMessage("test", VehicleAction.SendResponse(_, ObjectDetachMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _, _, _))) => ()
+ case MessageEnvelope("test", _, SendResponse(Seq(ObjectDetachMessage(PlanetSideGUID(2), PlanetSideGUID(1), _, _, _, _)))) => ()
case _ =>
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-5: ${vehicleMsgs(4)}")
}
vehicleMsgs(5) match {
- case VehicleServiceMessage("test", VehicleAction.SendResponse(_, CargoMountPointStatusMessage(PlanetSideGUID(2), _, _, PlanetSideGUID(1), 1, CargoStatus.Empty, 0))) => ()
+ case MessageEnvelope("test", _, SendResponse(Seq(CargoMountPointStatusMessage(PlanetSideGUID(2), _, _, PlanetSideGUID(1), 1, CargoStatus.Empty, 0)))) => ()
case _ =>
assert(false, s"VehicleControlPrepareForDeletionMountedCargoTest-6: ${vehicleMsgs(5)}")
}
@@ -476,8 +478,8 @@ class VehicleControlShieldsChargingTest extends ActorTest {
vehicle.Actor ! CommonMessages.ChargeShields(15, None)
val msg = probe.receiveOne(500 milliseconds)
assert(msg match {
- case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(10), 68, 15)) => true
- case _ => false
+ case MessageEnvelope(_, _, PlanetsideAttribute(PlanetSideGUID(10), 68, 15)) => true
+ case _ => false
})
assert(vehicle.Shields == 15)
assert(vehicle.History.exists({ p => p.isInstanceOf[ShieldCharge] }))
@@ -544,7 +546,7 @@ class VehicleControlShieldsNotChargingTooEarlyTest extends ActorTest {
val msg = probe.receiveOne(200 milliseconds)
//assert(msg.isInstanceOf[Vehicle.UpdateShieldsCharge])
assert(msg match {
- case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(10), 68, 15)) => true
+ case MessageEnvelope(_, _, PlanetsideAttribute(PlanetSideGUID(10), 68, 15)) => true
case _ => false
})
assert(vehicle.Shields == 15)
@@ -1004,7 +1006,7 @@ class VehicleControlInteractWithLavaTest extends ActorTest {
msg_burn.foreach { msg =>
assert(
msg match {
- case VehicleServiceMessage("test-zone", VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(2), 0, _)) => true
+ case MessageEnvelope("test-zone", _, PlanetsideAttribute(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
@@ -1102,7 +1104,7 @@ class ApcControlCanChargeCapacitor extends FreedContextActorTest {
do {
val msg = vehicleProbe.receiveOne(3.seconds)
msg match {
- case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(1), 113, capacitance)) =>
+ case MessageEnvelope(_, _, PlanetsideAttribute(PlanetSideGUID(1), 113, capacitance)) =>
assert(capacitance > 0)
case _ =>
assert(false)
@@ -1176,17 +1178,17 @@ class ApcControlCanEmp extends FreedContextActorTest {
apc.Actor ! SpecialEmp.Burst()
val vehicleMsgs = vehicleProbe.receiveN(2, 500.milliseconds)
vehicleMsgs.head match {
- case VehicleServiceMessage(_, VehicleAction.PlanetsideAttribute(_, PlanetSideGUID(1), 113, 0)) => ;
+ case MessageEnvelope(_, _, PlanetsideAttribute(PlanetSideGUID(1), 113, 0)) => ;
case _ => assert(false)
}
vehicleMsgs(1) match {
- case VehicleServiceMessage(
- "test-zone",
- VehicleAction.SendResponse(
- _,
- TriggerEffectMessage(_, "apc_explosion_emp_vs", None, Some(TriggeredEffectLocation(Vector3.Zero, Vector3.Zero)))
- )
- ) => ;
+ case MessageEnvelope(
+ "test-zone",
+ _,
+ SendResponse(Seq(
+ TriggerEffectMessage(_, "apc_explosion_emp_vs", None, Some(TriggeredEffectLocation(Vector3.Zero, Vector3.Zero)))
+ ))
+ ) => ;
case _ => assert(false)
}
assert(apc.Capacitor == 0)
diff --git a/src/test/scala/objects/terminal/ProximityTest.scala b/src/test/scala/objects/terminal/ProximityTest.scala
index f3c89992a..2d6334774 100644
--- a/src/test/scala/objects/terminal/ProximityTest.scala
+++ b/src/test/scala/objects/terminal/ProximityTest.scala
@@ -2,29 +2,23 @@
package objects.terminal
import java.util.concurrent.atomic.AtomicInteger
-
import akka.actor.Props
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.structures.{Building, StructureType}
-import net.psforever.objects.serverobject.terminals.{
- ProximityTerminal,
- ProximityTerminalControl,
- ProximityUnit,
- Terminal
-}
+import net.psforever.objects.serverobject.terminals.{ProximityTerminal, ProximityTerminalControl, ProximityUnit, Terminal}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.types.{CharacterSex, CharacterVoice, PlanetSideEmpire, PlanetSideGUID}
import org.specs2.mutable.Specification
import net.psforever.services.Service
-import net.psforever.services.local.LocalService
import scala.concurrent.duration._
import akka.actor.typed.scaladsl.adapter._
import net.psforever.objects.avatar.Avatar
+import net.psforever.services.base.envelope.MessageEnvelope
class ProximityTest extends Specification {
@@ -195,7 +189,7 @@ class ProximityTerminalControlStartTest extends ActorTest {
avatar.GUID = PlanetSideGUID(1)
terminal.GUID = PlanetSideGUID(2)
- terminal.Actor ! Service.Startup()
+ terminal.Actor ! Service.Startup
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback")
@@ -206,7 +200,7 @@ class ProximityTerminalControlStartTest extends ActorTest {
assert(terminal.Owner.Continent.equals("test"))
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
- probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect])
+ probe1.expectMsgClass(1 second, classOf[MessageEnvelope])
probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action])
assert(terminal.NumberUsers == 1)
}
@@ -263,7 +257,7 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest {
avatar.GUID = PlanetSideGUID(1)
avatar2.GUID = PlanetSideGUID(2)
terminal.GUID = PlanetSideGUID(3)
- terminal.Actor ! Service.Startup()
+ terminal.Actor ! Service.Startup
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback-1")
@@ -276,7 +270,7 @@ class ProximityTerminalControlTwoUsersTest extends ActorTest {
assert(terminal.Owner.Continent.equals("test"))
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
- probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect])
+ probe1.expectMsgClass(1 second, classOf[MessageEnvelope])
probe2.expectMsgClass(5 second, classOf[ProximityUnit.Action])
terminal.Actor.tell(CommonMessages.Use(avatar2, Some(avatar2)), probe3.ref)
@@ -322,7 +316,7 @@ class ProximityTerminalControlStopTest extends ActorTest {
avatar.GUID = PlanetSideGUID(1)
terminal.GUID = PlanetSideGUID(2)
- terminal.Actor ! Service.Startup()
+ terminal.Actor ! Service.Startup
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback")
@@ -334,7 +328,7 @@ class ProximityTerminalControlStopTest extends ActorTest {
assert(terminal.Owner.Continent.equals("test"))
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
- probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect])
+ probe1.expectMsgClass(1 second, classOf[MessageEnvelope])
probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action])
terminal.Actor ! CommonMessages.Unuse(avatar, Some(avatar))
@@ -346,7 +340,7 @@ class ProximityTerminalControlStopTest extends ActorTest {
case out => assert(false, s"last message $out is not StopAction")
}
//probe2.expectMsgClass(1 second, classOf[ProximityUnit.StopAction])
- probe1.expectMsgClass(1 second, classOf[Terminal.StopProximityEffect])
+ probe1.expectMsgClass(1 second, classOf[MessageEnvelope])
assert(terminal.NumberUsers == 0)
}
}
@@ -400,7 +394,7 @@ class ProximityTerminalControlNotStopTest extends ActorTest {
avatar.GUID = PlanetSideGUID(1)
avatar2.GUID = PlanetSideGUID(2)
terminal.GUID = PlanetSideGUID(3)
- terminal.Actor ! Service.Startup()
+ terminal.Actor ! Service.Startup
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback-1")
@@ -412,7 +406,7 @@ class ProximityTerminalControlNotStopTest extends ActorTest {
assert(terminal.Owner.Continent.equals("test"))
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
- probe1.expectMsgClass(100 millisecond, classOf[Terminal.StartProximityEffect])
+ probe1.expectMsgClass(100 millisecond, classOf[MessageEnvelope])
assert(terminal.NumberUsers == 1)
terminal.Actor.tell(CommonMessages.Use(avatar2, Some(avatar2)), probe3.ref)
@@ -424,7 +418,7 @@ class ProximityTerminalControlNotStopTest extends ActorTest {
assert(terminal.NumberUsers == 1)
terminal.Actor ! CommonMessages.Unuse(avatar2, Some(avatar2))
- probe1.expectMsgClass(100 millisecond, classOf[Terminal.StopProximityEffect])
+ probe1.expectMsgClass(100 millisecond, classOf[MessageEnvelope])
assert(terminal.NumberUsers == 0)
}
}
@@ -434,9 +428,4 @@ object ProximityTest {
val avatarId = new AtomicInteger(0)
class SampleTerminal extends Terminal(GlobalDefinitions.dropship_vehicle_terminal) with ProximityUnit
-
- class ProbedLocalService(probe: TestProbe, zone: Zone) extends LocalService(zone) {
- self.tell(Service.Join("test"), probe.ref)
- }
-
}
diff --git a/src/test/scala/service/HartServiceTest.scala b/src/test/scala/service/HartServiceTest.scala
index 3952a8f7a..c0a4a33c3 100644
--- a/src/test/scala/service/HartServiceTest.scala
+++ b/src/test/scala/service/HartServiceTest.scala
@@ -3,7 +3,7 @@ package service
import akka.actor.{ActorRef, Props}
import akka.testkit.TestProbe
-import base.ActorTest
+import _root_.base.ActorTest
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.services.hart.{HartService, HartTimer}
import net.psforever.types.PlanetSideGUID
diff --git a/src/test/scala/service/HartTimerTest.scala b/src/test/scala/service/HartTimerTest.scala
index 038909b17..486d88dd0 100644
--- a/src/test/scala/service/HartTimerTest.scala
+++ b/src/test/scala/service/HartTimerTest.scala
@@ -1,9 +1,9 @@
// Copyright (c) 2021 PSForever
package service
-import akka.actor.Props
+import akka.actor.{ActorRef, Props}
import akka.testkit.TestProbe
-import base.ActorTest
+import _root_.base.ActorTest
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.services.hart.HartTimer
import net.psforever.types.PlanetSideGUID
@@ -14,11 +14,11 @@ class HartTimerNotScheduled extends ActorTest {
"HartTimer" should {
val catchall = new TestProbe(system).ref
val zone = new Zone("test", new ZoneMap("test"), 0) {
- override def SetupNumberPools() = {}
- override def AvatarEvents = catchall
- override def LocalEvents = catchall
- override def VehicleEvents = catchall
- override def Activity = catchall
+ override def SetupNumberPools(): Unit = {}
+ override def AvatarEvents: ActorRef = catchall
+ override def LocalEvents: ActorRef = catchall
+ override def VehicleEvents: ActorRef = catchall
+ override def Activity: ActorRef = catchall
}
val timer = system.actorOf(Props(classOf[HartTimer], zone), "hart-timer")
@@ -34,11 +34,11 @@ class HartTimerInitializedPairingScheduled extends ActorTest {
"HartTimer" should {
val catchall = new TestProbe(system).ref
val zone = new Zone("test", new ZoneMap("test"), 0) {
- override def SetupNumberPools() = {}
- override def AvatarEvents = catchall
- override def LocalEvents = catchall
- override def VehicleEvents = catchall
- override def Activity = catchall
+ override def SetupNumberPools(): Unit = {}
+ override def AvatarEvents: ActorRef = catchall
+ override def LocalEvents: ActorRef = catchall
+ override def VehicleEvents: ActorRef = catchall
+ override def Activity: ActorRef = catchall
}
val timer = system.actorOf(Props(classOf[HartTimer], zone), "hart-timer")
@@ -54,4 +54,4 @@ class HartTimerInitializedPairingScheduled extends ActorTest {
}
}
-object HartTimerTest { /* initially left empty */ }
+object HartTimerTest { /* initially left empty */ }
\ No newline at end of file
diff --git a/src/test/scala/service/LocalServiceTest.scala b/src/test/scala/service/LocalServiceTest.scala
deleted file mode 100644
index 4bdaac10e..000000000
--- a/src/test/scala/service/LocalServiceTest.scala
+++ /dev/null
@@ -1,376 +0,0 @@
-// Copyright (c) 2017 PSForever
-package service
-
-import akka.actor.Props
-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.control.VehicleControl
-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)
-
- "LocalService" should {
- "construct" in {
- system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- assert(true)
- }
- }
-}
-
-class LocalService2Test extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "subscribe" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- assert(true)
- }
- }
-}
-
-class LocalService3Test extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "subscribe to a specific channel" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! Service.Leave()
- assert(true)
- }
- }
-}
-
-class LocalService4Test extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "subscribe" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! Service.LeaveAll()
- assert(true)
- }
- }
-}
-
-class LocalService5Test extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "pass an unhandled message" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! "hello"
- expectNoMessage()
- }
- }
-}
-
-
-
-class DeployItemTest extends ActorTest {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "deploy-item-test-service")
- val objDef = GlobalDefinitions.motionalarmsensor
- val obj = new SensorDeployable(objDef)
- obj.Position = Vector3(1, 2, 3)
- obj.Orientation = Vector3(4, 5, 6)
- obj.GUID = PlanetSideGUID(40)
- val pkt = ObjectCreateMessage(
- objDef.ObjectId,
- obj.GUID,
- objDef.Packet.ConstructorData(obj).get
- )
-
- "AvatarService" should {
- "pass DeployItem" in {
- service ! Service.Join("test")
- service ! LocalServiceMessage("test", LocalAction.DeployItem(obj))
- expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(0), LocalResponse.SendResponse(pkt)))
- }
- }
-}
-
-class DeployableMapIconTest extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "pass DeployableMapIcon" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage(
- "test",
- LocalAction.DeployableMapIcon(
- PlanetSideGUID(10),
- DeploymentAction.Build,
- DeployableInfo(PlanetSideGUID(40), DeployableIcon.Boomer, Vector3(1, 2, 3), PlanetSideGUID(11))
- )
- )
- expectMsg(
- LocalServiceResponse(
- "/test/Local",
- PlanetSideGUID(10),
- LocalResponse.DeployableMapIcon(
- DeploymentAction.Build,
- DeployableInfo(PlanetSideGUID(40), DeployableIcon.Boomer, Vector3(1, 2, 3), PlanetSideGUID(11))
- )
- )
- )
- }
- }
-}
-
-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 {
- 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))))
- }
- }
-}
-
-class HackClearTest extends ActorTest {
- ServiceManager.boot(system)
- val obj = new PlanetSideServerObject() {
- def Faction = PlanetSideEmpire.NEUTRAL
- def Definition = null
- GUID = PlanetSideGUID(40)
- }
-
- "LocalService" should {
- "pass HackClear" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage("test", LocalAction.HackClear(PlanetSideGUID(10), obj, 0L, HackState7.Unk8))
- expectMsg(
- LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.SendHackMessageHackCleared(PlanetSideGUID(40), 0L, HackState7.Unk8))
- )
- }
- }
-}
-
-class ProximityTerminalEffectOnTest extends ActorTest {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal)
- terminal.GUID = PlanetSideGUID(1)
-
- "LocalService" should {
- "pass ProximityTerminalEffect (true)" in {
- service ! Service.Join("nowhere")
- service ! Terminal.StartProximityEffect(terminal)
- expectMsg(
- LocalServiceResponse(
- "/nowhere/Local",
- PlanetSideGUID(0),
- LocalResponse.ProximityTerminalEffect(PlanetSideGUID(1), true)
- )
- )
- }
- }
-}
-
-class ProximityTerminalEffectOffTest extends ActorTest {
- ServiceManager.boot(system)
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal)
- terminal.GUID = PlanetSideGUID(1)
-
- "LocalService" should {
- "pass ProximityTerminalEffect (false)" in {
- service ! Service.Join("nowhere")
- service ! Terminal.StopProximityEffect(terminal)
- expectMsg(
- LocalServiceResponse(
- "/nowhere/Local",
- PlanetSideGUID(0),
- LocalResponse.ProximityTerminalEffect(PlanetSideGUID(1), false)
- )
- )
- }
- }
-}
-
-class RouterTelepadTransportTest extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "pass RouterTelepadTransport" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage(
- "test",
- LocalAction.RouterTelepadTransport(
- PlanetSideGUID(10),
- PlanetSideGUID(11),
- PlanetSideGUID(12),
- PlanetSideGUID(13)
- )
- )
- expectMsg(
- LocalServiceResponse(
- "/test/Local",
- PlanetSideGUID(10),
- LocalResponse.RouterTelepadTransport(PlanetSideGUID(11), PlanetSideGUID(12), PlanetSideGUID(13))
- )
- )
- }
- }
-}
-
-class SetEmpireTest extends ActorTest {
- ServiceManager.boot(system)
- val obj = new SensorDeployable(GlobalDefinitions.motionalarmsensor)
-
- "LocalService" should {
- "pass SetEmpire" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage("test", LocalAction.SetEmpire(PlanetSideGUID(10), PlanetSideEmpire.TR))
- expectMsg(
- LocalServiceResponse(
- "/test/Local",
- PlanetSideGUID(0),
- LocalResponse.SetEmpire(PlanetSideGUID(10), PlanetSideEmpire.TR)
- )
- )
- }
- }
-}
-
-class ToggleTeleportSystemTest extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "pass ToggleTeleportSystem" in {
- val router = Vehicle(GlobalDefinitions.router)
- router.Actor = system.actorOf(Props(classOf[VehicleControl], router), "test-router")
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage("test", LocalAction.ToggleTeleportSystem(PlanetSideGUID(10), router, None))
- expectMsg(
- LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.ToggleTeleportSystem(router, None))
- )
- }
- }
-}
-
-class TriggerEffectTest extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "pass TriggerEffect (1)" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage("test", LocalAction.TriggerEffect(PlanetSideGUID(10), "on", PlanetSideGUID(40)))
- expectMsg(
- LocalServiceResponse(
- "/test/Local",
- PlanetSideGUID(10),
- LocalResponse.TriggerEffect(PlanetSideGUID(40), "on", None, None)
- )
- )
- }
- }
-}
-
-class TriggerEffectInfoTest extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "pass TriggerEffect (2)" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage(
- "test",
- LocalAction.TriggerEffectInfo(PlanetSideGUID(10), "on", PlanetSideGUID(40), true, 1000)
- )
- expectMsg(
- LocalServiceResponse(
- "/test/Local",
- PlanetSideGUID(10),
- LocalResponse.TriggerEffect(PlanetSideGUID(40), "on", Some(TriggeredEffect(true, 1000)), None)
- )
- )
- }
- }
-}
-
-class TriggerEffectLocationTest extends ActorTest {
- ServiceManager.boot(system)
-
- "LocalService" should {
- "pass TriggerEffect (3)" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage(
- "test",
- LocalAction.TriggerEffectLocation(
- PlanetSideGUID(10),
- "spawn_object_failed_effect",
- Vector3(1.1f, 2.2f, 3.3f),
- Vector3(4.4f, 5.5f, 6.6f)
- )
- )
- expectMsg(
- LocalServiceResponse(
- "/test/Local",
- PlanetSideGUID(10),
- LocalResponse.TriggerEffect(
- PlanetSideGUID(0),
- "spawn_object_failed_effect",
- None,
- Some(TriggeredEffectLocation(Vector3(1.1f, 2.2f, 3.3f), Vector3(4.4f, 5.5f, 6.6f)))
- )
- )
- )
- }
- }
-}
-
-class TriggerSoundTest extends ActorTest {
- import net.psforever.packet.game.TriggeredSound
- ServiceManager.boot(system)
-
- "LocalService" should {
- "pass TriggerSound" in {
- val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
- service ! Service.Join("test")
- service ! LocalServiceMessage(
- "test",
- LocalAction.TriggerSound(PlanetSideGUID(10), TriggeredSound.LockedOut, Vector3(1.1f, 2.2f, 3.3f), 0, 0.75f)
- )
- expectMsg(
- LocalServiceResponse(
- "/test/Local",
- PlanetSideGUID(10),
- LocalResponse.TriggerSound(TriggeredSound.LockedOut, Vector3(1.1f, 2.2f, 3.3f), 0, 0.75f)
- )
- )
- }
- }
-}
-
-object LocalServiceTest {
- //decoy
-}
diff --git a/src/test/scala/service/VehicleServiceTest.scala b/src/test/scala/service/VehicleServiceTest.scala
deleted file mode 100644
index 691780b58..000000000
--- a/src/test/scala/service/VehicleServiceTest.scala
+++ /dev/null
@@ -1,428 +0,0 @@
-// Copyright (c) 2017 PSForever
-package service
-
-import akka.actor.Props
-import base.ActorTest
-import net.psforever.objects._
-import net.psforever.objects.vehicles.control.VehicleControl
-import net.psforever.objects.zones.Zone
-import net.psforever.types.{PlanetSideGUID, _}
-import net.psforever.services.{Service, ServiceManager}
-import net.psforever.services.vehicle._
-
-class VehicleService1Test extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "construct" in {
- system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- assert(true)
- }
- }
-}
-
-class VehicleService2Test extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "subscribe" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- assert(true)
- }
- }
-}
-
-class VehicleService3Test extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "subscribe to a specific channel" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! Service.Leave()
- assert(true)
- }
- }
-}
-
-class VehicleService4Test extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "subscribe" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! Service.LeaveAll()
- assert(true)
- }
- }
-}
-
-class VehicleService5Test extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass an unhandled message" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! "hello"
- expectNoMessage()
- }
- }
-}
-
-class OwnershipTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass Awareness" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage("test", VehicleAction.Ownership(PlanetSideGUID(10), PlanetSideGUID(11)))
- expectMsg(
- VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.Ownership(PlanetSideGUID(11)))
- )
- }
- }
-}
-
-class ChildObjectStateTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass ChildObjectState" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.ChildObjectState(PlanetSideGUID(10), PlanetSideGUID(11), 1.2f, 3.4f)
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.ChildObjectState(PlanetSideGUID(11), 1.2f, 3.4f)
- )
- )
- }
- }
-}
-
-class DeployRequestTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass DeployRequest" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.DeployRequest(
- PlanetSideGUID(10),
- PlanetSideGUID(11),
- DriveState.Mobile,
- 0,
- false,
- Vector3(1.2f, 3.4f, 5.6f)
- )
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.DeployRequest(PlanetSideGUID(11), DriveState.Mobile, 0, false, Vector3(1.2f, 3.4f, 5.6f))
- )
- )
- }
- }
-}
-
-class DismountVehicleTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass DismountVehicle" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage("test", VehicleAction.DismountVehicle(PlanetSideGUID(10), BailType.Normal, false))
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.DismountVehicle(BailType.Normal, false)
- )
- )
- }
- }
-}
-
-class InventoryStateTest extends ActorTest {
- ServiceManager.boot(system)
- val tool = Tool(GlobalDefinitions.beamer)
- tool.AmmoSlots.head.Box.GUID = PlanetSideGUID(13)
- val cdata = tool.Definition.Packet.ConstructorData(tool).get
-
- "VehicleService" should {
- "pass InventoryState" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.InventoryState(PlanetSideGUID(10), tool, PlanetSideGUID(11), 0, cdata)
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.InventoryState(tool, PlanetSideGUID(11), 0, cdata)
- )
- )
- }
- }
-}
-
-class InventoryState2Test extends ActorTest {
- ServiceManager.boot(system)
- val tool = Tool(GlobalDefinitions.beamer)
- tool.AmmoSlots.head.Box.GUID = PlanetSideGUID(13)
- val cdata = tool.Definition.Packet.ConstructorData(tool).get
-
- "VehicleService" should {
- "pass InventoryState2" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.InventoryState2(PlanetSideGUID(10), PlanetSideGUID(11), PlanetSideGUID(12), 13)
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.InventoryState2(PlanetSideGUID(11), PlanetSideGUID(12), 13)
- )
- )
- }
- }
-}
-
-class KickPassengerTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass KickPassenger" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.KickPassenger(PlanetSideGUID(10), 0, false, PlanetSideGUID(11))
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.KickPassenger(0, false, PlanetSideGUID(11))
- )
- )
- }
- }
-}
-
-class LoadVehicleTest extends ActorTest {
- ServiceManager.boot(system)
- val vehicle = Vehicle(GlobalDefinitions.quadstealth)
- vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "test-vehicle")
- val cdata = vehicle.Definition.Packet.ConstructorData(vehicle).get
-
- "VehicleService" should {
- "pass LoadVehicle" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.LoadVehicle(PlanetSideGUID(10), vehicle, 12, PlanetSideGUID(11), cdata)
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.LoadVehicle(vehicle, 12, PlanetSideGUID(11), cdata)
- )
- )
- }
- }
-}
-
-class MountVehicleTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass MountVehicle" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage("test", VehicleAction.MountVehicle(PlanetSideGUID(10), PlanetSideGUID(11), 0))
- expectMsg(
- VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.MountVehicle(PlanetSideGUID(11), 0))
- )
- }
- }
-}
-
-class SeatPermissionsTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass SeatPermissions" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.SeatPermissions(PlanetSideGUID(10), PlanetSideGUID(11), 0, 12L)
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.SeatPermissions(PlanetSideGUID(11), 0, 12L)
- )
- )
- }
- }
-}
-
-class StowEquipmentTest extends ActorTest {
- ServiceManager.boot(system)
- val tool = Tool(GlobalDefinitions.beamer)
- tool.GUID = PlanetSideGUID(12)
- tool.AmmoSlots.head.Box.GUID = PlanetSideGUID(13)
- val toolDef = tool.Definition
- val cdata = tool.Definition.Packet.DetailedConstructorData(tool).get
-
- "StowEquipment" should {
- "pass StowEquipment" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.StowEquipment(PlanetSideGUID(10), PlanetSideGUID(11), 0, tool)
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.StowEquipment(PlanetSideGUID(11), 0, toolDef.ObjectId, tool.GUID, cdata)
- )
- )
- }
- }
-}
-
-class UnstowEquipmentTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass UnstowEquipment" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage("test", VehicleAction.UnstowEquipment(PlanetSideGUID(10), PlanetSideGUID(11)))
- expectMsg(
- VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.UnstowEquipment(PlanetSideGUID(11)))
- )
- }
- }
-}
-
-class VehicleStateTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass VehicleState" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.VehicleState(
- PlanetSideGUID(10),
- PlanetSideGUID(11),
- 0,
- Vector3(1.2f, 3.4f, 5.6f),
- Vector3(7.8f, 9.1f, 2.3f),
- Some(Vector3(4.5f, 6.7f, 8.9f)),
- Option(1),
- 2,
- 3,
- 4,
- false,
- true
- )
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.VehicleState(
- PlanetSideGUID(11),
- 0,
- Vector3(1.2f, 3.4f, 5.6f),
- Vector3(7.8f, 9.1f, 2.3f),
- Some(Vector3(4.5f, 6.7f, 8.9f)),
- Option(1),
- 2,
- 3,
- 4,
- false,
- true
- )
- )
- )
- }
- }
-}
-
-class TransferPassengerChannelTest extends ActorTest {
- ServiceManager.boot(system)
-
- "VehicleService" should {
- "pass TransferPassengerChannel" in {
- val service = system.actorOf(Props(classOf[VehicleService], Zone.Nowhere), "v-service")
- val fury = Vehicle(GlobalDefinitions.fury)
- fury.Actor = system.actorOf(Props(classOf[VehicleControl], fury), "test-fury")
- service ! Service.Join("test")
- service ! VehicleServiceMessage(
- "test",
- VehicleAction.TransferPassengerChannel(
- PlanetSideGUID(10),
- "old_channel",
- "new_channel",
- fury,
- PlanetSideGUID(11)
- )
- )
- expectMsg(
- VehicleServiceResponse(
- "/test/Vehicle",
- PlanetSideGUID(10),
- VehicleResponse.TransferPassengerChannel("old_channel", "new_channel", fury, PlanetSideGUID(11))
- )
- )
- }
- }
-}
-
-//class TransferPassengerTest extends ActorTest {
-// ServiceManager.boot(system)
-// "VehicleService" should {
-// "pass TransferPassenger" in {
-// val fury = Vehicle(GlobalDefinitions.fury)
-// val service = system.actorOf(Props[VehicleService], "v-service")
-// service ! Service.Join("test")
-// service ! VehicleServiceMessage("test", VehicleAction.TransferPassenger(PlanetSideGUID(10), "temp_channel", fury, PlanetSideGUID(11)))
-// expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.TransferPassenger("temp_channel", fury, PlanetSideGUID(11))))
-// }
-// }
-//}
-
-object VehicleServiceTest {
- //decoy
-}
diff --git a/src/test/scala/service/avatar/AvatarActionTest.scala b/src/test/scala/service/avatar/AvatarActionTest.scala
new file mode 100644
index 000000000..f83658d50
--- /dev/null
+++ b/src/test/scala/service/avatar/AvatarActionTest.scala
@@ -0,0 +1,215 @@
+// Copyright (c) 2026 PSForever
+package service.avatar
+
+import net.psforever.objects.avatar.Avatar
+import net.psforever.objects.ballistics.Projectile
+import net.psforever.objects.sourcing.SourceEntry
+import net.psforever.objects.zones.{Zone, ZoneMap}
+import net.psforever.objects.{GlobalDefinitions, Player, Tool}
+import net.psforever.packet.game.ObjectCreateMessage
+import net.psforever.packet.game.objectcreate.{BasicCharacterData, DroppedItemData, ObjectCreateMessageParent, PlacementData}
+import net.psforever.services.avatar.AvatarAction
+import net.psforever.services.base.message.ObjectDelete
+import net.psforever.types._
+import org.specs2.mutable.Specification
+
+object AvatarActionTest {
+ assert(GlobalDefinitions.suppressor != null, "missing definition - suppressor does not exist")
+ assert(GlobalDefinitions.avatar != null, "missing definition - avatar does not exist")
+
+ private var i: Int = 1
+ val testSuppressor: Tool = {
+ val obj = new Tool(GlobalDefinitions.suppressor)
+ obj.Position = Vector3(1, 2, 3)
+ obj.Orientation = Vector3(4, 5, 6)
+ obj.GUID = PlanetSideGUID(i)
+ i += 1
+ obj.AmmoSlots.map(_.Box).foreach { box =>
+ box.GUID = PlanetSideGUID(i)
+ i += 1
+ }
+ obj
+ }
+
+ val testPlayer: Player = {
+ val avatar = new Avatar(id = 1, BasicCharacterData("testPlayer", PlanetSideEmpire.TR, CharacterSex.Male, 0, CharacterVoice.Mute))
+ avatar.locker.GUID = PlanetSideGUID(i)
+ i += 1
+ val obj = new Player(avatar)
+ obj.Position = Vector3(1, 2, 3)
+ obj.Orientation = Vector3(4, 5, 6)
+ obj.GUID = PlanetSideGUID(i)
+ obj.Spawn()
+ i += 1
+ obj
+ }
+}
+
+class AvatarActionTest extends Specification {
+ import AvatarActionTest._
+
+ "DropItem" should {
+ "respond" in {
+ val obj = testSuppressor
+ val msg = AvatarAction.DropItem(obj)
+ val definition = obj.Definition
+ val objectData = DroppedItemData(
+ PlacementData(obj.Position, obj.Orientation),
+ definition.Packet.ConstructorData(obj).get
+ )
+ msg.response() match {
+ case AvatarAction.DropCreatedItem(pkt) =>
+ pkt match {
+ case ObjectCreateMessage(_, oid, guid, _, data) =>
+ oid mustEqual definition.ObjectId
+ guid mustEqual obj.GUID
+ data mustEqual objectData
+ case _ =>
+ ko
+ }
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "EquipmentInHand" should {
+ "respond" in {
+ val obj = testSuppressor
+ val msg = AvatarAction.EquipmentInHand(PlanetSideGUID(100), 2, obj)
+ val definition = obj.Definition
+ val objectData = definition.Packet.ConstructorData(obj).get
+ msg.response() match {
+ case AvatarAction.EquipmentCreatedInHand(pkt) =>
+ pkt match {
+ case ObjectCreateMessage(_, oid, guid, pdata, data) =>
+ oid mustEqual definition.ObjectId
+ guid mustEqual obj.GUID
+ pdata.contains(ObjectCreateMessageParent(PlanetSideGUID(100), 2)) mustEqual true
+ data mustEqual objectData
+ case _ =>
+ ko
+ }
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "LoadPlayer (1)" should {
+ "respond" in {
+ val obj = testPlayer
+ val definition = obj.Definition
+ val id = definition.ObjectId
+ val guid = obj.GUID
+ val objectData = definition.Packet.ConstructorData(obj).get
+ val msg = AvatarAction.LoadPlayer(id, guid, objectData, None)
+ msg.response() match {
+ case AvatarAction.LoadCreatedPlayer(pkt) =>
+ pkt match {
+ case ObjectCreateMessage(_, oid, guid, _, data) =>
+ oid mustEqual id
+ guid mustEqual guid
+ data mustEqual objectData
+ case _ =>
+ ko
+ }
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "LoadPlayer (2)" should {
+ "respond" in {
+ val obj = testPlayer
+ val definition = obj.Definition
+ val id = definition.ObjectId
+ val guid = obj.GUID
+ val parentData = ObjectCreateMessageParent(PlanetSideGUID(100), 2)
+ val objectData = definition.Packet.ConstructorData(obj).get
+ val msg = AvatarAction.LoadPlayer(id, guid, objectData, Some(parentData))
+ msg.response() match {
+ case AvatarAction.LoadCreatedPlayer(pkt) =>
+ pkt match {
+ case ObjectCreateMessage(_, oid, guid, pdata, data) =>
+ oid mustEqual id
+ guid mustEqual guid
+ pdata.contains(parentData) mustEqual true
+ data mustEqual objectData
+ case _ =>
+ ko
+ }
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "LoadProjectile" should {
+ assert(GlobalDefinitions.wasp_rocket_projectile != null, "missing definition - wasp_rocket_projectile does not exist")
+ assert(GlobalDefinitions.wasp_weapon_system != null, "missing definition - wasp_weapon_system does not exist")
+
+ "respond" in {
+ val obj = new Projectile(
+ GlobalDefinitions.wasp_rocket_projectile,
+ GlobalDefinitions.wasp_weapon_system,
+ GlobalDefinitions.wasp_weapon_system.FireModes.head,
+ Some((1, SourceEntry.None)),
+ SourceEntry.None,
+ GlobalDefinitions.wasp_weapon_system.ObjectId,
+ Vector3(1, 2, 3),
+ Vector3(4, 5, 6),
+ Some(Vector3(7, 8, 9))
+ )
+ obj.GUID = PlanetSideGUID(1)
+ val definition = obj.Definition
+ val id = definition.ObjectId
+ val guid = obj.GUID
+ val objectData = definition.Packet.ConstructorData(obj).get
+ val msg = AvatarAction.LoadProjectile(id, guid, objectData)
+ msg.response() match {
+ case AvatarAction.LoadCreatedProjectile(pkt) =>
+ pkt match {
+ case ObjectCreateMessage(_, oid, guid, _, data) =>
+ oid mustEqual id
+ guid mustEqual guid
+ data mustEqual objectData
+ case _ =>
+ ko
+ }
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "PickupItem" should {
+ "respond" in {
+ val obj = testSuppressor
+ val msg = AvatarAction.PickupItem(obj, 2)
+ msg.response() match {
+ case ObjectDelete(guid, slot) =>
+ guid mustEqual obj.GUID
+ slot mustEqual 2
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "Release" should {
+ val testZone: Zone = new Zone(id = "test", new ZoneMap( name = "test"), zoneNumber = 1)
+
+ "respond" in {
+ val obj = testPlayer
+ val msg = AvatarAction.Release(obj, testZone)
+ msg.response() match {
+ case AvatarAction.ReleasePlayer(player) =>
+ (player == obj) mustEqual true
+ case _ =>
+ ko
+ }
+ }
+ }
+}
diff --git a/src/test/scala/service/base/EnvelopeTest.scala b/src/test/scala/service/base/EnvelopeTest.scala
new file mode 100644
index 000000000..b2f11c1f5
--- /dev/null
+++ b/src/test/scala/service/base/EnvelopeTest.scala
@@ -0,0 +1,89 @@
+// Copyright (c) 2026 PSForever
+package service.base
+
+import net.psforever.services.base.EventSystemStamp
+import net.psforever.services.base.envelope._
+import net.psforever.services.base.message.{EventMessage, EventResponse, SelfRespondingEvent}
+import net.psforever.types.PlanetSideGUID
+import org.specs2.mutable.Specification
+
+object EnvelopeTest {
+ case object TestStamp extends EventSystemStamp
+
+ val TestFilter: PlanetSideGUID = PlanetSideGUID(1)
+
+ final def StringWithSlashes(str: String): String = s"/$str/"
+
+ final case class TestMessage(value: Int) extends SelfRespondingEvent
+
+ final case class TestOutputEvent(value: Int) extends EventResponse
+
+ final case class TestInputMessage(value: Int) extends EventMessage {
+ def response(): EventResponse = TestOutputEvent(value + 2)
+ }
+}
+
+class EnvelopeTest extends Specification {
+ import EnvelopeTest._
+
+ "MessageEnvelope" should {
+ "construct" in {
+ MessageEnvelope("test", TestFilter, TestMessage(5))
+ ok
+ }
+
+ "message match" in {
+ val input = MessageEnvelope("test", TestFilter, TestMessage(5))
+ input match {
+ case GenericMessageEnvelope("test", TestFilter, TestMessage(5)) =>
+ ok
+ case _ =>
+ ko
+ }
+ }
+
+ "response (no stamp)" in {
+ val input = MessageEnvelope("test", TestFilter, TestMessage(5))
+ input match {
+ case reply @ GenericResponseEnvelope("test", TestFilter, NoReply) =>
+ reply.stamp mustEqual Undelivered
+ case _ =>
+ ko
+ }
+ }
+
+ "response" in {
+ val input = MessageEnvelope("test", TestFilter, TestMessage(5))
+ val output = input.response(TestStamp)
+ output match {
+ case reply @ GenericResponseEnvelope("test", TestFilter, TestMessage(5)) =>
+ reply.stamp mustEqual TestStamp
+ case _ =>
+ ko
+ }
+ }
+
+ "response (different from input)" in {
+ val input = MessageEnvelope("test", TestFilter, TestInputMessage(5))
+ val output = input.response(TestStamp)
+ output match {
+ case reply @ GenericResponseEnvelope("test", TestFilter, TestOutputEvent(7)) =>
+ reply.stamp mustEqual TestStamp
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "GenericResponseEnvelope" should {
+ "construct (quick)" in {
+ val input = GenericResponseEnvelope(TestStamp, "test", TestFilter, TestMessage(5))
+ input match {
+ case reply @ GenericResponseEnvelope("test", TestFilter, TestMessage(5)) =>
+ reply.stamp mustEqual TestStamp
+ case _ =>
+ ko
+ }
+ }
+ }
+}
diff --git a/src/test/scala/service/base/EventMessageTest.scala b/src/test/scala/service/base/EventMessageTest.scala
new file mode 100644
index 000000000..8b9b1bf50
--- /dev/null
+++ b/src/test/scala/service/base/EventMessageTest.scala
@@ -0,0 +1,42 @@
+// Copyright (c) 2026 PSForever
+package service.base
+
+import net.psforever.services.base.message.{EventMessage, EventResponse, SelfRespondingEvent}
+import org.specs2.mutable.Specification
+
+object EventMessageTest {
+ final case class TestOutputEvent(value: Int) extends EventResponse
+
+ final case class TestInputMessage(value: Int) extends EventMessage {
+ def response(): EventResponse = TestOutputEvent(value + 2)
+ }
+
+ final case class TestMessage(value: Int) extends SelfRespondingEvent
+}
+
+class EventMessageTest extends Specification {
+ import EventMessageTest._
+
+ "EventMessage" should {
+ "construct" in {
+ TestInputMessage(5)
+ ok
+ }
+
+ "response" in {
+ TestInputMessage(5).response() mustEqual TestOutputEvent(7)
+ }
+ }
+
+ "SelfResponseMessage" should {
+ "construct" in {
+ TestMessage(5)
+ ok
+ }
+
+ "response (is same as self)" in {
+ val msg = TestMessage(5)
+ msg.response() mustEqual msg
+ }
+ }
+}
diff --git a/src/test/scala/service/base/EventServiceCacheSupportTest.scala b/src/test/scala/service/base/EventServiceCacheSupportTest.scala
new file mode 100644
index 000000000..7a10dfcdf
--- /dev/null
+++ b/src/test/scala/service/base/EventServiceCacheSupportTest.scala
@@ -0,0 +1,222 @@
+// Copyright (c) 2026 PSForever
+package service.base
+
+import akka.actor.{ActorRef, ActorSystem, Props}
+import akka.testkit.TestProbe
+import base.ActorTest
+import net.psforever.objects.Default
+import net.psforever.services.Service
+import net.psforever.services.base.message.EventMessage
+import net.psforever.services.base.{CachedEnvelope, CachedGenericEventEnvelope, EventServiceSupport, GenericEventServiceWithCacheAndSupport, GenericSupportEnvelope}
+import net.psforever.types.PlanetSideGUID
+
+import scala.concurrent.duration._
+
+object EventServiceCacheSupportTest {
+ final case class CachedSupportTestEnvelope(
+ guid: PlanetSideGUID,
+ channel: String,
+ override val msg: EventMessage,
+ supportMessage: Any
+ ) extends CachedGenericEventEnvelope with GenericSupportEnvelope {
+ assert(guid != Default.GUID0, "can not cache message under default GUID")
+ def filter: PlanetSideGUID = Default.GUID0
+ def supportLabel: String = "supportActor"
+ }
+
+ class TestCacheService(eventSupportServices: List[EventServiceSupport])
+ extends GenericEventServiceWithCacheAndSupport(EventServiceTestBase.TestStamp, eventSupportServices)
+
+ def SpawnTestSystem(eventSupportServices: List[EventServiceSupport])(implicit system: ActorSystem, self: ActorRef): ActorRef = {
+ val name = self.getClass.getSimpleName.replace("EventServiceCacheSupportTest", "")
+ system.actorOf(Props(classOf[TestCacheService], eventSupportServices), name = s"EventServiceCacheSupportTest.$name")
+ }
+}
+
+class EventServiceCacheSupportTestDefault extends ActorTest {
+ "GenericEventServiceWithCacheAndSupport" should {
+ "construct" in {
+ EventServiceCacheSupportTest.SpawnTestSystem(List())
+ }
+ }
+}
+
+class EventServiceCacheSupportTestSupportNormally extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventServiceWithCacheAndSupport" should {
+ "send a valid message to both subscribed channel and support class, like normal GenericEventServiceWithSupport" in {
+ val mainProbe = TestProbe("MainProbe")
+ val supportProbe = TestProbe("SupportProbe")
+ val events = EventServiceCacheSupportTest.SpawnTestSystem(List(TestSupportActorLoader))
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val originalMessage = TestSupportEnvelope("test", SupportActorRepliesWith("hello world", supportProbe.ref))
+ events ! originalMessage
+ //main reply
+ val mainReply = mainProbe.receiveOne(250 milliseconds)
+ mainReply match {
+ case msg if msg == originalMessage => ()
+ case badmsg =>
+ assert(false, s"(1) expected delivery of test envelope, but received $badmsg instead")
+ }
+ //support reply
+ val supportReply = supportProbe.receiveOne(250 milliseconds)
+ supportReply match {
+ case msg: String if msg.equals("hello world") => ()
+ case badmsg =>
+ assert(false, s"(2) expected delivery of test envelope payload 'hello world', but received '$badmsg' instead")
+ }
+ }
+ }
+}
+
+class EventServiceCacheSupportTestCachedMessages extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventServiceWithCacheAndSupport" should {
+ "wait on sending designated cache-able messages after a few milliseconds" in {
+ val mainProbe = TestProbe("MainProbe")
+ val events = EventServiceCacheSupportTest.SpawnTestSystem(List())
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val firstMessage = CachedEnvelope(PlanetSideGUID(1), "test", TestMessage(1))
+ events ! firstMessage
+ mainProbe.expectNoMessage(50 milliseconds)
+ val reply = mainProbe.receiveOne(125 milliseconds)
+ reply match {
+ case msg if msg == firstMessage => ()
+ case badmsg =>
+ assert(false, s"(3) expected delivery of test envelope, but received $badmsg instead")
+ }
+ }
+ }
+}
+
+class EventServiceCacheSupportTestMultipleCachedMessagesAtOnce extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventServiceWithCacheAndSupport" should {
+ "send cache-able messages within a time span in bulk" in {
+ val mainProbe = TestProbe("MainProbe")
+ val events = EventServiceCacheSupportTest.SpawnTestSystem(List())
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val firstMessage = CachedEnvelope(PlanetSideGUID(1), "test", TestMessage(1))
+ val secondMessage = CachedEnvelope(PlanetSideGUID(2), "test", TestMessage(2))
+ val thirdMessage = CachedEnvelope(PlanetSideGUID(3), "test", TestMessage(3))
+ events ! firstMessage
+ events ! secondMessage
+ events ! thirdMessage
+ mainProbe.expectNoMessage(50 milliseconds)
+ val reply = mainProbe.receiveN(3, 125 milliseconds)
+ reply.head match {
+ case msg if msg == firstMessage => ()
+ case badmsg =>
+ assert(false, s"(4) expected delivery of test envelope, but received $badmsg instead")
+ }
+ reply(1) match {
+ case msg if msg == secondMessage => ()
+ case badmsg =>
+ assert(false, s"(5) expected delivery of test envelope, but received $badmsg instead")
+ }
+ reply(2) match {
+ case msg if msg == thirdMessage => ()
+ case badmsg =>
+ assert(false, s"(6) expected delivery of test envelope, but received $badmsg instead")
+ }
+ mainProbe.expectNoMessage(65 milliseconds)
+ }
+ }
+}
+
+class EventServiceCacheSupportTestMultipleCachedSameMessages extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventServiceWithCacheAndSupport" should {
+ "only caches and dispatches the last message with a given filtering token" in {
+ val mainProbe = TestProbe("MainProbe")
+ val events = EventServiceCacheSupportTest.SpawnTestSystem(List())
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val firstMessage = CachedEnvelope(PlanetSideGUID(1), "test", TestMessage(1))
+ val secondMessage = CachedEnvelope(PlanetSideGUID(1), "test", TestMessage(2))
+ val thirdMessage = CachedEnvelope(PlanetSideGUID(1), "test", TestMessage(3)) //this one!
+ events ! firstMessage
+ mainProbe.expectNoMessage(50 milliseconds)
+ events ! secondMessage
+ events ! thirdMessage
+ val reply = mainProbe.receiveOne(125 milliseconds)
+ reply match {
+ case badmsg if badmsg == firstMessage =>
+ assert(false, s"(1) received wrong message - $badmsg")
+ case badmsg if badmsg == secondMessage =>
+ assert(false, s"(2) received wrong message - $badmsg")
+ case msg if msg == thirdMessage => ()
+ case badmsg =>
+ assert(false, s"(7) expected delivery of test envelope, but received $badmsg instead")
+ }
+ mainProbe.expectNoMessage(150 milliseconds)
+ }
+ }
+}
+
+class EventServiceCacheSupportTestMultipleCachedMessages extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventServiceWithCacheAndSupport" should {
+ "send cache-able messages within a time span, separated if they are part of different caches" in {
+ val mainProbe = TestProbe("MainProbe")
+ val events = EventServiceCacheSupportTest.SpawnTestSystem(List())
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val firstMessage = CachedEnvelope(PlanetSideGUID(1), "test", TestMessage(1))
+ //first cache flush
+ events ! firstMessage
+ mainProbe.expectNoMessage(50 milliseconds)
+ val firstReply = mainProbe.receiveOne(125 milliseconds)
+ firstReply match {
+ case msg if msg == firstMessage => ()
+ case badmsg =>
+ assert(false, s"(8) expected delivery of test envelope, but received $badmsg instead")
+ }
+ mainProbe.expectNoMessage(100 milliseconds)
+ //second cache flush
+ val secondMessage = CachedEnvelope(PlanetSideGUID(2), "test", TestMessage(2))
+ events ! secondMessage
+ mainProbe.expectNoMessage(50 milliseconds)
+ val reply = mainProbe.receiveOne(125 milliseconds)
+ reply match {
+ case msg if msg == secondMessage => ()
+ case badmsg =>
+ assert(false, s"(9) expected delivery of test envelope, but received $badmsg instead")
+ }
+ }
+ }
+}
+
+class EventServiceCacheSupportTestSupportDelayed extends ActorTest {
+ import EventServiceCacheSupportTest._
+ import EventServiceTestBase._
+ "GenericEventServiceWithCacheAndSupport" should {
+ "cache a message for a support actor, but only dispatch that message to the support actor when flushing the cache" in {
+ val mainProbe = TestProbe("MainProbe")
+ val supportProbe = TestProbe("SupportProbe")
+ val events = EventServiceCacheSupportTest.SpawnTestSystem(List(TestSupportActorLoader))
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val originalMessage = CachedSupportTestEnvelope(
+ PlanetSideGUID(1),
+ "test",
+ TestMessage(1),
+ SupportActorRepliesWith("hello world", supportProbe.ref)
+ )
+ events ! originalMessage
+ //main reply
+ supportProbe.expectNoMessage(50 milliseconds)
+ mainProbe.expectNoMessage(10 milliseconds)
+ val mainReply = mainProbe.receiveOne(125 milliseconds)
+ mainReply match {
+ case msg if msg == originalMessage => ()
+ case badmsg =>
+ assert(false, s"(10) expected delivery of test envelope, but received $badmsg instead")
+ }
+ //support reply
+ val supportReply = supportProbe.receiveOne(10 milliseconds)
+ supportReply match {
+ case msg: String if msg.equals("hello world") => ()
+ case badmsg =>
+ assert(false, s"(11) expected delivery of test envelope payload 'hello world', but received '$badmsg' instead")
+ }
+ }
+ }
+}
diff --git a/src/test/scala/service/base/EventServiceSupportTest.scala b/src/test/scala/service/base/EventServiceSupportTest.scala
new file mode 100644
index 000000000..53d96d3c7
--- /dev/null
+++ b/src/test/scala/service/base/EventServiceSupportTest.scala
@@ -0,0 +1,134 @@
+// Copyright (c) 2026 PSForever
+package service.base
+
+import akka.actor.{ActorRef, ActorSystem, Props}
+import akka.testkit.TestProbe
+import base.ActorTest
+import net.psforever.services.Service
+import net.psforever.services.base.{EventServiceSupport, GenericEventServiceWithSupport, GenericSupportEnvelopeOnly}
+
+import scala.concurrent.duration._
+
+object EventServiceSupportTest {
+ final case class TestSupportOnlyEnvelope(supportLabel: String, supportMessage: EventServiceTestBase.SupportActorRepliesWith)
+ extends GenericSupportEnvelopeOnly
+
+ class TestSupportService(eventSupportServices: List[EventServiceSupport])
+ extends GenericEventServiceWithSupport(EventServiceTestBase.TestStamp, eventSupportServices)
+
+ def SpawnTestSystem(eventSupportServices: List[EventServiceSupport])(implicit system: ActorSystem, self: ActorRef): ActorRef = {
+ val name = self.getClass.getSimpleName.replace("EventServiceSupportTest", "")
+ system.actorOf(Props(classOf[TestSupportService], eventSupportServices), name = s"EventServiceSupportTest.$name")
+ }
+}
+
+class EventServiceSupportTestDefault extends ActorTest {
+ "GenericEventServiceWithSupport" should {
+ "construct" in {
+ EventServiceSupportTest.SpawnTestSystem(List())
+ }
+ }
+}
+
+class EventServiceSupportTestLoadSupportClass extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventServiceWithSupport" should {
+ "construct with setting up a test support class" in {
+ EventServiceSupportTest.SpawnTestSystem(List(TestSupportActorLoader))
+ }
+ }
+}
+
+class EventServiceSupportTestSendToSupportClass extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventServiceWithSupport" should {
+ "send a valid message to both subscribed channel and support class" in {
+ val mainProbe = TestProbe("MainProbe")
+ val supportProbe = TestProbe("SupportProbe")
+ val events = EventServiceSupportTest.SpawnTestSystem(List(TestSupportActorLoader))
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val originalMessage = TestSupportEnvelope("test", SupportActorRepliesWith("hello world", supportProbe.ref))
+ events ! originalMessage
+ //main reply
+ val mainReply = mainProbe.receiveOne(250 milliseconds)
+ mainReply match {
+ case msg if msg == originalMessage => ()
+ case badmsg =>
+ assert(false, s"(1) expected delivery of test envelope, but received $badmsg instead")
+ }
+ //support reply
+ val supportReply = supportProbe.receiveOne(250 milliseconds)
+ supportReply match {
+ case msg: String if msg.equals("hello world") => ()
+ case badmsg =>
+ assert(false, s"(2) expected delivery of test envelope payload 'hello world', but received '$badmsg' instead")
+ }
+ }
+ }
+}
+
+class EventServiceSupportTestSendToSupportClassOnly1 extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventServiceWithSupport" should {
+ "send a valid message to support class (but not to subscribed channel)" in {
+ val mainProbe = TestProbe("MainProbe")
+ val supportProbe = TestProbe("SupportProbe")
+ val events = EventServiceSupportTest.SpawnTestSystem(List(TestSupportActorLoader))
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val originalMessage = TestSupportEnvelope("notatest", SupportActorRepliesWith("hello world", supportProbe.ref))
+ events ! originalMessage
+ //main reply (no reply)
+ mainProbe.expectNoMessage(500 milliseconds)
+ //support reply
+ val supportReply = supportProbe.receiveOne(250 milliseconds)
+ supportReply match {
+ case msg: String if msg.equals("hello world") => ()
+ case badmsg =>
+ assert(false, s"(3) expected delivery of test envelope payload 'hello world', but received '$badmsg' instead")
+ }
+ }
+ }
+}
+
+class EventServiceSupportTestSendToSupportClassOnly2 extends ActorTest {
+ import EventServiceSupportTest._
+ import EventServiceTestBase._
+ "GenericEventServiceWithSupport" should {
+ "send a valid message to support class (skip subscribed channel)" in {
+ val mainProbe = TestProbe("MainProbe")
+ val supportProbe = TestProbe("SupportProbe")
+ val events = EventServiceSupportTest.SpawnTestSystem(List(TestSupportActorLoader))
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val originalMessage = TestSupportOnlyEnvelope("supportActor", SupportActorRepliesWith("hello world", supportProbe.ref))
+ events ! originalMessage
+ //main reply (no reply)
+ mainProbe.expectNoMessage(500 milliseconds)
+ //support reply
+ val supportReply = supportProbe.receiveOne(250 milliseconds)
+ supportReply match {
+ case msg: String if msg.equals("hello world") => ()
+ case badmsg =>
+ assert(false, s"(4) expected delivery of test envelope payload 'hello world', but received '$badmsg' instead")
+ }
+ }
+ }
+}
+
+class EventServiceSupportTestSendToNoOne extends ActorTest {
+ import EventServiceSupportTest._
+ import EventServiceTestBase._
+ "GenericEventServiceWithSupport" should {
+ "send a valid message that neither support class nor subscribed channel handle" in {
+ val mainProbe = TestProbe("MainProbe")
+ val supportProbe = TestProbe("SupportProbe")
+ val events = EventServiceSupportTest.SpawnTestSystem(List(TestSupportActorLoader))
+ events.tell(Service.Join("test"), mainProbe.ref)
+ val originalMessage = TestSupportOnlyEnvelope("notASupportActor", SupportActorRepliesWith("hello world", supportProbe.ref))
+ events ! originalMessage
+ //main reply (no reply)
+ mainProbe.expectNoMessage(500 milliseconds)
+ //support reply (no reply)
+ supportProbe.expectNoMessage(500 milliseconds)
+ }
+ }
+}
diff --git a/src/test/scala/service/base/EventServiceTest.scala b/src/test/scala/service/base/EventServiceTest.scala
new file mode 100644
index 000000000..1be95949a
--- /dev/null
+++ b/src/test/scala/service/base/EventServiceTest.scala
@@ -0,0 +1,179 @@
+// Copyright (c) 2026 PSForever
+package service.base
+
+import akka.actor.{ActorRef, ActorSystem, Props}
+import akka.testkit.TestProbe
+import base.ActorTest
+import net.psforever.objects.Default
+import net.psforever.services.Service
+import net.psforever.services.base.GenericEventService
+import net.psforever.services.base.envelope.{GenericResponseEnvelope, MessageEnvelope}
+
+import scala.concurrent.duration._
+
+object EventServiceTest {
+ class TestService() extends GenericEventService(EventServiceTestBase.TestStamp)
+
+ def SpawnTestSystem()(implicit system: ActorSystem, self: ActorRef): ActorRef = {
+ val name = self.getClass.getSimpleName.replace("EventServiceTest", "")
+ system.actorOf(Props[TestService](), name = s"EventServiceTest.$name")
+ }
+}
+
+class EventServiceTestDefault extends ActorTest {
+ "GenericEventSystem" should {
+ "construct" in {
+ EventServiceTest.SpawnTestSystem()
+ }
+ }
+}
+
+class EventServiceTestSubscribe extends ActorTest {
+ "GenericEventSystem" should {
+ "be subscribed to by channel name" in {
+ val probe = TestProbe("testProbe")
+ val events = EventServiceTest.SpawnTestSystem()
+ events.tell(Service.Join("test"), probe.ref)
+ probe.expectNoMessage(100 milliseconds)
+ }
+ }
+}
+
+class EventServiceTestSubscribeConfirm extends ActorTest {
+ "GenericEventSystem" should {
+ "be subscribed to by channel name and send a confirmation when prompted" in {
+ val probe = TestProbe("testProbe")
+ val events = EventServiceTest.SpawnTestSystem()
+ events.tell(Service.Join("test", sendJoinConfirmation = true), probe.ref)
+ val reply = probe.receiveOne(100 milliseconds)
+ assert(reply == Service.JoinConfirmation(events, "test"), "join confirmation expected but not received")
+ }
+ }
+}
+
+class EventServiceTestSubscriptionMessage extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventSystem" should {
+ "receive messages from a subscribed channel" in {
+ val probe = TestProbe("testProbe")
+ val events = EventServiceTest.SpawnTestSystem()
+ events.tell(Service.Join("test"), probe.ref)
+ events ! MessageEnvelope("test", Default.GUID0, TestMessage(5))
+ probe.receiveN(1, 100 milliseconds)
+ }
+ }
+}
+
+class EventServiceTestSubscriptionReply extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventSystem" should {
+ "receive messages that are responses to the original message from a subscribed channel" in {
+ val probe = TestProbe("testProbe")
+ val events = EventServiceTest.SpawnTestSystem()
+ val msg = MessageEnvelope("test", Default.GUID0, TestMessage(5))
+ // s => "/$s" is the default channel manipulation of the event system
+ val formalReply = msg.response(EventServiceTestBase.TestStamp)
+ events.tell(Service.Join("test"), probe.ref)
+ events ! MessageEnvelope("test", Default.GUID0, TestMessage(5))
+ val reply = probe.receiveOne(100 milliseconds)
+ assert(reply == formalReply, "(1) message expected but not received format")
+ }
+ }
+}
+
+class EventServiceTestNotSubscribed extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventSystem" should {
+ "not receive messages from an unsubscribed channel" in {
+ val probe = TestProbe("testProbe")
+ val missedProbe = TestProbe("testProbe")
+ val events = EventServiceTest.SpawnTestSystem()
+ events.tell(Service.Join("test"), probe.ref)
+ events.tell(Service.Join("notATest"), missedProbe.ref)
+ events ! MessageEnvelope("test", Default.GUID0, TestMessage(5))
+ val reply = probe.receiveOne(100 milliseconds)
+ reply match {
+ case GenericResponseEnvelope("test", _, TestMessage(5)) => ()
+ case _ => assert(false, "(2) message expected but not received")
+ }
+ missedProbe.expectNoMessage(100 milliseconds)
+ }
+ }
+}
+
+class EventServiceTestUnexpectedMessages extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventSystem" should {
+ "ignore unexpected messages" in {
+ val probe = TestProbe("testProbe")
+ val events = EventServiceTest.SpawnTestSystem()
+ events.tell(Service.Join("test"), probe.ref)
+ events ! TestMessage(5)
+ probe.expectNoMessage(250 milliseconds)
+ //the warn log should show something
+ }
+ }
+}
+
+class EventServiceTestLeave extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventSystem" should {
+ "leave single channels" in {
+ val probe = TestProbe("testProbe")
+ val events = EventServiceTest.SpawnTestSystem()
+ events.tell(Service.Join("test"), probe.ref)
+ events.tell(Service.Join("anotherTest"), probe.ref)
+
+ events ! MessageEnvelope("test", Default.GUID0, TestMessage(5))
+ events ! MessageEnvelope("anotherTest", Default.GUID0, TestMessage(5))
+ val reply1 = probe.receiveN(2, 100 milliseconds)
+ reply1.head match {
+ case GenericResponseEnvelope("test", _, _) => ()
+ case _ => assert(false, "(3) message expected but not received")
+ }
+ reply1(1) match {
+ case GenericResponseEnvelope("anotherTest", _, _) => ()
+ case _ => assert(false, "(4) message expected but not received")
+ }
+
+ events.tell(Service.Leave("anotherTest"), probe.ref)
+ events ! MessageEnvelope("test", Default.GUID0, TestMessage(5))
+ events ! MessageEnvelope("anotherTest", Default.GUID0, TestMessage(6))
+ val reply2 = probe.receiveOne(100 milliseconds)
+ reply2 match {
+ case GenericResponseEnvelope("test", _, TestMessage(5)) => ()
+ case _ => assert(false, "(5) message expected but not received")
+ }
+ probe.expectNoMessage(250 milliseconds)
+ }
+ }
+}
+
+class EventServiceTestLeaveAll extends ActorTest {
+ import EventServiceTestBase._
+ "GenericEventSystem" should {
+ "leave all channels (1)" in {
+ val probe = TestProbe("testProbe")
+ val events = EventServiceTest.SpawnTestSystem()
+ events.tell(Service.Join("test"), probe.ref)
+ events.tell(Service.Join("anotherTest"), probe.ref)
+
+ events ! MessageEnvelope("test", Default.GUID0, TestMessage(5))
+ events ! MessageEnvelope("anotherTest", Default.GUID0, TestMessage(6))
+ val reply = probe.receiveN(2,100 milliseconds)
+ reply.head match {
+ case GenericResponseEnvelope("test", _, TestMessage(5)) => ()
+ case _ => assert(false, "(6) message expected but not received")
+ }
+ reply(1) match {
+ case GenericResponseEnvelope("anotherTest", _, TestMessage(6)) => ()
+ case _ => assert(false, "(7) message expected but not received")
+ }
+
+ events.tell(Service.LeaveAll, probe.ref)
+ events ! MessageEnvelope("test", Default.GUID0, TestMessage(5))
+ events ! MessageEnvelope("anotherTest", Default.GUID0, TestMessage(6))
+ probe.expectNoMessage(250 milliseconds)
+ }
+ }
+}
diff --git a/src/test/scala/service/base/EventServiceTestBase.scala b/src/test/scala/service/base/EventServiceTestBase.scala
new file mode 100644
index 000000000..81ec8b1be
--- /dev/null
+++ b/src/test/scala/service/base/EventServiceTestBase.scala
@@ -0,0 +1,39 @@
+package service.base
+
+import akka.actor.{Actor, ActorContext, ActorRef, Props}
+import net.psforever.objects.Default
+import net.psforever.services.base.message.SelfRespondingEvent
+import net.psforever.services.base.{EventServiceSupport, EventSystemStamp, GenericSupportEnvelope}
+import net.psforever.types.PlanetSideGUID
+
+object EventServiceTestBase {
+ case object TestStamp extends EventSystemStamp
+
+ final case class TestMessage(value: Int) extends SelfRespondingEvent
+
+ final case class SupportActorRepliesWith(msg: String, sendTo: ActorRef) extends SelfRespondingEvent
+
+ class TestSupportActor extends Actor {
+ def receive: Receive = {
+ case SupportActorRepliesWith(msg, sendTo) =>
+ sendTo ! msg
+ case _ => ()
+ }
+ }
+
+ case object TestSupportActorLoader extends EventServiceSupport {
+ def label: String = "supportActor"
+ def constructor(context: ActorContext): ActorRef = {
+ context.actorOf(Props[TestSupportActor](), name = "supportActor")
+ }
+ }
+
+ final case class TestSupportEnvelope(
+ channel: String,
+ msg: SupportActorRepliesWith
+ ) extends GenericSupportEnvelope {
+ def filter: PlanetSideGUID = Default.GUID0
+ def supportLabel: String = "supportActor"
+ def supportMessage: Any = msg
+ }
+}
diff --git a/src/test/scala/service/local/LocalActionTest.scala b/src/test/scala/service/local/LocalActionTest.scala
new file mode 100644
index 000000000..87d055260
--- /dev/null
+++ b/src/test/scala/service/local/LocalActionTest.scala
@@ -0,0 +1,73 @@
+// Copyright (c) 2026 PSForever
+package service.local
+
+import net.psforever.objects.{ExplosiveDeployable, GlobalDefinitions}
+import net.psforever.packet.game.{ObjectCreateMessage, TriggeredEffect, TriggeredEffectLocation}
+import net.psforever.services.Service
+import net.psforever.services.base.message.SendResponse
+import net.psforever.services.local.LocalAction
+import net.psforever.types.{PlanetSideGUID, Vector3}
+import org.specs2.mutable.Specification
+
+class LocalActionTest extends Specification {
+ "DeployItem" should {
+ assert(GlobalDefinitions.boomer != null, "missing definition - Boomer does not exist")
+
+ "respond" in {
+ val obj = new ExplosiveDeployable(GlobalDefinitions.boomer)
+ obj.GUID = PlanetSideGUID(1)
+ val msg = LocalAction.DeployItem(obj)
+ val definition = obj.Definition
+ val objectData = definition.Packet.ConstructorData(obj).get
+ msg.response() match {
+ case SendResponse(packets) =>
+ packets.head match {
+ case ObjectCreateMessage(_, oid, guid, _, data) =>
+ oid mustEqual definition.ObjectId
+ guid mustEqual obj.GUID
+ data mustEqual objectData
+ case _ =>
+ ko
+ }
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "TriggerEffect" should {
+ "respond" in {
+ val msg = LocalAction.TriggerEffect("on", PlanetSideGUID(1))
+ msg.response() match {
+ case LocalAction.TriggerEffectAtLocation(PlanetSideGUID(1), "on", None, None) =>
+ ok
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "TriggerEffectInfo" should {
+ "respond" in {
+ val msg = LocalAction.TriggerEffectInfo(PlanetSideGUID(1), "on", unk1 = true, unk2 = 10L)
+ msg.response() match {
+ case LocalAction.TriggerEffectAtLocation(PlanetSideGUID(1), "on", Some(TriggeredEffect(true, 10L)), None) =>
+ ok
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "TriggerEffectLocation" should {
+ "respond" in {
+ val msg = LocalAction.TriggerEffectLocation("on", Vector3(1, 2, 3), Vector3(4, 5, 6))
+ msg.response() match {
+ case LocalAction.TriggerEffectAtLocation(Default.GUID0, "on", None, Some(TriggeredEffectLocation(Vector3(1, 2, 3), Vector3(4, 5, 6)))) =>
+ ok
+ case _ =>
+ ko
+ }
+ }
+ }
+}
diff --git a/src/test/scala/service/vehicle/VehicleActionTest.scala b/src/test/scala/service/vehicle/VehicleActionTest.scala
new file mode 100644
index 000000000..f028ab38a
--- /dev/null
+++ b/src/test/scala/service/vehicle/VehicleActionTest.scala
@@ -0,0 +1,102 @@
+// Copyright (c) 2026 PSForever
+package service.vehicle
+
+import net.psforever.objects.zones.{Zone, ZoneMap}
+import net.psforever.objects.{GlobalDefinitions, Tool, Vehicle}
+import net.psforever.packet.game.ObjectCreateMessage
+import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
+import net.psforever.services.vehicle.VehicleAction
+import net.psforever.types.{DriveState, PlanetSideGUID}
+import org.specs2.mutable.Specification
+
+object VehicleActionTest {
+ assert(GlobalDefinitions.quadstealth != null, "missing definition - quadstealth does not exist")
+ assert(GlobalDefinitions.ams_respawn_tube != null, "missing definition - ams_respawn_tube does not exist")
+ assert(GlobalDefinitions.ams != null, "missing definition - AMS does not exist")
+
+ final val testZone: Zone = {
+ var i = 1
+ val notAms = new Vehicle(GlobalDefinitions.quadstealth)
+ notAms.GUID = PlanetSideGUID(i)
+ notAms.Health = 1
+ i += 1
+ val ams = new Vehicle(GlobalDefinitions.ams)
+ ams.Health = 1
+ ams.GUID = PlanetSideGUID(i)
+ i += 1
+ ams.Utilities.values.foreach { utility =>
+ utility.apply().GUID = PlanetSideGUID(i)
+ i += 1
+ }
+ ams.DeploymentState = DriveState.Deployed
+ new Zone(id = "test", new ZoneMap( name = "test"), zoneNumber = 1) {
+ override def Vehicles: List[Vehicle] = List(notAms, ams)
+ }
+ }
+}
+
+class VehicleActionTest extends Specification {
+ import VehicleActionTest._
+
+ "EquipmentInSlot" should {
+ assert(GlobalDefinitions.suppressor != null, "missing definition - Suppressor does not exist")
+
+ "respond" in {
+ var i = 1
+ val obj = new Tool(GlobalDefinitions.suppressor)
+ obj.GUID = PlanetSideGUID(i)
+ i += 1
+ obj.AmmoSlots.map(_.Box).foreach { box =>
+ box.GUID = PlanetSideGUID(i)
+ i += 1
+ }
+ val msg = VehicleAction.EquipmentInSlot(PlanetSideGUID(1), 2, obj)
+ val definition = obj.Definition
+ val objectData = definition.Packet.ConstructorData(obj).get
+ msg.response() match {
+ case VehicleAction.EquipmentCreatedInSlot(packets) =>
+ packets match {
+ case ObjectCreateMessage(_, oid, guid, pdata, data) =>
+ oid mustEqual definition.ObjectId
+ guid mustEqual obj.GUID
+ pdata.contains(ObjectCreateMessageParent(PlanetSideGUID(1), 2)) mustEqual true
+ data mustEqual objectData
+ case _ =>
+ ko
+ }
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "UpdateAmsSpawnPoint" should {
+ "respond" in {
+ testZone.Vehicles.size mustEqual 2
+ val msg = VehicleAction.UpdateAmsSpawnPoint(testZone)
+ msg.response() match {
+ case VehicleAction.UpdateAmsSpawnList(list) =>
+ list.size mustEqual 1
+ list.head.Definition mustEqual GlobalDefinitions.ams_respawn_tube
+ list.head.Owner.Definition mustEqual GlobalDefinitions.ams
+ case _ =>
+ ko
+ }
+ }
+ }
+
+ "AMSDeploymentChange" should {
+ "respond" in {
+ testZone.Vehicles.size mustEqual 2
+ val msg = VehicleAction.AMSDeploymentChange(testZone)
+ msg.response() match {
+ case VehicleAction.UpdateAmsSpawnList(list) =>
+ list.size mustEqual 1
+ list.head.Definition mustEqual GlobalDefinitions.ams_respawn_tube
+ list.head.Owner.Definition mustEqual GlobalDefinitions.ams
+ case _ =>
+ ko
+ }
+ }
+ }
+}