This commit is contained in:
Fate-JH 2026-06-23 18:14:11 +00:00 committed by GitHub
commit e08cde5cd9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
227 changed files with 7961 additions and 9091 deletions

View file

@ -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"

View file

@ -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")

View file

@ -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)

View file

@ -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
})
}
}

View file

@ -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()}"
}
}

View file

@ -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 {

View file

@ -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, _) =>

View file

@ -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)

View file

@ -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)
}
}
}

View file

@ -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)
)
}
}

View file

@ -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 =>

View file

@ -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, _) =>

View file

@ -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"))
}

View file

@ -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)
)
}
}

View file

@ -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)
}
}

View file

@ -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 =>

View file

@ -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 */

View file

@ -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, _) =>

View file

@ -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(

View file

@ -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 {

View file

@ -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 =>

View file

@ -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, _) =>

View file

@ -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) {

View file

@ -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 = {

View file

@ -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(

View file

@ -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 {

View file

@ -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 _ =>

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -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 {

View file

@ -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

View file

@ -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
}
}
}

View file

@ -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(

View file

@ -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(

View file

@ -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)
)
}

View file

@ -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)),

View file

@ -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))
}
/**

View file

@ -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(

View file

@ -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()

View file

@ -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 = {

View file

@ -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
}
}

View file

@ -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,

View file

@ -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 _ =>
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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) })
}
/**

View file

@ -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)
)

View file

@ -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 => ()
}

View file

@ -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 {

View file

@ -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)))
)
}

View file

@ -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)
)
}
}

View file

@ -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)
)
}
}

View file

@ -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
}

View file

@ -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)?
}

View file

@ -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)
)
}
}

View file

@ -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))
}
}

View file

@ -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 _ =>

View file

@ -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)
)
}
}

View file

@ -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()
}

View file

@ -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))
}
}

View file

@ -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))
)
}
}

View file

@ -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 = {

View file

@ -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 {

View file

@ -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(

View file

@ -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))
}
}

View file

@ -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

View file

@ -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))
})
}
}
}

View file

@ -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 _ => ()

View file

@ -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)

View file

@ -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)
)
}
}

View file

@ -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.<br>
* <br>
* 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.<br>
* <br>
* 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
}
}

View file

@ -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))
)
}
}

View file

@ -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))
)
}
}

View file

@ -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)
)
}
}

View file

@ -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)

View file

@ -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

View file

@ -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 _ =>
}

View file

@ -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 {

View file

@ -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)
})
}
/**

View file

@ -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

View file

@ -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)
)
}
}

View file

@ -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

View file

@ -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 _ => ()
}

View file

@ -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))
}
}

View file

@ -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))
}
/**

View file

@ -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.

View file

@ -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")

View file

@ -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

View file

@ -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 _ => ()

View file

@ -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

View file

@ -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) =>

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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()
}

View file

@ -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)
}

View file

@ -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
}

Some files were not shown because too many files have changed in this diff Show more