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% threshold: 0.25%
ignore: 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/ObjectType.scala"
- "src/main/scala/net/psforever/objects/avatar/Avatars.scala" - "src/main/scala/net/psforever/objects/avatar/Avatars.scala"
- "src/main/scala/net/psforever/objects/ballistics/DamageResolution.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/EquipmentSize.scala"
- "src/main/scala/net/psforever/objects/equipment/Kits.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/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/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/pad/AutoDriveControls.scala"
- "src/main/scala/net/psforever/objects/serverobject/structures/StructureType.scala" - "src/main/scala/net/psforever/objects/serverobject/structures/StructureType.scala"
- "src/main/scala/net/psforever/objects/serverobject/shuttle/ShuttleAmenity.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/ControlPacketOpcode.scala"
- "src/main/scala/net/psforever/packet/CryptoPacketOpcode.scala" - "src/main/scala/net/psforever/packet/CryptoPacketOpcode.scala"
- "src/main/scala/net/psforever/packet/GamePacketOpcode.scala" - "src/main/scala/net/psforever/packet/GamePacketOpcode.scala"
- "src/main/scala/net/psforever/types/Angular.scala" - "src/main/scala/net/psforever/packet/ResetSequenceOpcode.scala"
- "src/main/scala/net/psforever/types/CertificationType.scala" - "src/main/scala/net/psforever/persistence"
- "src/main/scala/net/psforever/types/ChatMessageType.scala" - "src/main/scala/net/psforever/services/account/IPAddress.scala"
- "src/main/scala/net/psforever/types/DriveState.scala" - "src/main/scala/net/psforever/services/account/ReceiveAccountData.scala"
- "src/main/scala/net/psforever/types/EmoteType.scala" - "src/main/scala/net/psforever/services/account/ReceiveIPAddress.scala"
- "src/main/scala/net/psforever/types/ExoSuitType.scala" - "src/main/scala/net/psforever/services/account/RetrieveAccountData.scala"
- "src/main/scala/net/psforever/types/GrenadeState.scala" - "src/main/scala/net/psforever/services/account/RetrieveIPAddress.scala"
- "src/main/scala/net/psforever/types/ImplantType.scala" - "src/main/scala/net/psforever/services/account/StoreAccountData.scala"
- "src/main/scala/net/psforever/types/MeritCommendation.scala" - "src/main/scala/net/psforever/services/account/StoreIPAddress.scala"
- "src/main/scala/net/psforever/types/PlanetSideEmpire.scala"
- "src/main/scala/net/psforever/types/TransactionType.scala"
- "src/main/scala/net/psforever/services/avatar/AvatarAction.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/avatar/AvatarService.scala"
- "src/main/scala/net/psforever/services/galaxy/GalaxyAction.scala" - "src/main/scala/net/psforever/services/base/bus"
- "src/main/scala/net/psforever/services/galaxy/GalaxyResponse.scala" - "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/HartEvent.scala"
- "src/main/scala/net/psforever/services/hart/HartTimerActions.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/LocalAction"
- "src/main/scala/net/psforever/services/local/LocalResponse.scala" - "src/main/scala/net/psforever/services/local/LocalService"
- "src/main/scala/net/psforever/services/vehicle/VehicleAction.scala" - "src/main/scala/net/psforever/services/teamwork/SquadServiceMessage.scala"
- "src/main/scala/net/psforever/services/vehicle/VehicleResponse.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 zones = Zones.zones :+ Zone.Nowhere
val serviceManager = ServiceManager.boot val serviceManager = ServiceManager.boot
serviceManager ! ServiceManager.Register(classic.Props[AccountIntermediaryService](), "accountIntermediary") 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[SquadService](), "squad")
serviceManager ! ServiceManager.Register(classic.Props[AccountPersistenceService](), "accountPersistence") serviceManager ! ServiceManager.Register(classic.Props[AccountPersistenceService](), "accountPersistence")
serviceManager ! ServiceManager.Register(classic.Props[PropertyOverrideManager](), "propertyOverrideManager") serviceManager ! ServiceManager.Register(classic.Props[PropertyOverrideManager](), "propertyOverrideManager")

View file

@ -32,7 +32,7 @@ import scala.concurrent.duration._
class AutoRepairFacilityIntegrationTest extends FreedContextActorTest { class AutoRepairFacilityIntegrationTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id) 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) expectNoMessage(1000 milliseconds)
val guid = new NumberPoolHub(new MaxNumberSource(max = 10)) val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
val avatarProbe = new TestProbe(system) val avatarProbe = new TestProbe(system)
@ -105,7 +105,7 @@ class AutoRepairFacilityIntegrationTest extends FreedContextActorTest {
class AutoRepairFacilityIntegrationGiveNtuTest extends FreedContextActorTest { class AutoRepairFacilityIntegrationGiveNtuTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id) 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) expectNoMessage(1000 milliseconds)
val guid = new NumberPoolHub(new MaxNumberSource(max = 10)) val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
val avatarProbe = new TestProbe(system) val avatarProbe = new TestProbe(system)
@ -160,7 +160,7 @@ class AutoRepairFacilityIntegrationGiveNtuTest extends FreedContextActorTest {
class AutoRepairFacilityIntegrationAntGiveNtuTest extends FreedContextActorTest { class AutoRepairFacilityIntegrationAntGiveNtuTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id) 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) expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]() var buildingMap = new TrieMap[Int, Building]()
val guid = new NumberPoolHub(new MaxNumberSource(max = 10)) val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
@ -251,7 +251,7 @@ class AutoRepairFacilityIntegrationAntGiveNtuTest extends FreedContextActorTest
class AutoRepairFacilityIntegrationTerminalDestroyedTerminalAntTest extends FreedContextActorTest { class AutoRepairFacilityIntegrationTerminalDestroyedTerminalAntTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id) 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) expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]() var buildingMap = new TrieMap[Int, Building]()
val guid = new NumberPoolHub(new MaxNumberSource(max = 10)) val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
@ -353,7 +353,7 @@ class AutoRepairFacilityIntegrationTerminalDestroyedTerminalAntTest extends Free
class AutoRepairFacilityIntegrationTerminalIncompleteRepairTest extends FreedContextActorTest { class AutoRepairFacilityIntegrationTerminalIncompleteRepairTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id) 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) expectNoMessage(1000 milliseconds)
var buildingMap = new TrieMap[Int, Building]() var buildingMap = new TrieMap[Int, Building]()
val guid = new NumberPoolHub(new MaxNumberSource(max = 10)) val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
@ -469,7 +469,7 @@ class AutoRepairFacilityIntegrationTerminalIncompleteRepairTest extends FreedCon
class AutoRepairTowerIntegrationTest extends FreedContextActorTest { class AutoRepairTowerIntegrationTest extends FreedContextActorTest {
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id) 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) expectNoMessage(1000 milliseconds)
val guid = new NumberPoolHub(new MaxNumberSource(max = 10)) val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
val avatarProbe = new TestProbe(system) 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.{GlobalDefinitions, Player, Vehicle}
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.types.{PlanetSideGUID, _} 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 akka.actor.typed.scaladsl.adapter._
import net.psforever.actors.zone.ZoneActor import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.Avatar import net.psforever.objects.avatar.Avatar
import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.services.base.envelope.GenericMessageEnvelope
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -37,7 +38,7 @@ class VehicleSpawnControl2Test extends ActorTest {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) 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.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
vehicle.Seats(0).mount(player) vehicle.Seats(0).mount(player)
@ -69,11 +70,11 @@ class VehicleSpawnControl3Test extends ActorTest {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player2, vehicle, terminal) //second order (vehicle shared) pad.Actor ! VehicleSpawnPad.VehicleOrder(player2, vehicle, terminal) //second order (vehicle shared)
assert(probe.receiveOne(1 seconds) match { assert(probe.receiveOne(1 seconds) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Queue, _) => true case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, _) => true
case _ => false case _ => false
}) })
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) 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.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
vehicle.Seats(0).mount(player) 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.ServerVehicleOverrideStart])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideEnd]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
assert(probe.receiveOne(1 minute) match { assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false case _ => false
}) })
assert(probe.receiveOne(1 minute) match { assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false case _ => false
}) })
@ -110,14 +111,6 @@ class VehicleSpawnControl4Test extends ActorTest {
player.Continent = "problem" //problem player.Continent = "problem" //problem
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order 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) probe.expectNoMessage(5 seconds)
} }
} }
@ -133,18 +126,18 @@ class VehicleSpawnControl5Test extends ActorTest() {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage]) probe.expectMsgClass(1 minute, classOf[GenericMessageEnvelope])
vehicle.Health = 0 //problem vehicle.Health = 0 //problem
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match { assert(probe.receiveOne(1 minute) match {
case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true case GenericMessageEnvelope(_, _, VehicleAction.LoadVehicle(_, _, _, _)) => true
case _ => false case _ => false
}) })
assert(probe.receiveOne(1 minute) match { assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false case _ => false
}) })
} }
} }
@ -160,18 +153,18 @@ class VehicleSpawnControl6Test extends ActorTest() {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer])
probe.expectMsgClass(1 minute, classOf[VehicleServiceMessage]) probe.expectMsgClass(1 minute, classOf[GenericMessageEnvelope])
player.Die player.Die
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match { assert(probe.receiveOne(1 minute) match {
case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true case GenericMessageEnvelope(_, _, VehicleAction.LoadVehicle(_, _, _, _)) => true
case _ => false case _ => false
}) })
assert(probe.receiveOne(1 minute) match { assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false case _ => false
}) })
} }
} }
@ -188,18 +181,18 @@ class VehicleSpawnControl7Test extends ActorTest {
pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order pad.Actor ! VehicleSpawnPad.VehicleOrder(player, vehicle, terminal) //order
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.ConcealPlayer]) 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.AttachToRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.DetachFromRails])
probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer]) probe.expectMsgClass(1 minute, classOf[VehicleSpawnPad.RevealPlayer])
assert(probe.receiveOne(1 minute) match { assert(probe.receiveOne(1 minute) match {
case VehicleServiceMessage(_, VehicleAction.LoadVehicle(_, _, _, _, _)) => true case GenericMessageEnvelope(_, _, VehicleAction.LoadVehicle(_, _, _, _)) => true
case _ => false case _ => false
}) })
assert(probe.receiveOne(1 minute) match { assert(probe.receiveOne(1 minute) match {
case VehicleSpawnPad.PeriodicReminder(_, VehicleSpawnPad.Reminders.Blocked, _) => true case VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, _) => true
case _ => false 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. # before it is dropped. Can be used as a watchdog for hung server sessions.
outbound-grace-time = 1 minute 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 { 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.avatar.scoring.{Assist, Death, EquipmentStat, KDAStat, Kill, Life, ScoreCard, SupportActivity}
import net.psforever.objects.sourcing.{TurretSource, VehicleSource} import net.psforever.objects.sourcing.{TurretSource, VehicleSource}
import net.psforever.packet.game.ImplantAction 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.types.{ChatMessageType, StatisticalCategory, StatisticalElement}
import net.psforever.zones.Zones import net.psforever.zones.Zones
import org.joda.time.{LocalDateTime, Seconds} 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.objectcreate.{BasicCharacterData, ObjectClass, RibbonBars}
import net.psforever.packet.game.{Friend => GameFriend, _} import net.psforever.packet.game.{Friend => GameFriend, _}
import net.psforever.persistence import net.psforever.persistence
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.{SendResponse, PlanetsideAttribute}
import net.psforever.services.avatar.AvatarAction
import net.psforever.types.{ import net.psforever.types.{
CharacterSex, CharacterSex,
CharacterVoice, CharacterVoice,
@ -585,9 +587,10 @@ object AvatarActor {
def displayLookingForSquad(session: Session, state: Int): Unit = { def displayLookingForSquad(session: Session, state: Int): Unit = {
val player = session.player val player = session.player
session.zone.AvatarEvents ! AvatarServiceMessage( session.zone.AvatarEvents ! MessageEnvelope(
player.Faction.toString, 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) => case SetLookingForSquad(lfs) =>
avatarCopy(avatar.copy(lookingForSquad = lfs)) avatarCopy(avatar.copy(lookingForSquad = lfs))
sessionActor ! SessionActor.SendResponse(PlanetsideAttributeMessage(session.get.player.GUID, 53, 0)) sessionActor ! SessionActor.SendResponse(PlanetsideAttributeMessage(session.get.player.GUID, 53, 0))
session.get.zone.AvatarEvents ! AvatarServiceMessage( session.get.zone.AvatarEvents ! MessageEnvelope(
avatar.faction.toString, 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 Behaviors.same
@ -1794,9 +1798,9 @@ class AvatarActor(
) )
val player = session.get.player val player = session.get.player
val zone = player.Zone val zone = player.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.SendResponse(Service.defaultPlayerGUID, DisplayedAwardMessage(player.GUID, ribbon, bar)) SendResponse(DisplayedAwardMessage(player.GUID, ribbon, bar))
) )
Behaviors.same Behaviors.same
@ -2073,9 +2077,9 @@ class AvatarActor(
case Success(_) => case Success(_) =>
val zone = session.get.zone val zone = session.get.zone
avatarCopy(avatar.copy(decoration = avatar.decoration.copy(cosmetics = Some(cosmetics)))) avatarCopy(avatar.copy(decoration = avatar.decoration.copy(cosmetics = Some(cosmetics))))
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.PlanetsideAttributeToAll( PlanetsideAttribute(
session.get.player.GUID, session.get.player.GUID,
106, 106,
Cosmetic.valuesToAttributeValue(cosmetics) Cosmetic.valuesToAttributeValue(cosmetics)
@ -3000,13 +3004,13 @@ class AvatarActor(
val next = BattleRank.withExperience(newBep).value val next = BattleRank.withExperience(newBep).value
val br24 = BattleRank.BR24.value val br24 = BattleRank.BR24.value
sessionActor ! SessionActor.SendResponse(BattleExperienceMessage(pguid, newBep, localModifier)) 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) { if (current < br24 && next >= br24 || current >= br24 && next < br24) {
setCosmetics(Set()).onComplete { _ => setCosmetics(Set()).onComplete { _ =>
val evts = events val evts = events
val name = player.Name val name = player.Name
val guid = pguid 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 // 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 sess = session.get
val zone = sess.zone val zone = sess.zone
avatar = avatar.copy(cep = cep) avatar = avatar.copy(cep = cep)
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(zone.id, PlanetsideAttribute(sess.player.GUID, 18, cep))
zone.id,
AvatarAction.PlanetsideAttributeToAll(sess.player.GUID, 18, cep)
)
case Failure(exception) => case Failure(exception) =>
log.error(exception)("db failure") log.error(exception)("db failure")
} }
@ -3152,7 +3153,7 @@ class AvatarActor(
if (exp > 0L) { if (exp > 0L) {
setBep(exp, msg) setBep(exp, msg)
zone.actor ! ZoneActor.RewardOurSupporters(playerSource, historyTranscript, killStat, exp) zone.actor ! ZoneActor.RewardOurSupporters(playerSource, historyTranscript, killStat, exp)
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
player.Name, AvatarAction.ShareKillExperienceWithSquad(player, exp)) player.Name, AvatarAction.ShareKillExperienceWithSquad(player, exp))
} }
} }
@ -3163,12 +3164,9 @@ class AvatarActor(
val _session = session.get val _session = session.get
val zone = _session.zone val zone = _session.zone
val player = _session.player val player = _session.player
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
player.Name, player.Name,
AvatarAction.SendResponse( SendResponse(AvatarStatisticsMessage(DeathStatistic(ScoreCard.deathCount(avatar.scorecard))))
Service.defaultPlayerGUID,
AvatarStatisticsMessage(DeathStatistic(ScoreCard.deathCount(avatar.scorecard)))
)
) )
} }
@ -3494,8 +3492,8 @@ class AvatarActor(
value: Int value: Int
): Unit = { ): Unit = {
import akka.actor.typed.scaladsl.adapter.TypedActorRefOps import akka.actor.typed.scaladsl.adapter.TypedActorRefOps
import net.psforever.services.avatar.{AvatarResponse => RESP} val resp = AvatarAction.AvatarImplant(action, index, value)
sessionActor.toClassic ! AvatarServiceResponse("", guid, RESP.AvatarImplant(action, index, value)) sessionActor.toClassic ! GenericResponseEnvelope(AvatarStamp, "", guid, resp)
} }
private def buyImplantAction( private def buyImplantAction(
@ -3654,9 +3652,9 @@ class AvatarActor(
// Start client-side initialization timer, visible on the character screen // Start client-side initialization timer, visible on the character screen
// Progress accumulates according to the client's knowledge of the implant initialization time // 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 // 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, avatar.name,
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, actionProgress)) SendResponse(ActionProgressMessage(slot + 6, actionProgress))
) )
implant.copy(initialized = false, active = false, timer = futureDelay) implant.copy(initialized = false, active = false, timer = futureDelay)
} else { } else {
@ -3703,9 +3701,9 @@ class AvatarActor(
def stopImplantInitializationTimer(implant: Implant, slot: Int): Implant = { def stopImplantInitializationTimer(implant: Implant, slot: Int): Implant = {
cancelImplantInitializedTimer(slot) cancelImplantInitializedTimer(slot)
//can not formally stop the initialization time on the character information window; set it to 100 to make it look blank //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, avatar.name,
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, 100)) SendResponse(ActionProgressMessage(slot + 6, 100))
) )
implant.copy(initialized = false, active = false, timer = 0L) implant.copy(initialized = false, active = false, timer = 0L)
} }
@ -3773,9 +3771,10 @@ class AvatarActor(
private def deactivateImplant(implant: Implant, slot: Int): Implant = { private def deactivateImplant(implant: Implant, slot: Int): Implant = {
cancelImplantInitializedTimer(slot) cancelImplantInitializedTimer(slot)
// Deactivation sound / effect // Deactivation sound / effect
session.get.zone.AvatarEvents ! AvatarServiceMessage( session.get.zone.AvatarEvents ! MessageEnvelope(
session.get.zone.id, 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) sendAvatarImplantMessageToSelf(session.get.player.GUID, ImplantAction.Activation, slot, value = 0)
implant.copy(active = false) implant.copy(active = false)
@ -3852,10 +3851,7 @@ class AvatarActor(
val newHealth = player.Health = originalHealth + 1 val newHealth = player.Health = originalHealth + 1
val events = zone.AvatarEvents val events = zone.AvatarEvents
player.LogActivity(HealFromImplant(implant.definition.implantType, 1)) player.LogActivity(HealFromImplant(implant.definition.implantType, 1))
events ! AvatarServiceMessage( events ! MessageEnvelope(zone.id, PlanetsideAttribute(guid, 0, newHealth))
zone.id,
AvatarAction.PlanetsideAttributeToAll(guid, 0, newHealth)
)
false false
} else { } else {
!aliveAndWounded !aliveAndWounded
@ -3867,9 +3863,10 @@ class AvatarActor(
// Activation sound / effect // Activation sound / effect
val sess = session.get val sess = session.get
val zone = sess.zone val zone = sess.zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.PlanetsideAttribute( sess.player.GUID,
PlanetsideAttribute(
sess.player.GUID, sess.player.GUID,
28, 28,
implant.definition.implantType.value * 2 + 1 implant.definition.implantType.value * 2 + 1
@ -3892,9 +3889,9 @@ class AvatarActor(
case (implantOpt @ Some(implant), slot) => case (implantOpt @ Some(implant), slot) =>
//update ongoing progress //update ongoing progress
val actionProgress = calculateImplantTimerStats(implant, AvatarActor.initializationTime(implant))._3 val actionProgress = calculateImplantTimerStats(implant, AvatarActor.initializationTime(implant))._3
session.get.zone.AvatarEvents ! AvatarServiceMessage( session.get.zone.AvatarEvents ! MessageEnvelope(
avatar.name, avatar.name,
AvatarAction.SendResponse(Service.defaultPlayerGUID, ActionProgressMessage(slot + 6, actionProgress)) SendResponse(ActionProgressMessage(slot + 6, actionProgress))
) )
implantOpt implantOpt
case (None, _) => case (None, _) =>

View file

@ -3,7 +3,7 @@ package net.psforever.actors.session
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware, typed} import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware, typed}
import net.psforever.actors.session.normal.NormalMode 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.TurretDeployable
import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.containable.Containable 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.CavernRotationService.SendCavernRotationUpdates
import net.psforever.services.ServiceManager.LookupResult import net.psforever.services.ServiceManager.LookupResult
import net.psforever.services.account.{PlayerToken, ReceiveAccountData} 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.chat.ChatService
import net.psforever.services.galaxy.GalaxyServiceResponse import net.psforever.services.galaxy.GalaxyStamp
import net.psforever.services.local.LocalServiceResponse import net.psforever.services.local.LocalStamp
import net.psforever.services.teamwork.SquadServiceResponse 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.joda.time.LocalDateTime
import org.log4s.MDC import org.log4s.MDC
@ -94,6 +95,26 @@ object SessionActor {
private final case object PokeClient extends Command private final case object PokeClient extends Command
final case class SetMode(mode: PlayerMode) 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) 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] val data = new SessionData(middlewareActor, context)
private[this] var mode: PlayerMode = NormalMode private[this] var mode: PlayerMode = NormalMode
private[this] var logic: ModeLogic = _ 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 = { override def postStop(): Unit = {
clientKeepAlive.cancel() clientKeepAlive.cancel()
@ -119,7 +143,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
buffer.addOne(msg) buffer.addOne(msg)
case _ if data.whenAllEventBusesLoaded() => case _ if data.whenAllEventBusesLoaded() =>
context.become(inTheGame) 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.foreach { self.tell(_, self) } //we forget the original sender, shouldn't be doing callbacks at this point
buffer.clear() buffer.clear()
case _ => () case _ => ()
@ -160,37 +184,39 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
if (mode != newMode) { if (mode != newMode) {
logic.switchFrom(data.session) logic.switchFrom(data.session)
mode = newMode mode = newMode
logic = newMode.setup(data) changeModeSetup(newMode)
} }
logic.switchTo(data.session) 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 = { private def parse(sender: ActorRef): Receive = {
/* really common messages (very frequently, every life) */ /* really common messages (very frequently, every life) */
case packet: PlanetSideGamePacket => case packet: PlanetSideGamePacket =>
handleGamePkt(packet) handleGamePkt(packet)
case AvatarServiceResponse(toChannel, guid, reply) => case SquadServiceResponse(_, excluded, reply) =>
logic.avatarResponse.handle(toChannel, guid, reply) logic.squad.handle(reply, excluded)
case GalaxyServiceResponse(_, reply) => case envelope: GenericResponseEnvelope =>
logic.galaxy.handle(reply) handleGenericResponseEnvelope(envelope)
case LocalServiceResponse(toChannel, guid, reply) =>
logic.local.handle(toChannel, guid, reply)
case Mountable.MountMessages(tplayer, reply) => case Mountable.MountMessages(tplayer, reply) =>
logic.mountResponse.handle(tplayer, reply) logic.mountResponse.handle(tplayer, reply)
case SquadServiceResponse(_, excluded, response) =>
logic.squad.handle(response, excluded)
case Terminal.TerminalMessage(tplayer, msg, order) => case Terminal.TerminalMessage(tplayer, msg, order) =>
logic.terminals.handle(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, _) => case ChatService.MessageResponse(fromSession, message, _) =>
logic.chat.handleIncomingMessage(message, fromSession) logic.chat.handleIncomingMessage(message, fromSession)
@ -369,6 +395,52 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
logic.general.handleReceiveDefaultMessage(default, sender) 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 = { private def handleGamePkt: PlanetSideGamePacket => Unit = {
case packet: ConnectToWorldRequestMessage => case packet: ConnectToWorldRequestMessage =>
logic.general.handleConnectToWorldRequest(packet) 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.objects.zones.Zone
import net.psforever.packet.game.{ChatMsg, SetChatFilterMessage} import net.psforever.packet.game.{ChatMsg, SetChatFilterMessage}
import net.psforever.services.Service 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.services.chat.{ChatChannel, DefaultChannel, SpectatorChannel, SquadChannel}
import net.psforever.types.ChatMessageType.{CMT_TOGGLESPECTATORMODE, CMT_TOGGLE_GM} import net.psforever.types.ChatMessageType.{CMT_TOGGLESPECTATORMODE, CMT_TOGGLE_GM}
import net.psforever.types.{ChatMessageType, PlanetSideEmpire} import net.psforever.types.{ChatMessageType, PlanetSideEmpire}
@ -312,17 +314,20 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
val events = continent.AvatarEvents val events = continent.AvatarEvents
seeSpectatorsIn = Some(continent) seeSpectatorsIn = Some(continent)
events ! Service.Join(s"spectator") events ! Service.Join(s"spectator")
continent events ! BundledEnvelope(
.AllPlayers continent
.filter(_.spectator) .AllPlayers
.foreach { spectator => .filter(_.spectator)
val guid = spectator.GUID .map { spectator =>
val definition = spectator.Definition val guid = spectator.GUID
events ! AvatarServiceMessage( val definition = spectator.Definition
channel, MessageEnvelope(
AvatarAction.LoadPlayer(guid, definition.ObjectId, guid, definition.Packet.ConstructorData(spectator).get, None) channel,
) guid,
} AvatarAction.LoadPlayer(definition.ObjectId, guid, definition.Packet.ConstructorData(spectator).get, None)
)
}
)
true true
} }
@ -330,17 +335,16 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
val channel = player.Name val channel = player.Name
val events = continent.AvatarEvents val events = continent.AvatarEvents
seeSpectatorsIn = None seeSpectatorsIn = None
events ! Service.Leave(Some("spectator")) events ! Service.Leave("spectator")
continent events ! BundledEnvelope(
.AllPlayers continent
.filter(_.spectator) .AllPlayers
.foreach { spectator => .filter(_.spectator)
val guid = spectator.GUID .map { spectator =>
events ! AvatarServiceMessage( val guid = spectator.GUID
channel, MessageEnvelope(channel, guid, ObjectDelete(guid))
AvatarAction.ObjectDelete(guid, guid) }
) )
}
true true
} }
@ -392,9 +396,9 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
true true
case o: Deployable => case o: Deployable =>
o.Faction = foundFaction o.Faction = foundFaction
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.SetEmpire(Service.defaultPlayerGUID, o.GUID, foundFaction) SetEmpire(o.GUID, foundFaction)
) )
true true
case o: Building => case o: Building =>
@ -405,9 +409,9 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
true true
case o: PlanetSideGameObject with FactionAffinity => case o: PlanetSideGameObject with FactionAffinity =>
o.Faction = foundFaction o.Faction = foundFaction
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.SetEmpire(Service.defaultPlayerGUID, o.GUID, foundFaction) SetEmpire(o.GUID, foundFaction)
) )
true true
} }
@ -512,7 +516,7 @@ class ChatLogic(val ops: ChatOperations, implicit val context: ActorContext) ext
.foreach { .foreach {
case (_, false, _) => () case (_, false, _) => ()
case (faction, true, _) => 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.objects.zones.Zone
import net.psforever.packet.game.{ChatMsg, ObjectCreateDetailedMessage, PlanetsideAttributeMessage} import net.psforever.packet.game.{ChatMsg, ObjectCreateDetailedMessage, PlanetsideAttributeMessage}
import net.psforever.packet.game.objectcreate.RibbonBars 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.chat.{CustomerServiceChannel, SpectatorChannel}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.{ChatMessageType, MeritCommendation, PlanetSideGUID} import net.psforever.types.{ChatMessageType, MeritCommendation, PlanetSideGUID}
class CustomerServiceRepresentativeMode(data: SessionData) extends ModeLogic { class CustomerServiceRepresentativeMode(data: SessionData) extends ModeLogic {
@ -120,6 +121,10 @@ class CustomerServiceRepresentativeMode(data: SessionData) extends ModeLogic {
.GUID(player.VehicleSeated) .GUID(player.VehicleSeated)
.collect { case obj: PlanetSideGameObject with Vitality => .collect { case obj: PlanetSideGameObject with Vitality =>
CustomerServiceRepresentativeMode.topOffHealth(data, obj) CustomerServiceRepresentativeMode.topOffHealth(data, obj)
obj
}
.getOrElse {
data.updateBlockMap(player, player.Position)
} }
data.squad.updateSquad() data.squad.updateSquad()
} else { } else {
@ -144,13 +149,16 @@ case object CustomerServiceRepresentativeMode extends PlayerMode {
packet.DetailedConstructorData(player).get packet.DetailedConstructorData(player).get
)) ))
data.zoning.spawn.HandleSetCurrentAvatar(player) data.zoning.spawn.HandleSetCurrentAvatar(player)
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.LoadPlayer( zone.AvatarEvents ! MessageEnvelope(
zone.id,
pguid, pguid,
objectClass, AvatarAction.LoadPlayer(
pguid, objectClass,
packet.ConstructorData(player).get, pguid,
None packet.ConstructorData(player).get,
)) None
)
)
} }
def topOffHealth(data: SessionData, obj: PlanetSideGameObject with Vitality): Unit = { def topOffHealth(data: SessionData, obj: PlanetSideGameObject with Vitality): Unit = {
@ -174,14 +182,14 @@ case object CustomerServiceRepresentativeMode extends PlayerMode {
player.Health = maxHealthOfPlayer.toInt player.Health = maxHealthOfPlayer.toInt
player.LogActivity(player.ClearHistory().head) player.LogActivity(player.ClearHistory().head)
data.sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOfPlayer)) 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 //below half armor, full armor
val maxArmor = player.MaxArmor.toLong val maxArmor = player.MaxArmor.toLong
if (player.Armor < maxArmor) { if (player.Armor < maxArmor) {
player.Armor = maxArmor.toInt player.Armor = maxArmor.toInt
data.sendResponse(PlanetsideAttributeMessage(guid, 4, maxArmor)) 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 val guid = vehicle.GUID
vehicle.Shields = maxShieldsOfVehicle.toInt vehicle.Shields = maxShieldsOfVehicle.toInt
data.sendResponse(PlanetsideAttributeMessage(guid, shieldsUi, maxShieldsOfVehicle)) data.sendResponse(PlanetsideAttributeMessage(guid, shieldsUi, maxShieldsOfVehicle))
data.continent.VehicleEvents ! VehicleServiceMessage( data.continent.VehicleEvents ! MessageEnvelope(
data.continent.id, 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) { if (obj.Health < maxHealthOf) {
obj.Health = maxHealthOf.toInt obj.Health = maxHealthOf.toInt
data.sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOf)) data.sendResponse(PlanetsideAttributeMessage(guid, 0, maxHealthOf))
data.continent.VehicleEvents ! VehicleServiceMessage( data.continent.VehicleEvents ! MessageEnvelope(
data.continent.id, 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.PlanetSideGamePacket
import net.psforever.packet.game.OutfitEventAction.{Initial, OutfitInfo, OutfitRankNames, Unk1} 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.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.support.CorpseEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.AvatarAction
import net.psforever.services.local.{LocalAction, LocalServiceMessage} 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 net.psforever.types.{CapacitorStateType, ChatMessageType, Cosmetic, ExoSuitType, PlanetSideEmpire, PlanetSideGUID, Vector3}
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -132,10 +134,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
val eagleEye: Boolean = ops.canSeeReallyFar val eagleEye: Boolean = ops.canSeeReallyFar
val isNotVisible: Boolean = sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing || val isNotVisible: Boolean = sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing ||
(player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime) (player.isAlive && sessionLogic.zoning.spawn.deadState == DeadState.RespawnTime)
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
channel, channel,
avatarGuid,
AvatarAction.PlayerState( AvatarAction.PlayerState(
avatarGuid,
player.Position, player.Position,
player.Velocity, player.Velocity,
yaw, yaw,
@ -163,15 +165,8 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
} }
def handleEmote(pkt: EmoteMsg): Unit = { def handleEmote(pkt: EmoteMsg): Unit = {
val EmoteMsg(avatarGuid, emote) = pkt sendResponse(pkt)
val pZone = player.Zone ops.handleEmote(pkt)
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)))
}
} }
def handleDropItem(pkt: DropItemMessage): Unit = { 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 => case Some(obj: Player) if obj.isBackpack =>
obj.Position = Vector3.Zero 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) => case Some(obj: Player) =>
sessionLogic.general.suicide(obj) sessionLogic.general.suicide(obj)
@ -439,9 +434,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
ops.dropSpecialSlotItem() ops.dropSpecialSlotItem()
case GenericAction.MaxAnchorsExtend_RCV => case GenericAction.MaxAnchorsExtend_RCV =>
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.PlanetsideAttribute(player.GUID, 19, 1) player.GUID,
PlanetsideAttribute(player.GUID, 19, 1)
) )
definition match { definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster => case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
@ -459,9 +455,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
} }
case GenericAction.MaxAnchorsRelease_RCV => case GenericAction.MaxAnchorsRelease_RCV =>
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.PlanetsideAttribute(player.GUID, 19, 0) player.GUID,
PlanetsideAttribute(player.GUID, 19, 0)
) )
definition match { definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster => 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.{GlobalDefinitions, PlanetSideGameObject, Player, Vehicle, Vehicles}
import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.environment.interaction.ResetAllEnvironmentInteractions 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.mount.Mountable
import net.psforever.objects.serverobject.structures.WarpGate import net.psforever.objects.serverobject.structures.WarpGate
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech 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.vehicles.AccessPermissionGroup
import net.psforever.objects.vital.InGameHistory 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.packet.game.{ChatMsg, DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlanetsideAttributeMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
import net.psforever.services.Service import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.base.message.{SendResponse, SetEmpire}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3} import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3}
object MountHandlerLogic { object MountHandlerLogic {
@ -160,7 +159,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _) case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
if obj.Definition == GlobalDefinitions.vanu_sentry_turret => if obj.Definition == GlobalDefinitions.vanu_sentry_turret =>
sessionLogic.zoning.CancelZoningProcess() 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)) sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
ops.updateWeaponAtSeatPosition(obj, seatNumber) ops.updateWeaponAtSeatPosition(obj, seatNumber)
ops.MountingAction(tplayer, 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) val (pos, zang) = Vehicles.dismountShuttle(obj, mountPoint)
tplayer.Position = pos tplayer.Position = pos
sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true)) sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true))
continent.LocalEvents ! LocalServiceMessage( continent.LocalEvents ! MessageEnvelope(
continent.id, 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 sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
@ -213,25 +212,21 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountAction(tplayer, obj, seatNum) ops.DismountAction(tplayer, obj, seatNum)
continent.actor ! ZoneActor.RemoveFromBlockMap(player) //character doesn't need it 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 //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 //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 //the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone //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 //having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
events ! VehicleServiceMessage( events ! BundledEnvelope(
player.Name, MessageEnvelope(player.Name,
VehicleAction.SendResponse( SendResponse(Seq(
Service.defaultPlayerGUID, PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)) //cower in the shuttle bay 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 sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
case Mountable.CanDismount(obj: Vehicle, seatNum, _) case Mountable.CanDismount(obj: Vehicle, seatNum, _)
@ -256,9 +251,10 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountVehicleAction(tplayer, obj, seatNum) ops.DismountVehicleAction(tplayer, obj, seatNum)
case Mountable.CanDismount(obj: Vehicle, seat_num, _) => case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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, _) => 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.{Player, Session, Vehicle}
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.PlanetSidePacket 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.chat.SpectatorChannel
import net.psforever.services.teamwork.{SquadAction, SquadServiceMessage} import net.psforever.services.teamwork.{SquadAction, SquadServiceMessage}
import net.psforever.types.{ChatMessageType, SquadRequestType} import net.psforever.types.{ChatMessageType, SquadRequestType}
@ -45,7 +47,7 @@ class SpectatorCSRModeLogic(data: SessionData) extends ModeLogic {
// //
player.spectator = true player.spectator = true
data.chat.JoinChannel(SpectatorChannel) 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.CMT_TOGGLESPECTATORMODE, "on"))
sendResponse(ChatMsg(ChatMessageType.UNK_225, "CSR SPECTATOR MODE ON")) sendResponse(ChatMsg(ChatMessageType.UNK_225, "CSR SPECTATOR MODE ON"))
} }
@ -59,9 +61,10 @@ class SpectatorCSRModeLogic(data: SessionData) extends ModeLogic {
// //
player.spectator = false player.spectator = false
data.chat.LeaveChannel(SpectatorChannel) data.chat.LeaveChannel(SpectatorChannel)
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, 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")) 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.Zone
import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game.{ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage} 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} import net.psforever.types.{DriveState, Vector3}
object VehicleLogic { object VehicleLogic {
@ -76,10 +78,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Position = position obj.Position = position
obj.Orientation = angle obj.Orientation = angle
// //
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
player.GUID,
VehicleAction.VehicleState( VehicleAction.VehicleState(
player.GUID,
vehicle_guid, vehicle_guid,
unk1, unk1,
position, position,
@ -92,7 +94,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
is_decelerating, is_decelerating,
obj.Cloaked obj.Cloaked
) )
) ) //todo CachedMessage
sessionLogic.squad.updateSquad() sessionLogic.squad.updateSquad()
case (None, _) => case (None, _) =>
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone") //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.Position = position
obj.Orientation = angle obj.Orientation = angle
obj.DeploymentState = if (is_crouched || !notMountedState) DriveState.Kneeling else DriveState.Mobile obj.DeploymentState = if (is_crouched || !notMountedState) DriveState.Kneeling else DriveState.Mobile
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.FrameVehicleState( player.GUID,
player.GUID, VehicleAction.FrameVehicleState(vehicle_guid, unk1, position, angle, velocity, unk2, unk3, unk4, is_crouched, is_airborne, ascending_flight, flight_time, unk9, unkA)
vehicle_guid, ) //todo CachedMessage
unk1,
position,
angle,
velocity,
unk2,
unk3,
unk4,
is_crouched,
is_airborne,
ascending_flight,
flight_time,
unk9,
unkA
)
)
sessionLogic.squad.updateSquad() sessionLogic.squad.updateSquad()
case (None, _) => case (None, _) =>
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone") //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) val angle = Vector3(0f, pitch, yaw)
tool.Orientation = angle tool.Orientation = angle
player.Orientation = angle player.Orientation = angle
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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 //TODO status condition of "playing getting out of vehicle to allow for late packets without warning
if (player.death_by == -1) { if (player.death_by == -1) {
@ -256,22 +244,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Velocity = vel obj.Velocity = vel
sessionLogic.updateBlockMap(obj, pos) sessionLogic.updateBlockMap(obj, pos)
obj.zoneInteractions() obj.zoneInteractions()
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! CachedEnvelope(
continent.id, continent.id,
VehicleAction.VehicleState( player.GUID,
player.GUID, VehicleAction.VehicleState(vehicle_guid, unk1, pos, ang, obj.Velocity, obj.Flying, 0, 0, 15, unk5 = false, obj.Cloaked)
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) { if (obj.DeploymentState != DriveState.Mobile) {
obj.DeploymentState = DriveState.Mobile obj.DeploymentState = DriveState.Mobile
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero)) sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero))
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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 // Copyright (c) 2024 PSForever
package net.psforever.actors.session.normal package net.psforever.actors.session.normal
import akka.actor.Actor.Receive
import akka.actor.{ActorContext, ActorRef, typed} import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.AvatarActor 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.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} import net.psforever.types.{MemberAction, PlanetSideEmpire}
object GalaxyHandlerLogic { object GalaxyHandlerLogic {
@ -26,68 +28,62 @@ class GalaxyHandlerLogic(val ops: SessionGalaxyHandlers, implicit val context: A
def handleUpdateIgnoredPlayers(pkt: FriendsResponse): Unit = { def handleUpdateIgnoredPlayers(pkt: FriendsResponse): Unit = {
sendResponse(pkt) sendResponse(pkt)
pkt.friends.foreach { f => pkt.friends.foreach { f =>
galaxyService ! GalaxyServiceMessage(GalaxyAction.LogStatusChange(f.name)) galaxyService ! MessageEnvelope("", GalaxyAction.LogStatusChange(f.name))
} }
} }
/* response handlers */ /* response handlers */
def handle(reply: GalaxyResponse.Response): Unit = { def receive: Receive = {
reply match { case GalaxyAction.HotSpotUpdate(zone_index, priority, hot_spot_info) =>
case GalaxyResponse.HotSpotUpdate(zone_index, priority, hot_spot_info) => sendResponse(
sendResponse( HotSpotUpdateMessage(
HotSpotUpdateMessage( zone_index,
zone_index, priority,
priority, hot_spot_info.map { spot => PacketHotSpotInfo(spot.DisplayLocation.x, spot.DisplayLocation.y, 40) }
hot_spot_info.map { spot => PacketHotSpotInfo(spot.DisplayLocation.x, spot.DisplayLocation.y, 40) }
)
) )
)
case GalaxyResponse.MapUpdate(msg) => case GalaxyAction.MapUpdate(msg) =>
sendResponse(msg) sendResponse(msg)
import net.psforever.actors.zone.ZoneActor import net.psforever.actors.zone.ZoneActor
import net.psforever.zones.Zones import net.psforever.zones.Zones
Zones.zones.find(_.Number == msg.continent_id) match { Zones.zones.find(_.Number == msg.continent_id) match {
case Some(zone) => case Some(zone) =>
zone.actor ! ZoneActor.BuildingInfoState(msg) zone.actor ! ZoneActor.BuildingInfoState(msg)
case None => case None =>
} }
case GalaxyResponse.UpdateBroadcastPrivileges(zoneId, gateMapId, fromFactions, toFactions) => case GalaxyAction.UpdateBroadcastPrivileges(zoneId, gateMapId, fromFactions, toFactions) =>
val faction = player.Faction val faction = player.Faction
val from = fromFactions.contains(faction) val from = fromFactions.contains(faction)
val to = toFactions.contains(faction) val to = toFactions.contains(faction)
if (from && !to) { if (from && !to) {
sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, PlanetSideEmpire.NEUTRAL)) sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, PlanetSideEmpire.NEUTRAL))
} else if (!from && to) { } else if (!from && to) {
sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, faction)) sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, faction))
} }
case GalaxyResponse.FlagMapUpdate(msg) => case GalaxyAction.FlagMapUpdate(msg) =>
sendResponse(msg) sendResponse(msg)
case GalaxyResponse.TransferPassenger(temp_channel, vehicle, _, manifest) => case GalaxyAction.TransferPassenger(_, temp_channel, vehicle, _, manifest) =>
sessionLogic.zoning.handleTransferPassenger(temp_channel, vehicle, manifest) sessionLogic.zoning.handleTransferPassenger(temp_channel, vehicle, manifest)
case GalaxyResponse.LockedZoneUpdate(zone, time) => case GalaxyAction.LockedZoneUpdate(zone, time) =>
sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time)) sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
case GalaxyResponse.UnlockedZoneUpdate(zone) => case GalaxyAction.UnlockedZoneUpdate(zone) =>
sendResponse(ZoneInfoMessage(zone.Number, empire_status=true, lock_time=0L)) sendResponse(ZoneInfoMessage(zone.Number, empire_status=true, lock_time=0L))
val popBO = 0 val popBO = 0
val pop = zone.LivePlayers.distinctBy(_.CharId) val pop = zone.LivePlayers.distinctBy(_.CharId)
val popTR = pop.count(_.Faction == PlanetSideEmpire.TR) val popTR = pop.count(_.Faction == PlanetSideEmpire.TR)
val popNC = pop.count(_.Faction == PlanetSideEmpire.NC) val popNC = pop.count(_.Faction == PlanetSideEmpire.NC)
val popVS = pop.count(_.Faction == PlanetSideEmpire.VS) val popVS = pop.count(_.Faction == PlanetSideEmpire.VS)
sendResponse(ZonePopulationUpdateMessage(zone.Number, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO)) 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)) => case GalaxyAction.LogStatusChange(name)
avatarActor ! AvatarActor.MemberListRequest(MemberAction.UpdateFriend, name) if TestFilter(() => avatar.people.friend.exists(_.name.equals(name))) =>
avatarActor ! AvatarActor.MemberListRequest(MemberAction.UpdateFriend, name)
case GalaxyResponse.SendResponse(msg) =>
sendResponse(msg)
case _ => ()
}
} }
} }

View file

@ -42,8 +42,9 @@ import net.psforever.objects.zones.{ZoneProjectile, Zoning}
import net.psforever.packet.PlanetSideGamePacket 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.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.account.{AccountPersistenceService, RetrieveAccountData}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.AvatarAction
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.local.support.CaptureFlagManager import net.psforever.services.local.support.CaptureFlagManager
import net.psforever.types.{CapacitorStateType, ChatMessageType, Cosmetic, ExoSuitType, ImplantType, PlanetSideEmpire, PlanetSideGUID, Vector3} import net.psforever.types.{CapacitorStateType, ChatMessageType, Cosmetic, ExoSuitType, ImplantType, PlanetSideEmpire, PlanetSideGUID, Vector3}
import net.psforever.util.Config import net.psforever.util.Config
@ -179,10 +180,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case _ => case _ =>
false false
}) })
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
avatarGuid,
AvatarAction.PlayerState( AvatarAction.PlayerState(
avatarGuid,
player.Position, player.Position,
player.Velocity, player.Velocity,
yaw, yaw,
@ -196,7 +197,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
isNotVisible, isNotVisible,
eagleEye eagleEye
) )
) ) //todo CachedMessage
sessionLogic.squad.updateSquad() sessionLogic.squad.updateSquad()
if (player.death_by == -1) { if (player.death_by == -1) {
sessionLogic.kickedByAdministration() sessionLogic.kickedByAdministration()
@ -213,15 +214,8 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
} }
def handleEmote(pkt: EmoteMsg): Unit = { def handleEmote(pkt: EmoteMsg): Unit = {
val EmoteMsg(avatarGuid, emote) = pkt sendResponse(pkt)
val pZone = player.Zone ops.handleEmote(pkt)
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)))
}
} }
def handleDropItem(pkt: DropItemMessage): Unit = { def handleDropItem(pkt: DropItemMessage): Unit = {
@ -525,9 +519,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case GenericAction.MaxAnchorsExtend_RCV => case GenericAction.MaxAnchorsExtend_RCV =>
log.info(s"${player.Name} has anchored ${player.Sex.pronounObject}self to the ground") log.info(s"${player.Name} has anchored ${player.Sex.pronounObject}self to the ground")
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.PlanetsideAttribute(player.GUID, 19, 1) player.GUID,
PlanetsideAttribute(player.GUID, 19, 1)
) )
definition match { definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster => case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
@ -546,9 +541,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case GenericAction.MaxAnchorsRelease_RCV => case GenericAction.MaxAnchorsRelease_RCV =>
log.info(s"${player.Name} has released the anchors") log.info(s"${player.Name} has released the anchors")
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.PlanetsideAttribute(player.GUID, 19, 0) player.GUID,
PlanetsideAttribute(player.GUID, 19, 0)
) )
definition match { definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster => case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>

View file

@ -1,17 +1,19 @@
// Copyright (c) 2024 PSForever // Copyright (c) 2024 PSForever
package net.psforever.actors.session.normal package net.psforever.actors.session.normal
import akka.actor.Actor.Receive
import akka.actor.ActorContext import akka.actor.ActorContext
import net.psforever.actors.session.support.SpawnOperations.ActivityQueuedTask import net.psforever.actors.session.support.SpawnOperations.ActivityQueuedTask
import net.psforever.actors.session.support.{LocalHandlerFunctions, SessionData, SessionLocalHandlers, SpawnOperations} import net.psforever.actors.session.support.{LocalHandlerFunctions, SessionData, SessionLocalHandlers, SpawnOperations}
import net.psforever.objects.ce.Deployable import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.vehicles.MountableWeapons import net.psforever.objects.vehicles.MountableWeapons
import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable} 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, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage} 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.{InterstellarClusterService, Service}
import net.psforever.services.local.LocalResponse import net.psforever.services.local.LocalAction
import net.psforever.types.{ChatMessageType, PlanetSideGUID, SpawnGroup} import net.psforever.types.{ChatMessageType, SpawnGroup}
object LocalHandlerLogic { object LocalHandlerLogic {
def apply(ops: SessionLocalHandlers): LocalHandlerLogic = { def apply(ops: SessionLocalHandlers): LocalHandlerLogic = {
@ -34,244 +36,218 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act
/* response handlers */ /* response handlers */
/** def receive: Receive = {
* na case SendResponse(msgs) =>
* @param toChannel na msgs.foreach {
* @param guid na case msg @ (m: GenericObjectActionMessage)
* @param reply na if (m.code == 58 || m.code == 60 || m.code == 61) && !sessionLogic.zoning.spawn.startEnqueueSquadMessages =>
*/ // delay building virus alert if player is dead/respawning
def handle(toChannel: String, guid: PlanetSideGUID, reply: LocalResponse.Response): Unit = { sessionLogic.zoning.spawn.enqueueNewActivity(ActivityQueuedTask(
val resolvedPlayerGuid = if (player.HasGUID) { SpawnOperations.delaySendGenericObjectActionMessage(msg), 1)
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
) )
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 */ /* 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.vehicles.AccessPermissionGroup
import net.psforever.objects.vital.InGameHistory 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.packet.game.{ChatMsg, DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlanetsideAttributeMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
import net.psforever.services.Service import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.base.message.{SendResponse, SetEmpire}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3} import net.psforever.types.{BailType, ChatMessageType, DriveState, PlanetSideGUID, Vector3}
object MountHandlerLogic { object MountHandlerLogic {
@ -191,7 +191,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
if obj.Definition == GlobalDefinitions.vanu_sentry_turret => if obj.Definition == GlobalDefinitions.vanu_sentry_turret =>
log.info(s"${player.Name} mounts the ${obj.Definition.Name}") log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount") 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)) sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
ops.updateWeaponAtSeatPosition(obj, seatNumber) ops.updateWeaponAtSeatPosition(obj, seatNumber)
ops.MountingAction(tplayer, 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) val (pos, zang) = Vehicles.dismountShuttle(obj, mountPoint)
tplayer.Position = pos tplayer.Position = pos
sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true)) sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true))
continent.LocalEvents ! LocalServiceMessage( continent.LocalEvents ! MessageEnvelope(
continent.id, 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 sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
@ -249,25 +249,21 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountAction(tplayer, obj, seatNum) ops.DismountAction(tplayer, obj, seatNum)
continent.actor ! ZoneActor.RemoveFromBlockMap(player) //character doesn't need it 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 //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 //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 //the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone //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 //having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
events ! VehicleServiceMessage( events ! BundledEnvelope(
player.Name, MessageEnvelope(player.Name,
VehicleAction.SendResponse( SendResponse(Seq(
Service.defaultPlayerGUID, PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)) //cower in the shuttle bay 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 sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
case Mountable.CanDismount(obj: Vehicle, seatNum, _) case Mountable.CanDismount(obj: Vehicle, seatNum, _)
@ -293,9 +289,10 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountVehicleAction(tplayer, obj, seatNum) ops.DismountVehicleAction(tplayer, obj, seatNum)
case Mountable.CanDismount(obj: Vehicle, seat_num, _) => case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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, _) => case Mountable.CanDismount(obj: PlanetSideGameObject with Mountable with FactionAffinity with InGameHistory, seatNum, _) =>

View file

@ -1,21 +1,23 @@
// Copyright (c) 2024 PSForever // Copyright (c) 2024 PSForever
package net.psforever.actors.session.normal package net.psforever.actors.session.normal
import akka.actor.Actor.Receive
import akka.actor.{ActorContext, ActorRef, typed} import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.AvatarActor import net.psforever.actors.session.AvatarActor
import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions} import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions}
import net.psforever.objects.avatar.SpecialCarry 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.equipment.{Equipment, JammableMountedWeapons, JammableUnit}
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow} import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects.serverobject.interior.Sidedness.OutsideOf import net.psforever.objects.serverobject.interior.Sidedness.OutsideOf
import net.psforever.objects.serverobject.mount.Mountable import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.pad.VehicleSpawnPad import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent 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.Service
import net.psforever.services.base.envelope.GenericResponseEnvelope
import net.psforever.services.local.support.CaptureFlagManager 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} import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
object VehicleHandlerLogic { object VehicleHandlerLogic {
@ -31,365 +33,319 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
private val galaxyService: ActorRef = ops.galaxyService private val galaxyService: ActorRef = ops.galaxyService
/** def receive: Receive = {
* na case VehicleAction.VehicleState(
* vehicleGuid,
* @param toChannel na unk1,
* @param guid na pos,
* @param reply na orient,
*/ vel,
def handle(toChannel: String, guid: PlanetSideGUID, reply: VehicleResponse.Response): Unit = { unk2,
val resolvedPlayerGuid = if (player.HasGUID) { unk3,
player.GUID unk4,
} else { wheelDirection,
PlanetSideGUID(-1) unk5,
} unk6
val isNotSameTarget = resolvedPlayerGuid != guid ) if TestFilter(() => { NotSameTarget && player.VehicleSeated.contains(vehicleGuid) }) =>
reply match { //player who is also in the vehicle (not driver)
case VehicleResponse.VehicleState( sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, orient, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
vehicleGuid, player.Position = pos
unk1, player.Orientation = orient
pos, player.Velocity = vel
orient, sessionLogic.updateLocalBlockMap(pos)
vel, //llu destruction check
unk2, if (player.Carrying.contains(SpecialCarry.CaptureFlag)) {
unk3, continent
unk4, .GUID(player.VehicleSeated)
wheelDirection, .collect { case vehicle: Vehicle =>
unk5, CaptureFlagManager.ReasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, vehicle)
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))
} }
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, _) case VehicleAction.VehicleState(
if sessionLogic.general.accessedContainer.map(_.GUID).contains(target) => vehicleGuid,
//TODO when vehicle weapons can be changed without visual glitches, rewrite this unk1,
continent.GUID(target).collect { case vehicle: Vehicle => pos,
//external participant: observe changes to equipment ang,
(oldWeapons ++ oldInventory).foreach { case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0)) } vel,
changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory) 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, _) => case VehicleAction.ChildObjectState(objectGuid, pitch, yaw)
//TODO when vehicle weapons can be changed without visual glitches, rewrite this if TestFilter(NotSameTargetTest) =>
continent.GUID(target).collect { case vehicle: Vehicle => sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
}
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( 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.Zone
import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game.{ChatMsg, ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage} 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} import net.psforever.types.{ChatMessageType, DriveState, Vector3}
object VehicleLogic { object VehicleLogic {
@ -75,10 +77,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Position = position obj.Position = position
obj.Orientation = angle obj.Orientation = angle
// //
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! CachedEnvelope(
continent.id, continent.id,
player.GUID,
VehicleAction.VehicleState( VehicleAction.VehicleState(
player.GUID,
vehicle_guid, vehicle_guid,
unk1, unk1,
position, position,
@ -162,26 +164,11 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Position = position obj.Position = position
obj.Orientation = angle obj.Orientation = angle
obj.DeploymentState = if (is_crouched || !notMountedState) DriveState.Kneeling else DriveState.Mobile obj.DeploymentState = if (is_crouched || !notMountedState) DriveState.Kneeling else DriveState.Mobile
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.FrameVehicleState( player.GUID,
player.GUID, VehicleAction.FrameVehicleState(vehicle_guid, unk1, position, angle, velocity, unk2, unk3, unk4, is_crouched, is_airborne, ascending_flight, flight_time, unk9, unkA)
vehicle_guid, ) //todo CachedMessage
unk1,
position,
angle,
velocity,
unk2,
unk3,
unk4,
is_crouched,
is_airborne,
ascending_flight,
flight_time,
unk9,
unkA
)
)
sessionLogic.squad.updateSquad() sessionLogic.squad.updateSquad()
case (None, _) => case (None, _) =>
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone") //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) val angle = Vector3(0f, pitch, yaw)
tool.Orientation = angle tool.Orientation = angle
player.Orientation = angle player.Orientation = angle
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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 //TODO status condition of "playing getting out of vehicle to allow for late packets without warning
if (player.death_by == -1) { if (player.death_by == -1) {
@ -252,22 +240,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Velocity = vel obj.Velocity = vel
sessionLogic.updateBlockMap(obj, pos) sessionLogic.updateBlockMap(obj, pos)
obj.zoneInteractions() obj.zoneInteractions()
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! CachedEnvelope(
continent.id, continent.id,
VehicleAction.VehicleState( player.GUID,
player.GUID, VehicleAction.VehicleState(vehicle_guid, unk1, pos, ang, obj.Velocity, obj.Flying, 0, 0, 15, unk5 = false, obj.Cloaked)
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) { val mobileShift: String = if (obj.DeploymentState != DriveState.Mobile) {
obj.DeploymentState = DriveState.Mobile obj.DeploymentState = DriveState.Mobile
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero)) sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero))
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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" "; enforcing Mobile deployment state"
} else { } else {

View file

@ -16,7 +16,10 @@ import net.psforever.objects.zones.ZoneProjectile
import net.psforever.packet.PlanetSideGamePacket 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.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.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 net.psforever.types.{ExoSuitType, Vector3}
import scala.concurrent.duration.DurationInt import scala.concurrent.duration.DurationInt
@ -74,10 +77,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
player.Crouching = isCrouching player.Crouching = isCrouching
player.Jumping = isJumping player.Jumping = isJumping
player.Cloaked = player.ExoSuit == ExoSuitType.Infiltration && isCloaking player.Cloaked = player.ExoSuit == ExoSuitType.Infiltration && isCloaking
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! CachedEnvelope(
"spectator", "spectator",
avatarGuid,
AvatarAction.PlayerState( AvatarAction.PlayerState(
avatarGuid,
player.Position, player.Position,
player.Velocity, player.Velocity,
yaw, yaw,
@ -106,8 +109,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
} }
def handleEmote(pkt: EmoteMsg): Unit = { def handleEmote(pkt: EmoteMsg): Unit = {
val EmoteMsg(avatarGuid, emote) = pkt sendResponse(pkt)
sendResponse(EmoteMsg(avatarGuid, emote))
} }
def handleDropItem(pkt: DropItemMessage): Unit = { /* intentionally blank */ } def handleDropItem(pkt: DropItemMessage): Unit = { /* intentionally blank */ }
@ -228,9 +230,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case GenericAction.MaxAnchorsExtend_RCV => case GenericAction.MaxAnchorsExtend_RCV =>
log.info(s"${player.Name} has anchored ${player.Sex.pronounObject}self to the ground") log.info(s"${player.Name} has anchored ${player.Sex.pronounObject}self to the ground")
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored player.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.PlanetsideAttribute(player.GUID, 19, 1) player.GUID,
PlanetsideAttribute(player.GUID, 19, 1)
) )
definition match { definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster => case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster =>
@ -249,9 +252,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
case GenericAction.MaxAnchorsRelease_RCV => case GenericAction.MaxAnchorsRelease_RCV =>
log.info(s"${player.Name} has released the anchors") log.info(s"${player.Name} has released the anchors")
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.PlanetsideAttribute(player.GUID, 19, 0) player.GUID,
PlanetsideAttribute(player.GUID, 19, 0)
) )
definition match { definition match {
case GlobalDefinitions.trhev_dualcycler | GlobalDefinitions.trhev_burster => 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.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.vital.InGameHistory import net.psforever.objects.vital.InGameHistory
import net.psforever.packet.game.{DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState} import net.psforever.packet.game.{DelayedPathMountMsg, DismountVehicleCargoMsg, DismountVehicleMsg, GenericObjectActionMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectDetachMessage, PlayerStasisMessage, PlayerStateShiftMessage, ShiftState}
import net.psforever.services.Service import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.base.message.SendResponse
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.VehicleAction
object MountHandlerLogic { object MountHandlerLogic {
def apply(ops: SessionMountHandlers): 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) val (pos, zang) = Vehicles.dismountShuttle(obj, mountPoint)
tplayer.Position = pos tplayer.Position = pos
sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true)) sendResponse(DelayedPathMountMsg(pguid, sguid, u1=60, u2=true))
continent.LocalEvents ! LocalServiceMessage( continent.LocalEvents ! MessageEnvelope(
continent.id, 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) obj.Zone.actor ! ZoneActor.RemoveFromBlockMap(player)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
@ -76,25 +76,21 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountAction(tplayer, obj, seatNum) ops.DismountAction(tplayer, obj, seatNum)
continent.actor ! ZoneActor.RemoveFromBlockMap(player) //character doesn't need it 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 //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 //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 //the player will fall to the ground and is perfectly vulnerable in this state
//additionally, our player must exist in the current zone //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 //having no in-game avatar target will throw us out of the map screen when deploying and cause softlock
events ! VehicleServiceMessage( events ! BundledEnvelope(
player.Name, MessageEnvelope(player.Name,
VehicleAction.SendResponse( SendResponse(Seq(
Service.defaultPlayerGUID, PlayerStasisMessage(pguid),
PlayerStateShiftMessage(ShiftState(unk=0, obj.Position, obj.Orientation.z, vel=None)) //cower in the shuttle bay 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) context.self ! SessionActor.SetMode(NormalMode)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
@ -111,9 +107,10 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
ops.DismountVehicleAction(tplayer, obj, seatNum) ops.DismountVehicleAction(tplayer, obj, seatNum)
case Mountable.CanDismount(obj: Vehicle, seat_num, _) => case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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, _) => 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.avatar.{BattleRank, CommandRank, DeployableToolbox, FirstTimeEvents, Implant, ProgressDecoration, Shortcut => AvatarShortcut}
import net.psforever.objects.ce.Deployable import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.ServerObject 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.PlanetSidePacket
import net.psforever.packet.game.{DeployableInfo, DeployableObjectsInfoMessage, DeploymentAction, ObjectCreateDetailedMessage, ObjectDeleteMessage} import net.psforever.packet.game.{DeployableInfo, DeployableObjectsInfoMessage, DeploymentAction, ObjectCreateDetailedMessage, ObjectDeleteMessage}
import net.psforever.packet.game.objectcreate.{ObjectClass, ObjectCreateMessageParent, RibbonBars} import net.psforever.packet.game.objectcreate.{ObjectClass, ObjectCreateMessageParent, RibbonBars}
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.ObjectDelete
import net.psforever.services.chat.SpectatorChannel import net.psforever.services.chat.SpectatorChannel
import net.psforever.services.teamwork.{SquadAction, SquadServiceMessage} import net.psforever.services.teamwork.{SquadAction, SquadServiceMessage}
import net.psforever.types.{CapacitorStateType, ChatMessageType, ExoSuitType, MeritCommendation, SquadRequestType} import net.psforever.types.{CapacitorStateType, ChatMessageType, ExoSuitType, MeritCommendation, SquadRequestType}
@ -68,7 +68,7 @@ class SpectatorModeLogic(data: SessionData) extends ModeLogic {
player.Inventory.Items player.Inventory.Items
.foreach { entry => sendResponse(ObjectDeleteMessage(entry.GUID, 0)) } .foreach { entry => sendResponse(ObjectDeleteMessage(entry.GUID, 0)) }
sendResponse(ObjectDeleteMessage(player.avatar.locker.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() player.Holsters()
.collect { case slot if slot.Equipment.nonEmpty => sendResponse(ObjectDeleteMessage(slot.Equipment.get.GUID, 0)) } .collect { case slot if slot.Equipment.nonEmpty => sendResponse(ObjectDeleteMessage(slot.Equipment.get.GUID, 0)) }
val vehicleAndSeat = data.vehicles.GetMountableAndSeat(None, player, continent) match { val vehicleAndSeat = data.vehicles.GetMountableAndSeat(None, player, continent) match {
@ -111,7 +111,7 @@ class SpectatorModeLogic(data: SessionData) extends ModeLogic {
.foreach { obj => .foreach { obj =>
sendResponse(DeployableObjectsInfoMessage( sendResponse(DeployableObjectsInfoMessage(
DeploymentAction.Dismiss, 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) { 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.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.chat.SquadChannel
import net.psforever.services.teamwork.SquadResponse import net.psforever.services.teamwork.SquadResponse
import net.psforever.types.{ChatMessageType, PlanetSideGUID, SquadListDecoration, SquadResponseType} import net.psforever.types.{PlanetSideGUID, SquadListDecoration, SquadResponseType}
object SquadHandlerLogic { object SquadHandlerLogic {
def apply(ops: SessionSquadHandlers): SquadHandlerLogic = { def apply(ops: SessionSquadHandlers): SquadHandlerLogic = {

View file

@ -1,14 +1,16 @@
// Copyright (c) 2024 PSForever // Copyright (c) 2024 PSForever
package net.psforever.actors.session.spectator package net.psforever.actors.session.spectator
import akka.actor.Actor.Receive
import akka.actor.ActorContext import akka.actor.ActorContext
import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions} 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.equipment.Equipment
import net.psforever.objects.serverobject.pad.VehicleSpawnPad import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent 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.packet.game.{ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ServerVehicleOverrideMsg, VehicleStateMessage}
import net.psforever.services.vehicle.{VehicleResponse, VehicleServiceResponse} import net.psforever.services.base.envelope.GenericResponseEnvelope
import net.psforever.services.vehicle.{VehicleAction, VehicleStamp}
import net.psforever.types.{BailType, PlanetSideGUID, Vector3} import net.psforever.types.{BailType, PlanetSideGUID, Vector3}
object VehicleHandlerLogic { object VehicleHandlerLogic {
@ -24,230 +26,184 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
//private val galaxyService: ActorRef = ops.galaxyService //private val galaxyService: ActorRef = ops.galaxyService
/** def receive: Receive = {
* na case VehicleAction.VehicleState(
* vehicleGuid,
* @param toChannel na unk1,
* @param guid na pos,
* @param reply na orient,
*/ vel,
def handle(toChannel: String, guid: PlanetSideGUID, reply: VehicleResponse.Response): Unit = { unk2,
val resolvedPlayerGuid = if (player.HasGUID) { unk3,
player.GUID unk4,
} else { wheelDirection,
PlanetSideGUID(-1) unk5,
} unk6
val isNotSameTarget = resolvedPlayerGuid != guid ) if TestFilter(() => { NotSameTarget && player.VehicleSeated.contains(vehicleGuid) }) =>
reply match { //player who is also in the vehicle (not driver)
case VehicleResponse.VehicleState( sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, orient, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
vehicleGuid, player.Position = pos
unk1, player.Orientation = orient
pos, player.Velocity = vel
orient, sessionLogic.updateLocalBlockMap(pos)
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)
case VehicleResponse.VehicleState( case VehicleAction.VehicleState(
vehicleGuid, vehicleGuid,
unk1, unk1,
pos, pos,
ang, ang,
vel, vel,
unk2, unk2,
unk3, unk3,
unk4, unk4,
wheelDirection, wheelDirection,
unk5, unk5,
unk6 unk6
) if isNotSameTarget => ) if TestFilter(NotSameTargetTest) =>
//player who is watching the vehicle from the outside //player who is watching the vehicle from the outside
sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6)) sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
case VehicleResponse.ChildObjectState(objectGuid, pitch, yaw) if isNotSameTarget => case VehicleAction.ChildObjectState(objectGuid, pitch, yaw)
sendResponse(ChildObjectStateMessage(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) case VehicleAction.FrameVehicleState(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)
if isNotSameTarget => if TestFilter(NotSameTargetTest) =>
sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)) sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
case VehicleResponse.ChangeFireState_Start(weaponGuid) if isNotSameTarget => case VehicleAction.DismountVehicle(bailType, wasKickedByDriver)
sendResponse(ChangeFireStateMessage_Start(weaponGuid)) if TestFilter(NotSameTargetTest) =>
sendResponse(DismountVehicleMsg(FilterGuid, bailType, wasKickedByDriver))
case VehicleResponse.ChangeFireState_Stop(weaponGuid) if isNotSameTarget => case VehicleAction.MountVehicle(vehicleGuid, seat)
sendResponse(ChangeFireStateMessage_Stop(weaponGuid)) if TestFilter(NotSameTargetTest) =>
sendResponse(ObjectAttachMessage(vehicleGuid, FilterGuid, seat))
case VehicleResponse.Reload(itemGuid) if isNotSameTarget => case VehicleAction.DeployRequest(objectGuid, state, unk1, unk2, pos)
sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0)) 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 => case VehicleAction.EquipmentCreatedInSlot(pkt)
sendResponse(ObjectDetachMessage(weapon_guid, previous_guid, Vector3.Zero, 0)) if TestFilter(NotSameTargetTest) =>
//TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0)) sendResponse(pkt)
sendResponse(
ObjectCreateMessage( case VehicleAction.InventoryState(obj, parentGuid, start, conData)
ammo_id, if TestFilter(NotSameTargetTest) =>
ammo_guid, //TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
ObjectCreateMessageParent(weapon_guid, weapon_slot), val objGuid = obj.GUID
ammo_data 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 => case VehicleAction.KickCargo(cargo, _, _)
continent.GUID(weaponGuid).collect { if TestFilter(() => { player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive }) =>
case tool: Tool if tool.Magazine == 0 => sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
// 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 => case VehicleSpawnPad.AttachToRails(vehicle, pad) =>
sendResponse(DismountVehicleMsg(guid, bailType, wasKickedByDriver)) sendResponse(ObjectAttachMessage(pad.GUID, vehicle.GUID, slot=3))
case VehicleResponse.MountVehicle(vehicleGuid, seat) if isNotSameTarget => case VehicleSpawnPad.ConcealPlayer(playerGuid) =>
sendResponse(ObjectAttachMessage(vehicleGuid, guid, seat)) sendResponse(GenericObjectActionMessage(playerGuid, code=9))
case VehicleResponse.DeployRequest(objectGuid, state, unk1, unk2, pos) if isNotSameTarget => case VehicleSpawnPad.DetachFromRails(vehicle, pad) =>
sendResponse(DeployRequestMessage(guid, objectGuid, state, unk1, unk2, pos)) val padDefinition = pad.Definition
sendResponse(
case VehicleResponse.SendResponse(msg) => ObjectDetachMessage(
sendResponse(msg) pad.GUID,
vehicle.GUID,
case VehicleResponse.AttachToRails(vehicleGuid, padGuid) => pad.Position + Vector3.z(padDefinition.VehicleCreationZOffset),
sendResponse(ObjectAttachMessage(padGuid, vehicleGuid, slot=3)) pad.Orientation.z + padDefinition.VehicleCreationZOrientOffset
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 => case VehicleSpawnPad.ResetSpawnPad(pad) =>
sendResponse(pkt) sendResponse(GenericObjectActionMessage(pad.GUID, code=23))
case VehicleResponse.GenericObjectAction(objectGuid, action) if isNotSameTarget => case VehicleSpawnPad.RevealPlayer(playerGuid) =>
sendResponse(GenericObjectActionMessage(objectGuid, action)) sendResponse(GenericObjectActionMessage(playerGuid, code=10))
case VehicleResponse.InventoryState(obj, parentGuid, start, conData) if isNotSameTarget => case VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, _) =>
//TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly? sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
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 => case VehicleAction.ChangeLoadout(target, oldWeapons, _, oldInventory, _) =>
//seat number (first field) seems to be correct if passenger is kicked manually by driver //TODO when vehicle weapons can be changed without visual glitches, rewrite this
//but always seems to return 4 if user is kicked by mount permissions changing continent.GUID(target).collect { case vehicle: Vehicle =>
sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver)) changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
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 _ => ()
}
} }
private def changeLoadoutDeleteOldEquipment( private def changeLoadoutDeleteOldEquipment(

View file

@ -7,7 +7,9 @@ import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.Vehicle import net.psforever.objects.Vehicle
import net.psforever.objects.serverobject.deploy.Deployment import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.packet.game.{ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage} 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} import net.psforever.types.{DriveState, Vector3}
object VehicleLogic { object VehicleLogic {
@ -39,22 +41,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
obj.Velocity = vel obj.Velocity = vel
sessionLogic.updateBlockMap(obj, pos) sessionLogic.updateBlockMap(obj, pos)
obj.zoneInteractions() obj.zoneInteractions()
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! CachedEnvelope(
continent.id, continent.id,
VehicleAction.VehicleState( player.GUID,
player.GUID, VehicleAction.VehicleState(vehicle_guid, unk1, pos, ang, obj.Velocity, obj.Flying, 0, 0, 15, unk5 = false, obj.Cloaked)
vehicle_guid,
unk1,
pos,
ang,
obj.Velocity,
obj.Flying,
0,
0,
15,
unk5 = false,
obj.Cloaked
)
) )
case _ => () case _ => ()
} }
@ -92,9 +82,10 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
val mobileShift: String = if (obj.DeploymentState != DriveState.Mobile) { val mobileShift: String = if (obj.DeploymentState != DriveState.Mobile) {
obj.DeploymentState = DriveState.Mobile obj.DeploymentState = DriveState.Mobile
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero)) sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Mobile, 0, unk3=false, Vector3.Zero))
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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" "; enforcing Mobile deployment state"
} else { } else {

View file

@ -17,10 +17,10 @@ import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.zones.{Zone, ZoneInfo} import net.psforever.objects.zones.{Zone, ZoneInfo}
import net.psforever.packet.game.TimeOfDayMessage.GetTimeOfDayValue import net.psforever.packet.game.TimeOfDayMessage.GetTimeOfDayValue
import net.psforever.packet.game.{SetChatFilterMessage, TimeOfDayMessage} import net.psforever.packet.game.{SetChatFilterMessage, TimeOfDayMessage}
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.SendResponse
import net.psforever.services.chat.{DefaultChannel, OutfitChannel, SquadChannel} 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.services.teamwork.{SquadResponse, SquadService, SquadServiceResponse}
import net.psforever.types.ChatMessageType.CMT_QUIT import net.psforever.types.ChatMessageType.CMT_QUIT
import org.log4s.Logger import org.log4s.Logger
@ -405,10 +405,7 @@ class ChatOperations(
} }
else { else {
if (building.CaptureTerminalIsHacked) { if (building.CaptureTerminalIsHacked) {
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! CaptureEnvelope(HackCaptureActor.ResecureCaptureTerminal(terminal, zone, PlayerSource.Nobody))
zone.id,
LocalAction.ResecureCaptureTerminal(terminal, PlayerSource.Nobody)
)
} }
building.Actor ! BuildingActor.SetFaction(faction) building.Actor ! BuildingActor.SetFaction(faction)
building.Actor ! BuildingActor.AmenityStateChange(terminal, Some(false)) building.Actor ! BuildingActor.AmenityStateChange(terminal, Some(false))
@ -1444,10 +1441,7 @@ class ChatOperations(
val msg = TimeOfDayMessage(zone.GetTimeOfDay(), zone.GetTimeOfDaySpeed()) val msg = TimeOfDayMessage(zone.GetTimeOfDay(), zone.GetTimeOfDaySpeed())
// update players in zone // update players in zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(zone.id, SendResponse(msg))
zone.id,
AvatarAction.SendResponse(Service.defaultPlayerGUID, msg)
)
sendResponse(ChatMsg(messageType = UNK_227, contents = f"@CMT_SETTIME_OK^$hh~^$mm%02d~")) sendResponse(ChatMsg(messageType = UNK_227, contents = f"@CMT_SETTIME_OK^$hh~^$mm%02d~"))
case _ => case _ =>
@ -1482,10 +1476,7 @@ class ChatOperations(
val msg = TimeOfDayMessage(zone.GetTimeOfDay(), zone.GetTimeOfDaySpeed()) val msg = TimeOfDayMessage(zone.GetTimeOfDay(), zone.GetTimeOfDaySpeed())
// update players in zone // update players in zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(zone.id, SendResponse(msg))
zone.id,
AvatarAction.SendResponse(Service.defaultPlayerGUID, msg)
)
sendResponse(ChatMsg(messageType = UNK_227, contents = s"@CMT_SETTIMESPEED_OK^$timeSpeed~")) sendResponse(ChatMsg(messageType = UNK_227, contents = s"@CMT_SETTIMESPEED_OK^$timeSpeed~"))
case _ => 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.vehicles.Utility.InternalTelepad
import net.psforever.objects.zones.blockmap.BlockMapEntity import net.psforever.objects.zones.blockmap.BlockMapEntity
import net.psforever.objects.zones.exp.ToDatabase import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.services.RemoverActor import net.psforever.services.avatar.support.GroundEnvelope
import net.psforever.services.local.{LocalAction, LocalServiceMessage} 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.collection.mutable
import scala.concurrent.ExecutionContext.Implicits.global 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.objectcreate._
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.account.AccountPersistenceService 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.local.support.CaptureFlagManager
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.VehicleAction
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.types._ import net.psforever.types._
import net.psforever.util.Config import net.psforever.util.Config
@ -193,6 +197,32 @@ class GeneralOperations(
private[session] var progressBarUpdate: Cancellable = Default.Cancellable private[session] var progressBarUpdate: Cancellable = Default.Cancellable
private var charSavedTimer: 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 = { def handleDropItem(pkt: DropItemMessage): GeneralOperations.ItemDropState.Behavior = {
val DropItemMessage(itemGuid) = pkt val DropItemMessage(itemGuid) = pkt
(sessionLogic.validObject(itemGuid, decorator = "DropItem"), player.FreeHand.Equipment) match { (sessionLogic.validObject(itemGuid, decorator = "DropItem"), player.FreeHand.Equipment) match {
@ -376,7 +406,7 @@ class GeneralOperations(
val detectedTargets = sessionLogic.shooting.FindDetectedProjectileTargets(targets) val detectedTargets = sessionLogic.shooting.FindDetectedProjectileTargets(targets)
val mode = 7 + (if (weapon.Projectile == GlobalDefinitions.wasp_rocket_projectile) 1 else 0) val mode = 7 + (if (weapon.Projectile == GlobalDefinitions.wasp_rocket_projectile) 1 else 0)
detectedTargets.foreach { target => detectedTargets.foreach { target =>
continent.AvatarEvents ! AvatarServiceMessage(target, AvatarAction.ProjectileAutoLockAwareness(mode)) continent.AvatarEvents ! MessageEnvelope(target, AvatarAction.ProjectileAutoLockAwareness(mode))
} }
case _ => () case _ => ()
} }
@ -456,7 +486,7 @@ class GeneralOperations(
case attacker case attacker
if attacker.Faction != player.Faction && if attacker.Faction != player.Faction &&
System.currentTimeMillis() - llu.LastCollectionTime >= Config.app.game.experience.cep.lluSlayerCreditDuration.toMillis => System.currentTimeMillis() - llu.LastCollectionTime >= Config.app.game.experience.cep.lluSlayerCreditDuration.toMillis =>
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
attacker.Name, attacker.Name,
AvatarAction.AwardCep(attacker.CharId, Config.app.game.experience.cep.lluSlayerCredit) AvatarAction.AwardCep(attacker.CharId, Config.app.game.experience.cep.lluSlayerCredit)
) )
@ -714,7 +744,7 @@ class GeneralOperations(
* @param channel the channel name * @param channel the channel name
*/ */
private def unaccessContainerChannel(events: ActorRef, channel: String): Unit = { 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) => case _ if continent.EquipmentOnGround.contains(obj) =>
obj.Position = Vector3.Zero obj.Position = Vector3.Zero
continent.Ground ! Zone.Ground.RemoveItem(objectGuid) continent.Ground ! Zone.Ground.RemoveItem(objectGuid)
continent.AvatarEvents ! AvatarServiceMessage.Ground(RemoverActor.ClearSpecific(List(obj), continent)) continent.AvatarEvents ! GroundEnvelope(RemoverActor.ClearSpecific(List(obj), continent))
true true
case _ => case _ =>
Zone.EquipmentIs.Where(obj, objectGuid, continent) match { Zone.EquipmentIs.Where(obj, objectGuid, continent) match {
@ -876,9 +906,22 @@ class GeneralOperations(
* @param unk2 na * @param unk2 na
*/ */
def hackObject(targetGuid: PlanetSideGUID, unk1: Long, unk2: HackState7): Unit = { 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 * Send a PlanetsideAttributeMessage packet to the client
* @param targetGuid The target of the attribute * @param targetGuid The target of the attribute
@ -887,7 +930,7 @@ class GeneralOperations(
*/ */
def sendPlanetsideAttributeMessage( def sendPlanetsideAttributeMessage(
targetGuid: PlanetSideGUID, targetGuid: PlanetSideGUID,
attributeNumber: PlanetsideAttributeEnum, attributeNumber: Int,
attributeValue: Long attributeValue: Long
): Unit = { ): Unit = {
sendResponse(PlanetsideAttributeMessage(targetGuid, attributeNumber, attributeValue)) sendResponse(PlanetsideAttributeMessage(targetGuid, attributeNumber, attributeValue))
@ -986,18 +1029,18 @@ class GeneralOperations(
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ArmorShieldOff")) sendResponse(ChatMsg(ChatMessageType.UNK_227, "@ArmorShieldOff"))
} }
player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal player.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.PlanetsideAttributeToAll(player.GUID, 8, 0) PlanetsideAttribute(player.GUID, 8, 0)
) )
} }
} }
} }
private def activateMaxSpecialStateMessage(): Unit = { private def activateMaxSpecialStateMessage(): Unit = {
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.PlanetsideAttributeToAll(player.GUID, 8, 1) PlanetsideAttribute(player.GUID, 8, 1)
) )
} }
@ -1010,9 +1053,10 @@ class GeneralOperations(
case (Some(obj), Some(seatNum)) => case (Some(obj), Some(seatNum)) =>
tplayer.VehicleSeated = None tplayer.VehicleSeated = None
obj.Seats(seatNum).unmount(tplayer) obj.Seats(seatNum).unmount(tplayer)
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.KickPassenger(tplayer.GUID, seatNum, unk2=false, obj.GUID) tplayer.GUID,
VehicleAction.KickPassenger(seatNum, unk2=false, obj.GUID)
) )
case _ => () case _ => ()
} }
@ -1249,7 +1293,7 @@ class GeneralOperations(
continent.GUID(specialItemSlotGuid) match { continent.GUID(specialItemSlotGuid) match {
case Some(llu: CaptureFlag) => case Some(llu: CaptureFlag) =>
if (llu.Target.GUID == captureTerminal.Owner.GUID) { if (llu.Target.GUID == captureTerminal.Owner.GUID) {
continent.LocalEvents ! LocalServiceMessage(continent.id, LocalAction.LluCaptured(llu)) continent.LocalEvents ! CaptureEnvelope(HackCaptureActor.FlagCaptured(llu))
} else { } else {
log.info( log.info(
s"LLU target is not this base. Target GUID: ${llu.Target.GUID} This base: ${captureTerminal.Owner.GUID}" 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 events = continent.AvatarEvents
val zoneid = continent.id val zoneid = continent.id
val destinationPosition = dest.Position 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 player.Position = destinationPosition
events ! AvatarServiceMessage(zoneid, AvatarAction.LoadPlayer( events ! BundledEnvelope(
pguid, MessageEnvelope(zoneid, pguid, ObjectDelete(pguid)),
player.Definition.ObjectId, MessageEnvelope(player.Name,
pguid, SendResponse(PlayerStateShiftMessage(ShiftState(0, destinationPosition, player.Orientation.z)))
player.Definition.Packet.ConstructorData(player).get, ),
None MessageEnvelope(zoneid, pguid, AvatarAction.LoadPlayer(
)) player.Definition.ObjectId,
useRouterTelepadEffect(pguid, sguid, dguid) pguid,
continent.LocalEvents ! LocalServiceMessage( player.Definition.Packet.ConstructorData(player).get,
continent.id, None
LocalAction.RouterTelepadTransport(pguid, pguid, sguid, dguid) )),
MessageEnvelope(zoneid, pguid, LocalAction.RouterTelepadTransport(pguid, sguid, dguid))
) )
useRouterTelepadEffect(pguid, sguid, dguid)
sessionLogic.zoning.spawn.ShiftPosition = destinationPosition sessionLogic.zoning.spawn.ShiftPosition = destinationPosition
player.LogActivity(TelepadUseActivity(VehicleSource(router), DeployableSource(remoteTelepad), PlayerSource(player))) player.LogActivity(TelepadUseActivity(VehicleSource(router), DeployableSource(remoteTelepad), PlayerSource(player)))
} else { } 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.objects.sourcing.{PlayerSource, SourceEntry, UniquePlayer}
import net.psforever.packet.game.objectcreate.ConstructorData import net.psforever.packet.game.objectcreate.ConstructorData
import net.psforever.objects.zones.exp import net.psforever.objects.zones.exp
import net.psforever.services.Service import net.psforever.services.avatar.{AvatarAction, AvatarStamp}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage, AvatarServiceResponse} import net.psforever.services.base.envelope.{GenericResponseEnvelope, MessageEnvelope}
import net.psforever.services.base.message.SendResponse
import net.psforever.services.chat.OutfitChannel import net.psforever.services.chat.OutfitChannel
import scala.collection.mutable import scala.collection.mutable
@ -16,14 +17,11 @@ import scala.collection.mutable
import net.psforever.actors.session.AvatarActor import net.psforever.actors.session.AvatarActor
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.avatar.AvatarResponse
import net.psforever.types._ import net.psforever.types._
import net.psforever.util.Config import net.psforever.util.Config
trait AvatarHandlerFunctions extends CommonSessionInterfacingFunctionality { trait AvatarHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
val ops: SessionAvatarHandlers val ops: SessionAvatarHandlers
def handle(toChannel: String, guid: PlanetSideGUID, reply: AvatarResponse.Response): Unit
} }
class SessionAvatarHandlers( class SessionAvatarHandlers(
@ -36,7 +34,7 @@ class SessionAvatarHandlers(
mutable.LongMap[SessionAvatarHandlers.LastUpstream]() mutable.LongMap[SessionAvatarHandlers.LastUpstream]()
private[session] val hidingPlayerRandomizer = new scala.util.Random private[session] val hidingPlayerRandomizer = new scala.util.Random
def changeAmmoProcedures( def changeAmmoProcedure(
weaponGuid: PlanetSideGUID, weaponGuid: PlanetSideGUID,
previousAmmoGuid: PlanetSideGUID, previousAmmoGuid: PlanetSideGUID,
ammoTypeId: Int, ammoTypeId: Int,
@ -45,7 +43,7 @@ class SessionAvatarHandlers(
ammoData: ConstructorData ammoData: ConstructorData
): Unit = { ): Unit = {
sendResponse(ObjectDetachMessage(weaponGuid, previousAmmoGuid, Vector3.Zero, 0)) sendResponse(ObjectDetachMessage(weaponGuid, previousAmmoGuid, Vector3.Zero, 0))
//TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0)) sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
sendResponse( sendResponse(
ObjectCreateMessage( ObjectCreateMessage(
ammoTypeId, ammoTypeId,
@ -140,7 +138,7 @@ class SessionAvatarHandlers(
val playersInZone = killer.Zone.Players.map { avatar => (avatar.id, avatar.basic.name) } val playersInZone = killer.Zone.Players.map { avatar => (avatar.id, avatar.basic.name) }
val squadMembersHere = playersInZone.filter(member => squadMembers.contains(member._2)) val squadMembersHere = playersInZone.filter(member => squadMembers.contains(member._2))
squadMembersHere.foreach { member => squadMembersHere.foreach { member =>
killer.Zone.AvatarEvents ! AvatarServiceMessage( killer.Zone.AvatarEvents ! MessageEnvelope(
member._2, member._2,
AvatarAction.AwardBep(member._1, expSplit, ExperienceType.Normal)) 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 playersInZone = vehicle.Zone.Players.map { avatar => (avatar.id, avatar.basic.name) }
val squadMembersHere = playersInZone.filter(member => squadMembers.contains(member._2)) val squadMembersHere = playersInZone.filter(member => squadMembers.contains(member._2))
squadMembersHere.foreach { member => squadMembersHere.foreach { member =>
vehicle.Zone.AvatarEvents ! AvatarServiceMessage( vehicle.Zone.AvatarEvents ! MessageEnvelope(
member._2, member._2,
AvatarAction.AwardBep(member._1, exp, ExperienceType.Normal)) AvatarAction.AwardBep(member._1, exp, ExperienceType.Normal))
} }
@ -212,12 +210,11 @@ class SessionAvatarHandlers(
def killedWhileMounted(obj: PlanetSideGameObject with Mountable, playerGuid: PlanetSideGUID): Unit = { def killedWhileMounted(obj: PlanetSideGameObject with Mountable, playerGuid: PlanetSideGUID): Unit = {
val playerName = player.Name val playerName = player.Name
//boot cadaver from mount on client //boot cadaver from mount on client
context.self ! AvatarServiceResponse( context.self ! GenericResponseEnvelope(
AvatarStamp,
playerName, playerName,
Service.defaultPlayerGUID, Default.GUID0,
AvatarResponse.SendResponse( SendResponse(ObjectDetachMessage(obj.GUID, playerGuid, player.Position, Vector3.Zero))
ObjectDetachMessage(obj.GUID, playerGuid, player.Position, Vector3.Zero)
)
) )
//player no longer seated //player no longer seated
obj.PassengerInSeat(player).foreach { seatNumber => obj.PassengerInSeat(player).foreach { seatNumber =>
@ -239,7 +236,7 @@ class SessionAvatarHandlers(
object SessionAvatarHandlers { object SessionAvatarHandlers {
private[session] case class LastUpstream( private[session] case class LastUpstream(
msg: Option[AvatarResponse.PlayerState], msg: Option[AvatarAction.PlayerState],
visible: Boolean, visible: Boolean,
shooting: Option[PlanetSideGUID], shooting: Option[PlanetSideGUID],
time: Long time: Long

View file

@ -4,6 +4,7 @@ package net.psforever.actors.session.support
import akka.actor.typed.receptionist.Receptionist import akka.actor.typed.receptionist.Receptionist
import akka.actor.typed.scaladsl.adapter._ import akka.actor.typed.scaladsl.adapter._
import akka.actor.{ActorContext, ActorRef, typed} import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.chat.ChatService import net.psforever.services.chat.ChatService
import scala.collection.mutable import scala.collection.mutable
@ -31,7 +32,7 @@ import net.psforever.packet._
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.account.AccountPersistenceService import net.psforever.services.account.AccountPersistenceService
import net.psforever.services.ServiceManager.LookupResult 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.services.{Service, InterstellarClusterService => ICS}
import net.psforever.types._ import net.psforever.types._
import net.psforever.util.Config import net.psforever.util.Config
@ -119,6 +120,8 @@ class SessionData(
def zoning: ZoningOperations = zoningOpt.orNull def zoning: ZoningOperations = zoningOpt.orNull
def chat: ChatOperations = chatOpt.orNull def chat: ChatOperations = chatOpt.orNull
val handlerFilters: CommonHandlerFilters = new CommonHandlerFilters()
ServiceManager.serviceManager ! Lookup("accountIntermediary") ServiceManager.serviceManager ! Lookup("accountIntermediary")
ServiceManager.serviceManager ! Lookup("accountPersistence") ServiceManager.serviceManager ! Lookup("accountPersistence")
ServiceManager.serviceManager ! Lookup("galaxy") ServiceManager.serviceManager ! Lookup("galaxy")
@ -567,9 +570,10 @@ class SessionData(
case (Some(obj), Some(seatNum)) => case (Some(obj), Some(seatNum)) =>
tplayer.VehicleSeated = None tplayer.VehicleSeated = None
obj.Seats(seatNum).unmount(tplayer) obj.Seats(seatNum).unmount(tplayer)
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.KickPassenger(tplayer.GUID, seatNum, unk2=false, obj.GUID) tplayer.GUID,
VehicleAction.KickPassenger(seatNum, unk2=false, obj.GUID)
) )
case _ => () case _ => ()
} }
@ -615,12 +619,12 @@ class SessionData(
squadResponseOpt.foreach(_.stop()) squadResponseOpt.foreach(_.stop())
zoningOpt.foreach(_.stop()) zoningOpt.foreach(_.stop())
chatOpt.foreach(_.stop()) chatOpt.foreach(_.stop())
continent.AvatarEvents ! Service.Leave() continent.AvatarEvents ! Service.LeaveAll
continent.LocalEvents ! Service.Leave() continent.LocalEvents ! Service.LeaveAll
continent.VehicleEvents ! Service.Leave() continent.VehicleEvents ! Service.LeaveAll
galaxyService ! Service.Leave() galaxyService ! Service.LeaveAll
if (avatar != null && squadService != Default.Actor) { 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 akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.packet.game.FriendsResponse 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 ops: SessionGalaxyHandlers
def handleUpdateIgnoredPlayers(pkt: FriendsResponse): Unit def handleUpdateIgnoredPlayers(pkt: FriendsResponse): Unit
def handle(reply: GalaxyResponse.Response): Unit
} }
class SessionGalaxyHandlers( 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.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects.serverobject.interior.Sidedness import net.psforever.objects.serverobject.interior.Sidedness
import net.psforever.packet.game.{GenericObjectActionMessage, ObjectDeleteMessage, PlanetsideAttributeMessage, TriggerEffectMessage} import net.psforever.packet.game.{GenericObjectActionMessage, ObjectDeleteMessage, PlanetsideAttributeMessage, TriggerEffectMessage}
import net.psforever.services.local.LocalResponse
import net.psforever.types.{PlanetSideGUID, Vector3} import net.psforever.types.{PlanetSideGUID, Vector3}
trait LocalHandlerFunctions extends CommonSessionInterfacingFunctionality { trait LocalHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
def ops: SessionLocalHandlers def ops: SessionLocalHandlers
def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit
def handleDeployableIsDismissed(obj: Deployable): Unit def handleDeployableIsDismissed(obj: Deployable): Unit
def handle(toChannel: String, guid: PlanetSideGUID, reply: LocalResponse.Response): Unit
} }
class SessionLocalHandlers( 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.affinity.FactionAffinity
import net.psforever.objects.serverobject.interior.Sidedness.OutsideOf import net.psforever.objects.serverobject.interior.Sidedness.OutsideOf
import net.psforever.objects.{PlanetSideGameObject, Tool, Vehicle} 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.objects.vital.InGameHistory
import net.psforever.packet.game.{DismountVehicleCargoMsg, GenericObjectActionMessage, InventoryStateMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectAttachMessage, ObjectDetachMessage, PlanetsideAttributeMessage} import net.psforever.packet.game.{DismountVehicleCargoMsg, GenericObjectActionMessage, InventoryStateMessage, MountVehicleCargoMsg, MountVehicleMsg, ObjectAttachMessage, ObjectDetachMessage, PlanetsideAttributeMessage}
import net.psforever.services.Service import net.psforever.services.base.CachedEnvelope
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} 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.types.{BailType, PlanetSideGUID, Vector3}
// //
import net.psforever.actors.session.AvatarActor import net.psforever.actors.session.AvatarActor
@ -185,9 +188,10 @@ class SessionMountHandlers(
avatarActor ! AvatarActor.DeactivateActiveImplants avatarActor ! AvatarActor.DeactivateActiveImplants
avatarActor ! AvatarActor.SuspendStaminaRegeneration(3.seconds) avatarActor ! AvatarActor.SuspendStaminaRegeneration(3.seconds)
sendResponse(ObjectAttachMessage(objGuid, playerGuid, seatNum)) sendResponse(ObjectAttachMessage(objGuid, playerGuid, seatNum))
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.MountVehicle(playerGuid, objGuid, seatNum) playerGuid,
VehicleAction.MountVehicle(objGuid, seatNum)
) )
} }
@ -202,13 +206,12 @@ class SessionMountHandlers(
if (tplayer.BailProtection) { if (tplayer.BailProtection) {
tplayer.ContributionFrom(obj) tplayer.ContributionFrom(obj)
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.SendResponse(Service.defaultPlayerGUID, PlanetsideAttributeMessage(obj.GUID, 81, 1)) SendResponse(
) PlanetsideAttributeMessage(obj.GUID, 81, 1),
continent.VehicleEvents ! VehicleServiceMessage( ObjectDetachMessage(obj.GUID, tplayer.GUID, tplayer.Position, obj.Orientation)
continent.id, )
VehicleAction.SendResponse(Service.defaultPlayerGUID, ObjectDetachMessage(obj.GUID, tplayer.GUID, tplayer.Position, obj.Orientation))
) )
} }
else { else {
@ -223,22 +226,10 @@ class SessionMountHandlers(
sessionLogic.vehicles.ServerVehicleOverrideStop(v) sessionLogic.vehicles.ServerVehicleOverrideStop(v)
}*/ }*/
v.Velocity = Vector3.Zero v.Velocity = Vector3.Zero
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! CachedEnvelope(
continent.id, continent.id,
VehicleAction.VehicleState( tplayer.GUID,
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)
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 _ => () case _ => ()
} }
@ -260,9 +251,10 @@ class SessionMountHandlers(
BailType.Normal BailType.Normal
} }
sendResponse(DismountVehicleMsg(playerGuid, bailType, wasKickedByDriver = false)) sendResponse(DismountVehicleMsg(playerGuid, bailType, wasKickedByDriver = false))
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, 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.OutfitEventAction.{Initial, Leaving, OutfitInfo, OutfitRankNames, Unk1, Update, UpdateMemberCount}
import net.psforever.packet.game.OutfitMembershipResponse.PacketType.CreateResponse import net.psforever.packet.game.OutfitMembershipResponse.PacketType.CreateResponse
import net.psforever.packet.game._ 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.services.chat.OutfitChannel
import net.psforever.types.ChatMessageType import net.psforever.types.ChatMessageType
import net.psforever.util.Config import net.psforever.util.Config
@ -48,58 +50,62 @@ object SessionOutfitHandlers {
import scala.concurrent.Future import scala.concurrent.Future
def HandleOutfitForm(outfitName: String, player: Player, session: SessionData): Unit = { 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) val cleanedName = sanitizeOutfitName(outfitName)
cleanedName match { cleanedName match {
case Some(validName) => case Some(validName) =>
ctx.run(findOutfitByName(validName)).flatMap { ctx.run(findOutfitByName(validName)).flatMap {
case existing if existing.nonEmpty => case existing if existing.nonEmpty =>
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(zone, pname,
ChatMsg(ChatMessageType.UNK_227, "@OutfitErrorNameAlreadyTaken")) ChatMsg(ChatMessageType.UNK_227, "@OutfitErrorNameAlreadyTaken")
)
Future.successful(()) Future.successful(())
case _ => case _ =>
createNewOutfit(validName, player.Faction.id, player.CharId).map { outfit => createNewOutfit(validName, player.Faction.id, charid).map { outfit =>
val seconds: Long = val outfitId = outfit.id
outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000 val outfitName = outfit.name
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(player.Zone, player.Name, player.outfit_id = outfitId
OutfitEvent(outfit.id, Update( player.outfit_name = outfitName
OutfitInfo( zone.AvatarEvents ! BundledEnvelope(
outfit.name, 0, 0, 1, MessageEnvelope(pname, SendResponse(
OutfitRankNames("", "", "", "", "", "", "", ""), OutfitEvent(outfitId, Update(
"", OutfitInfo(
14, unk11 = true, 0, seconds, 0, 0, 0)))) outfitName, 0, 0, 1,
OutfitRankNames("", "", "", "", "", "", "", ""),
PlayerControl.sendResponse(player.Zone, player.Name, "",
OutfitMemberUpdate(outfit.id, player.CharId, 7, flag = true)) 14, unk11 = true, 0, seconds, 0, 0, 0)
)),
PlayerControl.sendResponse(player.Zone, player.Name, OutfitMemberUpdate(outfitId, charid, 7, flag = true),
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateSuccess")) ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateSuccess"),
OutfitMembershipResponse(CreateResponse, 0, 0, charid, 0, "", "", flag = true),
PlayerControl.sendResponse(player.Zone, player.Name, )),
OutfitMembershipResponse(CreateResponse, 0, 0, player.CharId, 0, "", "", flag = true)) MessageEnvelope(
zoneid,
player.outfit_id = outfit.id PlanetsideAttribute(player.GUID, 39, outfitId)
player.outfit_name = outfit.name ),
MessageEnvelope(
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.id, zoneid,
AvatarAction.PlanetsideAttributeToAll(player.GUID, 39, outfit.id)) player.GUID,
AvatarAction.PlanetsideStringAttribute(0, outfitName)
player.Zone.AvatarEvents ! AvatarServiceMessage(player.Zone.id, )
AvatarAction.PlanetsideStringAttribute(player.GUID, 0, outfit.name)) )
session.chat.JoinChannel(OutfitChannel(outfitId))
session.chat.JoinChannel(OutfitChannel(player.outfit_id))
} }
.recover { case e => .recover { case e =>
e.printStackTrace() e.printStackTrace()
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(zone, pname,
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure")) ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure")
)
} }
} }
case None => case None =>
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(zone, pname, ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
ChatMsg(ChatMessageType.UNK_227, "@OutfitCreateFailure"))
} }
} }
@ -120,69 +126,80 @@ object SessionOutfitHandlers {
} }
def HandleOutfitInviteAccept(invited: Player, session: SessionData): Unit = { 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) => case Some(outfitInvite) =>
val fromName = outfitInvite.sentFrom.Name
val fromCharId = outfitInvite.sentFrom.CharId
val fromZone = outfitInvite.sentFrom.Zone
val outfitId = outfitInvite.sentFrom.outfit_id val outfitId = outfitInvite.sentFrom.outfit_id
(for { (for {
_ <- addMemberToOutfit(outfitId, invited.CharId) _ <- addMemberToOutfit(outfitId, toCharId)
outfitOpt <- ctx.run(getOutfitById(outfitId)).map(_.headOption) outfitOpt <- ctx.run(getOutfitById(outfitId)).map(_.headOption)
memberCount <- ctx.run(getOutfitMemberCount(outfitId)) memberCount <- ctx.run(getOutfitMemberCount(outfitId))
points <- ctx.run(getOutfitPoints(outfitId)).map(_.headOption.map(_.points).getOrElse(0L)) points <- ctx.run(getOutfitPoints(outfitId)).map(_.headOption.map(_.points).getOrElse(0L))
} yield (outfitOpt, memberCount, points)) } yield (outfitOpt, memberCount, points))
.map { .map {
case (Some(outfit), memberCount, points) => case (Some(outfit), memberCount, points) =>
val outfitName = outfit.name
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 seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
PlayerControl.sendResponse(invited.Zone, invited.Name, fromZone.AvatarEvents ! BundledEnvelope(
OutfitEvent(outfitId, Initial(OutfitInfo( MessageEnvelope(fromName, SendResponse(
outfit.name, points, points, memberCount, OutfitMembershipResponse(
OutfitRankNames("", "", "", "", "", "", "", ""), OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
outfit.motd.getOrElse(""), toCharId, fromCharId, toName, outfitName, flag = false
14, unk11 = true, 0, seconds, 0, 0, 0)))) ),
OutfitEvent(outfitId, UpdateMemberCount(memberCount)),
PlayerControl.sendResponse(invited.Zone, invited.Name, OutfitMemberEvent(outfitId, toCharId,
OutfitMemberUpdate(outfit.id, invited.CharId, 0, flag=true)) OutfitMemberEventAction.Update(toName, 0, 0, 0,
OutfitMemberEventAction.PacketType.Padding, 0
OutfitInviteManager.removeOutfitInvite(invited.CharId) )
)
session.chat.JoinChannel(OutfitChannel(outfit.id)) ))
invited.outfit_id = outfit.id )
invited.outfit_name = outfit.name toZone.AvatarEvents ! BundledEnvelope(
MessageEnvelope(toName, SendResponse(
invited.Zone.AvatarEvents ! AvatarServiceMessage(invited.Zone.id, OutfitMembershipResponse(
AvatarAction.PlanetsideAttributeToAll(invited.GUID, 39, outfit.id)) OutfitMembershipResponse.PacketType.InviteAccepted, 0, 0,
toCharId, fromCharId, toName, outfitName, flag = true
invited.Zone.AvatarEvents ! AvatarServiceMessage(invited.Zone.id, ),
AvatarAction.PlanetsideStringAttribute(invited.GUID, 0, outfit.name)) OutfitEvent(outfitId, Initial(OutfitInfo(
case (None, _, _) => outfitName, points, points, memberCount,
OutfitRankNames("", "", "", "", "", "", "", ""),
PlayerControl.sendResponse(invited.Zone, invited.Name, outfit.motd.getOrElse(""),
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")) 14, unk11 = true, 0, seconds, 0, 0, 0
} ))),
.recover { case _ => OutfitMemberUpdate(outfitId, toCharId, 0, flag=true)
PlayerControl.sendResponse(invited.Zone, invited.Name, )),
ChatMsg(ChatMessageType.UNK_227, "Failed to join outfit")) 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 = { 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 same id, player has left the outfit by their own choice
if (kickedId == kickedBy.CharId) { if (kickedId == kickedBy.CharId) {
// store outfit_id since it will be nulled soon // store outfit_id since it will be nulled soon
val outfit_id = kickedBy.outfit_id
removeMemberFromOutfit(outfit_id, kickedId).map { removeMemberFromOutfit(outfit_id, kickedId).map {
case (deleted, _) => case (deleted, _) =>
if (deleted > 0) { if (deleted > 0) {
kickedBy.Zone.AvatarEvents ! BundledEnvelope(
PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, MessageEnvelope(kickedBy.Name, SendResponse(OutfitEvent(outfit_id, Leaving()))),
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)) session.chat.LeaveChannel(OutfitChannel(outfit_id))
kickedBy.outfit_name = "" kickedBy.outfit_name = ""
kickedBy.outfit_id = 0 kickedBy.outfit_id = 0
zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers) zones
.filter(p => p.outfit_id == outfit_id).foreach(outfitMember => .filter(z => z.AllPlayers.nonEmpty)
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name, .flatMap(_.AllPlayers)
OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked())) .filter(p => p.outfit_id == outfit_id)
) .foreach(outfitMember =>
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name,
kickedBy.Zone.AvatarEvents ! AvatarServiceMessage(kickedBy.Zone.id, OutfitMemberEvent(outfit_id, kickedId, OutfitMemberEventAction.Kicked())
AvatarAction.PlanetsideAttributeToAll(kickedBy.GUID, 39, 0)) )
)
kickedBy.Zone.AvatarEvents ! AvatarServiceMessage(kickedBy.Zone.id,
AvatarAction.PlanetsideStringAttribute(kickedBy.GUID, 0, ""))
} }
}.recover { case e => }.recover { case e =>
e.printStackTrace() e.printStackTrace()
} }
} }
else { else {
removeMemberFromOutfit(kickedBy.outfit_id, kickedId).map { removeMemberFromOutfit(outfit_id, kickedId).map {
case (deleted, _) => case (deleted, _) =>
if (deleted > 0) { if (deleted > 0) {
findPlayerByIdForOutfitAction(zones, kickedId, kickedBy).foreach { kicked => findPlayerByIdForOutfitAction(zones, kickedId, kickedBy).foreach { kicked =>
kicked.Zone.AvatarEvents ! BundledEnvelope(
PlayerControl.sendResponse(kicked.Zone, kicked.Name, MessageEnvelope(kicked.Name, SendResponse(
OutfitEvent(kickedBy.outfit_id, Leaving()) 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_id = 0
kicked.outfit_name = "" kicked.outfit_name = ""
PlayerControl.sendResponse(kicked.Zone, kicked.Name,
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked()))
} }
val avatarName: Future[Option[String]] = val avatarName: Future[Option[String]] =
ctx.run( ctx.run(quote { query[Avatar].filter(_.id == lift(kickedId)).map(_.name) }).map(_.headOption)
quote { query[Avatar].filter(_.id == lift(kickedId)).map(_.name) }
).map(_.headOption)
avatarName.foreach { avatarName.foreach {
case Some(name) => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, case Some(name) => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
@ -280,10 +301,14 @@ object SessionOutfitHandlers {
case None => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name, case None => PlayerControl.sendResponse(kickedBy.Zone, kickedBy.Name,
OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouKicked, 0, 1, kickedBy.CharId, kickedId, "NameNotFound", "", flag = true)) OutfitMembershipResponse(OutfitMembershipResponse.PacketType.YouKicked, 0, 1, kickedBy.CharId, kickedId, "NameNotFound", "", flag = true))
} }
zones.filter(z => z.AllPlayers.nonEmpty).flatMap(_.AllPlayers) zones
.filter(p => p.outfit_id == kickedBy.outfit_id).foreach(outfitMember => .filter(z => z.AllPlayers.nonEmpty)
PlayerControl.sendResponse(outfitMember.Zone, outfitMember.Name, .flatMap(_.AllPlayers)
OutfitMemberEvent(kickedBy.outfit_id, kickedId, OutfitMemberEventAction.Kicked())) .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 // this needs to be the kicked player
// session.chat.LeaveChannel(OutfitChannel(kickedBy.outfit_id)) // 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 = { def HandleOutfitPromote(zones: Seq[Zone], promotedId: Long, newRank: Int, promoter: Player): Unit = {
val outfit_id = promoter.outfit_id val outfit_id = promoter.outfit_id
findPlayerByIdForOutfitAction(zones, promotedId, promoter).foreach { promoted => findPlayerByIdForOutfitAction(zones, promotedId, promoter).foreach { promoted =>
if (newRank == 7) { if (newRank == 7) {
// demote owner to rank 6 // demote owner to rank 6
// promote promoted to rank 7 // promote promoted to rank 7
// update outfit // update outfit
updateOutfitOwner(outfit_id, promoter.avatar.id, promoted.avatar.id) updateOutfitOwner(outfit_id, promoter.avatar.id, promoted.avatar.id)
// TODO: does every member get the notification like this? // TODO: does every member get the notification like this?
getOutfitMemberPoints(outfit_id, promoter.avatar.id).map { getOutfitMemberPoints(outfit_id, promoter.avatar.id).map {
owner_points => owner_points =>
@ -324,7 +344,6 @@ object SessionOutfitHandlers {
}) })
}) })
} }
// update promoter rank // update promoter rank
PlayerControl.sendResponse( PlayerControl.sendResponse(
promoter.Zone, promoter.Name, promoter.Zone, promoter.Name,
@ -338,17 +357,19 @@ object SessionOutfitHandlers {
// TODO: does every member get the notification like this? // TODO: does every member get the notification like this?
getOutfitMemberPoints(outfit_id, promoted.avatar.id).map { getOutfitMemberPoints(outfit_id, promoted.avatar.id).map {
member_points => member_points =>
// tell everyone about the new rank of the promoted member zones.foreach { zone =>
zones.foreach(zone => { // tell everyone about the new rank of the promoted member
zone.AllPlayers val messages = zone.AllPlayers
.filter(_.outfit_id == outfit_id) .filter(_.outfit_id == outfit_id)
.foreach(player => { .map { player =>
PlayerControl.sendResponse( MessageEnvelope(player.Name, SendResponse(
zone, player.Name,
OutfitMemberEvent(outfit_id, promoted.avatar.id, 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 // update promoted rank
@ -364,7 +385,6 @@ object SessionOutfitHandlers {
memberCount <- ctx.run(query[Outfitmember].filter(_.outfit_id == lift(outfitId)).size) memberCount <- ctx.run(query[Outfitmember].filter(_.outfit_id == lift(outfitId)).size)
pointsTotal <- ctx.run(querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(outfitId))) pointsTotal <- ctx.run(querySchema[OutfitpointMv]("outfitpoint_mv").filter(_.outfit_id == lift(outfitId)))
} yield (outfitOpt, memberCount, pointsTotal.headOption.map(_.points).getOrElse(0L)) } yield (outfitOpt, memberCount, pointsTotal.headOption.map(_.points).getOrElse(0L))
val membersF = ctx.run(getOutfitMembersWithDetails(outfitId)) val membersF = ctx.run(getOutfitMembersWithDetails(outfitId))
for { for {
@ -373,43 +393,42 @@ object SessionOutfitHandlers {
} yield { } yield {
outfitOpt.foreach { outfit => outfitOpt.foreach { outfit =>
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
val outfitEventInitial = OutfitEvent(outfit.id, Initial(OutfitInfo(
PlayerControl.sendResponse(player.Zone, player.Name, outfit.name,
OutfitEvent(outfit.id, Initial(OutfitInfo( totalPoints,
outfit.name, totalPoints,
totalPoints, memberCount,
totalPoints, OutfitRankNames(
memberCount, outfit.rank0.getOrElse(""),
OutfitRankNames( outfit.rank1.getOrElse(""),
outfit.rank0.getOrElse(""), outfit.rank2.getOrElse(""),
outfit.rank1.getOrElse(""), outfit.rank3.getOrElse(""),
outfit.rank2.getOrElse(""), outfit.rank4.getOrElse(""),
outfit.rank3.getOrElse(""), outfit.rank5.getOrElse(""),
outfit.rank4.getOrElse(""), outfit.rank6.getOrElse(""),
outfit.rank5.getOrElse(""), outfit.rank7.getOrElse(""),
outfit.rank6.getOrElse(""), ),
outfit.rank7.getOrElse(""), outfit.motd.getOrElse(""),
), 14, unk11 = true, 0, seconds, 0, 0, 0))
outfit.motd.getOrElse(""), )
14, unk11 = true, 0, seconds, 0, 0, 0)))) val memberEventList = members.map { case (avatarId, avatarName, points, rank, login) =>
members.foreach { case (avatarId, avatarName, points, rank, login) =>
val lastLogin = findPlayerByIdForOutfitAction(zones, avatarId, player) match { val lastLogin = findPlayerByIdForOutfitAction(zones, avatarId, player) match {
case Some(_) => 0L case Some(_) => 0L
case None if player.Name == avatarName => 0L case None if player.Name == avatarName => 0L
case None => (System.currentTimeMillis() - login.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli) / 1000 case None => (System.currentTimeMillis() - login.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli) / 1000
} }
PlayerControl.sendResponse(player.Zone, player.Name, OutfitMemberEvent(outfit.id, avatarId,
OutfitMemberEvent(outfit.id, avatarId, OutfitMemberEventAction.Update(
OutfitMemberEventAction.Update( avatarName,
avatarName, rank,
rank, points,
points, lastLogin,
lastLogin, OutfitMemberEventAction.PacketType.Padding, 0)
OutfitMemberEventAction.PacketType.Padding, 0))) )
} }
PlayerControl.sendResponse(player.Zone, player.Name, player.Zone.AvatarEvents ! MessageEnvelope(player.Name, SendResponse(
OutfitEvent(outfit.id, Unk1())) outfitEventInitial +: memberEventList :+ OutfitEvent(outfit.id, Unk1())
))
} }
} }
} }
@ -420,16 +439,13 @@ object SessionOutfitHandlers {
futureResult.onComplete { futureResult.onComplete {
case Success(rows) => case Success(rows) =>
rows.foreach { case (outfitId, points, name, leaderName, memberCount) => player.Zone.AvatarEvents ! MessageEnvelope(player.Name, SendResponse(
PlayerControl.sendResponse(player.Zone, player.Name, rows.map { case (outfitId, points, name, leaderName, memberCount) =>
OutfitListEvent( OutfitListEvent(
OutfitListEventAction.ListElementOutfit( OutfitListEventAction.ListElementOutfit(outfitId, points, memberCount, name, leaderName)
outfitId, )
points, }
memberCount, ))
name,
leaderName)))
}
case Failure(_) => case Failure(_) =>
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(player.Zone, player.Name,
@ -439,9 +455,7 @@ object SessionOutfitHandlers {
} }
def HandleOutfitMotd(zones: Seq[Zone], message: String, player: Player): Unit = { def HandleOutfitMotd(zones: Seq[Zone], message: String, player: Player): Unit = {
val outfit_id = player.outfit_id val outfit_id = player.outfit_id
val outfitDetails = for { val outfitDetails = for {
_ <- updateOutfitMotd(outfit_id, message) _ <- updateOutfitMotd(outfit_id, message)
outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption) outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption)
@ -453,9 +467,8 @@ object SessionOutfitHandlers {
(outfitOpt, memberCount, totalPoints) <- outfitDetails (outfitOpt, memberCount, totalPoints) <- outfitDetails
} yield { } yield {
outfitOpt.foreach { outfit => outfitOpt.foreach { outfit =>
// send to all online players in outfit // send to all online players in outfit
val outfit_event = OutfitEvent( val outfit_event = SendResponse(OutfitEvent(
outfit_id, outfit_id,
Update( Update(
OutfitInfo( OutfitInfo(
@ -483,19 +496,15 @@ object SessionOutfitHandlers {
unk25 = 0 unk25 = 0
) )
) )
) ))
zones.foreach(zone => { zones.foreach { zone =>
zone.AllPlayers zone.AvatarEvents ! BundledEnvelope(
.filter(_.outfit_id == outfit_id) zone.AllPlayers
.filter(_.outfit_window_open) .filter { p => p.outfit_id == outfit_id && p.outfit_window_open }
.foreach(player => { .map(p => MessageEnvelope(p.Name, outfit_event))
PlayerControl.sendResponse( )
zone, player.Name, }
outfit_event
)
})
})
} }
} }
@ -504,9 +513,7 @@ object SessionOutfitHandlers {
} }
def HandleOutfitRank(zones: Seq[Zone], list: List[Option[String]], player: Player): Unit = { def HandleOutfitRank(zones: Seq[Zone], list: List[Option[String]], player: Player): Unit = {
val outfit_id = player.outfit_id val outfit_id = player.outfit_id
val outfitDetails = for { val outfitDetails = for {
_ <- updateOutfitRanks(outfit_id, list) _ <- updateOutfitRanks(outfit_id, list)
outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption) outfitOpt <- ctx.run(getOutfitById(outfit_id)).map(_.headOption)
@ -518,9 +525,8 @@ object SessionOutfitHandlers {
(outfitOpt, memberCount, totalPoints) <- outfitDetails (outfitOpt, memberCount, totalPoints) <- outfitDetails
} yield { } yield {
outfitOpt.foreach { outfit => outfitOpt.foreach { outfit =>
// send to all online players in outfit with window open // send to all online players in outfit with window open
val outfit_event = OutfitEvent( val outfit_event = SendResponse(OutfitEvent(
outfit_id, outfit_id,
Update( Update(
OutfitInfo( OutfitInfo(
@ -548,19 +554,15 @@ object SessionOutfitHandlers {
unk25 = 0 unk25 = 0
) )
) )
) ))
zones.foreach(zone => { zones.foreach { zone =>
zone.AllPlayers zone.AvatarEvents ! BundledEnvelope(
.filter(_.outfit_id == outfit_id) zone.AllPlayers
.filter(_.outfit_window_open) .filter { p => p.outfit_id == outfit_id && p.outfit_window_open }
.foreach(player => { .map(p => MessageEnvelope(p.Name, outfit_event))
PlayerControl.sendResponse( )
zone, player.Name, }
outfit_event
)
})
})
} }
} }
} }
@ -596,29 +598,34 @@ object SessionOutfitHandlers {
.map { .map {
case (Some(outfit), memberCount, points) => case (Some(outfit), memberCount, points) =>
val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000 val seconds: Long = outfit.created.atZone(ZoneId.systemDefault()).toInstant.toEpochMilli / 1000
player.Zone.AvatarEvents ! BundledEnvelope(
PlayerControl.sendResponse(player.Zone, player.Name, MessageEnvelope(player.Name, SendResponse(
OutfitEvent(outfitId, Update(OutfitInfo( OutfitEvent(outfitId, Update(OutfitInfo(
outfit.name, points, points, memberCount, outfit.name, points, points, memberCount,
OutfitRankNames(outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""), OutfitRankNames(
outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""), outfit.rank0.getOrElse(""), outfit.rank1.getOrElse(""), outfit.rank2.getOrElse(""),
outfit.rank6.getOrElse(""), outfit.rank7.getOrElse("")), outfit.rank3.getOrElse(""), outfit.rank4.getOrElse(""), outfit.rank5.getOrElse(""),
outfit.motd.getOrElse(""), outfit.rank6.getOrElse(""), outfit.rank7.getOrElse("")
14, unk11 = true, 0, seconds, 0, 0, 0)))) ),
outfit.motd.getOrElse(""),
PlayerControl.sendResponse(player.Zone, player.Name, 14, unk11 = true, 0, seconds, 0, 0, 0
OutfitMemberUpdate(outfit.id, player.CharId, membership.rank, flag = true)) ))),
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)) session.chat.JoinChannel(OutfitChannel(outfit.id))
player.outfit_id = outfit.id player.outfit_id = outfit.id
player.outfit_name = outfit.name 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, _, _) => case (None, _, _) =>
PlayerControl.sendResponse(player.Zone, player.Name, PlayerControl.sendResponse(player.Zone, player.Name,
ChatMsg(ChatMessageType.UNK_227, "Failed to load outfit")) ChatMsg(ChatMessageType.UNK_227, "Failed to load outfit"))
@ -849,7 +856,7 @@ object SessionOutfitHandlers {
query[Outfit] query[Outfit]
.filter(_.id == lift(outfit_id)) .filter(_.id == lift(outfit_id))
.update( .update(
_.rank0 -> lift(colorized(0)), _.rank0 -> lift(colorized.head),
_.rank1 -> lift(colorized(1)), _.rank1 -> lift(colorized(1)),
_.rank2 -> lift(colorized(2)), _.rank2 -> lift(colorized(2)),
_.rank3 -> lift(colorized(3)), _.rank3 -> lift(colorized(3)),

View file

@ -2,6 +2,8 @@
package net.psforever.actors.session.support package net.psforever.actors.session.support
import akka.actor.{ActorContext, ActorRef, typed} 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 net.psforever.services.teamwork.SquadServiceResponse
import scala.collection.mutable import scala.collection.mutable
@ -10,7 +12,6 @@ import net.psforever.actors.session.AvatarActor
import net.psforever.objects.teamwork.Squad import net.psforever.objects.teamwork.Squad
import net.psforever.objects.{Default, Player} import net.psforever.objects.{Default, Player}
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.teamwork.{SquadResponse, SquadServiceMessage, SquadAction => SquadServiceAction} import net.psforever.services.teamwork.{SquadResponse, SquadServiceMessage, SquadAction => SquadServiceAction}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3} import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
@ -105,9 +106,10 @@ class SessionSquadHandlers(
squadUI.get(player.CharId) match { squadUI.get(player.CharId) match {
case Some(elem) => case Some(elem) =>
sendResponse(PlanetsideAttributeMessage(player.GUID, 31, squad_supplement_id)) sendResponse(PlanetsideAttributeMessage(player.GUID, 31, squad_supplement_id))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
s"${player.Faction}", 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)) sendResponse(PlanetsideAttributeMessage(player.GUID, 32, elem.index))
case _ => case _ =>
@ -286,7 +288,7 @@ class SessionSquadHandlers(
* @param value value to associate the player * @param value value to associate the player
*/ */
def GiveSquadColorsForOthers(guid: PlanetSideGUID, factionChannel: String, value: Long): Unit = { 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.actors.session.AvatarActor
import net.psforever.objects.Vehicle import net.psforever.objects.Vehicle
import net.psforever.packet.game.ChatMsg import net.psforever.packet.game.ChatMsg
import net.psforever.services.vehicle.VehicleResponse
import net.psforever.types.{ChatMessageType, DriveState, PlanetSideGUID} import net.psforever.types.{ChatMessageType, DriveState, PlanetSideGUID}
trait VehicleHandlerFunctions extends CommonSessionInterfacingFunctionality { trait VehicleHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
def ops: SessionVehicleHandlers def ops: SessionVehicleHandlers
def handle(toChannel: String, guid: PlanetSideGUID, reply: VehicleResponse.Response): Unit
} }
class SessionVehicleHandlers( 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.vital.projectile.ProjectileReason
import net.psforever.objects.zones.exp.ToDatabase import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.packet.game.UplinkRequest 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.types.{ChatMessageType, PlanetSideEmpire, ValidPlanetSideGUID, Vector3}
import net.psforever.util.Config 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.serverobject.turret.FacilityTurret
import net.psforever.objects._ import net.psforever.objects._
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.AvatarAction
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{ExoSuitType, PlanetSideGUID} import net.psforever.types.{ExoSuitType, PlanetSideGUID}
trait WeaponAndProjectileFunctions extends CommonSessionInterfacingFunctionality { trait WeaponAndProjectileFunctions extends CommonSessionInterfacingFunctionality {
@ -281,14 +283,12 @@ class WeaponAndProjectileOperations(
.orElse { continent.GUID(weapon_guid) } .orElse { continent.GUID(weapon_guid) }
.collect { .collect {
case _: Equipment if containerOpt.exists(_.isInstanceOf[Player]) => case _: Equipment if containerOpt.exists(_.isInstanceOf[Player]) =>
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(continent.id, player.GUID, WeaponDryFire(weapon_guid))
continent.id,
AvatarAction.WeaponDryFire(player.GUID, weapon_guid)
)
case _: Equipment => case _: Equipment =>
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.WeaponDryFire(player.GUID, weapon_guid) player.GUID,
WeaponDryFire(weapon_guid)
) )
} }
.orElse { .orElse {
@ -348,14 +348,21 @@ class WeaponAndProjectileOperations(
sendResponse(UplinkResponse(code.value, 0)) sendResponse(UplinkResponse(code.value, 0))
sendResponse(PlanetsideAttributeMessage(player.GUID, 59, 1200000)) sendResponse(PlanetsideAttributeMessage(player.GUID, 59, 1200000))
avatarActor ! AvatarActor.UpdateCUDTime("emp_blast") avatarActor ! AvatarActor.UpdateCUDTime("emp_blast")
player.Zone.LocalEvents ! LocalServiceMessage(s"${player.Zone.id}", player.Zone.LocalEvents ! MessageEnvelope(
LocalAction.SendPacket(TriggerEffectMessage(ValidPlanetSideGUID(0), empColor, None, Some(TriggeredEffectLocation(player.Position, Vector3(0, 0, 90)))))) 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) { context.system.scheduler.scheduleOnce(delay = 1 seconds) {
Zone.serverSideDamage(player.Zone, player, empSize, SpecialEmp.createEmpInteraction(empSize, player.Position), Zone.serverSideDamage(player.Zone, player, empSize, SpecialEmp.createEmpInteraction(empSize, player.Position),
ExplosiveDeployableControl.detectionForExplosiveSource(player), Zone.findAllTargets) ExplosiveDeployableControl.detectionForExplosiveSource(player), Zone.findAllTargets)
} }
case UplinkRequestType.OrbitalStrike => 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)) sendResponse(UplinkResponse(code.value, 0))
orbitalStrikePos = pos orbitalStrikePos = pos
case UplinkRequestType.Unknown5 => case UplinkRequestType.Unknown5 =>
@ -380,9 +387,16 @@ class WeaponAndProjectileOperations(
sendResponse(PlanetsideAttributeMessage(player.GUID, 60, 10800000)) sendResponse(PlanetsideAttributeMessage(player.GUID, 60, 10800000))
avatarActor ! AvatarActor.UpdateCUDTime("orbital_strike") avatarActor ! AvatarActor.UpdateCUDTime("orbital_strike")
context.system.scheduler.scheduleOnce(delay = 5 seconds) { context.system.scheduler.scheduleOnce(delay = 5 seconds) {
player.Zone.LocalEvents ! LocalServiceMessage(s"${player.Zone.id}", player.Zone.LocalEvents ! MessageEnvelope(
LocalAction.SendPacket(TriggerEffectMessage(ValidPlanetSideGUID(0), strikeType, None, Some(TriggeredEffectLocation(orbitalStrikePos.get, Vector3(0, 0, 90)))))) s"${player.Zone.id}",
player.Zone.LocalEvents ! LocalServiceMessage(s"$playerFaction", LocalAction.SendPacket(OrbitalStrikeWaypointMessage(player.GUID, None))) 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) { context.system.scheduler.scheduleOnce(delay = 5 seconds) {
val sectorTargets = Zone.findOrbitalStrikeTargets(player.Zone, orbitalStrikePos.get, osSize.DamageRadius, Zone.getOrbitbalStrikeTargets) 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) } 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") log.info(s"${player.Name} changed ${player.Sex.possessive} ${obj.Definition.Name}'s fire mode to #$modeIndex")
} }
sendResponse(ChangeFireModeMessage(item_guid, modeIndex)) sendResponse(ChangeFireModeMessage(item_guid, modeIndex))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
sessionLogic.zoning.zoneChannel, sessionLogic.zoning.zoneChannel,
AvatarAction.ChangeFireMode(player.GUID, item_guid, modeIndex) player.GUID,
AvatarAction.ChangeFireMode(item_guid, modeIndex)
) )
} }
case Some(_) => case Some(_) =>
@ -478,10 +493,10 @@ class WeaponAndProjectileOperations(
projectile.Position = shot_pos projectile.Position = shot_pos
projectile.Orientation = shot_orient projectile.Orientation = shot_orient
projectile.Velocity = shot_vel projectile.Velocity = shot_vel
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! CachedEnvelope(
continent.id, continent.id,
player.GUID,
AvatarAction.ProjectileState( AvatarAction.ProjectileState(
player.GUID,
projectileGlobalUID, projectileGlobalUID,
shot_pos, shot_pos,
shot_vel, shot_vel,
@ -742,12 +757,9 @@ class WeaponAndProjectileOperations(
(target.GUID, (target, proxyCopy, proxyCopy.shot_origin, target.Position)) (target.GUID, (target, proxyCopy, proxyCopy.shot_origin, target.Position))
}.unzip }.unzip
//chain lash effect //chain lash effect
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.SendResponse( SendResponse(ChainLashMessage(hitPos, projectile.profile.ObjectId, guidRefs.toList))
PlanetSideGUID(0),
ChainLashMessage(hitPos, projectile.profile.ObjectId, guidRefs.toList)
)
) )
//chain lash target output //chain lash target output
outputRefs.toList outputRefs.toList
@ -931,12 +943,9 @@ class WeaponAndProjectileOperations(
tool.Magazine = 0 tool.Magazine = 0
sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, weapon_guid, 0)) sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, weapon_guid, 0))
sendResponse(ChangeFireStateMessage_Stop(weapon_guid)) sendResponse(ChangeFireStateMessage_Stop(weapon_guid))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(continent.id, player.GUID, ChangeFireState_Stop(weapon_guid))
continent.id,
AvatarAction.ChangeFireState_Stop(player.GUID, weapon_guid)
)
sendResponse(WeaponDryFireMessage(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") } .map { sessionLogic.validObject(_, decorator="FindDetectedProjectileTargets") }
.flatMap { .flatMap {
case Some(obj: Vehicle) if !obj.Cloaked => 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) } obj.Seats.values.flatMap { seat => seat.occupants.map(_.Name) }
case Some(obj: Mountable) => case Some(obj: Mountable) =>
obj.Seats.values.flatMap { seat => seat.occupants.map(_.Name) } obj.Seats.values.flatMap { seat => seat.occupants.map(_.Name) }
@ -1077,9 +1086,10 @@ class WeaponAndProjectileOperations(
} }
def fireStateStartPlayerMessages(itemGuid: PlanetSideGUID): Unit = { def fireStateStartPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
sessionLogic.zoning.zoneChannel, 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 => case turret: FacilityTurret if continent.map.cavern =>
turret.Actor ! VanuSentry.ChangeFireStart turret.Actor ! VanuSentry.ChangeFireStart
} }
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.ChangeFireState_Start(player.GUID, itemGuid) player.GUID,
ChangeFireState_Start(itemGuid)
) )
} }
@ -1116,9 +1127,10 @@ class WeaponAndProjectileOperations(
} }
def fireStateStopPlayerMessages(itemGuid: PlanetSideGUID): Unit = { def fireStateStopPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
sessionLogic.zoning.zoneChannel, 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 => case turret: FacilityTurret if continent.map.cavern =>
turret.Actor ! VanuSentry.ChangeFireStop turret.Actor ! VanuSentry.ChangeFireStop
} }
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.ChangeFireState_Stop(player.GUID, itemGuid) player.GUID,
ChangeFireState_Stop(itemGuid)
) )
} }
@ -1186,16 +1199,14 @@ class WeaponAndProjectileOperations(
used by ReloadMessage handling used by ReloadMessage handling
*/ */
def reloadPlayerMessages(itemGuid: PlanetSideGUID): Unit = { def reloadPlayerMessages(itemGuid: PlanetSideGUID): Unit = {
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(sessionLogic.zoning.zoneChannel, player.GUID, ReloadTool(itemGuid))
sessionLogic.zoning.zoneChannel,
AvatarAction.Reload(player.GUID, itemGuid)
)
} }
def reloadVehicleMessages(itemGuid: PlanetSideGUID): Unit = { def reloadVehicleMessages(itemGuid: PlanetSideGUID): Unit = {
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.Reload(player.GUID, itemGuid) player.GUID,
ReloadTool(itemGuid)
) )
} }
@ -1369,10 +1380,10 @@ class WeaponAndProjectileOperations(
val previous_box_guid = previousBox.GUID val previous_box_guid = previousBox.GUID
val boxDef = box.Definition val boxDef = box.Definition
sendResponse(ChangeAmmoMessage(tool_guid, box.Capacity)) sendResponse(ChangeAmmoMessage(tool_guid, box.Capacity))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
sessionLogic.zoning.zoneChannel, sessionLogic.zoning.zoneChannel,
AvatarAction.ChangeAmmo( player.GUID,
player.GUID, ChangeAmmo(
tool_guid, tool_guid,
ammoSlotIndex, ammoSlotIndex,
previous_box_guid, previous_box_guid,
@ -1470,15 +1481,10 @@ class WeaponAndProjectileOperations(
def modifyAmmunitionInMountable(obj: PlanetSideServerObject with Container)(box: AmmoBox, reloadValue: Int): Unit = { def modifyAmmunitionInMountable(obj: PlanetSideServerObject with Container)(box: AmmoBox, reloadValue: Int): Unit = {
modifyAmmunition(obj)(box, reloadValue) modifyAmmunition(obj)(box, reloadValue)
obj.Find(box).collect { index => obj.Find(box).collect { index =>
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
s"${obj.Actor}", s"${obj.Actor}",
VehicleAction.InventoryState( player.GUID,
player.GUID, VehicleAction.InventoryState(box, obj.GUID, index, box.Definition.Packet.DetailedConstructorData(box).get)
box,
obj.GUID,
index,
box.Definition.Packet.DetailedConstructorData(box).get
)
) )
} }
} }
@ -1582,10 +1588,7 @@ class WeaponAndProjectileOperations(
shootingStop.clear() shootingStop.clear()
(prefire ++ shooting).foreach { guid => (prefire ++ shooting).foreach { guid =>
sendResponse(ChangeFireStateMessage_Stop(guid)) sendResponse(ChangeFireStateMessage_Stop(guid))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(continent.id, player.GUID, ChangeFireState_Stop(guid))
continent.id,
AvatarAction.ChangeFireState_Stop(player.GUID, guid)
)
} }
prefire.clear() prefire.clear()
shooting.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.tube.SpawnTube
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret import net.psforever.objects.serverobject.turret.auto.AutomatedTurret
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource} 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.vital.{InGameHistory, IncarnationActivity, ReconstructionActivity, SpawningActivity}
import net.psforever.objects.zones.blockmap.BlockMapEntity import net.psforever.objects.zones.blockmap.BlockMapEntity
import net.psforever.packet.game.GenericAction.FirstPersonViewWithEffect 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 net.psforever.services.chat.DefaultChannel
import scala.concurrent.duration._ 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.game.objectcreate.ObjectClass
import net.psforever.packet.{PlanetSideGamePacket, game} import net.psforever.packet.{PlanetSideGamePacket, game}
import net.psforever.persistence.Savedplayer import net.psforever.persistence.Savedplayer
import net.psforever.services.RemoverActor
import net.psforever.services.ServiceManager.{Lookup, LookupResult} import net.psforever.services.ServiceManager.{Lookup, LookupResult}
import net.psforever.services.account.{AccountPersistenceService, PlayerToken} import net.psforever.services.account.{AccountPersistenceService, PlayerToken}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.AvatarAction
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage} import net.psforever.services.base.support.RemoverActor
import net.psforever.services.galaxy.GalaxyAction
import net.psforever.services.hart.HartTimer import net.psforever.services.hart.HartTimer
import net.psforever.services.local.support.HackCaptureActor 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.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.services.{CavernRotationService, Service, ServiceManager, InterstellarClusterService => ICS}
import net.psforever.types._ import net.psforever.types._
import net.psforever.util.{Config, DefinitionUtil} import net.psforever.util.{Config, DefinitionUtil}
@ -118,7 +122,7 @@ object ZoningOperations {
additionalChannels: List[String] additionalChannels: List[String]
): Unit = { ): Unit = {
val events = zone.LocalEvents 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 (zone
.blockMap .blockMap
.sector(position, range = 100f) .sector(position, range = 100f)
@ -126,7 +130,7 @@ object ZoningOperations {
.filter(p => Sidedness.equals(side, p.WhichSide)) .filter(p => Sidedness.equals(side, p.WhichSide))
.map(_.Name) ++ additionalChannels) .map(_.Name) ++ additionalChannels)
.foreach { target => .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 */ Vector3.DistanceSquared(t.Position.xy, posxy) < 2500f && /* literal 50m */
heightDiff < 5f && heightDiff > -1f 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 => (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 => (soundTargets.map(_.Name) ++ additionalChannels).foreach { target =>
events ! LocalServiceMessage(target, soundMessage) events ! MessageEnvelope(target, soundMessage)
} }
} }
@ -547,8 +551,8 @@ class ZoningOperations(
sendResponse(OCM.apply(projectile)) sendResponse(OCM.apply(projectile))
} }
//spawn point update request //spawn point update request
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, player.Name,
VehicleAction.UpdateAmsSpawnPoint(continent) VehicleAction.UpdateAmsSpawnPoint(continent)
) )
spawn.upstreamMessageCount = 0 spawn.upstreamMessageCount = 0
@ -595,14 +599,14 @@ class ZoningOperations(
context.self context.self
) )
LivePlayerList.Add(avatar.id, avatar) LivePlayerList.Add(avatar.id, avatar)
galaxyService.tell(GalaxyServiceMessage(GalaxyAction.LogStatusChange(avatar.name)), context.parent) galaxyService.tell(MessageEnvelope("", GalaxyAction.LogStatusChange(avatar.name)), context.parent)
//PropertyOverrideMessage //PropertyOverrideMessage
ServiceManager.serviceManager ! Lookup("propertyOverrideManager") ServiceManager.serviceManager ! Lookup("propertyOverrideManager")
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 112, 0)) // disable festive backpacks
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
spawn.initializeFriendsAndIgnoredLists() spawn.initializeFriendsAndIgnoredLists()
//the following subscriptions last until character switch/logout //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. 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.faction}") //channel will be player.Faction
sessionLogic.squadService ! Service.Join(s"${avatar.id}") //channel will be player.CharId (in order to work with packets) 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) //the only zone-level event system subscription necessary before BeginZoningMessage (for persistence purposes)
zone.AvatarEvents ! Service.Join(player.Name) zone.AvatarEvents ! Service.Join(player.Name)
sessionLogic.persist() sessionLogic.persist()
oldZone.AvatarEvents ! Service.Leave() oldZone.AvatarEvents ! Service.LeaveAll
oldZone.LocalEvents ! Service.Leave() oldZone.LocalEvents ! Service.LeaveAll
oldZone.VehicleEvents ! Service.Leave() oldZone.VehicleEvents ! Service.LeaveAll
if (player.isAlive && zoningType != Zoning.Method.Reset) { if (player.isAlive && zoningType != Zoning.Method.Reset) {
if (player.HasGUID) { if (player.HasGUID) {
@ -649,9 +653,9 @@ class ZoningOperations(
val oldZone = session.zone val oldZone = session.zone
session = session.copy(zone = foundZone) session = session.copy(zone = foundZone)
sessionLogic.persist() sessionLogic.persist()
oldZone.AvatarEvents ! Service.Leave() oldZone.AvatarEvents ! Service.LeaveAll
oldZone.LocalEvents ! Service.Leave() oldZone.LocalEvents ! Service.LeaveAll
oldZone.VehicleEvents ! Service.Leave() oldZone.VehicleEvents ! Service.LeaveAll
//the only zone-level event system subscription necessary before BeginZoningMessage (for persistence purposes) //the only zone-level event system subscription necessary before BeginZoningMessage (for persistence purposes)
foundZone.AvatarEvents ! Service.Join(player.Name) foundZone.AvatarEvents ! Service.Join(player.Name)
foundZone.Population ! Zone.Population.Join(avatar) foundZone.Population ! Zone.Population.Join(avatar)
@ -760,7 +764,7 @@ class ZoningOperations(
case _ => case _ =>
interstellarFerry match { interstellarFerry match {
case None => 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 interstellarFerryTopLevelGUID = None
case Some(_) => () //wait patiently case Some(_) => () //wait patiently
} }
@ -768,7 +772,7 @@ class ZoningOperations(
} }
private def handleTransferPassengerVehicle(vehicle: Vehicle, temporaryChannel: String): Unit = { 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 spawn.deadState = DeadState.Release
sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, player.Faction, unk5=true)) 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 interstellarFerry = Some(vehicle) //on the other continent and registered to that continent's GUID system
@ -851,7 +855,7 @@ class ZoningOperations(
case None => case None =>
spawn.deadState = DeadState.Release // cancel movement updates spawn.deadState = DeadState.Release // cancel movement updates
player.Position = position 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) 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 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 if obj.Destroyed => configAmenityAsDestroyed(obj)
case obj => configAmenityAsWorking(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)) sendResponse(OCM.apply(llu))
// Attach it to a player if it has a carrier // Attach it to a player if it has a carrier
if (llu.Carrier.nonEmpty) { if (llu.Carrier.nonEmpty) {
continent.LocalEvents ! LocalServiceMessage( continent.LocalEvents ! MessageEnvelope(
continent.id, continent.id,
LocalAction.SendPacket(ObjectAttachMessage(llu.Carrier.get.GUID, llu.GUID, 252)) PlanetSideGUID(-1),
SendResponse(ObjectAttachMessage(llu.Carrier.get.GUID, llu.GUID, 252))
) )
} }
case _ => () case _ => ()
@ -1349,9 +1354,10 @@ class ZoningOperations(
val pguid = player.GUID val pguid = player.GUID
val toChannel = manifest.file val toChannel = manifest.file
val topLevel = interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID) val topLevel = interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID)
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
s"${vehicle.Actor}", s"${vehicle.Actor}",
VehicleAction.TransferPassengerChannel(pguid, s"${vehicle.Actor}", toChannel, vehicle, topLevel) pguid,
VehicleAction.TransferPassengerChannel(s"${vehicle.Actor}", toChannel, vehicle, topLevel)
) )
manifest.cargo.foreach { manifest.cargo.foreach {
case ManifestPassengerEntry("MISSING_DRIVER", index) => case ManifestPassengerEntry("MISSING_DRIVER", index) =>
@ -1362,9 +1368,10 @@ class ZoningOperations(
cargo.Actor ! CargoBehavior.StartCargoDismounting(bailed = false) cargo.Actor ! CargoBehavior.StartCargoDismounting(bailed = false)
case entry => case entry =>
val cargo = vehicle.CargoHolds(entry.mount).occupant.get val cargo = vehicle.CargoHolds(entry.mount).occupant.get
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
entry.name, 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 = interstellarFerryTopLevelGUID =
if (manifest.passengers.isEmpty && manifest.cargo.count { !_.name.equals("MISSING_DRIVER") } == 0) { if (manifest.passengers.isEmpty && manifest.cargo.count { !_.name.equals("MISSING_DRIVER") } == 0) {
//do not delete if vehicle has passengers or cargo //do not delete if vehicle has passengers or cargo
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
continent.id, continent.id,
VehicleAction.UnloadVehicle(pguid, vehicle, topLevel) pguid,
VehicleAction.UnloadVehicle(vehicle, topLevel)
) )
None None
} else { } else {
@ -1470,17 +1478,14 @@ class ZoningOperations(
case Some(manifest) => case Some(manifest) =>
val toChannel = manifest.file val toChannel = manifest.file
val topLevel = interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID) val topLevel = interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID)
galaxyService ! GalaxyServiceMessage( galaxyService ! MessageEnvelope(toChannel, GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest))
toChannel,
GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest)
)
vehicle.CargoHolds.values vehicle.CargoHolds.values
.collect { .collect {
case hold if hold.isOccupied => case hold if hold.isOccupied =>
val cargo = hold.occupant.get val cargo = hold.occupant.get
cargo.Continent = toZoneId cargo.Continent = toZoneId
//point to the cargo vehicle to instigate cargo vehicle driver transportation //point to the cargo vehicle to instigate cargo vehicle driver transportation
// galaxyService ! GalaxyServiceMessage( // galaxyService ! MesdsageEnvelope(
// toChannel, // toChannel,
// GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest) // GalaxyAction.TransferPassenger(player_guid, toChannel, vehicle, topLevel, manifest)
// ) // )
@ -1972,7 +1977,7 @@ class ZoningOperations(
guid, guid,
Deployable.Icon(obj.Definition.Item), Deployable.Icon(obj.Definition.Item),
obj.Position, 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") log.info(s"RestoreInfo: player $name is already logged in zone ${inZone.id}; rejoining that character")
sessionLogic.persistFunc = UpdatePersistence(from) sessionLogic.persistFunc = UpdatePersistence(from)
//tell the old WorldSessionActor to kill itself by using its own subscriptions against itself //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() spawn.switchAvatarStatisticsFieldToRefreshAfterRespawn()
//find and reload previous player //find and reload previous player
( (
@ -2594,9 +2599,10 @@ class ZoningOperations(
vehicle.CargoHolds.values vehicle.CargoHolds.values
.collect { case hold if hold.isOccupied => hold.occupant.get } .collect { case hold if hold.isOccupied => hold.occupant.get }
.foreach { _.MountedIn = vguid } .foreach { _.MountedIn = vguid }
events ! VehicleServiceMessage( events ! MessageEnvelope(
zoneid, zoneid,
VehicleAction.LoadVehicle(player.GUID, vehicle, vObjectId, vguid, data) player.GUID,
VehicleAction.LoadVehicle(vehicle, vObjectId, vguid, data)
) )
carrierInfo match { carrierInfo match {
case (Some(carrier), Some((index, _))) => 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 //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 vehicleToDelete = interstellarFerryTopLevelGUID.orElse(originalSeated).getOrElse(PlanetSideGUID(0))
val zone = vehicle.PreviousGatingManifest().get.origin val zone = vehicle.PreviousGatingManifest().get.origin
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, zone.id,
VehicleAction.UnloadVehicle(player.GUID, vehicle, vehicleToDelete) player.GUID,
VehicleAction.UnloadVehicle(vehicle, vehicleToDelete)
) )
log.debug( log.debug(
s"AvatarCreate: cleaning up ghost of transitioning vehicle ${vehicle.Definition.Name}@${vehicleToDelete.guid} in zone ${zone.id}" 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 definition = player.avatar.definition
val guid = player.GUID val guid = player.GUID
sendResponse(OCM.detailed(player)) sendResponse(OCM.detailed(player))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
s"spectator", 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 _ => case _ =>
@ -2649,9 +2657,10 @@ class ZoningOperations(
val guid = player.GUID val guid = player.GUID
usingSpawnTubeAnimation() usingSpawnTubeAnimation()
sendResponse(OCM.detailed(player)) sendResponse(OCM.detailed(player))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
zoneid, 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) continent.Population ! Zone.Population.Spawn(avatar, player, avatarActor)
@ -2721,10 +2730,10 @@ class ZoningOperations(
interimUngunnedVehicle = Some(vguid) interimUngunnedVehicle = Some(vguid)
interimUngunnedVehicleSeat = Some(seat) interimUngunnedVehicleSeat = Some(seat)
} }
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
pguid,
AvatarAction.LoadPlayer( AvatarAction.LoadPlayer(
pguid,
pdef.ObjectId, pdef.ObjectId,
pguid, pguid,
pdef.Packet.ConstructorData(tplayer).get, pdef.Packet.ConstructorData(tplayer).get,
@ -2880,9 +2889,9 @@ class ZoningOperations(
case _ => () case _ => ()
} }
if (player.VisibleSlots.contains(index)) { if (player.VisibleSlots.contains(index)) {
events ! AvatarServiceMessage( events ! MessageEnvelope(
zoneId, zoneId,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, obj.GUID) ObjectDelete(obj.GUID)
) )
} else { } else {
sendResponse(ObjectDeleteMessage(obj.GUID, 0)) 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). * To the game, that is a backpack (or some pastry, festive graphical modification allowing).
* @see `AvatarAction.ObjectDelete` * @see `AvatarAction.ObjectDelete`
* @see `AvatarAction.Release` * @see `AvatarAction.Release`
* @see `AvatarServiceMessage`
* @see `FriskDeadBody` * @see `FriskDeadBody`
* @see `GUIDTask.unregisterPlayer` * @see `GUIDTask.unregisterPlayer`
* @see `ObjectDeleteMessage` * @see `ObjectDeleteMessage`
@ -2916,7 +2924,7 @@ class ZoningOperations(
val pguid = tplayer.GUID val pguid = tplayer.GUID
zone.Population ! Zone.Population.Release(avatar) zone.Population ! Zone.Population.Release(avatar)
sendResponse(ObjectDeleteMessage(pguid, 0)) 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)) 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). * 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. * A player who has been kicked may not turn into a corpse.
* @see `AvatarAction.Release` * @see `AvatarAction.Release`
* @see `AvatarServiceMessage`
* @see `CorpseConverter.converter` * @see `CorpseConverter.converter`
* @see `DepictPlayerAsCorpse` * @see `DepictPlayerAsCorpse`
* @see `Player.Release` * @see `Player.Release`
@ -2939,7 +2946,7 @@ class ZoningOperations(
tplayer.Release tplayer.Release
DepictPlayerAsCorpse(tplayer) DepictPlayerAsCorpse(tplayer)
zone.Population ! Zone.Corpse.Add(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 = { def TryDisposeOfLootedCorpse(obj: Player): Boolean = {
if (obj.isBackpack && WellLootedDeadBody(obj)) { 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 true
} else { } else {
false 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 // 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 val effect = if (player.IsInVRZone || zoneId.startsWith("tz")) 2 else 1
sendResponse(ObjectDeleteMessage(player_guid, unk1=effect)) sendResponse(ObjectDeleteMessage(player_guid, unk1=effect))
continent.AvatarEvents ! AvatarServiceMessage( continent.AvatarEvents ! MessageEnvelope(
continent.id, continent.id,
AvatarAction.ObjectDelete(player_guid, player_guid, unk=effect) player_guid,
ObjectDelete(player_guid, unk=effect)
) )
InGameHistory.SpawnReconstructionActivity(player, toZoneNumber, betterSpawnPoint) InGameHistory.SpawnReconstructionActivity(player, toZoneNumber, betterSpawnPoint)
LoadZoneAsPlayerUsing(player, pos, ori, toSide, zoneId) LoadZoneAsPlayerUsing(player, pos, ori, toSide, zoneId)
@ -3338,7 +3346,7 @@ class ZoningOperations(
//looking for squad (members) //looking for squad (members)
if (tplayer.avatar.lookingForSquad) { if (tplayer.avatar.lookingForSquad) {
sendResponse(PlanetsideAttributeMessage(guid, 53, 1)) 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))) 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 //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) { if (tplayer.ExoSuit == ExoSuitType.MAX) {
sendResponse(PlanetsideAttributeMessage(guid, 7, tplayer.Capacitor.toLong)) sendResponse(PlanetsideAttributeMessage(guid, 7, tplayer.Capacitor.toLong))
sendResponse(PlanetsideAttributeMessage(guid, 4, tplayer.Armor)) 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 // for issue #1269
continent.AllPlayers.filter(_.ExoSuit == ExoSuitType.MAX).foreach(max => sendResponse(PlanetsideAttributeMessage(max.GUID, 4, max.Armor))) 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 { continent.GUID(tplayer.avatar.vehicle) match {
case Some(vehicle: Vehicle) if vehicle.OwnerName.contains(tplayer.Name) => case Some(vehicle: Vehicle) if vehicle.OwnerName.contains(tplayer.Name) =>
vehicle.OwnerGuid = guid vehicle.OwnerGuid = guid
continent.VehicleEvents ! VehicleServiceMessage( continent.VehicleEvents ! MessageEnvelope(
s"${tplayer.Faction}", s"${tplayer.Faction}",
VehicleAction.Ownership(guid, vehicle.GUID) guid,
VehicleAction.Ownership(vehicle.GUID)
) )
case _ => case _ =>
avatarActor ! AvatarActor.SetVehicle(None) avatarActor ! AvatarActor.SetVehicle(None)
@ -3487,13 +3496,13 @@ class ZoningOperations(
case Some(b: Building) if b.hasCavernLockBenefit => case Some(b: Building) if b.hasCavernLockBenefit =>
tplayer.MaxHealth = 120 tplayer.MaxHealth = 120
tplayer.Health = 120 tplayer.Health = 120
tplayer.Zone.AvatarEvents ! AvatarServiceMessage( val guid = tplayer.GUID
tplayer.Zone.id, val zone = tplayer.Zone
AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 0, 120) val channel = zone.id
) val events = zone.AvatarEvents
tplayer.Zone.AvatarEvents ! AvatarServiceMessage( events ! MessageEnvelope(
tplayer.Zone.id, channel,
AvatarAction.PlanetsideAttributeToAll(tplayer.GUID, 1, 120) SendResponse(PlanetsideAttributeMessage(guid, 0, 120), PlanetsideAttributeMessage(guid, 1, 120))
) )
case _ => () case _ => ()
} }
@ -3996,13 +4005,20 @@ class ZoningOperations(
} }
GoToDeploymentMap() GoToDeploymentMap()
val pZone = player.Zone val pZone = player.Zone
val msg = GenericObjectAction(player.GUID, GenericObjectActionEnum.PlayerDeconstructs.id)
sendResponse(GenericActionMessage(FirstPersonViewWithEffect)) sendResponse(GenericActionMessage(FirstPersonViewWithEffect))
pZone.blockMap.sector(player).livePlayerList.collect { case t if t.GUID != player.GUID => val (localMessageRecipients, localMesages) = pZone.blockMap.sector(player).livePlayerList
pZone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendGenericObjectActionMessage(t.GUID, player.GUID, GenericObjectActionEnum.PlayerDeconstructs)) .collect {
} case t if t.GUID != player.GUID =>
pZone.AllPlayers.collect { case t if t.GUID != player.GUID && !t.allowInteraction => (t.Name, MessageEnvelope(t.Name, msg))
pZone.LocalEvents ! LocalServiceMessage(t.Name, LocalAction.SendGenericObjectActionMessage(t.GUID, player.GUID, GenericObjectActionEnum.PlayerDeconstructs)) }
} .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 = { def stopDeconstructing(): Unit = {

View file

@ -11,8 +11,9 @@ import net.psforever.objects.zones.Zone
import net.psforever.packet.PlanetSideGamePacket import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.ContinentalLockUpdateMessage import net.psforever.packet.game.ContinentalLockUpdateMessage
import net.psforever.persistence import net.psforever.persistence
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage} import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.base.message.{SendResponse, SetEmpire}
import net.psforever.services.galaxy.GalaxyAction
import net.psforever.services.{InterstellarClusterService, ServiceManager} import net.psforever.services.{InterstellarClusterService, ServiceManager}
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
import net.psforever.util.Database.ctx import net.psforever.util.Database.ctx
@ -167,7 +168,7 @@ object BuildingActor {
val building = details.building val building = details.building
val zone = building.Zone val zone = building.Zone
building.Faction = faction 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 Behaviors.same
case MapUpdate() => case MapUpdate() =>
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage())) details.galaxyService ! BundledEnvelope(
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(details.building.densityLevelUpdateMessage(building))) MessageEnvelope("", GalaxyAction.MapUpdate(details.building.infoUpdateMessage())),
MessageEnvelope("", SendResponse(details.building.densityLevelUpdateMessage(building)))
)
Behaviors.same Behaviors.same
case AmenityStateChange(amenity, data) => case AmenityStateChange(amenity, data) =>
@ -254,15 +257,15 @@ class BuildingActor(
logic.ntu(details, msg) logic.ntu(details, msg)
case DensityLevelUpdate(building) => case DensityLevelUpdate(building) =>
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(details.building.densityLevelUpdateMessage(building))) details.galaxyService ! MessageEnvelope("", SendResponse(details.building.densityLevelUpdateMessage(building)))
Behaviors.same Behaviors.same
case ContinentalLock(zone) => case ContinentalLock(zone) =>
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(ContinentalLockUpdateMessage(zone.Number, zone.lockedBy))) details.galaxyService ! MessageEnvelope("", SendResponse(ContinentalLockUpdateMessage(zone.Number, zone.lockedBy)))
Behaviors.same Behaviors.same
case HomeLockBenefits(msg) => case HomeLockBenefits(msg) =>
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.SendResponse(msg)) details.galaxyService ! MessageEnvelope("", SendResponse(msg))
Behaviors.same 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.avatar.{AvatarBot, AvatarBotActor}
import net.psforever.objects.guid.{GUIDTask, StraightforwardTask, TaskBundle, TaskWorkflow} import net.psforever.objects.guid.{GUIDTask, StraightforwardTask, TaskBundle, TaskWorkflow}
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.local.LocalAction
import net.psforever.types.{CharacterSex, CharacterVoice, ExoSuitType, PlanetSideEmpire, PlanetSideGUID, Vector3} import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.{CharacterSex, CharacterVoice, ExoSuitType, PlanetSideEmpire, Vector3}
import net.psforever.util.Config import net.psforever.util.Config
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
@ -282,7 +283,6 @@ class ShootingRangeTargetSpawnerActor(zone: Zone) extends Actor {
* @param bot the bot to remove * @param bot the bot to remove
*/ */
private def RemoveBot(bot: AvatarBot): Boolean = { private def RemoveBot(bot: AvatarBot): Boolean = {
import net.psforever.services.Service
activeInfantryTargets.indexOf(bot) match { activeInfantryTargets.indexOf(bot) match {
case -1 => 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.") 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 => case index =>
activeInfantryTargets.remove(index) activeInfantryTargets.remove(index)
} }
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, 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 //spawn a replacement bot
context.system.scheduler.scheduleOnce( context.system.scheduler.scheduleOnce(
@ -356,10 +356,9 @@ class ShootingRangeTargetSpawnerActor(zone: Zone) extends Actor {
def action(): Future[Any] = { def action(): Future[Any] = {
zone.Transport ! Zone.Vehicle.Spawn(localVehicle) zone.Transport ! Zone.Vehicle.Spawn(localVehicle)
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, zone.id,
VehicleAction.LoadVehicle( VehicleAction.LoadVehicle(
PlanetSideGUID(0),
localVehicle, localVehicle,
localVehicle.Definition.ObjectId, localVehicle.Definition.ObjectId,
localVehicle.GUID, 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.packet.game.{BuildingInfoUpdateMessage, PlanetsideAttributeMessage}
import net.psforever.util.Database._ import net.psforever.util.Database._
import net.psforever.persistence 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.collection.mutable
import scala.util.{Failure, Success} import scala.util.{Failure, Success}
@ -234,26 +235,26 @@ class ZoneActor(
} }
buildingOpt.foreach { building => buildingOpt.foreach { building =>
if (msg.generator_state == PlanetSideGeneratorState.Normal && building.hasCavernLockBenefit) { if (msg.generator_state == PlanetSideGeneratorState.Normal && building.hasCavernLockBenefit) {
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 1)) SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 1))
) )
} }
msg.is_hacked match { msg.is_hacked match {
case true if building.BuildingType == StructureType.Facility && !zone.map.cavern => case true if building.BuildingType == StructureType.Facility && !zone.map.cavern =>
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0)) SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
) )
case false if building.hasCavernLockBenefit => case false if building.hasCavernLockBenefit =>
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, 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 => case false if building.BuildingType == StructureType.Facility && !zone.map.cavern && !building.hasCavernLockBenefit =>
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0)) SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
) )
case _ => case _ =>
} }

View file

@ -7,9 +7,10 @@ import net.psforever.actors.commands.NtuCommand
import net.psforever.actors.zone.{BuildingActor, BuildingControlDetails, ZoneActor} import net.psforever.actors.zone.{BuildingActor, BuildingControlDetails, ZoneActor}
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType} import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType}
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior} import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior}
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.galaxy.GalaxyAction
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} 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. * 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 // 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 => { building.HackableAmenities.foreach(amenity => {
if (amenity.HackedBy.isDefined) { 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 // No map update needed - will be sent by `HackCaptureActor` when required
case _ => case _ =>
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage())) details.galaxyService ! MessageEnvelope("", GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
} }
Behaviors.same Behaviors.same
} }

View file

@ -7,9 +7,10 @@ import net.psforever.actors.commands.NtuCommand
import net.psforever.actors.zone.{BuildingActor, BuildingControlDetails} import net.psforever.actors.zone.{BuildingActor, BuildingControlDetails}
import net.psforever.objects.serverobject.structures.{Amenity, Building} import net.psforever.objects.serverobject.structures.{Amenity, Building}
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior} import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior}
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.galaxy.GalaxyAction
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
import net.psforever.types.PlanetSideEmpire
/** /**
* The logic that governs standard facilities and structures. * 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 // 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 => { building.HackableAmenities.foreach(amenity => {
if (amenity.HackedBy.isDefined) { 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 // No map update needed - will be sent by `HackCaptureActor` when required
case _ => case _ =>
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage())) details.galaxyService ! MessageEnvelope("", GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
} }
Behaviors.same 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.structures.{Amenity, Building}
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior} import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior}
import net.psforever.objects.sourcing.PlayerSource import net.psforever.objects.sourcing.PlayerSource
import net.psforever.packet.game.PlanetsideAttributeMessage import net.psforever.packet.game.{GenericObjectActionMessage, PlanetsideAttributeMessage}
import net.psforever.services.{InterstellarClusterService, Service} import net.psforever.services.InterstellarClusterService
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage} import net.psforever.services.base.message.{GenericObjectAction, PlanetsideAttribute, SendResponse}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.galaxy.GalaxyAction
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} 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. * A package class that conveys the important information for handling facility updates.
@ -101,10 +102,7 @@ case object MajorFacilityLogic
hackedAmenities hackedAmenities
} }
amenitiesToClear.foreach { amenity => amenitiesToClear.foreach { amenity =>
building.Zone.LocalEvents ! LocalServiceMessage( building.Zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(amenity))
amenity.Zone.id,
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), amenity)
)
} }
// No map update needed - will be sent by `HackCaptureActor` when required // No map update needed - will be sent by `HackCaptureActor` when required
case dome: ForceDomePhysics => case dome: ForceDomePhysics =>
@ -120,7 +118,7 @@ case object MajorFacilityLogic
.filter(amenity => applicable.contains(amenity.Definition)) .filter(amenity => applicable.contains(amenity.Definition))
.foreach { _.Actor ! msg } .foreach { _.Actor ! msg }
case _ => case _ =>
details.galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(details.building.infoUpdateMessage())) details.galaxyService ! MessageEnvelope("", GalaxyAction.MapUpdate(details.building.infoUpdateMessage()))
} }
Behaviors.same Behaviors.same
} }
@ -205,30 +203,24 @@ case object MajorFacilityLogic
case Some(GeneratorControl.Event.UnderAttack) => case Some(GeneratorControl.Event.UnderAttack) =>
val events = zone.AvatarEvents val events = zone.AvatarEvents
val guid = building.GUID val guid = building.GUID
val msg = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, guid, 15) val msg = GenericObjectAction(guid, 15)
building.PlayersInSOI.foreach { player => events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) })
events ! AvatarServiceMessage(player.Name, msg)
}
false false
case Some(GeneratorControl.Event.Critical) => case Some(GeneratorControl.Event.Critical) =>
val events = zone.AvatarEvents val events = zone.AvatarEvents
val guid = building.GUID val guid = building.GUID
val msg = AvatarAction.PlanetsideAttributeToAll(guid, 46, 1) val msg = PlanetsideAttribute(guid, 46, 1)
building.PlayersInSOI.foreach { player => events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) })
events ! AvatarServiceMessage(player.Name, msg)
}
true true
case Some(GeneratorControl.Event.Destabilized) => case Some(GeneratorControl.Event.Destabilized) =>
val events = zone.AvatarEvents val events = zone.AvatarEvents
val guid = building.GUID val guid = building.GUID
val msg = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, guid, 16) val msg = GenericObjectAction(guid, 16)
building.PlayersInSOI.foreach { player => events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) })
events ! AvatarServiceMessage(player.Name, msg)
}
if (building.hasCavernLockBenefit) { if (building.hasCavernLockBenefit) {
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0)) SendResponse(PlanetsideAttributeMessage(building.GUID, 67, 0))
) )
} }
false false
@ -237,10 +229,9 @@ case object MajorFacilityLogic
case Some(GeneratorControl.Event.Offline) => case Some(GeneratorControl.Event.Offline) =>
powerLost(details) powerLost(details)
val zone = building.Zone val zone = building.Zone
val msg = AvatarAction.PlanetsideAttributeToAll(building.GUID, 46, 2) val events = zone.AvatarEvents
building.PlayersInSOI.foreach { player => val msg = PlanetsideAttribute(building.GUID, 46, 2)
zone.AvatarEvents ! AvatarServiceMessage(player.Name, msg) events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, msg) }) //???
} //???
true true
case Some(GeneratorControl.Event.Normal) => case Some(GeneratorControl.Event.Normal) =>
true true
@ -249,13 +240,13 @@ case object MajorFacilityLogic
powerRestored(details) powerRestored(details)
val events = zone.AvatarEvents val events = zone.AvatarEvents
val guid = building.GUID val guid = building.GUID
val msg1 = AvatarAction.PlanetsideAttributeToAll(guid, 46, 0) //1. reset ???; might be global?
val msg2 = AvatarAction.GenericObjectAction(Service.defaultPlayerGUID, guid, 17) //2. This facility's generator is back on line
building.PlayersInSOI.foreach { player => val list = SendResponse(
val name = player.Name PlanetsideAttributeMessage(guid, 46, 0),
events ! AvatarServiceMessage(name, msg1) //reset ???; might be global? GenericObjectActionMessage(guid, 17)
events ! AvatarServiceMessage(name, msg2) //This facility's generator is back on line )
} events ! BundledEnvelope(building.PlayersInSOI.map { player => MessageEnvelope(player.Name, list) })
true true
case _ => case _ =>
false false
@ -283,7 +274,7 @@ case object MajorFacilityLogic
(bldg.GetFlag, bldg.CaptureTerminal) match { (bldg.GetFlag, bldg.CaptureTerminal) match {
case (Some(flag), Some(terminal)) if (flag.Target eq building) && flag.Faction != building.Faction => 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 //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 _ => () case _ => ()
} }
Behaviors.same Behaviors.same
@ -305,10 +296,12 @@ case object MajorFacilityLogic
building.Amenities.foreach { amenity => building.Amenities.foreach { amenity =>
amenity.Actor ! powerMsg amenity.Actor ! powerMsg
} }
//amenities disabled; red warning lights //1. amenities disabled; red warning lights
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 48, 1)) //2 .disable spawn target on deployment map
//disable spawn target on deployment map events ! MessageEnvelope(
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 38, 0)) zoneId,
SendResponse(PlanetsideAttributeMessage(guid, 48, 1), PlanetsideAttributeMessage(guid, 38, 0))
)
Behaviors.same Behaviors.same
} }
@ -328,10 +321,12 @@ case object MajorFacilityLogic
building.Amenities.foreach { amenity => building.Amenities.foreach { amenity =>
amenity.Actor ! powerMsg amenity.Actor ! powerMsg
} }
//amenities enabled; normal lights //1. amenities enabled; normal lights
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 48, 0)) //2. enable spawn target on deployment map
//enable spawn target on deployment map events ! MessageEnvelope(
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(guid, 38, 1)) zoneId,
SendResponse(PlanetsideAttributeMessage(guid, 48, 0), PlanetsideAttributeMessage(guid, 38, 1))
)
Behaviors.same Behaviors.same
} }

View file

@ -4,9 +4,10 @@ package net.psforever.actors.zone.building
import akka.actor.typed.Behavior import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.Behaviors
import net.psforever.actors.commands.NtuCommand 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.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.types.PlanetSideEmpire
import net.psforever.util.Config import net.psforever.util.Config
@ -182,7 +183,7 @@ case object WarpGateLogic
val pairedWgFaction = pairedWg.Faction val pairedWgFaction = pairedWg.Faction
if (pairedWgFaction != terminalWgFaction) { if (pairedWgFaction != terminalWgFaction) {
pairedWg.Faction = 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 //the terminal warpgate can not be considered broadcast for other faction
if (terminalWg.AllowBroadcastFor.contains(pairedWgFaction)) { if (terminalWg.AllowBroadcastFor.contains(pairedWgFaction)) {
@ -208,9 +209,7 @@ case object WarpGateLogic
warpgate.Zone.Number, warpgate.MapId, previousAllowances, setBroadcastTo warpgate.Zone.Number, warpgate.MapId, previousAllowances, setBroadcastTo
) )
warpgate.AllowBroadcastFor = setBroadcastTo warpgate.AllowBroadcastFor = setBroadcastTo
(setBroadcastTo ++ previousAllowances).foreach { faction => events ! BundledEnvelope((setBroadcastTo ++ previousAllowances).map { faction => MessageEnvelope(faction.toString, msg) })
events ! GalaxyServiceMessage(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.vital.TerminalUsedActivity
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.types.{ExoSuitType, PlanetSideGUID, TransactionType, Vector3} import net.psforever.types.{ExoSuitType, PlanetSideGUID, TransactionType, Vector3}
import net.psforever.services.Service import net.psforever.services.avatar.AvatarAction
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.message.ObjectDelete
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future import scala.concurrent.Future
@ -280,7 +281,7 @@ object WorldSession {
* @throws `RuntimeException` if slot is not a player visible slot (holsters) * @throws `RuntimeException` if slot is not a player visible slot (holsters)
* @see `ask` * @see `ask`
* @see `AvatarAction.ObjectDelete` * @see `AvatarAction.ObjectDelete`
* @see `AvatarAction.SendResponse` * @see `SendResponse`
* @see `Containable.CanNotPutItemInSlot` * @see `Containable.CanNotPutItemInSlot`
* @see `Containable.PutItemInSlotOnly` * @see `Containable.PutItemInSlotOnly`
* @see `GUIDTask.registerEquipment` * @see `GUIDTask.registerEquipment`
@ -289,7 +290,7 @@ object WorldSession {
* @see `ObjectHeldMessage` * @see `ObjectHeldMessage`
* @see `Player.DrawnSlot` * @see `Player.DrawnSlot`
* @see `Player.LastDrawnSlot` * @see `Player.LastDrawnSlot`
* @see `Service.defaultPlayerGUID` * @see `Default.GUID0`
* @see `TaskBundle` * @see `TaskBundle`
* @see `Zone.AvatarEvents` * @see `Zone.AvatarEvents`
* @param player the player whose visible slot will be equipped and drawn * @param player the player whose visible slot will be equipped and drawn
@ -326,10 +327,7 @@ object WorldSession {
case _ => case _ =>
forcedTolowerRaisedArm(localPlayer, localPlayer.GUID, localZone) forcedTolowerRaisedArm(localPlayer, localPlayer.GUID, localZone)
localPlayer.DrawnSlot = localSlot localPlayer.DrawnSlot = localSlot
localZone.AvatarEvents ! AvatarServiceMessage( localZone.AvatarEvents ! MessageEnvelope(localZone.id, localGUID, AvatarAction.ObjectHeld(localSlot, localSlot))
localZone.id,
AvatarAction.ObjectHeld(localGUID, localSlot, localSlot)
)
} }
Future(this) Future(this)
} }
@ -370,10 +368,7 @@ object WorldSession {
localZone.GUID(item_guid) match { localZone.GUID(item_guid) match {
case Some(_) => () case Some(_) => ()
case None => //acting on old data? case None => //acting on old data?
localZone.AvatarEvents ! AvatarServiceMessage( localZone.AvatarEvents ! MessageEnvelope(localZone.id, ObjectDelete(item_guid))
localZone.id,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item_guid)
)
} }
case _ => () case _ => ()
} }
@ -532,7 +527,6 @@ object WorldSession {
* Failure of this process is not supported and may lead to irregular behavior. * Failure of this process is not supported and may lead to irregular behavior.
* @see `ActorRef` * @see `ActorRef`
* @see `AvatarAction.ObjectDelete` * @see `AvatarAction.ObjectDelete`
* @see `AvatarServiceMessage`
* @see `Containable.MoveItem` * @see `Containable.MoveItem`
* @see `Container` * @see `Container`
* @see `Equipment` * @see `Equipment`
@ -597,10 +591,7 @@ object WorldSession {
localGUID match { localGUID match {
case Some(guid) => case Some(guid) =>
//see LockerContainerControl.RemoveItemFromSlotCallback //see LockerContainerControl.RemoveItemFromSlotCallback
localSource.Zone.AvatarEvents ! AvatarServiceMessage( localSource.Zone.AvatarEvents ! MessageEnvelope(localChannel, ObjectDelete(guid))
localChannel,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
)
case None => () case None => ()
} }
val moveResult = ask(localDestination.Actor, Containable.PutItemInSlotOrAway(localItem, Some(localDestSlot))) 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. * Remove an item from a player's locker inventory.
* Failure of this process is not supported and may lead to irregular behavior. * Failure of this process is not supported and may lead to irregular behavior.
* @see `ActorRef` * @see `ActorRef`
* @see `AvatarAction.ObjectDelete` * @see `ObjectDelete`
* @see `AvatarServiceMessage`
* @see `Containable.MoveItem` * @see `Containable.MoveItem`
* @see `Container` * @see `Container`
* @see `Equipment` * @see `Equipment`
@ -702,10 +692,7 @@ object WorldSession {
localGUID match { localGUID match {
case Some(guid) => case Some(guid) =>
//see LockerContainerControl.RemoveItemFromSlotCallback //see LockerContainerControl.RemoveItemFromSlotCallback
localSource.Zone.AvatarEvents ! AvatarServiceMessage( localSource.Zone.AvatarEvents ! MessageEnvelope(localChannel, ObjectDelete(guid))
localChannel,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
)
case None => () case None => ()
} }
val moveResult = ask(localDestination.Actor, Containable.PutItemInSlotOrAway(localItem, Some(localDestSlot))) 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), * 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 - * treat it like the sidearm occupier rather than the already-drawn weapon -
* the old weapon goes into the backpack or onto the ground. * the old weapon goes into the backpack or onto the ground.
* @see `AvatarAction.ObjectHeld` * @see `ObjectHeld`
* @see `AvatarServiceMessage`
* @see `Containable.RemoveItemFromSlot` * @see `Containable.RemoveItemFromSlot`
* @see `countRestrictAttempts` * @see `countRestrictAttempts`
* @see `forcedTolowerRaisedArm` * @see `forcedTolowerRaisedArm`
@ -795,10 +781,7 @@ object WorldSession {
} }
//put up hand with grenade in it //put up hand with grenade in it
tplayer.DrawnSlot = slotNum tplayer.DrawnSlot = slotNum
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(zone.id, guid, AvatarAction.ObjectHeld(slotNum, slotNum))
zone.id,
AvatarAction.ObjectHeld(guid, slotNum, slotNum)
)
log.info(s"${tplayer.Name} has quickly drawn a ${grenade.Definition.Name}") log.info(s"${tplayer.Name} has quickly drawn a ${grenade.Definition.Name}")
None None
case None => case None =>
@ -872,8 +855,7 @@ object WorldSession {
/** /**
* If the player has a raised arm, lower it. * If the player has a raised arm, lower it.
* Do it manually, bypassing the checks in the normal procedure. * Do it manually, bypassing the checks in the normal procedure.
* @see `AvatarAction.ObjectHeld` * @see `ObjectHeld`
* @see `AvatarServiceMessage`
* @see `Player.DrawnSlot` * @see `Player.DrawnSlot`
* @see `Player.HandsDownSlot` * @see `Player.HandsDownSlot`
* @param tplayer the player * @param tplayer the player
@ -885,10 +867,7 @@ object WorldSession {
val slot = tplayer.DrawnSlot val slot = tplayer.DrawnSlot
if (slot != Player.HandsDownSlot) { if (slot != Player.HandsDownSlot) {
tplayer.DrawnSlot = Player.HandsDownSlot tplayer.DrawnSlot = Player.HandsDownSlot
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(zone.id, guid, AvatarAction.ObjectHeld(Player.HandsDownSlot, slot))
zone.id,
AvatarAction.ObjectHeld(guid, Player.HandsDownSlot, slot)
)
true true
} else { } else {
false false
@ -951,7 +930,7 @@ object WorldSession {
player.ContributionFrom(term) player.ContributionFrom(term)
} }
} }
player.Zone.AvatarEvents ! AvatarServiceMessage( player.Zone.AvatarEvents ! MessageEnvelope(
player.Name, player.Name,
AvatarAction.TerminalOrderResult(guid, transaction, result) 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.etc.TriggerUsedReason
import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.ObjectDelete
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.LocalAction
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
import scala.annotation.unused import scala.annotation.unused
@ -87,9 +87,9 @@ class BoomerDeployableControl(mine: BoomerDeployable)
val events = mine.Zone.LocalEvents val events = mine.Zone.LocalEvents
val msg = LocalAction.DeployItem(mine) val msg = LocalAction.DeployItem(mine)
originalOwner.collect { name => 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 = { override def dismissDeployable() : Unit = {
@ -107,10 +107,7 @@ class BoomerDeployableControl(mine: BoomerDeployable)
zone.Ground ! Zone.Ground.RemoveItem(guid) zone.Ground ! Zone.Ground.RemoveItem(guid)
case _ => () case _ => ()
} }
zone.AvatarEvents! AvatarServiceMessage( zone.AvatarEvents! MessageEnvelope(zone.id, ObjectDelete(guid))
zone.id,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, guid)
)
TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, trigger)) TaskWorkflow.execute(GUIDTask.unregisterObject(zone.GUID, trigger))
case None => () case None => ()
} }

View file

@ -1,7 +1,12 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.objects package net.psforever.objects
import net.psforever.types.{PlanetSideGUID, ValidPlanetSideGUID}
object Default { object Default {
//'g'lobal 'u'nique 'id'entifier
final val GUID0: PlanetSideGUID = ValidPlanetSideGUID(0)
//cancellable //cancellable
import akka.actor.Cancellable import akka.actor.Cancellable
protected class InternalCancellable extends 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.sourcing.{PlayerSource, SourceEntry}
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.LocalAction
object Deployables { object Deployables {
//private val log = org.log4s.getLogger("Deployables") //private val log = org.log4s.getLogger("Deployables")
@ -92,13 +93,9 @@ object Deployables {
} }
target.AssignOwnership(None) target.AssignOwnership(None)
} }
events ! LocalServiceMessage( events ! MessageEnvelope(
s"${target.Faction}", s"${target.Faction}",
LocalAction.DeployableMapIcon( LocalAction.DeployableMapIcon(DeploymentAction.Dismiss, DeployableInfo(target.GUID, Deployable.Icon(item), target.Position, PlanetSideGUID(0)))
PlanetSideGUID(0),
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.vital.projectile.ProjectileReason
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.types.Vector3 import net.psforever.types.Vector3
import net.psforever.services.Service import net.psforever.services.avatar.AvatarAction
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.LocalAction
import scala.annotation.unused import scala.annotation.unused
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -182,7 +182,7 @@ object ExplosiveDeployableControl {
target.Health = 1 // short-circuit logic in DestructionAwareness target.Health = 1 // short-circuit logic in DestructionAwareness
val zone = target.Zone val zone = target.Zone
zone.Activity ! Zone.HotSpot.Activity(cause) 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.serverSideDamage(
zone, zone,
target, target,
@ -210,14 +210,14 @@ object ExplosiveDeployableControl {
Some(if (target.Jammed || target.Destroyed) 0 seconds else 500 milliseconds) Some(if (target.Jammed || target.Destroyed) 0 seconds else 500 milliseconds)
) )
target.Destroyed = true target.Destroyed = true
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.Destroy(target.GUID, attribution, Service.defaultPlayerGUID, target.Position) AvatarAction.Destroy(target.GUID, attribution, Default.GUID0, target.Position)
) )
if (target.Health == 0) { if (target.Health == 0) {
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, 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.sourcing.{PlayerSource, SourceEntry, TurretSource}
import net.psforever.objects.vital.{DismountingActivity, InGameActivity, MountingActivity, ShieldCharge} import net.psforever.objects.vital.{DismountingActivity, InGameActivity, MountingActivity, ShieldCharge}
import net.psforever.packet.game.HackState1 import net.psforever.packet.game.HackState1
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.PlanetSideGUID import net.psforever.services.base.message.PlanetsideAttribute
import scala.annotation.unused import scala.annotation.unused
@ -98,9 +98,9 @@ class FieldTurretControl(turret: TurretDeployable)
if (canChargeShields) { if (canChargeShields) {
turret.LogActivity(ShieldCharge(amount, motivator)) turret.LogActivity(ShieldCharge(amount, motivator))
turret.Shields = turret.Shields + amount turret.Shields = turret.Shields + amount
turret.Zone.VehicleEvents ! VehicleServiceMessage( turret.Zone.VehicleEvents ! MessageEnvelope(
s"${turret.Actor}", 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.objects.zones.Zone
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.types.{ChatMessageType, ExoSuitType, PlanetSideGUID, Vector3} import net.psforever.types.{ChatMessageType, ExoSuitType, PlanetSideGUID, Vector3}
import net.psforever.services.Service import net.psforever.services.avatar.AvatarAction
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.base.message.{ObjectDelete, SendResponse}
import net.psforever.services.local.LocalAction
import scala.annotation.tailrec import scala.annotation.tailrec
import scala.collection.mutable.ArrayBuffer
object Players { object Players {
private val log = org.log4s.getLogger("Players") private val log = org.log4s.getLogger("Players")
@ -48,10 +50,7 @@ object Players {
) { ) {
val events = target.Zone.AvatarEvents val events = target.Zone.AvatarEvents
val uname = user.Name val uname = user.Name
events ! AvatarServiceMessage( events ! MessageEnvelope(uname, SendResponse(RepairMessage(target.GUID, progress.toInt)))
uname,
AvatarAction.SendResponse(Service.defaultPlayerGUID, RepairMessage(target.GUID, progress.toInt))
)
true true
} else { } else {
false false
@ -61,7 +60,7 @@ object Players {
/** /**
* na * na
* @see `AvatarAction.Revive` * @see `AvatarAction.Revive`
* @see `AvatarResponse.Revive` * @see `AvatarAction.Revive`
* @param target the player being revived * @param target the player being revived
* @param medic the name of the player doing the reviving * @param medic the name of the player doing the reviving
* @param item the tool being used to revive the target player * @param item the tool being used to revive the target player
@ -76,12 +75,12 @@ object Players {
PlayerControl.sendResponse( PlayerControl.sendResponse(
target.Zone, target.Zone,
medicName, medicName,
AvatarAction.SendResponse( Default.GUID0,
Service.defaultPlayerGUID, SendResponse(
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine) 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 { ExoSuitDefinition.Select(exosuit, player.Faction).Permissions match {
case Nil => case Nil =>
true true
case permissions if player.IsInVRZone => case _ if player.IsInVRZone =>
true true
case permissions if subtype != 0 => case permissions if subtype != 0 =>
val certs = player.avatar.certifications val certs = player.avatar.certifications
@ -316,7 +315,7 @@ object Players {
): Boolean = { ): Boolean = {
if (player.Zone == obj.Zone && addFunc(obj)) { if (player.Zone == obj.Zone && addFunc(obj)) {
obj.Actor ! Deployable.Ownership(player) 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 true
} else { } else {
false false
@ -333,7 +332,7 @@ object Players {
//sent to avatar event bus to preempt additional tool management //sent to avatar event bus to preempt additional tool management
buildCooldownReset(zone, channel, obj.GUID) buildCooldownReset(zone, channel, obj.GUID)
//sent to local event bus to cooperate with deployable management //sent to local event bus to cooperate with deployable management
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
channel, channel,
LocalAction.DeployableUIFor(obj.Definition.Item) LocalAction.DeployableUIFor(obj.Definition.Item)
) )
@ -347,10 +346,7 @@ object Players {
*/ */
def buildCooldownReset(zone: Zone, channel: String, guid: PlanetSideGUID): Unit = { def buildCooldownReset(zone: Zone, channel: String, guid: PlanetSideGUID): Unit = {
//sent to avatar event bus to preempt additional tool management //sent to avatar event bus to preempt additional tool management
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(channel, SendResponse(GenericObjectActionMessage(guid, 21)))
channel,
AvatarAction.SendResponse(Service.defaultPlayerGUID, GenericObjectActionMessage(guid, 21))
)
} }
/** /**
@ -406,10 +402,7 @@ object Players {
} }
}) { }) {
val zone = player.Zone val zone = player.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(zone.id, ObjectDelete(tool.GUID))
zone.id,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, tool.GUID)
)
true true
} else { } else {
false false
@ -444,27 +437,20 @@ object Players {
if ((player.Slot(index).Equipment = obj).contains(obj)) { if ((player.Slot(index).Equipment = obj).contains(obj)) {
val fireMode = tool.FireModeIndex val fireMode = tool.FireModeIndex
val ammoType = tool.AmmoTypeIndex val ammoType = tool.AmmoTypeIndex
val list: ArrayBuffer[MessageEnvelope] = ArrayBuffer()
player.Inventory -= x.start player.Inventory -= x.start
obj.FireModeIndex = fireMode obj.FireModeIndex = fireMode
//TODO any penalty for being handed an OCM version of the tool? //TODO any penalty for being handed an OCM version of the tool?
events ! AvatarServiceMessage( list.append(MessageEnvelope(zone.id, AvatarAction.EquipmentInHand(pguid, index, obj)))
zone.id,
AvatarAction.EquipmentInHand(Service.defaultPlayerGUID, pguid, index, obj)
)
if (obj.AmmoTypeIndex != ammoType) { if (obj.AmmoTypeIndex != ammoType) {
obj.AmmoTypeIndex = ammoType obj.AmmoTypeIndex = ammoType
events ! AvatarServiceMessage( list.append(MessageEnvelope(name, SendResponse(ChangeAmmoMessage(obj.GUID, ammoType))))
name,
AvatarAction.SendResponse(Service.defaultPlayerGUID, ChangeAmmoMessage(obj.GUID, ammoType))
)
} }
if (player.DrawnSlot == Player.HandsDownSlot) { if (player.DrawnSlot == Player.HandsDownSlot) {
player.DrawnSlot = index player.DrawnSlot = index
events ! AvatarServiceMessage( list.append(MessageEnvelope(zone.id, pguid, AvatarAction.ObjectHeld(index, index)))
zone.id,
AvatarAction.ObjectHeld(pguid, index, index)
)
} }
events ! BundledEnvelope(list)
} }
case Nil => ; //no replacements found 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.serverobject.repair.RepairableEntity
import net.psforever.objects.vital.SimpleResolutions import net.psforever.objects.vital.SimpleResolutions
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{PlanetSideGUID, Vector3} import net.psforever.types.{PlanetSideGUID, Vector3}
import net.psforever.services.Service import net.psforever.services.base.message.PlanetsideAttribute
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.LocalAction
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.annotation.unused import scala.annotation.unused
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -75,9 +75,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
override def StartJammeredSound(target: Any, dur: Int): Unit = override def StartJammeredSound(target: Any, dur: Int): Unit =
target match { target match {
case obj: PlanetSideServerObject if !jammedSound => case obj: PlanetSideServerObject if !jammedSound =>
obj.Zone.VehicleEvents ! VehicleServiceMessage( obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 1) PlanetsideAttribute(obj.GUID, 54, 1)
) )
super.StartJammeredSound(obj, dur) super.StartJammeredSound(obj, dur)
case _ => ; case _ => ;
@ -87,9 +87,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
target match { target match {
case obj: PlanetSideServerObject with JammableUnit => case obj: PlanetSideServerObject with JammableUnit =>
val zone = obj.Zone val zone = obj.Zone
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, unk1=false, 1000) LocalAction.TriggerEffectInfo(obj.GUID, "on", unk1=false, 1000)
) )
super.StartJammeredStatus(obj, dur) super.StartJammeredStatus(obj, dur)
case _ => ; case _ => ;
@ -99,9 +99,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
target match { target match {
case obj: PlanetSideServerObject if jammedSound => case obj: PlanetSideServerObject if jammedSound =>
val zone = obj.Zone val zone = obj.Zone
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 54, 0) PlanetsideAttribute(obj.GUID, 54, 0)
) )
case _ => ; case _ => ;
} }
@ -112,9 +112,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
target match { target match {
case obj: PlanetSideServerObject with JammableUnit if obj.Jammed => case obj: PlanetSideServerObject with JammableUnit if obj.Jammed =>
val zone = sensor.Zone val zone = sensor.Zone
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.TriggerEffectInfo(Service.defaultPlayerGUID, "on", obj.GUID, unk1=true, 1000) LocalAction.TriggerEffectInfo(obj.GUID, "on", unk1=true, 1000)
) )
case _ => ; case _ => ;
} }
@ -124,9 +124,9 @@ class SensorDeployableControl(sensor: SensorDeployable)
override def finalizeDeployable(callback: ActorRef) : Unit = { override def finalizeDeployable(callback: ActorRef) : Unit = {
super.finalizeDeployable(callback) super.finalizeDeployable(callback)
val zone = sensor.Zone val zone = sensor.Zone
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, 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 = { def DestructionAwareness(target: Deployable, attribution: PlanetSideGUID): Unit = {
Deployables.AnnounceDestroyDeployable(target, Some(1 seconds)) Deployables.AnnounceDestroyDeployable(target, Some(1 seconds))
val zone = target.Zone val zone = target.Zone
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, 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 //position the explosion effect near the bulky area of the sensor stalk
val ang = target.Orientation val ang = target.Orientation
@ -157,9 +157,9 @@ object SensorDeployableControl {
pos.z + math.cos(yRadians).toFloat * 0.875f pos.z + math.cos(yRadians).toFloat * 0.875f
) )
} }
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, 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)? //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.serverobject.repair.RepairableEntity
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.vital.resolution.ResolutionCalculations 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.types.PlanetSideGUID
import net.psforever.services.Service
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
class ShieldGeneratorDeployable(cdef: ShieldGeneratorDefinition) class ShieldGeneratorDeployable(cdef: ShieldGeneratorDefinition)
extends Deployable(cdef) extends Deployable(cdef)
with Hackable with Hackable
with JammableUnit with JammableUnit
class ShieldGeneratorDefinition extends DeployableDefinition(240) class ShieldGeneratorDefinition extends DeployableDefinition(objectId = 240)
with WithShields { with WithShields {
Packet = new ShieldGeneratorConverter Packet = new ShieldGeneratorConverter
DeployCategory = DeployableCategory.ShieldGenerators DeployCategory = DeployableCategory.ShieldGenerators
override def Initialize(obj: Deployable, context: ActorContext) = { override def Initialize(obj: Deployable, context: ActorContext): Unit = {
obj.Actor = obj.Actor =
context.actorOf(Props(classOf[ShieldGeneratorControl], obj), PlanetSideServerObject.UniqueActorName(obj)) context.actorOf(Props(classOf[ShieldGeneratorControl], obj), PlanetSideServerObject.UniqueActorName(obj))
} }
@ -39,10 +39,10 @@ class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
with JammableBehavior with JammableBehavior
with DamageableEntity with DamageableEntity
with RepairableEntity { with RepairableEntity {
def DeployableObject = gen def DeployableObject: ShieldGeneratorDeployable = gen
def JammableObject = gen def JammableObject: ShieldGeneratorDeployable = gen
def DamageableObject = gen def DamageableObject: ShieldGeneratorDeployable = gen
def RepairableObject = gen def RepairableObject: ShieldGeneratorDeployable = gen
deletionType = 1 //from DeployableBehavior deletionType = 1 //from DeployableBehavior
override def postStop(): Unit = { override def postStop(): Unit = {
@ -125,9 +125,9 @@ class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
override def StartJammeredStatus(target: Any, dur: Int): Unit = override def StartJammeredStatus(target: Any, dur: Int): Unit =
target match { target match {
case obj: PlanetSideServerObject with JammableUnit => case obj: PlanetSideServerObject with JammableUnit =>
obj.Zone.VehicleEvents ! VehicleServiceMessage( obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1) PlanetsideAttribute(obj.GUID, 27, 1)
) )
super.StartJammeredStatus(obj, dur) super.StartJammeredStatus(obj, dur)
case _ => ; case _ => ;
@ -138,9 +138,9 @@ class ShieldGeneratorControl(gen: ShieldGeneratorDeployable)
override def CancelJammeredStatus(target: Any): Unit = { override def CancelJammeredStatus(target: Any): Unit = {
target match { target match {
case obj: PlanetSideServerObject with JammableUnit if obj.Jammed => case obj: PlanetSideServerObject with JammableUnit if obj.Jammed =>
obj.Zone.VehicleEvents ! VehicleServiceMessage( obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 0) PlanetsideAttribute(obj.GUID, 27, 0)
) )
case _ => ; case _ => ;
} }
@ -160,9 +160,9 @@ object ShieldGeneratorControl {
//shields //shields
if (damageToShields) { if (damageToShields) {
val zone = target.Zone val zone = target.Zone
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, 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.SimpleResolutions
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone 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._ import scala.concurrent.duration._
@ -133,6 +134,6 @@ object TelepadControl {
} }
def TelepadError(zone: Zone, channel: String, msg: String): Unit = { 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.objects.equipment.ChargeFireModeDefinition
import net.psforever.packet.game.QuantityUpdateMessage import net.psforever.packet.game.QuantityUpdateMessage
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.SendResponse
object Tools { object Tools {
/** /**
@ -22,12 +22,9 @@ object Tools {
tool.FireMode match { tool.FireMode match {
case mode: ChargeFireModeDefinition if tool.Magazine > 0 => case mode: ChargeFireModeDefinition if tool.Magazine > 0 =>
val magazine = tool.Magazine -= mode.RoundsPerInterval val magazine = tool.Magazine -= mode.RoundsPerInterval
player.Zone.AvatarEvents ! AvatarServiceMessage( player.Zone.AvatarEvents ! MessageEnvelope(
player.Name, player.Name,
AvatarAction.SendResponse( SendResponse(QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, magazine))
Service.defaultPlayerGUID,
QuantityUpdateMessage(tool.AmmoSlot.Box.GUID, magazine)
)
) )
player.isAlive player.isAlive
case _ => 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.vital.{SimpleResolutions, StandardVehicleResistance}
import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game.TriggeredSound 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 import scala.concurrent.duration.FiniteDuration
@ -109,9 +110,10 @@ abstract class TurretDeployableControl
case player: Player => case player: Player =>
seat.unmount(player) seat.unmount(player)
player.VehicleSeated = None player.VehicleSeated = None
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, 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.transfer.TransferContainer
import net.psforever.objects.serverobject.structures.WarpGate import net.psforever.objects.serverobject.structures.WarpGate
import net.psforever.objects.vehicles._ import net.psforever.objects.vehicles._
import net.psforever.objects.vehicles.control.CargoBehavior
import net.psforever.objects.zones.Zone 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.types.{ChatMessageType, DriveState, PlanetSideEmpire, PlanetSideGUID, Vector3}
import net.psforever.services.Service import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.{GenericObjectAction, PlanetsideAttribute, SendResponse, SetEmpire}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.LocalAction
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.VehicleAction
import scala.collection.mutable.ArrayBuffer
//import scala.concurrent.duration._ //import scala.concurrent.duration._
@ -45,9 +48,10 @@ object Vehicles {
val locked = VehicleLockState.Locked.id val locked = VehicleLockState.Locked.id
Array(0, 3).foreach(group => vehicle.PermissionGroup(group, locked)) Array(0, 3).foreach(group => vehicle.PermissionGroup(group, locked))
Vehicles.ReloadAccessPermissions(vehicle, tplayer.Faction.toString) Vehicles.ReloadAccessPermissions(vehicle, tplayer.Faction.toString)
vehicle.Zone.VehicleEvents ! VehicleServiceMessage( vehicle.Zone.VehicleEvents ! MessageEnvelope(
vehicle.Zone.id, vehicle.Zone.id,
VehicleAction.Ownership(tplayer.GUID, vehicle.GUID) tplayer.GUID,
VehicleAction.Ownership(vehicle.GUID)
) )
Some(vehicle) Some(vehicle)
case None => case None =>
@ -88,9 +92,9 @@ object Vehicles {
val empire = VehicleLockState.Empire.id val empire = VehicleLockState.Empire.id
(0 to 2).foreach(group => vehicle.PermissionGroup(group, empire)) (0 to 2).foreach(group => vehicle.PermissionGroup(group, empire))
ReloadAccessPermissions(vehicle, vehicle.Faction.toString) ReloadAccessPermissions(vehicle, vehicle.Faction.toString)
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, zone.id,
VehicleAction.LoseOwnership(ownerGuid.getOrElse(Service.defaultPlayerGUID), guid) VehicleAction.LoseOwnership(ownerGuid.getOrElse(Default.GUID0), guid)
) )
result result
} }
@ -138,13 +142,14 @@ object Vehicles {
val pguid = player.GUID val pguid = player.GUID
if (vehicle.OwnerGuid.contains(pguid)) { if (vehicle.OwnerGuid.contains(pguid)) {
vehicle.AssignOwnership(None) 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 vguid = vehicle.GUID
val empire = VehicleLockState.Empire.id val empire = VehicleLockState.Empire.id
(0 to 2).foreach(group => { (0 to 2).foreach(group => {
vehicle.PermissionGroup(group, empire) vehicle.PermissionGroup(group, empire)
/*vehicle.Zone.VehicleEvents ! VehicleServiceMessage( /*vehicle.Zone.VehicleEvents ! MessageEnvelope(
s"${vehicle.Faction}", s"${vehicle.Faction}",
pguid,
VehicleAction.SeatPermissions(pguid, vguid, group, empire) VehicleAction.SeatPermissions(pguid, vguid, group, empire)
)*/ )*/
}) })
@ -167,9 +172,9 @@ object Vehicles {
def ReloadAccessPermissions(vehicle: Vehicle, toChannel: String): Unit = { def ReloadAccessPermissions(vehicle: Vehicle, toChannel: String): Unit = {
val vehicle_guid = vehicle.GUID val vehicle_guid = vehicle.GUID
(0 to 3).foreach(group => { (0 to 3).foreach(group => {
vehicle.Zone.AvatarEvents ! AvatarServiceMessage( vehicle.Zone.AvatarEvents ! MessageEnvelope(
toChannel, 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 hFaction = hacker.Faction
val zone = target.Zone val zone = target.Zone
val zoneid = zone.id val zoneid = zone.id
val avatarEvents = zone.AvatarEvents
val vehicleEvents = zone.VehicleEvents val vehicleEvents = zone.VehicleEvents
val localEvents = zone.LocalEvents
val previousOwnerName = target.OwnerName.getOrElse("") val previousOwnerName = target.OwnerName.getOrElse("")
vehicleEvents ! VehicleServiceMessage( val occupantMessages: ArrayBuffer[MessageEnvelope] = ArrayBuffer()
val vehicleMessages: ArrayBuffer[MessageEnvelope] = ArrayBuffer()
vehicleMessages.append(MessageEnvelope(
zoneid, zoneid,
VehicleAction.SendResponse( SendResponse(HackMessage(HackState1.Unk2, tGuid, hGuid, 100, 0f, HackState.Hacked, HackState7.Unk8))
Service.defaultPlayerGUID, ))
HackMessage(HackState1.Unk2, tGuid, hGuid, 100, 0f, HackState.Hacked, HackState7.Unk8)
)
)
target.Actor ! CommonMessages.Hack(hacker, target) target.Actor ! CommonMessages.Hack(hacker, target)
// Forcefully dismount any cargo // Forcefully dismount any cargo
target.CargoHolds.foreach { case (_, cargoHold) => target.CargoHolds.foreach { case (_, cargoHold) =>
@ -269,24 +273,29 @@ object Vehicles {
player: Player => player: Player =>
seat.unmount(player) seat.unmount(player)
player.VehicleSeated = None player.VehicleSeated = None
vehicleEvents ! VehicleServiceMessage( occupantMessages.append(MessageEnvelope(
zoneid, 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 // In case BFR is occupied and may or may not be crouched
if (GlobalDefinitions.isBattleFrameVehicle(target.Definition) && target.Seat(0).isDefined) { if (GlobalDefinitions.isBattleFrameVehicle(target.Definition) && target.Seat(0).isDefined) {
zone.LocalEvents ! LocalServiceMessage( vehicleMessages.appendAll(List(
zoneid, MessageEnvelope(zoneid,
LocalAction.SendGenericObjectActionMessage(PlanetSideGUID(-1), target.GUID, GenericObjectActionEnum.BFRShieldsDown)) GenericObjectAction(target.GUID, GenericObjectActionEnum.BFRShieldsDown.id)
zone.LocalEvents ! LocalServiceMessage( ),
zoneid, MessageEnvelope(zoneid,
LocalAction.SendResponse( 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))) 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( MessageEnvelope(zoneid,
VehicleStateMessage(target.GUID, 0, target.Position, target.Orientation, Some(Vector3(0f, 0f, 0f)), None, 0, 0, 15, is_decelerating=false, is_cloaked=false))) 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 // 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) Vehicles.Own(target, hacker)
//todo: Send HackMessage -> HackCleared to vehicle? can be found in packet captures. Not sure if necessary. //todo: Send HackMessage -> HackCleared to vehicle? can be found in packet captures. Not sure if necessary.
// And broadcast the faction change to other clients // And broadcast the faction change to other clients
zone.AvatarEvents ! AvatarServiceMessage( vehicleMessages.append(MessageEnvelope(zoneid, SetEmpire(tGuid, hFaction)))
zoneid,
AvatarAction.SetEmpire(Service.defaultPlayerGUID, tGuid, hFaction)
)
} }
localEvents ! LocalServiceMessage( vehicleMessages.append(MessageEnvelope(
zoneid, 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))) { if (zone.Players.exists(_.name.equals(previousOwnerName))) {
localEvents ! LocalServiceMessage( vehicleMessages.append(MessageEnvelope(previousOwnerName, SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackStolen"))))
previousOwnerName,
LocalAction.SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackStolen"))
)
} }
localEvents ! LocalServiceMessage( occupantMessages.append(MessageEnvelope(hacker.Name, SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackVehicleOwned"))))
hacker.Name,
LocalAction.SendResponse(ChatMsg(ChatMessageType.UNK_226, "@JackVehicleOwned"))
)
// Clean up after specific vehicles, e.g. remove router telepads // Clean up after specific vehicles, e.g. remove router telepads
// If AMS is deployed, swap it to the new faction // If AMS is deployed, swap it to the new faction
target.Definition match { target.Definition match {
@ -341,16 +342,15 @@ object Vehicles {
util.Actor ! TelepadLike.Activate(util) util.Actor ! TelepadLike.Activate(util)
} }
case GlobalDefinitions.ams if target.DeploymentState == DriveState.Deployed => case GlobalDefinitions.ams if target.DeploymentState == DriveState.Deployed =>
vehicleEvents ! VehicleServiceMessage.AMSDeploymentChange(zone) vehicleMessages.append(MessageEnvelope(zone.id, VehicleAction.AMSDeploymentChange(zone)))
case _ => () case _ => ()
} }
vehicleEvents ! VehicleServiceMessage( vehicleMessages.append(MessageEnvelope(
zoneid, zoneid,
VehicleAction.SendResponse( SendResponse(HackMessage(HackState1.Unk2, tGuid, tGuid, 0, 1L, HackState.HackCleared, HackState7.Unk8))
Service.defaultPlayerGUID, ))
HackMessage(HackState1.Unk2, tGuid, tGuid, 0, 1L, HackState.HackCleared, HackState7.Unk8) avatarEvents ! BundledEnvelope(occupantMessages)
) vehicleEvents ! BundledEnvelope(vehicleMessages)
)
target.Actor ! CommonMessages.ClearHack() target.Actor ! CommonMessages.ClearHack()
} }

View file

@ -4,7 +4,6 @@ package net.psforever.objects.avatar
import akka.actor.{Actor, ActorRef} import akka.actor.{Actor, ActorRef}
import net.psforever.actors.zone.ShootingRangeTargetSpawner import net.psforever.actors.zone.ShootingRangeTargetSpawner
import net.psforever.objects.{GlobalDefinitions, Tool} import net.psforever.objects.{GlobalDefinitions, Tool}
import net.psforever.objects.avatar.AvatarBot
import net.psforever.objects.equipment._ import net.psforever.objects.equipment._
import net.psforever.objects.serverobject.aura.{Aura, AuraEffectBehavior} import net.psforever.objects.serverobject.aura.{Aura, AuraEffectBehavior}
import net.psforever.objects.serverobject.CommonMessages 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.objects.zones._
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.types._ import net.psforever.types._
import net.psforever.services.Service import net.psforever.services.avatar.AvatarAction
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment
import net.psforever.objects.serverobject.repair.Repairable import net.psforever.objects.serverobject.repair.Repairable
import net.psforever.objects.sourcing.PlayerSource import net.psforever.objects.sourcing.PlayerSource
import net.psforever.objects.vital.{HealFromEquipment, RepairFromEquipment} import net.psforever.objects.vital.{HealFromEquipment, RepairFromEquipment}
import net.psforever.objects.vital.etc.SuicideReason import net.psforever.objects.vital.etc.SuicideReason
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult} 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 java.util.concurrent.{Executors, TimeUnit}
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._ import scala.concurrent.duration._
import scala.util.Random import scala.util.Random
@ -53,7 +51,7 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
def InteractiveObject: AvatarBot = bot 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[this] val damageLog = org.log4s.getLogger(Damageable.LogChannel)
private val scheduler = Executors.newScheduledThreadPool(2) private val scheduler = Executors.newScheduledThreadPool(2)
/** suffocating, or regaining breath? */ /** suffocating, or regaining breath? */
@ -107,14 +105,13 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
if (!(bot.isMoving || user.isMoving)) { //only allow stationary heals if (!(bot.isMoving || user.isMoving)) { //only allow stationary heals
val newHealth = bot.Health = originalHealth + 10 val newHealth = bot.Health = originalHealth + 10
val magazine = item.Discharge() val magazine = item.Discharge()
events ! AvatarServiceMessage( events ! MessageEnvelope(
uname, uname,
AvatarAction.SendResponse( SendResponse(
Service.defaultPlayerGUID,
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong) 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( bot.LogActivity(
HealFromEquipment( HealFromEquipment(
PlayerSource(user), PlayerSource(user),
@ -124,10 +121,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
) )
} }
//progress bar remains visible for all heal attempts //progress bar remains visible for all heal attempts
events ! AvatarServiceMessage( events ! MessageEnvelope(
uname, uname,
AvatarAction.SendResponse( SendResponse(
Service.defaultPlayerGUID,
RepairMessage(guid, bot.Health * 100 / definition.MaxHealth) RepairMessage(guid, bot.Health * 100 / definition.MaxHealth)
) )
) )
@ -150,14 +146,13 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
val newArmor = bot.Armor = val newArmor = bot.Armor =
originalArmor + Repairable.applyLevelModifier(user, item, RepairToolValue(item)).toInt + definition.RepairMod originalArmor + Repairable.applyLevelModifier(user, item, RepairToolValue(item)).toInt + definition.RepairMod
val magazine = item.Discharge() val magazine = item.Discharge()
events ! AvatarServiceMessage( events ! MessageEnvelope(
uname, uname,
AvatarAction.SendResponse( SendResponse(
Service.defaultPlayerGUID,
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong) 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( bot.LogActivity(
RepairFromEquipment( RepairFromEquipment(
PlayerSource(user), PlayerSource(user),
@ -167,10 +162,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
) )
} }
//progress bar remains visible for all repair attempts //progress bar remains visible for all repair attempts
events ! AvatarServiceMessage( events ! MessageEnvelope(
uname, uname,
AvatarAction SendResponse(RepairMessage(guid, bot.Armor * 100 / bot.MaxArmor))
.SendResponse(Service.defaultPlayerGUID, RepairMessage(guid, bot.Armor * 100 / bot.MaxArmor))
) )
} }
@ -231,9 +225,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
//always do armor update //always do armor update
if (damageToArmor > 0) { if (damageToArmor > 0) {
val zone = target.Zone val zone = target.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.PlanetsideAttributeToAll(target.GUID, 4, target.Armor) PlanetsideAttribute(target.GUID, 4, target.Armor)
) )
} }
//choose //choose
@ -280,16 +274,13 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
announceConfrontation = true //TODO should we? announceConfrontation = true //TODO should we?
} }
if (damageToHealth > 0) { if (damageToHealth > 0) {
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 0, health)) events ! MessageEnvelope(zoneId, PlanetsideAttribute(targetGUID, 0, health))
announceConfrontation = true announceConfrontation = true
} }
val countableDamage = damageToHealth + damageToArmor val countableDamage = damageToHealth + damageToArmor
if(announceConfrontation) { if(announceConfrontation) {
if (aggravated) { if (aggravated) {
events ! AvatarServiceMessage( events ! MessageEnvelope(zoneId, targetGUID, SendResponse(AggravatedDamageMessage(targetGUID, countableDamage)))
zoneId,
AvatarAction.SendResponse(targetGUID, AggravatedDamageMessage(targetGUID, countableDamage))
)
} else { } else {
//activity on map //activity on map
zone.Activity ! Zone.HotSpot.Activity(cause) zone.Activity ! Zone.HotSpot.Activity(cause)
@ -332,22 +323,22 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
cause.adversarial match { cause.adversarial match {
case Some(a) => case Some(a) =>
damageLog.info(s"${a.defender.Name} was killed by ${a.attacker.Name}") damageLog.info(s"${a.defender.Name} was killed by ${a.attacker.Name}")
events ! AvatarServiceMessage( events ! MessageEnvelope(
zoneChannel, zoneChannel,
AvatarAction.DestroyDisplay(a.attacker, a.defender, a.implement) AvatarAction.DestroyDisplay(a.attacker, a.defender, a.implement)
) )
case _ => case _ =>
damageLog.info(s"${bot.Name} killed ${bot.Sex.pronounObject}self") 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 ! MessageEnvelope(nameChannel, bot_guid, AvatarAction.Killed(cause, None)) //align client interface fields with state
events ! AvatarServiceMessage(zoneChannel, AvatarAction.PlanetsideAttributeToAll(bot_guid, 0, 0)) //health events ! MessageEnvelope(zoneChannel, PlanetsideAttribute(bot_guid, 0, 0)) //health
val attribute = DamageableEntity.attributionTo(cause, target.Zone, bot_guid) val attribute = DamageableEntity.attributionTo(cause, target.Zone, bot_guid)
events ! AvatarServiceMessage( events ! MessageEnvelope(
nameChannel, nameChannel,
AvatarAction.SendResponse( bot_guid,
bot_guid, SendResponse(
DestroyMessage(bot_guid, attribute, bot_guid, pos) DestroyMessage(bot_guid, attribute, bot_guid, pos)
) //how many players get this message? ) //how many players get this message?
) )
@ -402,13 +393,13 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
private def performEmote(): Unit = { private def performEmote(): Unit = {
val zone = bot.Zone val zone = bot.Zone
zone.blockMap.sector(bot).livePlayerList.collect { t => 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 = { private def tickLogic(): Unit = {
val zone = bot.Zone val zone = bot.Zone
if (!bot.Destroyed && zone.AllPlayers.size > 0) { if (!bot.Destroyed && zone.AllPlayers.nonEmpty) {
bot.zoneInteractions() bot.zoneInteractions()
val rotateRNG = Random.nextDouble() val rotateRNG = Random.nextDouble()
if (canRotate) { if (canRotate) {
@ -424,10 +415,10 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
) )
} }
} }
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
bot.GUID,
AvatarAction.PlayerState( AvatarAction.PlayerState(
bot.GUID,
bot.Position, bot.Position,
bot.Velocity, bot.Velocity,
bot.Orientation.z, bot.Orientation.z,
@ -436,10 +427,10 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
0, 0,
bot.Crouching, bot.Crouching,
bot.Jumping, bot.Jumping,
false, jump_thrust = false,
bot.Cloaked, is_cloaked = bot.Cloaked,
false, spectator = false,
false weaponInHand = false
) )
) )
if (canEmote) { if (canEmote) {
@ -469,9 +460,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
override def StartJammeredSound(target: Any, dur: Int): Unit = override def StartJammeredSound(target: Any, dur: Int): Unit =
target match { target match {
case obj: AvatarBot if !jammedSound => case obj: AvatarBot if !jammedSound =>
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 1) PlanetsideAttribute(obj.GUID, 27, 1)
) )
super.StartJammeredSound(obj, 3000) super.StartJammeredSound(obj, 3000)
case _ => ; case _ => ;
@ -502,9 +493,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
override def CancelJammeredSound(target: Any): Unit = override def CancelJammeredSound(target: Any): Unit =
target match { target match {
case obj: AvatarBot if jammedSound => case obj: AvatarBot if jammedSound =>
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 0) PlanetsideAttribute(obj.GUID, 27, 0)
) )
super.CancelJammeredSound(obj) super.CancelJammeredSound(obj)
case _ => ; case _ => ;
@ -521,10 +512,9 @@ class AvatarBotActor(bot: AvatarBot, spawnerActor: ActorRef)
} }
def UpdateAuraEffect(target: AuraEffectBehavior.Target) : Unit = { def UpdateAuraEffect(target: AuraEffectBehavior.Target) : Unit = {
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
val zone = target.Zone val zone = target.Zone
val value = target.Aura.foldLeft(0)(_ + AvatarBotActor.auraEffectToAttributeValue(_)) 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.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage}
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.{ObjectDelete, SendResponse}
class CorpseControl(player: Player) extends Actor with ContainableBehavior { class CorpseControl(player: Player) extends Actor with ContainableBehavior {
def ContainerObject = player def ContainerObject = player
@ -25,9 +25,9 @@ class CorpseControl(player: Player) extends Actor with ContainableBehavior {
val obj = ContainerObject val obj = ContainerObject
obj.Find(item) match { obj.Find(item) match {
case Some(slot) => case Some(slot) =>
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
player.Zone.id, player.Zone.id,
AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectAttachMessage(obj.GUID, item.GUID, slot)) SendResponse(ObjectAttachMessage(obj.GUID, item.GUID, slot))
) )
case None => ; case None => ;
} }
@ -40,7 +40,7 @@ class CorpseControl(player: Player) extends Actor with ContainableBehavior {
val zone = obj.Zone val zone = obj.Zone
val events = zone.AvatarEvents val events = zone.AvatarEvents
item.Faction = PlanetSideEmpire.NEUTRAL 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 = { def PutItemInSlotCallback(item: Equipment, slot: Int): Unit = {
@ -48,10 +48,9 @@ class CorpseControl(player: Player) extends Actor with ContainableBehavior {
val zone = obj.Zone val zone = obj.Zone
val events = zone.AvatarEvents val events = zone.AvatarEvents
val definition = item.Definition val definition = item.Definition
events ! AvatarServiceMessage( events ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.SendResponse( SendResponse(
Service.defaultPlayerGUID,
ObjectCreateDetailedMessage( ObjectCreateDetailedMessage(
definition.ObjectId, definition.ObjectId,
item.GUID, item.GUID,
@ -65,12 +64,9 @@ class CorpseControl(player: Player) extends Actor with ContainableBehavior {
def SwapItemCallback(item: Equipment, fromSlot: Int): Unit = { def SwapItemCallback(item: Equipment, fromSlot: Int): Unit = {
val obj = ContainerObject val obj = ContainerObject
val zone = obj.Zone val zone = obj.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.SendResponse( SendResponse(ObjectDetachMessage(obj.GUID, item.GUID, Vector3.Zero, 0f))
Service.defaultPlayerGUID,
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._
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.types._ import net.psforever.types._
import net.psforever.services.Service import net.psforever.services.avatar.AvatarAction
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.local.LocalAction
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import net.psforever.objects.locker.LockerContainerControl import net.psforever.objects.locker.LockerContainerControl
import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment import net.psforever.objects.serverobject.environment.interaction.RespondsToZoneEnvironment
import net.psforever.objects.serverobject.repair.Repairable 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.etc.{PainboxReason, SuicideReason}
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult} import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.packet.PlanetSideGamePacket 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 org.joda.time.{LocalDateTime, Seconds}
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -125,7 +126,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val zoneId = zone.id val zoneId = zone.id
sendResponse(zone, zoneId, PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health)) 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, 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.InitializeImplants
avatarActor ! AvatarActor.SuspendStaminaRegeneration(Duration(1, "second")) 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 if (!(player.isMoving || user.isMoving)) { //only allow stationary heals
val newHealth = player.Health = originalHealth + 10 val newHealth = player.Health = originalHealth + 10
val magazine = item.Discharge() val magazine = item.Discharge()
events ! AvatarServiceMessage( events ! MessageEnvelope(
uname, uname,
AvatarAction.SendResponse( SendResponse(InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong))
Service.defaultPlayerGUID,
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( player.LogActivity(
HealFromEquipment( HealFromEquipment(
PlayerSource(user), PlayerSource(user),
@ -174,14 +172,11 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
} }
if (player != user) { if (player != user) {
//"Someone is trying to heal you" //"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 //progress bar remains visible for all heal attempts
events ! AvatarServiceMessage( events ! MessageEnvelope(
uname, uname,
AvatarAction.SendResponse( SendResponse(RepairMessage(guid, player.Health * 100 / definition.MaxHealth))
Service.defaultPlayerGUID,
RepairMessage(guid, player.Health * 100 / definition.MaxHealth)
)
) )
} }
} }
@ -219,14 +214,11 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val newArmor = player.Armor = val newArmor = player.Armor =
originalArmor + Repairable.applyLevelModifier(user, item, RepairToolValue(item)).toInt + definition.RepairMod originalArmor + Repairable.applyLevelModifier(user, item, RepairToolValue(item)).toInt + definition.RepairMod
val magazine = item.Discharge() val magazine = item.Discharge()
events ! AvatarServiceMessage( events ! MessageEnvelope(
uname, uname,
AvatarAction.SendResponse( SendResponse(InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong))
Service.defaultPlayerGUID,
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( player.LogActivity(
RepairFromEquipment( RepairFromEquipment(
PlayerSource(user), PlayerSource(user),
@ -247,16 +239,15 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
if (player != user) { if (player != user) {
if (player.isAlive) { if (player.isAlive) {
//"Someone is trying to repair you" gets strobed twice for visibility //"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 events ! msg
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
context.system.scheduler.scheduleOnce(250 milliseconds, events, msg) context.system.scheduler.scheduleOnce(250 milliseconds, events, msg)
} }
//progress bar remains visible for all repair attempts //progress bar remains visible for all repair attempts
events ! AvatarServiceMessage( events ! MessageEnvelope(
uname, uname,
AvatarAction SendResponse(RepairMessage(guid, player.Armor * 100 / player.MaxArmor))
.SendResponse(Service.defaultPlayerGUID, RepairMessage(guid, player.Armor * 100 / player.MaxArmor))
) )
} }
} }
@ -321,16 +312,16 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
avatarActor ! AvatarActor.UpdateUseTime(kdef) avatarActor ! AvatarActor.UpdateUseTime(kdef)
player.Slot(slot).Equipment = None //remove from slot immediately; must exist on client for now player.Slot(slot).Equipment = None //remove from slot immediately; must exist on client for now
TaskWorkflow.execute(GUIDTask.unregisterEquipment(zone.GUID, kit)) TaskWorkflow.execute(GUIDTask.unregisterEquipment(zone.GUID, kit))
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.PlanetsideAttributeToAll(player.GUID, attribute, value) PlanetsideAttribute(player.GUID, attribute, value)
) )
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
player.Name, player.Name,
AvatarAction.UseKit(kguid, kdef.ObjectId) AvatarAction.UseKit(kguid, kdef.ObjectId)
) )
case _ => case _ =>
player.Zone.AvatarEvents ! AvatarServiceMessage( player.Zone.AvatarEvents ! MessageEnvelope(
player.Name, player.Name,
AvatarAction.KitNotUsed(kit.GUID, msg) AvatarAction.KitNotUsed(kit.GUID, msg)
) )
@ -344,15 +335,17 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val events = player.Zone.AvatarEvents val events = player.Zone.AvatarEvents
val resistance = player.TestArmMotion(slot) val resistance = player.TestArmMotion(slot)
if (resistance && !updateMyHolsterArm) { if (resistance && !updateMyHolsterArm) {
events ! AvatarServiceMessage( events ! MessageEnvelope(
player.Name, 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) { } else if ((!resistance && before != slot && (player.DrawnSlot = slot) != before) && ItemSwapSlot != before) {
val mySlot = if (updateMyHolsterArm) slot else -1 //use as a short-circuit val mySlot = if (updateMyHolsterArm) slot else -1 //use as a short-circuit
events ! AvatarServiceMessage( events ! MessageEnvelope(
Players.ZoneChannelIfSpectating(player), Players.ZoneChannelIfSpectating(player),
AvatarAction.ObjectHeld(player.GUID, mySlot, player.LastDrawnSlot) player.GUID,
AvatarAction.ObjectHeld(mySlot, player.LastDrawnSlot)
) )
val isHolsters = player.VisibleSlots.contains(slot) val isHolsters = player.VisibleSlots.contains(slot)
val equipment = player.Slot(slot).Equipment.orElse { player.Slot(before).Equipment } 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") log.info(s"${player.Name} has drawn a ${unholsteredItem.Definition.Name} from its holster")
if (unholsteredItem.Definition == GlobalDefinitions.remote_electronics_kit) { if (unholsteredItem.Definition == GlobalDefinitions.remote_electronics_kit) {
//rek beam/icon colour must match the player's correct hack level //rek beam/icon colour must match the player's correct hack level
events ! AvatarServiceMessage( events ! MessageEnvelope(
Players.ZoneChannelIfSpectating(player), Players.ZoneChannelIfSpectating(player),
AvatarAction.PlanetsideAttribute(unholsteredItem.GUID, 116, player.avatar.hackingSkillLevel()) unholsteredItem.GUID,
PlanetsideAttribute(unholsteredItem.GUID, 116, player.avatar.hackingSkillLevel())
) )
} }
case None => () 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 //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 && 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.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 => case None =>
log.info(s"${player.Name} lowers ${player.Sex.possessive} hand") 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) { if (exosuit == ExoSuitType.MAX) {
player.ResistArmMotion(PlayerControl.maxRestriction) player.ResistArmMotion(PlayerControl.maxRestriction)
} }
player.Zone.AvatarEvents ! AvatarServiceMessage( player.Zone.AvatarEvents ! MessageEnvelope(
player.Name, player.Name,
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result) 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) Deployables.initializeConstructionItem(player.avatar.certifications, citem)
} }
val zone = player.Zone val zone = player.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
Players.ZoneChannelIfSpectating(player), Players.ZoneChannelIfSpectating(player),
AvatarAction.ChangeLoadout( AvatarAction.ChangeLoadout(
player.GUID, player.GUID,
@ -548,7 +546,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
itemsToDrop itemsToDrop
) )
) )
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
player.Name, player.Name,
AvatarAction.TerminalOrderResult(msg.terminal_guid, msg.transaction_type, result=true) 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) => 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") log.warn(s"${player.Name} failed to pick up an item ($item_guid) from the ground because $reason")
if (reason.startsWith("@")) { if (reason.startsWith("@")) {
player.Zone.AvatarEvents ! AvatarServiceMessage( player.Zone.AvatarEvents ! MessageEnvelope(
player.Name, 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 val trigger = new BoomerTrigger
trigger.Companion = obj.GUID trigger.Companion = obj.GUID
obj.Trigger = trigger 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)) TaskWorkflow.execute(GUIDTask.unregisterEquipment(zone.GUID, tool))
player.Find(tool) match { player.Find(tool) match {
case Some(index) if player.VisibleSlots.contains(index) => 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) => case Player.LoseDeployable(obj) =>
if (player.avatar.deployables.Remove(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 _ => ; case _ => ;
@ -722,7 +720,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
//insert //insert
afterHolsters.foreach(elem => player.Slot(elem.start).Equipment = elem.obj) afterHolsters.foreach(elem => player.Slot(elem.start).Equipment = elem.obj)
afterInventory.foreach(elem => player.Inventory.InsertQuickly(elem.start, elem.obj)) afterInventory.foreach(elem => player.Inventory.InsertQuickly(elem.start, elem.obj))
player.Zone.AvatarEvents ! AvatarServiceMessage( player.Zone.AvatarEvents ! MessageEnvelope(
Players.ZoneChannelIfSpectating(player), Players.ZoneChannelIfSpectating(player),
AvatarAction.ChangeExosuit( AvatarAction.ChangeExosuit(
player.GUID, player.GUID,
@ -748,7 +746,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
def loseDeployableOwnership(obj: Deployable): Boolean = { def loseDeployableOwnership(obj: Deployable): Boolean = {
if (player.avatar.deployables.Remove(obj)) { if (player.avatar.deployables.Remove(obj)) {
obj.Actor ! Deployable.Ownership(None) 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 true
} }
else { else {
@ -769,18 +767,15 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case GlobalDefinitions.router_telepad => () /* no special animation */ case GlobalDefinitions.router_telepad => () /* no special animation */
case GlobalDefinitions.ace case GlobalDefinitions.ace
if obj.Definition.deployAnimation == DeployAnimation.Standard => if obj.Definition.deployAnimation == DeployAnimation.Standard =>
zone.LocalEvents ! LocalServiceMessage( val ownerGuid = obj.OwnerGuid.getOrElse(Default.GUID0)
zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.TriggerEffectLocation( ownerGuid,
obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID), LocalAction.TriggerEffectLocation("spawn_object_effect", obj.Position, obj.Orientation)
"spawn_object_effect",
obj.Position,
obj.Orientation
)
) )
case GlobalDefinitions.advanced_ace case GlobalDefinitions.advanced_ace
if obj.Definition.deployAnimation == DeployAnimation.Fdu => 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 _ => case _ =>
org.log4s org.log4s
.getLogger(name = "Deployables") .getLogger(name = "Deployables")
@ -883,9 +878,9 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
//always do armor update //always do armor update
if (damageToArmor > 0) { if (damageToArmor > 0) {
val zone = target.Zone val zone = target.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.PlanetsideAttributeToAll(target.GUID, 4, target.Armor) PlanetsideAttribute(target.GUID, 4, target.Armor)
) )
} }
//choose //choose
@ -941,10 +936,7 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
target.LogActivity(cause) target.LogActivity(cause)
//stat changes //stat changes
if (damageToCapacitor > 0) { if (damageToCapacitor > 0) {
events ! AvatarServiceMessage( events ! MessageEnvelope(target.Name, PlanetsideAttribute(targetGUID, 7, target.Capacitor.toLong))
target.Name,
AvatarAction.PlanetsideAttributeSelf(targetGUID, 7, target.Capacitor.toLong)
)
announceConfrontation = true //TODO should we? announceConfrontation = true //TODO should we?
} }
if (damageToStamina > 0) { if (damageToStamina > 0) {
@ -952,15 +944,15 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
announceConfrontation = true //TODO should we? announceConfrontation = true //TODO should we?
} }
if (damageToHealth > 0) { if (damageToHealth > 0) {
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 0, health)) events ! MessageEnvelope(zoneId, PlanetsideAttribute(targetGUID, 0, health))
announceConfrontation = true announceConfrontation = true
} }
val countableDamage = damageToHealth + damageToArmor val countableDamage = damageToHealth + damageToArmor
if(announceConfrontation) { if(announceConfrontation) {
if (aggravated) { if (aggravated) {
events ! AvatarServiceMessage( events ! MessageEnvelope(
zoneId, zoneId,
AvatarAction.SendResponse(Service.defaultPlayerGUID, AggravatedDamageMessage(targetGUID, countableDamage)) SendResponse(AggravatedDamageMessage(targetGUID, countableDamage))
) )
} else { } else {
//activity on map //activity on map
@ -973,42 +965,37 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
val name = pSource.Name val name = pSource.Name
zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match { zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
case Some(tplayer) => case Some(tplayer) =>
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
target.Name, target.Name,
AvatarAction.HitHint(tplayer.GUID, target.GUID) target.GUID,
HintsAtAttacker(tplayer.GUID)
) )
case None => case None =>
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
target.Name, target.Name,
AvatarAction.SendResponse( SendResponse(DamageWithPositionMessage(countableDamage, pSource.Position))
Service.defaultPlayerGUID,
DamageWithPositionMessage(countableDamage, pSource.Position)
)
) )
} }
case source => case source =>
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
target.Name, target.Name,
AvatarAction.SendResponse( SendResponse(DamageWithPositionMessage(countableDamage, source.Position))
Service.defaultPlayerGUID,
DamageWithPositionMessage(countableDamage, source.Position)
)
) )
} }
case None => case None =>
cause.interaction.cause match { cause.interaction.cause match {
case o: PainboxReason => case o: PainboxReason =>
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
target.Name, target.Name,
AvatarAction.EnvironmentalDamage(target.GUID, o.entity.GUID, countableDamage) AvatarAction.EnvironmentalDamage(target.GUID, o.entity.GUID, countableDamage)
) )
case _: CollisionReason => case _: CollisionReason =>
events ! AvatarServiceMessage( events ! MessageEnvelope(
zoneId, zoneId,
AvatarAction.SendResponse(Service.defaultPlayerGUID, AggravatedDamageMessage(targetGUID, countableDamage)) SendResponse(AggravatedDamageMessage(targetGUID, countableDamage))
) )
case _ => case _ =>
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
target.Name, target.Name,
AvatarAction.EnvironmentalDamage(target.GUID, ValidPlanetSideGUID(0), countableDamage) 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") 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 ! MessageEnvelope(nameChannel, player_guid, AvatarAction.Killed(cause, target.VehicleSeated)) //align client interface fields with state
events ! AvatarServiceMessage(zoneChannel, AvatarAction.PlanetsideAttributeToAll(player_guid, 0, 0)) //health events ! MessageEnvelope(zoneChannel, PlanetsideAttribute(player_guid, 0, 0)) //health
if (target.Capacitor > 0) { if (target.Capacitor > 0) {
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) val attribute = DamageableEntity.attributionTo(cause, target.Zone, player_guid)
events ! AvatarServiceMessage( events ! MessageEnvelope(
nameChannel, nameChannel,
AvatarAction.SendResponse( SendResponse(DestroyMessage(player_guid, attribute, Default.GUID0, pos)) //how many players get this message?
Service.defaultPlayerGUID,
DestroyMessage(player_guid, attribute, Service.defaultPlayerGUID, 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 = override def StartJammeredSound(target: Any, dur: Int): Unit =
target match { target match {
case obj: Player if !jammedSound => case obj: Player if !jammedSound =>
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 1) PlanetsideAttribute(obj.GUID, 27, 1)
) )
super.StartJammeredSound(obj, 3000) 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 = override def CancelJammeredSound(target: Any): Unit =
target match { target match {
case obj: Player if jammedSound => case obj: Player if jammedSound =>
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
AvatarAction.PlanetsideAttributeToAll(obj.GUID, 27, 0) PlanetsideAttribute(obj.GUID, 27, 0)
) )
super.CancelJammeredSound(obj) super.CancelJammeredSound(obj)
case _ => ; case _ => ()
} }
def RepairToolValue(item: Tool): Float = { def RepairToolValue(item: Tool): Float = {
@ -1167,9 +1151,9 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
obj.Find(item) match { obj.Find(item) match {
case Some(slot) => case Some(slot) =>
PutItemInSlotCallback(item, 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) { if (slot == obj.DrawnSlot) {
obj.DrawnSlot = Player.HandsDownSlot 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 = { def PutItemInSlotCallback(item: Equipment, slot: Int): Unit = {
@ -1209,10 +1193,10 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case Some(obj: BoomerDeployable) => case Some(obj: BoomerDeployable) =>
val deployables = player.avatar.deployables val deployables = player.avatar.deployables
if (!deployables.Contains(obj) && deployables.Valid(obj)) { if (!deployables.Contains(obj) && deployables.Valid(obj)) {
events ! AvatarServiceMessage(toChannel, AvatarAction.SendResponse( events ! MessageEnvelope(
Service.defaultPlayerGUID, toChannel,
GenericObjectAction2Message(1, player.GUID, trigger.GUID) SendResponse(GenericObjectAction2Message(1, player.GUID, trigger.GUID))
)) )
Players.gainDeployableOwnership(player, obj, deployables.AddOverLimit) Players.gainDeployableOwnership(player, obj, deployables.AddOverLimit)
} }
case _ => () case _ => ()
@ -1228,15 +1212,12 @@ class PlayerControl(player: Player, avatarActor: typed.ActorRef[AvatarActor.Comm
case _ => () case _ => ()
} }
events ! AvatarServiceMessage( events ! MessageEnvelope(
toChannel, toChannel,
AvatarAction.SendResponse( SendResponse(OCM.detailed(item, ObjectCreateMessageParent(guid, slot)))
Service.defaultPlayerGUID,
OCM.detailed(item, ObjectCreateMessageParent(guid, slot))
)
) )
if (!player.isBackpack && willBeVisible) { 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 { } else {
player.Name player.Name
} }
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
toChannel, toChannel,
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, item.GUID) ObjectDelete(item.GUID)
) )
} }
def UpdateAuraEffect(target: AuraEffectBehavior.Target) : Unit = { def UpdateAuraEffect(target: AuraEffectBehavior.Target) : Unit = {
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
val zone = target.Zone val zone = target.Zone
val value = target.Aura.foldLeft(0)(_ + PlayerControl.auraEffectToAttributeValue(_)) 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 = { 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 = { def sendResponse(zone: Zone, channel: String, filter: PlanetSideGUID, msg: EventMessage): Unit = {
zone.AvatarEvents ! AvatarServiceMessage(channel, msg) zone.AvatarEvents ! MessageEnvelope(channel, filter, msg)
} }
def maxRestriction(player: Player, slot: Int): Boolean = { 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.environment.interaction.{InteractionWith, RespondsToZoneEnvironment}
import net.psforever.objects.serverobject.interior.{Sidedness, TraditionalInteriorAware} import net.psforever.objects.serverobject.interior.{Sidedness, TraditionalInteriorAware}
import net.psforever.objects.zones.interaction.InteractsWithZone 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 net.psforever.types.Vector3
import scala.annotation.unused import scala.annotation.unused
@ -90,33 +92,32 @@ class WithEntrance()
): Sidedness = { ): Sidedness = {
import net.psforever.objects.{Player, Vehicle} import net.psforever.objects.{Player, Vehicle}
import net.psforever.packet.game.ChatMsg import net.psforever.packet.game.ChatMsg
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.types.ChatMessageType
import net.psforever.types.{ChatMessageType, PlanetSideGUID}
val channel = obj match { val channel = obj match {
case p: Player => p.Name case p: Player => p.Name
case v: Vehicle => v.Actor.toString() case v: Vehicle => v.Actor.toString()
case _ => "" case _ => ""
} }
if (door.Outwards == Vector3.Zero) { if (door.Outwards == Vector3.Zero) {
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
channel, channel,
AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "Door not configured.")) SendResponse(ChatMsg(ChatMessageType.UNK_229, "Door not configured."))
) )
WhichSide WhichSide
} else { } else {
val result = Vector3.DotProduct(Vector3.Unit(obj.Position - door.Position), door.Outwards) > 0f val result = Vector3.DotProduct(Vector3.Unit(obj.Position - door.Position), door.Outwards) > 0f
if (result && WhichSide != Sidedness.OutsideOf) { if (result && WhichSide != Sidedness.OutsideOf) {
//outside //outside
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
channel, channel,
AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "You are now outside")) SendResponse(ChatMsg(ChatMessageType.UNK_229, "You are now outside"))
) )
Sidedness.OutsideOf Sidedness.OutsideOf
} else if (!result && WhichSide != Sidedness.InsideOf) { } else if (!result && WhichSide != Sidedness.InsideOf) {
//inside //inside
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
channel, channel,
AvatarAction.SendResponse(PlanetSideGUID(0), ChatMsg(ChatMessageType.UNK_229, "You are now inside")) SendResponse(ChatMsg(ChatMessageType.UNK_229, "You are now inside"))
) )
Sidedness.InsideOf Sidedness.InsideOf
} else { } 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.serverobject.shuttle.OrbitalShuttlePad
import net.psforever.objects.zones.interaction.InteractsWithZone import net.psforever.objects.zones.interaction.InteractsWithZone
import net.psforever.packet.game.{ChatMsg, PlayerStateShiftMessage, ShiftState} import net.psforever.packet.game.{ChatMsg, PlayerStateShiftMessage, ShiftState}
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.SendResponse
import net.psforever.services.hart.ShuttleState import net.psforever.services.hart.ShuttleState
import net.psforever.types.ChatMessageType import net.psforever.types.ChatMessageType
@ -35,18 +35,12 @@ class WithGantry(val channel: String)
player.VehicleSeated.isEmpty => player.VehicleSeated.isEmpty =>
val (pos, ang) = Vehicles.dismountShuttle(shuttle, field.mountPoint) val (pos, ang) = Vehicles.dismountShuttle(shuttle, field.mountPoint)
val events = shuttle.Zone.AvatarEvents val events = shuttle.Zone.AvatarEvents
events ! AvatarServiceMessage( events ! MessageEnvelope(
channel, channel,
AvatarAction.SendResponse( SendResponse(PlayerStateShiftMessage(ShiftState(0, pos, ang, None))))
Service.defaultPlayerGUID, events ! MessageEnvelope(
PlayerStateShiftMessage(ShiftState(0, pos, ang, None)))
)
events ! AvatarServiceMessage(
channel, channel,
AvatarAction.SendResponse( SendResponse(ChatMsg(ChatMessageType.UNK_227, "@Vehicle_OS_PlacedOutsideHallway"))
Service.defaultPlayerGUID,
ChatMsg(ChatMessageType.UNK_227, "@Vehicle_OS_PlacedOutsideHallway")
)
) )
case (Some(_: Vehicle) , _)=> case (Some(_: Vehicle) , _)=>
obj.Actor ! RespondsToZoneEnvironment.Timer( 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.interaction.common.Watery.OxygenStateTarget
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction} import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment, interaction}
import net.psforever.objects.zones.interaction.InteractsWithZone 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 net.psforever.types.OxygenState
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -299,7 +300,7 @@ class WithWater(val channel: String)
cond: OxygenStateTarget, cond: OxygenStateTarget,
data: Option[OxygenStateTarget] data: Option[OxygenStateTarget]
): Unit = { ): 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 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 * 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". * where `c` stands for "campaign" and `s` stands for "session".
* "Session" values reflect on the UI as the K in K/D * "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._
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game._ import net.psforever.packet.game._
import net.psforever.services.Service import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.SetEmpire
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.LocalAction
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -111,7 +111,7 @@ trait DeployableBehavior {
obj, obj,
toOwner = "", toOwner = "",
toFaction, 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() startOwnerlessDecay()
} }
@ -198,14 +198,13 @@ trait DeployableBehavior {
None None
} }
//zone build //zone build
localEvents ! LocalServiceMessage(zone.id, LocalAction.DeployItem(obj)) localEvents ! BundledEnvelope(
//zone map icon /* zone build */
localEvents ! LocalServiceMessage( MessageEnvelope(zone.id, LocalAction.DeployItem(obj)),
obj.Faction.toString, /* zone map icon */
LocalAction.DeployableMapIcon( MessageEnvelope(
Service.defaultPlayerGUID, obj.Faction.toString,
DeploymentAction.Build, LocalAction.DeployableMapIcon(DeploymentAction.Build, DeployableInfo(obj.GUID, Deployable.Icon(obj.Definition.Item), obj.Position, obj.OwnerGuid.getOrElse(Default.GUID0)))
DeployableInfo(obj.GUID, Deployable.Icon(obj.Definition.Item), obj.Position, obj.OwnerGuid.getOrElse(Service.defaultPlayerGUID))
) )
) )
//local build management //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 //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 //this deployable control agency, however, will be expiring and can not be a recipient
zone.Deployables ! Zone.Deployable.Dismiss(obj) zone.Deployables ! Zone.Deployable.Dismiss(obj)
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.EliminateDeployable(obj, obj.GUID, obj.Position, deletionType) LocalAction.EliminateDeployable(obj, obj.GUID, obj.Position, deletionType)
) )
@ -285,27 +284,21 @@ object DeployableBehavior {
val localEvents = zone.LocalEvents val localEvents = zone.LocalEvents
if (originalFaction != toFaction) { if (originalFaction != toFaction) {
obj.Faction = toFaction obj.Faction = toFaction
//visual tells in regards to ownership by faction localEvents ! BundledEnvelope(
zone.AvatarEvents ! AvatarServiceMessage( /* visual tells in regards to ownership by faction */
zone.id, MessageEnvelope(zone.id, SetEmpire(dGuid, toFaction)),
AvatarAction.SetEmpire(Service.defaultPlayerGUID, dGuid, toFaction) /* remove knowledge by the previous owner's faction */
) MessageEnvelope(originalFaction.toString, LocalAction.DeployableMapIcon(DeploymentAction.Dismiss, info)),
//remove knowledge by the previous owner's faction /* display to the given faction */
localEvents ! LocalServiceMessage( MessageEnvelope(toFaction.toString, LocalAction.DeployableMapIcon(DeploymentAction.Build, info))
originalFaction.toString,
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Dismiss, info)
) )
//remove deployable from original owner's toolbox and UI counter //remove deployable from original owner's toolbox and UI counter
zone.AllPlayers.filter(p => obj.OriginalOwnerName.contains(p.Name)) localEvents ! BundledEnvelope(zone.AllPlayers
.foreach { originalOwner => .filter(p => obj.OriginalOwnerName.contains(p.Name))
.map { originalOwner =>
originalOwner.avatar.deployables.Remove(obj) originalOwner.avatar.deployables.Remove(obj)
originalOwner.Zone.LocalEvents ! LocalServiceMessage(originalOwner.Name, LocalAction.DeployableUIFor(obj.Definition.Item)) MessageEnvelope(originalOwner.Name, LocalAction.DeployableUIFor(obj.Definition.Item))
} })
//display to the given faction
localEvents ! LocalServiceMessage(
toFaction.toString,
LocalAction.DeployableMapIcon(Service.defaultPlayerGUID, DeploymentAction.Build, info)
)
} }
} }
} }

View file

@ -9,7 +9,9 @@ import net.psforever.objects.vehicles.Utility.InternalTelepad
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{GenericObjectActionMessage, ObjectCreateMessage, ObjectDeleteMessage} import net.psforever.packet.game.{GenericObjectActionMessage, ObjectCreateMessage, ObjectDeleteMessage}
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent 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 import net.psforever.types.PlanetSideGUID
trait TelepadLike { trait TelepadLike {
@ -113,24 +115,22 @@ object TelepadLike {
normally dispatched while the Router is transitioned into its Deploying state 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 it is safe, however, to perform these actions at any time during and after the Deploying state
*/ */
events ! LocalServiceMessage( events ! BundledEnvelope(
zoneId, MessageEnvelope(
LocalAction.SendResponse( zoneId,
ObjectCreateMessage( SendResponse(
udef.ObjectId, ObjectCreateMessage(
utilityGUID, udef.ObjectId,
ObjectCreateMessageParent(routerGUID, 2), //TODO stop assuming slot number utilityGUID,
udef.Packet.ConstructorData(obj).get ObjectCreateMessageParent(routerGUID, 2), //TODO stop assuming slot number
udef.Packet.ConstructorData(obj).get
)
) )
) ),
) MessageEnvelope(zoneId, SendResponse(Seq(
events ! LocalServiceMessage( GenericObjectActionMessage(utilityGUID, 27),
zoneId, GenericObjectActionMessage(utilityGUID, 30)
LocalAction.SendResponse(GenericObjectActionMessage(utilityGUID, 27)) )))
)
events ! LocalServiceMessage(
zoneId,
LocalAction.SendResponse(GenericObjectActionMessage(utilityGUID, 30))
) )
LinkTelepad(zone, utilityGUID) LinkTelepad(zone, utilityGUID)
} }
@ -138,14 +138,10 @@ object TelepadLike {
def LinkTelepad(zone: Zone, telepadGUID: PlanetSideGUID): Unit = { def LinkTelepad(zone: Zone, telepadGUID: PlanetSideGUID): Unit = {
val events = zone.LocalEvents val events = zone.LocalEvents
val zoneId = zone.id val zoneId = zone.id
events ! LocalServiceMessage( events ! MessageEnvelope(zoneId, SendResponse(Seq(
zoneId, GenericObjectActionMessage(telepadGUID, 27),
LocalAction.SendResponse(GenericObjectActionMessage(telepadGUID, 27)) GenericObjectActionMessage(telepadGUID, 28)
) )))
events ! LocalServiceMessage(
zoneId,
LocalAction.SendResponse(GenericObjectActionMessage(telepadGUID, 28))
)
} }
def InitializeTelepadDeployable(zone: Zone, internal: InternalTelepad, pad: TelepadDeployable): Unit = { 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) oldTpad.Actor ! TelepadLike.SeverLink(obj)
} }
obj.Telepad = None 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) => case TelepadLike.RequestLink(tpad: TelepadDeployable) =>
val zone = obj.Zone val zone = obj.Zone
@ -196,7 +192,7 @@ class TelepadControl(obj: InternalTelepad) extends akka.actor.Actor {
} }
} else { } else {
val channel = obj.Owner.asInstanceOf[Vehicle].OwnerName.getOrElse("") 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) tpad.Actor ! TelepadLike.SeverLink(obj)
} }
@ -204,7 +200,7 @@ class TelepadControl(obj: InternalTelepad) extends akka.actor.Actor {
if (obj.Telepad.contains(tpad.GUID)) { if (obj.Telepad.contains(tpad.GUID)) {
obj.Telepad = None obj.Telepad = None
val zone = obj.Zone 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 _ => () 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.etc.{ArmorSiphonModifiers, ArmorSiphonReason}
import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.packet.game.QuantityUpdateMessage import net.psforever.packet.game.QuantityUpdateMessage
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
import scala.collection.mutable import scala.collection.mutable
@ -78,9 +78,9 @@ object ArmorSiphonBehavior {
if(before < after) { if(before < after) {
obj.LogActivity(RepairFromArmorSiphon(asr.siphon.Definition, VehicleSource(obj), before - after)) obj.LogActivity(RepairFromArmorSiphon(asr.siphon.Definition, VehicleSource(obj), before - after))
val zone = obj.Zone val zone = obj.Zone
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 0, after) PlanetsideAttribute(obj.GUID, 0, after)
) )
} }
case _ => ; case _ => ;
@ -97,9 +97,9 @@ object ArmorSiphonBehavior {
val siphon = siphonSlot.Equipment.get.asInstanceOf[Tool] val siphon = siphonSlot.Equipment.get.asInstanceOf[Tool]
val zone = obj.Zone val zone = obj.Zone
//update current charge level //update current charge level
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
obj.Actor.toString, 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( siphonRecharge.put(guid, context.system.scheduler.scheduleWithFixedDelay(
initialDelay = 3000 milliseconds, initialDelay = 3000 milliseconds,
@ -119,9 +119,9 @@ object ArmorSiphonBehavior {
val before = siphon.Magazine val before = siphon.Magazine
val after = siphon.Magazine = before + 1 val after = siphon.Magazine = before + 1
if (after > before) { if (after > before) {
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
obj.Actor.toString, obj.Actor.toString,
VehicleAction.SendResponse(Service.defaultPlayerGUID, QuantityUpdateMessage(siphon.AmmoSlot.Box.GUID, after)) SendResponse(QuantityUpdateMessage(siphon.AmmoSlot.Box.GUID, after))
) )
if (after == siphon.MaxMagazine) { if (after == siphon.MaxMagazine) {
endSiphonRecharge(guid) 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.interaction.DamageResult
import net.psforever.objects.vital.projectile.ProjectileReason import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.zones.{Zone, ZoneAware} 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.types.Vector3
import net.psforever.services.Service
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.collection.mutable import scala.collection.mutable
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -234,7 +234,6 @@ trait JammableBehavior {
* @see `Service` * @see `Service`
* @see `VehicleAction` * @see `VehicleAction`
* @see `VehicleService` * @see `VehicleService`
* @see `VehicleServiceMessage`
* @see `Zone.VehicleEvents` * @see `Zone.VehicleEvents`
*/ */
trait JammableMountedWeapons extends JammableBehavior { trait JammableMountedWeapons extends JammableBehavior {
@ -243,9 +242,9 @@ trait JammableMountedWeapons extends JammableBehavior {
override def StartJammeredSound(target: Any, dur: Int): Unit = { override def StartJammeredSound(target: Any, dur: Int): Unit = {
target match { target match {
case obj: PlanetSideServerObject with MountedWeapons with JammableUnit if !jammedSound => case obj: PlanetSideServerObject with MountedWeapons with JammableUnit if !jammedSound =>
obj.Zone.VehicleEvents ! VehicleServiceMessage( obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 1) PlanetsideAttribute(obj.GUID, 27, 1)
) )
super.StartJammeredSound(target, dur) super.StartJammeredSound(target, dur)
case _ => ; case _ => ;
@ -264,9 +263,9 @@ trait JammableMountedWeapons extends JammableBehavior {
override def CancelJammeredSound(target: Any): Unit = { override def CancelJammeredSound(target: Any): Unit = {
target match { target match {
case obj: PlanetSideServerObject if jammedSound => case obj: PlanetSideServerObject if jammedSound =>
obj.Zone.VehicleEvents ! VehicleServiceMessage( obj.Zone.VehicleEvents ! MessageEnvelope(
obj.Zone.id, obj.Zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, 27, 0) PlanetsideAttribute(obj.GUID, 27, 0)
) )
case _ => ; case _ => ;
} }
@ -308,9 +307,9 @@ object JammableMountedWeapons {
def JammedWeaponStatus(zone: Zone, target: Equipment with JammableUnit, statusCode: Int): Unit = { def JammedWeaponStatus(zone: Zone, target: Equipment with JammableUnit, statusCode: Int): Unit = {
target.Jammed = statusCode == 1 target.Jammed = statusCode == 1
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, 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 = { private def sortKnapsack(list: List[InventoryItem], width: Int, height: Int): Unit = {
val root = new KnapsackNode(0, 0, width, height) val root = new KnapsackNode(0, 0, width, height)
list.foreach(item => { list.foreach { item =>
findKnapsackSpace(root, item.obj.Tile.Width, item.obj.Tile.Height) match { val tile = item.obj.Tile
val twidth = tile.Width
val theight = tile.Height
findKnapsackSpace(root, twidth, theight) match {
case Some(node) => case Some(node) =>
splitKnapsackSpace(node, item.obj.Tile.Width, item.obj.Tile.Height) splitKnapsackSpace(node, twidth, theight)
item.start = node.y * width + node.x item.start = node.y * width + node.x
case _ => ; case _ =>
item.start = -1 item.start = -1
} }
}) }
} }
/** /**
@ -720,42 +723,32 @@ object GridInventory {
* Horizontal space for the `down` child is emphasized over vertical space for the `right` child. * 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> * By dividing and reducing a defined space like this, it can be tightly packed with a given number of elements.<br>
* <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 x the x-coordinate, upper left corner
* @param y the y-coordinate, upper left corner * @param y the y-coordinate, upper left corner
* @param width the width * @param width the width
* @param height the height * @param height the height
*/ */
private class KnapsackNode(var x: Int, var y: Int, var width: Int, var height: Int) { private class KnapsackNode(val x: Int, val y: Int, val width: Int, val height: Int) {
private var used: Boolean = false private var used: Boolean = false
var down: Option[KnapsackNode] = None private var down: Option[KnapsackNode] = None
var right: Option[KnapsackNode] = None private var right: Option[KnapsackNode] = None
def Used: Boolean = used def Used: Boolean = used
/** def Down: Option[KnapsackNode] = down
* Initialize the `down` and `right` children of this node.
*/ def Right: Option[KnapsackNode] = right
def Split(): Unit = {
used = true
down = Some(new KnapsackNode(0, 0, 0, 0))
right = Some(new KnapsackNode(0, 0, 0, 0))
}
/** /**
* Change the dimensions of the node.<br> * Initialize the `down` and `right` children of this node.
* <br> * @param insertDown new "down" knapsack division
* Use: `{node}(nx, ny, nw, nh)` * @param insertRight new "right" knapsack division
* @param nx the new x-coordinate, upper left corner */
* @param ny the new y-coordinate, upper left corner def Split(insertDown: KnapsackNode, insertRight: KnapsackNode): Unit = {
* @param nw the new width used = true
* @param nh the new height down = Some(insertDown)
*/ right = Some(insertRight)
def apply(nx: Int, ny: Int, nw: Int, nh: Int): Unit = {
x = nx
y = ny
width = nw
height = nh
} }
} }
@ -768,7 +761,7 @@ object GridInventory {
*/ */
private def findKnapsackSpace(node: KnapsackNode, width: Int, height: Int): Option[KnapsackNode] = { private def findKnapsackSpace(node: KnapsackNode, width: Int, height: Int): Option[KnapsackNode] = {
if (node.Used) { 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) { } else if (width <= node.width && height <= node.height) {
Some(node) Some(node)
} else { } else {
@ -787,13 +780,14 @@ object GridInventory {
* @param height height of the element * @param height height of the element
*/ */
private def splitKnapsackSpace(node: KnapsackNode, width: Int, height: Int): Unit = { private def splitKnapsackSpace(node: KnapsackNode, width: Int, height: Int): Unit = {
node.Split() node.Split(
node.down.get(node.x, node.y + height, node.width, node.height - height) new KnapsackNode(node.x, node.y + height, node.width, node.height - height),
node.right.get(node.x + width, node.y, node.width - width, height) new KnapsackNode(node.x + width, node.y, node.width - width, height)
)
} }
def toPrintedList(inv: GridInventory): String = { def toPrintedList(inv: GridInventory): String = {
val list = new StringBuilder val list = new mutable.StringBuilder
list.append("\n") list.append("\n")
inv.Items.zipWithIndex.foreach { inv.Items.zipWithIndex.foreach {
case (InventoryItem(obj, start), index) => case (InventoryItem(obj, start), index) =>
@ -803,6 +797,6 @@ object GridInventory {
} }
def toPrintedGrid(inv: GridInventory): String = { 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.objects.serverobject.containable.{Containable, ContainableBehavior}
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
import net.psforever.packet.game.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage} import net.psforever.packet.game.{ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectDetachMessage}
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.{ObjectDelete, SendResponse}
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
/** /**
@ -19,7 +19,7 @@ import net.psforever.types.{PlanetSideEmpire, Vector3}
class LockerContainerControl(locker: LockerContainer, toChannel: String) class LockerContainerControl(locker: LockerContainer, toChannel: String)
extends Actor extends Actor
with ContainableBehavior { with ContainableBehavior {
def ContainerObject = locker def ContainerObject: LockerContainer = locker
def receive: Receive = def receive: Receive =
containerBehavior containerBehavior
@ -34,9 +34,9 @@ class LockerContainerControl(locker: LockerContainer, toChannel: String)
val obj = ContainerObject val obj = ContainerObject
obj.Find(item) match { obj.Find(item) match {
case Some(slot) => case Some(slot) =>
obj.Zone.AvatarEvents ! AvatarServiceMessage( obj.Zone.AvatarEvents ! MessageEnvelope(
toChannel, toChannel,
AvatarAction.SendResponse(Service.defaultPlayerGUID, ObjectAttachMessage(obj.GUID, item.GUID, slot)) SendResponse(ObjectAttachMessage(obj.GUID, item.GUID, slot))
) )
case None => ; case None => ;
} }
@ -46,17 +46,16 @@ class LockerContainerControl(locker: LockerContainer, toChannel: String)
def RemoveItemFromSlotCallback(item: Equipment, slot: Int): Unit = { def RemoveItemFromSlotCallback(item: Equipment, slot: Int): Unit = {
val zone = locker.Zone 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 = { def PutItemInSlotCallback(item: Equipment, slot: Int): Unit = {
val zone = locker.Zone val zone = locker.Zone
val definition = item.Definition val definition = item.Definition
item.Faction = PlanetSideEmpire.NEUTRAL item.Faction = PlanetSideEmpire.NEUTRAL
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
toChannel, toChannel,
AvatarAction.SendResponse( SendResponse(
Service.defaultPlayerGUID,
ObjectCreateDetailedMessage( ObjectCreateDetailedMessage(
definition.ObjectId, definition.ObjectId,
item.GUID, item.GUID,
@ -69,12 +68,9 @@ class LockerContainerControl(locker: LockerContainer, toChannel: String)
def SwapItemCallback(item: Equipment, fromSlot: Int): Unit = { def SwapItemCallback(item: Equipment, fromSlot: Int): Unit = {
val zone = locker.Zone val zone = locker.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
toChannel, toChannel,
AvatarAction.SendResponse( SendResponse(ObjectDetachMessage(locker.GUID, item.GUID, Vector3.Zero, 0f))
Service.defaultPlayerGUID,
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.serverobject.structures.Amenity
import net.psforever.objects.vital.interaction.DamageResult 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 * 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. * 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. * 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. * These `PlanetSideAttributeMessage` attributes are the same as reported during zone load client configuration.
* @see `AvatarAction.PlanetsideAttributeToAll` * @see `PlanetsideAttribute`
* @see `AvatarServiceMessage`
* @see `Zone.AvatarEvents` * @see `Zone.AvatarEvents`
* @param target the entity being destroyed * @param target the entity being destroyed
* @param cause historical information about the damage * @param cause historical information about the damage
@ -36,7 +37,9 @@ object DamageableAmenity {
val zoneId = zone.id val zoneId = zone.id
val events = zone.AvatarEvents val events = zone.AvatarEvents
val targetGUID = target.GUID val targetGUID = target.GUID
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 50, 1)) events ! MessageEnvelope(
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 51, 1)) zoneId,
SendResponse(PlanetsideAttributeMessage(targetGUID, 50, 1), PlanetsideAttributeMessage(targetGUID, 51, 1))
)
} }
} }

View file

@ -1,14 +1,16 @@
//Copyright (c) 2020 PSForever //Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.damage package net.psforever.objects.serverobject.damage
import net.psforever.objects.Default
import net.psforever.objects.equipment.JammableUnit import net.psforever.objects.equipment.JammableUnit
import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.vital.resolution.ResolutionCalculations import net.psforever.objects.vital.resolution.ResolutionCalculations
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
import net.psforever.services.Service import net.psforever.services.avatar.AvatarAction
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.base.message.PlanetsideAttribute
/** /**
* The "control" `Actor` mixin for damage-handling code, * The "control" `Actor` mixin for damage-handling code,
@ -140,12 +142,11 @@ object DamageableEntity {
* - reports its adjusted its health; * - reports its adjusted its health;
* - alert the activity monitor for that `Zone` about the damage; and, * - alert the activity monitor for that `Zone` about the damage; and,
* - provide a feedback message regarding the damage. * - provide a feedback message regarding the damage.
* @see `AvatarAction.PlanetsideAttributeToAll` * @see `PlanetsideAttribute`
* @see `AvatarAction.SendResponse` * @see `SendResponse`
* @see `AvatarServiceMessage`
* @see `DamageFeedbackMessage` * @see `DamageFeedbackMessage`
* @see `JammableUnit.Jammered` * @see `JammableUnit.Jammered`
* @see `Service.defaultPlayerGUID` * @see `Default.GUID0`
* @see `Zone.Activity` * @see `Zone.Activity`
* @see `Zone.AvatarEvents` * @see `Zone.AvatarEvents`
* @see `Zone.HotSpot.Activity` * @see `Zone.HotSpot.Activity`
@ -165,9 +166,9 @@ object DamageableEntity {
def DamageToHealth(target: Damageable.Target, cause: DamageResult, amount: Int): Boolean = { def DamageToHealth(target: Damageable.Target, cause: DamageResult, amount: Int): Boolean = {
if (amount > 0 && !target.Destroyed) { if (amount > 0 && !target.Destroyed) {
val zone = target.Zone val zone = target.Zone
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.PlanetsideAttributeToAll(target.GUID, 0, target.Health) PlanetsideAttribute(target.GUID, 0, target.Health)
) )
true true
} }
@ -181,8 +182,7 @@ object DamageableEntity {
* - reports its adjusted its health; and, * - reports its adjusted its health; and,
* - report about its destruction. * - report about its destruction.
* @see `AvatarAction.Destroy` * @see `AvatarAction.Destroy`
* @see `AvatarAction.PlanetsideAttribute` * @see `PlanetsideAttribute`
* @see `AvatarServiceMessage`
* @see `DamageFeedbackMessage` * @see `DamageFeedbackMessage`
* @see `JammableUnit.ClearJammeredSound` * @see `JammableUnit.ClearJammeredSound`
* @see `JammableUnit.ClearJammeredStatus` * @see `JammableUnit.ClearJammeredStatus`
@ -199,12 +199,12 @@ object DamageableEntity {
val zoneId = zone.id val zoneId = zone.id
val tguid = target.GUID val tguid = target.GUID
val attribution = attributionTo(cause, target.Zone) 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 if (target.isInstanceOf[SpawnTube]) {}//do nothing to prevent issue #1057
else { else {
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zoneId, 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 //Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.damage 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.serverobject.mount.Mountable
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry} import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult} import net.psforever.objects.vital.interaction.{DamageInteraction, DamageResult}
import net.psforever.packet.game.DamageWithPositionMessage import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.services.Service import net.psforever.services.avatar.AvatarAction
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} 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. * 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. * A damaged target alerts its occupants (as it is a `Mountable` object) of the source of the damage.
* *
* @see `AvatarAction.HitHint` * @see `HitHint`
* @see `AvatarAction.SendResponse` * @see `SendResponse`
* @see `AvatarServiceMessage`
* @see `DamageWithPositionMessage` * @see `DamageWithPositionMessage`
* @see `Mountable.Seats` * @see `Mountable.Seats`
* @see `Service.defaultPlayerGUID` * @see `Default.GUID0`
* @see `Zone.AvatarEvents` * @see `Zone.AvatarEvents`
* @see `Zone.LivePlayers` * @see `Zone.LivePlayers`
* @param target the entity being damaged * @param target the entity being damaged
@ -37,32 +37,34 @@ object DamageableMountable {
val zone = target.Zone val zone = target.Zone
val events = zone.AvatarEvents val events = zone.AvatarEvents
val occupants = target.Seats.values.toSeq.flatMap { seat => seat.occupants.filter(_.isAlive) } val occupants = target.Seats.values.toSeq.flatMap { seat => seat.occupants.filter(_.isAlive) }
((cause.adversarial match { events ! BundledEnvelope(
case Some(adversarial) => Some(adversarial.attacker) ((cause.adversarial match {
case None => None case Some(adversarial) => Some(adversarial.attacker)
}) match { case None => None
case Some(pSource: PlayerSource) => //player damage }) match {
val name = pSource.Name case Some(pSource: PlayerSource) => //player damage
(zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match { val name = pSource.Name
case Some(player) => (zone.LivePlayers.find(_.Name == name).orElse(zone.Corpses.find(_.Name == name)) match {
AvatarAction.HitHint(player.GUID, player.GUID) case Some(player) =>
case None => HintsAtAttacker(player.GUID)
AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(countableDamage, pSource.Position)) case None =>
}) match { SendResponse(DamageWithPositionMessage(countableDamage, pSource.Position))
case AvatarAction.HitHint(_, guid) => }) match {
occupants.map { tplayer => (tplayer.Name, AvatarAction.HitHint(guid, tplayer.GUID)) } case msg @ HintsAtAttacker(guid) =>
case msg => occupants.map { tplayer => (tplayer.Name, guid, msg) }
occupants.map { tplayer => (tplayer.Name, msg) } case msg =>
} occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
case Some(source) => //object damage }
val msg = AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(countableDamage, source.Position)) case Some(source) => //object damage
occupants.map { tplayer => (tplayer.Name, msg) } val msg = SendResponse(DamageWithPositionMessage(countableDamage, source.Position))
case None => occupants.map { tplayer => (tplayer.Name, Default.GUID0, msg) }
List.empty case None =>
}).foreach { List.empty
case (channel, msg) => }).map {
events ! AvatarServiceMessage(channel, msg) case (channel, filter, msg) =>
} MessageEnvelope(channel, filter, msg)
}
)
} }
/** /**
@ -78,7 +80,7 @@ object DamageableMountable {
val targets = target.Seats.values.flatMap(_.occupant).filter(_.isAlive) val targets = target.Seats.values.flatMap(_.occupant).filter(_.isAlive)
targets.foreach { player => targets.foreach { player =>
//make llu visible to others in zone if passenger is carrying one //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.LogActivity(cause)
player.Actor ! Player.Die( player.Actor ! Player.Die(
DamageInteraction(interaction.resolution, SourceEntry(player), interaction.cause, interaction.hitPos) DamageInteraction(interaction.resolution, SourceEntry(player), interaction.cause, interaction.hitPos)

View file

@ -2,7 +2,7 @@
package net.psforever.objects.serverobject.damage package net.psforever.objects.serverobject.damage
import akka.actor.{Actor, Cancellable} 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.equipment.JammableUnit
import net.psforever.objects.serverobject.damage.Damageable.Target import net.psforever.objects.serverobject.damage.Damageable.Target
import net.psforever.objects.sourcing.VehicleSource 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.Zone
import net.psforever.objects.zones.exp.ToDatabase import net.psforever.objects.zones.exp.ToDatabase
import net.psforever.packet.game.DamageWithPositionMessage import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
import net.psforever.types.Vector3 import net.psforever.types.Vector3
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -102,10 +102,9 @@ trait DamageableVehicle
* Most all vehicles and the weapons mounted to them can jam * Most all vehicles and the weapons mounted to them can jam
* if the projectile that strikes (near) them has jammering properties. * 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. * 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 `Vehicle.CargoHolds`
* @see `VehicleAction.PlanetsideAttribute` * @see `PlanetsideAttribute`
* @see `VehicleServiceMessage`
* @param target the entity being destroyed * @param target the entity being destroyed
* @param cause historical information about the damage * @param cause historical information about the damage
* @param amount how much damage was performed * @param amount how much damage was performed
@ -142,27 +141,27 @@ trait DamageableVehicle
} }
//stat changes //stat changes
if (damageToShields > 0) { if (damageToShields > 0) {
events ! VehicleServiceMessage( events ! MessageEnvelope(
shieldChannel, shieldChannel,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, obj.Definition.shieldUiAttribute, obj.Shields) PlanetsideAttribute(targetGUID, obj.Definition.shieldUiAttribute, obj.Shields)
) )
announceConfrontation = true announceConfrontation = true
} }
if (damageToHealth > 0) { if (damageToHealth > 0) {
events ! VehicleServiceMessage( events ! MessageEnvelope(
healthChannel, healthChannel,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, obj.Health) PlanetsideAttribute(targetGUID, 0, obj.Health)
) )
announceConfrontation = true announceConfrontation = true
} }
} }
if (announceConfrontation) { if (announceConfrontation) {
if (showAsAggravated) { if (showAsAggravated) {
val msg = VehicleAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(totalDamage, Vector3.Zero)) val msg = SendResponse(DamageWithPositionMessage(totalDamage, Vector3.Zero))
obj.Seats.values obj.Seats.values
.collect { case seat if seat.occupant.nonEmpty => seat.occupant.get.Name } .collect { case seat if seat.occupant.nonEmpty => seat.occupant.get.Name }
.foreach { channel => .foreach { channel =>
events ! VehicleServiceMessage(channel, msg) events ! MessageEnvelope(channel, msg)
} }
} }
else { else {
@ -180,13 +179,11 @@ trait DamageableVehicle
* Finally, the vehicle is tasked for deconstruction. * Finally, the vehicle is tasked for deconstruction.
* @see `Deployment.TryDeploymentChange` * @see `Deployment.TryDeploymentChange`
* @see `DriveState.Undeploying` * @see `DriveState.Undeploying`
* @see `Service.defaultPlayerGUID` * @see `Default.GUID0`
* @see `Vehicle.CargoHolds` * @see `Vehicle.CargoHolds`
* @see `VehicleAction.PlanetsideAttribute` * @see `PlanetsideAttribute`
* @see `RemoverActor.AddTask` * @see `RemoverActor.AddTask`
* @see `RemoverActor.ClearSpecific` * @see `RemoverActor.ClearSpecific`
* @see `VehicleServiceMessage`
* @see `VehicleServiceMessage.Decon`
* @see `Zone.VehicleEvents` * @see `Zone.VehicleEvents`
* @param target the entity being destroyed * @param target the entity being destroyed
* @param cause historical information about the damage * @param cause historical information about the damage
@ -217,9 +214,9 @@ trait DamageableVehicle
//shields //shields
if (obj.Shields > 0) { if (obj.Shields > 0) {
obj.Shields = 0 obj.Shields = 0
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, target.GUID, obj.Definition.shieldUiAttribute, 0) PlanetsideAttribute(target.GUID, obj.Definition.shieldUiAttribute, 0)
) )
} }
//database entry //database entry
@ -243,22 +240,22 @@ trait DamageableVehicle
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._ import scala.concurrent.duration._
val obj = DamageableObject val obj = DamageableObject
val guid0 = Service.defaultPlayerGUID val guid0 = Default.GUID0
val zone = obj.Zone val zone = obj.Zone
val zoneid = zone.id val zoneid = zone.id
val events = zone.VehicleEvents val events = zone.VehicleEvents
//health to 1, shields to 0 //health to 1, shields to 0
obj.Health = 1 obj.Health = 1
val guid = obj.GUID val guid = obj.GUID
events ! VehicleServiceMessage( events ! MessageEnvelope(
zoneid, zoneid,
VehicleAction.PlanetsideAttribute(guid0, guid, 0, 1) PlanetsideAttribute(guid, 0, 1)
) )
if (obj.Shields > 0) { if (obj.Shields > 0) {
obj.Shields = 0 obj.Shields = 0
zone.VehicleEvents ! VehicleServiceMessage( events ! MessageEnvelope(
zone.id, zone.id,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, obj.GUID, obj.Definition.shieldUiAttribute, 0) PlanetsideAttribute(obj.GUID, obj.Definition.shieldUiAttribute, 0)
) )
} }
//aggravation cancel //aggravation cancel

View file

@ -9,10 +9,10 @@ import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.DamageWithPositionMessage import net.psforever.packet.game.DamageWithPositionMessage
import net.psforever.types.Vector3 import net.psforever.types.Vector3
import net.psforever.services.Service import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.{ObjectDelete, PlanetsideAttribute, SendResponse}
import net.psforever.services.vehicle.support.TurretUpgrader import net.psforever.services.base.support.SupportActor
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.support.{TurretEnvelope, TurretUpgrader}
/** /**
* The "control" `Actor` mixin for damage-handling code for `WeaponTurret` objects. * The "control" `Actor` mixin for damage-handling code for `WeaponTurret` objects.
@ -62,21 +62,22 @@ trait DamageableWeaponTurret
//TODO some turrets have shields //TODO some turrets have shields
if (damageToHealth > 0) { if (damageToHealth > 0) {
DamageableMountable.DamageAwareness(DamageableObject, cause, damageToHealth) DamageableMountable.DamageAwareness(DamageableObject, cause, damageToHealth)
events ! VehicleServiceMessage( events ! MessageEnvelope(
zoneId, zoneId,
VehicleAction.PlanetsideAttribute(Service.defaultPlayerGUID, targetGUID, 0, obj.Health) PlanetsideAttribute(targetGUID, 0, obj.Health)
) )
announceConfrontation = true announceConfrontation = true
} }
} }
if (announceConfrontation) { if (announceConfrontation) {
if (aggravated) { if (aggravated) {
val msg = VehicleAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(damageToHealth, Vector3.Zero)) val msg = SendResponse(DamageWithPositionMessage(damageToHealth, Vector3.Zero))
obj.Seats.values events ! BundledEnvelope(obj.Seats.values
.collect { case seat if seat.occupant.nonEmpty => seat.occupant.get.Name } .collect { case seat if seat.occupant.nonEmpty => seat.occupant.get.Name }
.foreach { channel => .map { channel =>
events ! VehicleServiceMessage(channel, msg) MessageEnvelope(channel, msg)
} }
)
} }
else { else {
//activity on map //activity on map
@ -103,16 +104,15 @@ object DamageableWeaponTurret {
* A destroyed target dispatches a message to conceal (delete) its weapons from users. * 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 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. * If the type of entity is a `WeaponTurret`, the weapons are converted to their "normal" upgrade state.
* @see `AvatarAction.DeleteObject` * @see `DeleteObject`
* @see `AvatarServiceMessage`
* @see `MountedWeapons` * @see `MountedWeapons`
* @see `MountedWeapons.Weapons` * @see `MountedWeapons.Weapons`
* @see `Service.defaultPlayerGUID` * @see `Default.GUID0`
* @see `TurretUpgrade.None` * @see `TurretUpgrade.None`
* @see `TurretUpgrader.AddTask` * @see `TurretUpgrader.AddTask`
* @see `TurretUpgrader.ClearSpecific` * @see `TurretUpgrader.ClearSpecific`
* @see `WeaponTurret` * @see `WeaponTurret`
* @see `VehicleServiceMessage.TurretUpgrade` * @see `TurretMessage`
* @see `Zone.AvatarEvents` * @see `Zone.AvatarEvents`
* @see `Zone.VehicleEvents` * @see `Zone.VehicleEvents`
* @param target the entity being destroyed; * @param target the entity being destroyed;
@ -125,20 +125,18 @@ object DamageableWeaponTurret {
val zone = target.Zone val zone = target.Zone
val zoneId = zone.id val zoneId = zone.id
val avatarEvents = zone.AvatarEvents val avatarEvents = zone.AvatarEvents
target.Weapons.values avatarEvents ! BundledEnvelope(target.Weapons.values
.filter { .filter(_.Equipment.nonEmpty)
_.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 { target match {
case turret: WeaponTurret => case turret: WeaponTurret =>
if (turret.Upgrade != TurretUpgrade.None) { if (turret.Upgrade != TurretUpgrade.None) {
val vehicleEvents = zone.VehicleEvents val vehicleEvents = zone.VehicleEvents
vehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(turret), zone)) vehicleEvents ! TurretEnvelope(SupportActor.ClearSpecific(List(turret), zone))
vehicleEvents ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(turret, zone, TurretUpgrade.None)) vehicleEvents ! TurretEnvelope(TurretUpgrader.AddTask(turret, zone, TurretUpgrade.None))
} }
case _ => case _ =>
} }

View file

@ -4,8 +4,8 @@ package net.psforever.objects.serverobject.deploy
import akka.actor.{Actor, ActorRef, Cancellable} import akka.actor.{Actor, ActorRef, Cancellable}
import net.psforever.objects.Default import net.psforever.objects.Default
import net.psforever.types.{DriveState, Vector3} import net.psforever.types.{DriveState, Vector3}
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.VehicleAction
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -97,16 +97,15 @@ trait DeploymentBehavior {
val guid = obj.GUID val guid = obj.GUID
val zone = obj.Zone val zone = obj.Zone
val zoneChannel = zone.id val zoneChannel = zone.id
val GUID0 = Service.defaultPlayerGUID
//TODO remove this arbitrary allowance angle when no longer helpful //TODO remove this arbitrary allowance angle when no longer helpful
if (obj.Orientation.x > 30 && obj.Orientation.x < 330) { if (obj.Orientation.x > 30 && obj.Orientation.x < 330) {
obj.DeploymentState = prevState obj.DeploymentState = prevState
prevState prevState
} else if (state == DriveState.Deploying) { } else if (state == DriveState.Deploying) {
obj.Velocity = Some(Vector3.Zero) //no velocity obj.Velocity = Some(Vector3.Zero) //no velocity
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zoneChannel, zoneChannel,
VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero) VehicleAction.DeployRequest(guid, state, 0, unk2=false, Vector3.Zero)
) )
deploymentTimer.cancel() deploymentTimer.cancel()
deploymentTimer = context.system.scheduler.scheduleOnce(obj.DeployTime.milliseconds)({ deploymentTimer = context.system.scheduler.scheduleOnce(obj.DeployTime.milliseconds)({
@ -115,9 +114,9 @@ trait DeploymentBehavior {
state state
} else if (state == DriveState.Deployed) { } else if (state == DriveState.Deployed) {
obj.Velocity = Some(Vector3.Zero) //no velocity obj.Velocity = Some(Vector3.Zero) //no velocity
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zoneChannel, zoneChannel,
VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero) VehicleAction.DeployRequest(guid, state, 0, unk2=false, Vector3.Zero)
) )
state state
} else { } else {
@ -134,11 +133,10 @@ trait DeploymentBehavior {
val guid = obj.GUID val guid = obj.GUID
val zone = obj.Zone val zone = obj.Zone
val zoneChannel = zone.id val zoneChannel = zone.id
val GUID0 = Service.defaultPlayerGUID
if (state == DriveState.Undeploying) { if (state == DriveState.Undeploying) {
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zoneChannel, 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 import scala.concurrent.ExecutionContext.Implicits.global
deploymentTimer.cancel() deploymentTimer.cancel()
@ -147,9 +145,9 @@ trait DeploymentBehavior {
}) })
state state
} else if (state == DriveState.Mobile) { } else if (state == DriveState.Mobile) {
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zoneChannel, zoneChannel,
VehicleAction.DeployRequest(GUID0, guid, state, 0, unk2=false, Vector3.Zero) VehicleAction.DeployRequest(guid, state, 0, unk2=false, Vector3.Zero)
) )
state state
} else { } 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.vital.prop.DamageWithPosition
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.ChatMsg import net.psforever.packet.game.ChatMsg
import net.psforever.services.Service import net.psforever.services.base.envelope.{BundledEnvelope, MessageEnvelope}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.base.message.SendResponse
import net.psforever.services.local.LocalAction
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGeneratorState, Vector3} import net.psforever.types.{ChatMessageType, PlanetSideEmpire, PlanetSideGeneratorState, Vector3}
import scala.annotation.unused import scala.annotation.unused
@ -45,9 +46,9 @@ object ForceDomeControl {
val owner = dome.Owner val owner = dome.Owner
val zone = owner.Zone val zone = owner.Zone
owner.Actor ! BuildingActor.AmenityStateChange(dome) owner.Actor ! BuildingActor.AmenityStateChange(dome)
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.UpdateForceDomeStatus(Service.defaultPlayerGUID, owner.GUID, activationState) LocalAction.UpdateForceDomeStatus(owner.GUID, activationState)
) )
} }
@ -124,11 +125,11 @@ object ForceDomeControl {
state: Boolean state: Boolean
): Unit = { ): Unit = {
val zone = building.Zone val zone = building.Zone
val message = LocalAction.SendResponse(ChatMsg( val message = SendResponse(ChatMsg(
ChatMessageType.UNK_229, ChatMessageType.UNK_229,
s"The Capitol force dome at ${building.Name} will remain ${if (state) "activated" else "deactivated"}." 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 = { def NormalDomeStateMessage(building: Building): Unit = {
val events = building.Zone.LocalEvents val events = building.Zone.LocalEvents
val message = LocalAction.SendResponse(ChatMsg( val message = SendResponse(ChatMsg(
ChatMessageType.UNK_227, ChatMessageType.UNK_227,
"Expected capitol force dome state change will resume." "Expected capitol force dome state change will resume."
)) ))
building.PlayersInSOI.foreach { player => events ! BundledEnvelope(building.PlayersInSOI.map { player =>
events ! LocalServiceMessage(player.Name, message) MessageEnvelope(player.Name, message)
} })
} }
/** /**

View file

@ -67,37 +67,10 @@ object Door {
*/ */
sealed trait Exchange 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 type LockingMechanismLogic = (PlanetSideServerObject, Door) => Boolean
final case class UpdateMechanism(mechanism: LockingMechanismLogic) extends Exchange final case class UpdateMechanism(mechanism: LockingMechanismLogic) extends Exchange
case object Lock extends Exchange
case object Unlock extends Exchange
/** /**
* Overloaded constructor. * Overloaded constructor.
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields * @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.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.locks.IFFLock import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.structures.PoweredAmenityControl import net.psforever.objects.serverobject.structures.PoweredAmenityControl
import net.psforever.services.Service import net.psforever.services.base.envelope.GenericResponseEnvelope
import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse} 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`. * An `Actor` that handles messages being dispatched to a specific `Door`.
@ -19,24 +21,21 @@ class DoorControl(door: Door)
with FactionAffinityBehavior.Check { with FactionAffinityBehavior.Check {
def FactionObject: FactionAffinity = door def FactionObject: FactionAffinity = door
private var isLocked: Boolean = false
private var lockingMechanism: Door.LockingMechanismLogic = DoorControl.alwaysOpen private var lockingMechanism: Door.LockingMechanismLogic = DoorControl.alwaysOpen
def commonBehavior: Receive = checkBehavior def commonBehavior: Receive = checkBehavior
.orElse { .orElse {
case Door.Lock => case Door.UpdateMechanism(logic) =>
isLocked = true lockingMechanism = logic
if (door.isOpen) { if (door.isOpen) {
val zone = door.Zone val zone = door.Zone
door.Open = None 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 = def poweredStateLogic: Receive =
@ -48,7 +47,7 @@ class DoorControl(door: Door)
case CommonMessages.Use(player, _) => case CommonMessages.Use(player, _) =>
testToOpenDoor(player, door, door.Definition.initialOpeningDistance, sender()) testToOpenDoor(player, door, door.Definition.initialOpeningDistance, sender())
case IFFLock.DoorOpenResponse(target: Player) if !isLocked => case IFFLock.DoorOpenResponse(target: Player) =>
DoorControl.openDoor(target, door) DoorControl.openDoor(target, door)
case _ => () case _ => ()
@ -57,7 +56,7 @@ class DoorControl(door: Door)
def unpoweredStateLogic: Receive = { def unpoweredStateLogic: Receive = {
commonBehavior commonBehavior
.orElse { .orElse {
case CommonMessages.Use(player, _) if !isLocked => case CommonMessages.Use(player, _) =>
//without power, the door opens freely //without power, the door opens freely
DoorControl.openDoor(player, door) DoorControl.openDoor(player, door)
@ -83,7 +82,7 @@ class DoorControl(door: Door)
): Unit = { ): Unit = {
if ( if (
Doors.testForSpecificTargetHoldingDoorOpen(player, door, maximumDistance * maximumDistance).contains(player) && Doors.testForSpecificTargetHoldingDoorOpen(player, door, maximumDistance * maximumDistance).contains(player) &&
lockingMechanism(player, door) && !isLocked lockingMechanism(player, door)
) { ) {
DoorControl.openDoor(player, door, replyTo) DoorControl.openDoor(player, door, replyTo)
} }
@ -107,20 +106,21 @@ object DoorControl {
*/ */
private def openDoor(player: Player, door: Door, replyTo: ActorRef = Default.Actor): Unit = { private def openDoor(player: Player, door: Door, replyTo: ActorRef = Default.Actor): Unit = {
val zone = door.Zone val zone = door.Zone
val doorGUID = door.GUID
if (!door.isOpen) { if (!door.isOpen) {
//global open //global open
door.Open = player door.Open = player
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! DoorMessage(
zone.id, zone.id,
LocalAction.DoorOpens(Service.defaultPlayerGUID, zone, door) LocalAction.DoorOpens(zone, door),
DoorCloseActor.DoorIsOpen(door, zone, System.currentTimeMillis())
) )
} else { } else {
//the door should already open, but the requesting player does not see it as open //the door should already open, but the requesting player does not see it as open
replyTo ! LocalServiceResponse( replyTo ! GenericResponseEnvelope(
LocalStamp,
player.Name, player.Name,
Service.defaultPlayerGUID, Default.GUID0,
LocalResponse.DoorOpens(doorGUID) 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.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.TriggerEffectMessage import net.psforever.packet.game.TriggerEffectMessage
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{PlanetSideGeneratorState, Vector3} import net.psforever.types.{PlanetSideGeneratorState, Vector3}
import net.psforever.services.Service import net.psforever.services.base.message.SendResponse
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import scala.concurrent.duration._ import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
@ -111,12 +111,9 @@ class GeneratorControl(gen: Generator)
super.DestructionAwareness(gen, gen.LastDamage.get) super.DestructionAwareness(gen, gen.LastDamage.get)
GeneratorControl.UpdateOwner(gen, Some(GeneratorControl.Event.Destroyed)) GeneratorControl.UpdateOwner(gen, Some(GeneratorControl.Event.Destroyed))
//kaboom //kaboom
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! MessageEnvelope(
zone.id, zone.id,
AvatarAction.SendResponse( SendResponse(TriggerEffectMessage(gen.GUID, "explosion_generator", None, None))
Service.defaultPlayerGUID,
TriggerEffectMessage(gen.GUID, "explosion_generator", None, None)
)
) )
queuedExplosion.cancel() queuedExplosion.cancel()
queuedExplosion = Default.Cancellable 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.objects.zones.blockmap.BlockMapEntity
import net.psforever.packet.game.{GenericObjectActionMessage, HackMessage, HackState, HackState1, HackState7, TriggeredSound} import net.psforever.packet.game.{GenericObjectActionMessage, HackMessage, HackState, HackState1, HackState7, TriggeredSound}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.SendResponse
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope, HackEntityEnvelope}
import net.psforever.services.local.LocalAction
import scala.annotation.unused import scala.annotation.unused
import scala.util.{Failure, Success} import scala.util.{Failure, Success}
@ -88,10 +89,9 @@ object GenericHackables {
} else { } else {
(HackState.Ongoing, progress.toInt) (HackState.Ongoing, progress.toInt)
} }
target.Zone.AvatarEvents ! AvatarServiceMessage( target.Zone.AvatarEvents ! MessageEnvelope(
hacker.Name, hacker.Name,
AvatarAction.SendResponse( SendResponse(
Service.defaultPlayerGUID,
HackMessage(progressType, target.GUID, hacker.GUID, progressGrade, 0L, progressState, HackState7.Unk8) HackMessage(progressType, target.GUID, hacker.GUID, progressGrade, 0L, progressState, HackState7.Unk8)
) )
) )
@ -171,14 +171,17 @@ object GenericHackables {
val zoneId = zone.id val zoneId = zone.id
val pguid = tplayer.GUID val pguid = tplayer.GUID
log.info(s"${user.Name} hacked a ${target.Definition.Name}") log.info(s"${user.Name} hacked a ${target.Definition.Name}")
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zoneId, 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, zoneId,
LocalAction pguid,
.HackTemporarily(pguid, zone, target, hackValue, hackClearValue, target.HackEffectDuration(user.avatar.hackingSkillLevel())) LocalAction.HackObject(target.GUID, hackValue, HackState7.Unk8),
HackClearActor.ObjectIsHacked(target, zone, hackClearValue, HackState7.Unk8, duration)
) )
case Failure(_) => case Failure(_) =>
log.warn(s"Hack message failed on target: ${target.Definition.Name}@${target.GUID.guid}") log.warn(s"Hack message failed on target: ${target.Definition.Name}@${target.GUID.guid}")
@ -203,29 +206,19 @@ object GenericHackables {
val currVirus = building.virusId val currVirus = building.virusId
building.virusId = 8 building.virusId = 8
building.virusInstalledBy = None building.virusInstalledBy = None
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(target))
zoneId, zone.LocalEvents ! MessageEnvelope(
LocalAction
.ClearTemporaryHack(pguid, target)
)
zone.LocalEvents ! LocalServiceMessage(
zone.id, zone.id,
LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 60)) SendResponse(GenericObjectActionMessage(target.GUID, 60))
) )
currVirus match { currVirus match {
case 0L => case 0L =>
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach { iff => building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach { iff =>
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(iff))
zoneId,
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), iff)
)
} }
case 4L => case 4L =>
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach { term => building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach { term =>
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(term))
zoneId,
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), term)
)
} }
case _ => () case _ => ()
} }
@ -239,19 +232,13 @@ object GenericHackables {
case 0L => case 0L =>
if (virus != 0) { if (virus != 0) {
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach { iff => building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach { iff =>
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(iff))
zoneId,
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), iff)
)
} }
} }
case 4L => case 4L =>
if (virus != 4) { if (virus != 4) {
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach { term => building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach { term =>
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(term))
zoneId,
LocalAction.ClearTemporaryHack(PlanetSideGUID(0), term)
)
} }
} }
case _ => () case _ => ()
@ -274,42 +261,42 @@ object GenericHackables {
val hackState = hackStateMap.getOrElse(virus, HackState7.Unk8) val hackState = hackStateMap.getOrElse(virus, HackState7.Unk8)
building.virusId = virus building.virusId = virus
building.virusInstalledBy = Some(tplayer.Faction.id) building.virusInstalledBy = Some(tplayer.Faction.id)
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zoneId, 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, zoneId,
LocalAction pguid,
.HackTemporarily(pguid, zone, target, installedVirusDuration, hackClearValue, installedVirusDuration, unk2=hackState) LocalAction.HackObject(target.GUID, installedVirusDuration.toLong, hackState),
HackClearActor.ObjectIsHacked(target, zone, hackClearValue, hackState, installedVirusDuration)
) )
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! MessageEnvelope(
zone.id, zone.id,
LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 61)) SendResponse(GenericObjectActionMessage(target.GUID, 61), GenericObjectActionMessage(target.GUID, 58))
)
zone.LocalEvents ! LocalServiceMessage(
zone.id,
LocalAction.SendResponse(GenericObjectActionMessage(target.GUID, 58))
) )
//amenities if applicable //amenities if applicable
virus match { virus match {
case 0L => case 0L =>
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach{ iff => building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.lock_external).foreach{ iff =>
var setHacked = iff.asInstanceOf[PlanetSideServerObject with Hackable] iff.HackedBy = tplayer
setHacked.HackedBy = tplayer zone.LocalEvents ! HackEntityEnvelope(
zone.LocalEvents ! LocalServiceMessage( zoneId,
zoneId, pguid,
LocalAction.HackTemporarily(pguid, zone, iff, hackValue, hackClearValue, installedVirusDuration) LocalAction.HackObject(target.GUID, hackValue.toLong, HackState7.Unk8),
) HackClearActor.ObjectIsHacked(target, zone, hackClearValue, HackState7.Unk8, installedVirusDuration)
)
} }
case 4L => case 4L =>
building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach{ term => building.HackableAmenities.filter(d => d.Definition == GlobalDefinitions.order_terminal).foreach{ term =>
var setHacked = term.asInstanceOf[PlanetSideServerObject with Hackable] term.HackedBy = tplayer
setHacked.HackedBy = tplayer zone.LocalEvents ! HackEntityEnvelope(
zone.LocalEvents ! LocalServiceMessage( zoneId,
zoneId, pguid,
LocalAction.HackTemporarily(pguid, zone, term, hackValue, hackClearValue, installedVirusDuration) LocalAction.HackObject(term.GUID, hackValue.toLong, HackState7.Unk8),
) HackClearActor.ObjectIsHacked(target, zone, hackClearValue, HackState7.Unk8, installedVirusDuration)
)
} }
case _ => () case _ => ()
} }

View file

@ -1,8 +1,7 @@
// Copyright (c) 2020 PSForever // Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.locks package net.psforever.objects.serverobject.locks
import net.psforever.services.Service import net.psforever.services.local.support.{HackClearActor, HackClearEnvelope}
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
object IFFLocks { object IFFLocks {
@ -14,9 +13,6 @@ object IFFLocks {
*/ */
def FinishResecuringIFFLock(lock: IFFLock)(): Unit = { def FinishResecuringIFFLock(lock: IFFLock)(): Unit = {
val zone = lock.Zone val zone = lock.Zone
lock.Zone.LocalEvents ! LocalServiceMessage( lock.Zone.LocalEvents ! HackClearEnvelope(HackClearActor.ObjectIsResecured(lock))
zone.id,
LocalAction.ClearTemporaryHack(Service.defaultPlayerGUID, lock)
)
} }
} }

View file

@ -11,6 +11,7 @@ import net.psforever.objects.sourcing.AmenitySource
import net.psforever.objects.vital.TerminalUsedActivity import net.psforever.objects.vital.TerminalUsedActivity
import net.psforever.objects.zones.{Zone, ZoneAware, Zoning} import net.psforever.objects.zones.{Zone, ZoneAware, Zoning}
import net.psforever.objects.{Default, PlanetSideGameObject, Player, Vehicle} import net.psforever.objects.{Default, PlanetSideGameObject, Player, Vehicle}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.{PlanetSideGUID, TransactionType, Vector3} import net.psforever.types.{PlanetSideGUID, TransactionType, Vector3}
import scala.annotation.tailrec import scala.annotation.tailrec
@ -128,7 +129,7 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
} }
trackedOrder = None trackedOrder = None
handleOrderFunc = NewTasking 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 self ! akka.actor.Kill //should cause the actor to restart, which will abort any trapped messages
case _ => () case _ => ()
@ -164,19 +165,17 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
//first queued order //first queued order
orders = List(order) orders = List(order)
queueManagementTask() queueManagementTask()
pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder( pad.Zone.VehicleEvents ! MessageEnvelope(
name, name,
VehicleSpawnPad.Reminders.Queue, VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_PositionInQueue^2~^2~"))
Some(s"@SVCP_PositionInQueue^2~^2~")
) )
case -1 => case -1 =>
//new order //new order
orders = orders :+ order orders = orders :+ order
val size = orders.size + 1 val size = orders.size + 1
pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder( pad.Zone.VehicleEvents ! MessageEnvelope(
name, name,
VehicleSpawnPad.Reminders.Queue, VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_PositionInQueue^$size~^$size~"))
Some(s"@SVCP_PositionInQueue^$size~^$size~")
) )
case n if orders(n).vehicle.Definition ne order.vehicle.Definition => case n if orders(n).vehicle.Definition ne order.vehicle.Definition =>
//replace existing order with new order //replace existing order with new order
@ -185,10 +184,9 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
val originalVehicle = originalOrder.vehicle.Definition.Name val originalVehicle = originalOrder.vehicle.Definition.Name
orders = (orders.take(n) :+ order) ++ orders.drop(n+1) orders = (orders.take(n) :+ order) ++ orders.drop(n+1)
VehicleSpawnControl.DisposeVehicle(originalOrder.vehicle, zone) VehicleSpawnControl.DisposeVehicle(originalOrder.vehicle, zone)
zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder( zone.VehicleEvents ! MessageEnvelope(
name, name,
VehicleSpawnPad.Reminders.Queue, VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_ReplacedVehicleWithVehicle^@$originalVehicle~^@${order.vehicle.Definition.Name}~"))
Some(s"@SVCP_ReplacedVehicleWithVehicle^@$originalVehicle~^@${order.vehicle.Definition.Name}~")
) )
case _ => case _ =>
//order is the duplicate of an existing order; do nothing to the queue //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) val newOrder = VehicleSpawnControl.Order(driver, vehicle)
recursiveOrderReminder(orders.iterator, size) recursiveOrderReminder(orders.iterator, size)
trace(s"processing next order - a ${vehicle.Definition.Name} for $name") trace(s"processing next order - a ${vehicle.Definition.Name} for $name")
pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder( pad.Zone.VehicleEvents ! MessageEnvelope(
name, name,
VehicleSpawnPad.Reminders.Queue, VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_PositionInQueue^1~^$size~"))
Some(s"@SVCP_PositionInQueue^1~^$size~")
) )
trackedOrder = Some(newOrder) //guard on trackedOrder = Some(newOrder) //guard on
context.system.scheduler.scheduleOnce(2000 milliseconds, concealPlayer, newOrder) 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 = { private def CancelOrder(vehicle: Vehicle, player: Player, msg: Option[String]): Unit = {
if (vehicle.Seats.values.count(_.isOccupied) == 0) { if (vehicle.Seats.values.count(_.isOccupied) == 0) {
VehicleSpawnControl.DisposeSpawnedVehicle(vehicle, player, pad.Zone) 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, entry: VehicleSpawnPad.VehicleOrder,
cause: Option[Any] cause: Option[Any]
): Unit = { ): Unit = {
pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder( pad.Zone.VehicleEvents ! MessageEnvelope(
entry.player.Name, entry.player.Name,
VehicleSpawnPad.Reminders.Blocked, VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, cause)
cause
) )
} }
@ -465,10 +464,9 @@ class VehicleSpawnControl(pad: VehicleSpawnPad)
): Unit = { ): Unit = {
if (iter.hasNext) { if (iter.hasNext) {
val recipient = iter.next() val recipient = iter.next()
pad.Zone.VehicleEvents ! VehicleSpawnPad.PeriodicReminder( pad.Zone.VehicleEvents ! MessageEnvelope(
recipient.player.Name, recipient.player.Name,
VehicleSpawnPad.Reminders.Queue, VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Queue, Some(s"@SVCP_PositionInQueue^$position~^$size~"))
Some(s"@SVCP_PositionInQueue^$position~^$size~")
) )
recursiveOrderReminder(iter, size, position + 1) recursiveOrderReminder(iter, size, position + 1)
} }
@ -564,7 +562,7 @@ object VehicleSpawnControl {
*/ */
private def DisposeSpawnedVehicle(vehicle: Vehicle, player: Player, zone: Zone): Unit = { private def DisposeSpawnedVehicle(vehicle: Vehicle, player: Player, zone: Zone): Unit = {
DisposeVehicle(vehicle, zone) 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.{Player, Vehicle}
import net.psforever.objects.serverobject.structures.Amenity import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.serverobject.terminals.Terminal import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.services.base.message.SelfRespondingEvent
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
/** /**
@ -25,7 +26,6 @@ class VehicleSpawnPad(spDef: VehicleSpawnPadDefinition) extends Amenity {
} }
object VehicleSpawnPad { object VehicleSpawnPad {
/** /**
* Message to the spawn pad to enqueue the following vehicle order. * Message to the spawn pad to enqueue the following vehicle order.
* This is the entry point to vehicle spawn pad functionality. * This is the entry point to vehicle spawn pad functionality.
@ -39,14 +39,14 @@ object VehicleSpawnPad {
* @see `GenericObjectActionMessage` * @see `GenericObjectActionMessage`
* @param player_guid the player * @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`. * Message is intended to undo the effects of the above message, `ConcealPlayer`.
* @see `ConcealPlayer` * @see `ConcealPlayer`
* @param player_guid the player * @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"). * 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 vehicle the vehicle being spawned
* @param pad the spawn pad * @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"). * 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 vehicle the vehicle being spawned
* @param pad the spawn pad * @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. * Message that resets the spawn pad for its next order fulfillment operation by lowering the lifting platform.
* @see `GenericObjectActionMessage` * @see `GenericObjectActionMessage`
* @param pad the spawn pad * @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. * 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. * 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 vehicle the vehicle being spawned
* @param pad the spawn pad * @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. * 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. * 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 vehicle the vehicle being spawned
* @param pad the spawn pad * @param pad the spawn pad
*/ */
final case class PlayerSeatedInVehicle( //TODO while using fake rails (later edit: what does this mean?)
driver_name: String, final case class PlayerSeatedInVehicle(vehicle: Vehicle, pad: VehicleSpawnPad) extends SelfRespondingEvent
vehicle: Vehicle,
pad: VehicleSpawnPad
) //TODO while using fake rails
/** /**
* Message that starts the newly-spawned vehicle to begin driving away from the spawn pad. * 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. * Information about the driving process is available on the vehicle itself.
* This information should only be communicated to the driver's client only. * This information should only be communicated to the driver's client only.
* @see `VehicleDefinition` * @see `VehicleDefinition`
* @param driver_name the person who will drive the vehicle
* @param vehicle the vehicle * @param vehicle the vehicle
* @param pad the spawn pad * @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. * Message that transitions the newly-spawned vehicle into a cancellable auto-drive state.
* Information about the driving process is available on the vehicle itself. * Information about the driving process is available on the vehicle itself.
* This information should only be communicated to the driver's client only. * This information should only be communicated to the driver's client only.
* @see `VehicleDefinition` * @see `VehicleDefinition`
* @param driver_name the person who will drive the vehicle
* @param vehicle the vehicle * @param vehicle the vehicle
* @param pad the spawn pad * @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. * 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 * @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. * 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 reason the nature of the message
* @param data optional information for rendering the message to the client * @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. * 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 akka.actor.Props
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.services.base.envelope.MessageEnvelope
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -28,7 +29,7 @@ class VehicleSpawnControlConcealPlayer(pad: VehicleSpawnPad) extends VehicleSpaw
case order @ VehicleSpawnControl.Order(driver, vehicle) => case order @ VehicleSpawnControl.Order(driver, vehicle) =>
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) { if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) {
trace(s"hiding ${driver.Name}") 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) context.system.scheduler.scheduleOnce(2000 milliseconds, loadVehicle, order)
} else { } else {
trace(s"integral component lost; abort order fulfillment") 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 akka.actor.Props
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} 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`. * 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) => case order @ VehicleSpawnControl.Order(driver, vehicle) =>
trace(s"returning control of ${vehicle.Definition.Name} to its current driver") trace(s"returning control of ${vehicle.Definition.Name} to its current driver")
if (vehicle.PassengerInSeat(driver).nonEmpty) { 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 finalClear ! order

View file

@ -4,8 +4,9 @@ package net.psforever.objects.serverobject.pad.process
import akka.actor.Cancellable import akka.actor.Cancellable
import net.psforever.objects.Default import net.psforever.objects.Default
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.types.{PlanetSideGUID, Vector3} import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.types.Vector3
import net.psforever.services.vehicle.VehicleAction
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._ 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 //ensure the vacant vehicle is above the trench and the doors
vehicle.Position = pad.Position + Vector3.z(pad.Definition.VehicleCreationZOffset) vehicle.Position = pad.Position + Vector3.z(pad.Definition.VehicleCreationZOffset)
val definition = vehicle.Definition val definition = vehicle.Definition
pad.Zone.VehicleEvents ! VehicleServiceMessage( pad.Zone.VehicleEvents ! MessageEnvelope(
s"${pad.Continent}", s"${pad.Continent}",
VehicleAction.LoadVehicle( VehicleAction.LoadVehicle(vehicle, definition.ObjectId, vehicle.GUID, definition.Packet.ConstructorData(vehicle).get)
PlanetSideGUID(0),
vehicle,
definition.ObjectId,
vehicle.GUID,
definition.Packet.ConstructorData(vehicle).get
)
) )
} }
context.parent ! VehicleSpawnControl.ProcessControl.Reminder context.parent ! VehicleSpawnControl.ProcessControl.Reminder
@ -70,7 +65,7 @@ class VehicleSpawnControlFinalClearance(pad: VehicleSpawnPad) extends VehicleSpa
} }
case VehicleSpawnControlFinalClearance.NextOrder => case VehicleSpawnControlFinalClearance.NextOrder =>
pad.Zone.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad) pad.Zone.VehicleEvents ! MessageEnvelope(pad.Zone.id, VehicleSpawnPad.ResetSpawnPad(pad))
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
case _ => () case _ => ()

View file

@ -7,8 +7,8 @@ import akka.util.Timeout
import net.psforever.objects.GlobalDefinitions import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.VehicleAction
import net.psforever.types.Vector3 import net.psforever.types.Vector3
import net.psforever.zones.Zones import net.psforever.zones.Zones
@ -68,9 +68,9 @@ class VehicleSpawnControlLoadVehicle(pad: VehicleSpawnPad) extends VehicleSpawnC
val vtype = definition.ObjectId val vtype = definition.ObjectId
val vguid = v.GUID val vguid = v.GUID
val vdata = definition.Packet.ConstructorData(v).get val vdata = definition.Packet.ConstructorData(v).get
zone.VehicleEvents ! VehicleServiceMessage( zone.VehicleEvents ! MessageEnvelope(
zone.id, zone.id,
VehicleAction.LoadVehicle(Service.defaultPlayerGUID, v, vtype, vguid, vdata) VehicleAction.LoadVehicle(v, vtype, vguid, vdata)
) )
railJack ! temp.get railJack ! temp.get
temp = None 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.prop.DamageProperties
import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.services.base.envelope.MessageEnvelope
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -40,7 +41,7 @@ class VehicleSpawnControlRailJack(pad: VehicleSpawnPad) extends VehicleSpawnCont
pad.Definition.killBox(pad, vehicle.Definition.CanFly), pad.Definition.killBox(pad, vehicle.Definition.CanFly),
Zone.findAllTargets 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) context.system.scheduler.scheduleOnce(10 milliseconds, seatDriver, order)
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) => 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 akka.actor.{ActorRef, Props}
import net.psforever.objects.{Default, Vehicle} import net.psforever.objects.{Default, Vehicle}
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.services.base.envelope.MessageEnvelope
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._ import scala.concurrent.duration._
@ -46,7 +47,7 @@ class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnCo
vehicle.Actor ! Vehicle.Deconstruct(Some(pad.Definition.VehicleCreationDeconstructTime.seconds)) vehicle.Actor ! Vehicle.Deconstruct(Some(pad.Definition.VehicleCreationDeconstructTime.seconds))
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) { if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty) {
trace("driver to be made seated in vehicle") 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 { } else {
trace("driver lost; vehicle stranded on pad") trace("driver lost; vehicle stranded on pad")
} }
@ -58,7 +59,7 @@ class VehicleSpawnControlSeatDriver(pad: VehicleSpawnPad) extends VehicleSpawnCo
if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty && if (VehicleSpawnControl.validateOrderCredentials(pad, driver, vehicle).isEmpty &&
entry.vehicle.PassengerInSeat(entry.driver).contains(0)) { entry.vehicle.PassengerInSeat(entry.driver).contains(0)) {
trace(s"driver ${entry.driver.Name} has taken the wheel") 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 { } else {
trace("driver lost, but operations can continue") 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 akka.actor.Props
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad} import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.types.Vector3 import net.psforever.types.Vector3
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
@ -31,18 +32,18 @@ class VehicleSpawnControlServerVehicleOverride(pad: VehicleSpawnPad) extends Veh
val driverFailState = val driverFailState =
!driver.isAlive || driver.Continent != pad.Continent || !vehicle.PassengerInSeat(driver).contains(0) !driver.isAlive || driver.Continent != pad.Continent || !vehicle.PassengerInSeat(driver).contains(0)
vehicle.MountedIn = None 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 || driverFailState) {
if (vehicleFailState) { if (vehicleFailState) {
trace(s"vehicle was already destroyed") trace(s"vehicle was already destroyed")
} else { } else {
trace(s"driver is not ready") 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 driverControl ! order
} else { } else {
trace(s"telling ${driver.Name} that the server is assuming control of the ${vehicle.Definition.Name}") 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) context.system.scheduler.scheduleOnce(4000 milliseconds, driverControl, order)
} }

View file

@ -59,7 +59,7 @@ class PainboxControl(painbox: Painbox) extends PoweredAmenityControl {
} }
var commonBehavior: Receive = { var commonBehavior: Receive = {
case Service.Startup() => case Service.Startup =>
if (!disabled && domain.midpoint == Vector3.Zero) { if (!disabled && domain.midpoint == Vector3.Zero) {
initialStartup() initialStartup()
} }

View file

@ -5,7 +5,9 @@ import net.psforever.objects.Tool
import net.psforever.objects.serverobject.structures.Amenity import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.sourcing.{SourceEntry, SourceWithHealthEntry} import net.psforever.objects.sourcing.{SourceEntry, SourceWithHealthEntry}
import net.psforever.objects.vital.{DamagingActivity, RepairFromEquipment, SpawningActivity} 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 * 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. * 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. * These `PlanetSideAttributeMessage` attributes are the same as reported during zone load client configuration.
* @see `AvatarAction.PlanetsideAttributeToAll` * @see `PlanetsideAttribute`
* @see `AvatarServiceMessage`
* @see `Zone.AvatarEvents` * @see `Zone.AvatarEvents`
* @param target the entity being destroyed * @param target the entity being destroyed
*/ */
@ -37,8 +38,10 @@ object RepairableAmenity {
val zoneId = zone.id val zoneId = zone.id
val events = zone.AvatarEvents val events = zone.AvatarEvents
val targetGUID = target.GUID val targetGUID = target.GUID
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 50, 0)) events ! MessageEnvelope(
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(targetGUID, 51, 0)) zoneId,
SendResponse(PlanetsideAttributeMessage(targetGUID, 50, 0), PlanetsideAttributeMessage(targetGUID, 51, 0))
)
RestorationOfHistory(target) RestorationOfHistory(target)
} }

View file

@ -8,8 +8,8 @@ import net.psforever.objects.vital.RepairFromEquipment
import net.psforever.objects.{Player, Tool} import net.psforever.objects.{Player, Tool}
import net.psforever.packet.game.{ChatMsg, InventoryStateMessage, RepairMessage} import net.psforever.packet.game.{ChatMsg, InventoryStateMessage, RepairMessage}
import net.psforever.types.{ChatMessageType, PlanetSideEmpire, Vector3} import net.psforever.types.{ChatMessageType, PlanetSideEmpire, Vector3}
import net.psforever.services.Service import net.psforever.services.base.envelope.MessageEnvelope
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.base.message.{PlanetsideAttribute, SendResponse}
/** /**
* The "control" `Actor` mixin for repair-handling code, * 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. * 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. * Restore the target entity to a not destroyed state if applicable.
* Always show the repair progress bar window by using the appropriate packet. * Always show the repair progress bar window by using the appropriate packet.
* @see `AvatarAction.PlanetsideAttributeToAll` * @see `PlanetsideAttribute`
* @see `AvatarAction.SendResponse` * @see `SendResponse`
* @see `AvatarService` * @see `AvatarService`
* @see `InventoryStateMessage` * @see `InventoryStateMessage`
* @see `PlanetSideGameObject.isMoving` * @see `PlanetSideGameObject.isMoving`
* @see `RepairMessage` * @see `RepairMessage`
* @see `Service.defaultPlayerGUID` * @see `Default.GUID0`
* @see `Tool.Discharge` * @see `Tool.Discharge`
* @see `Zone.AvatarEvents` * @see `Zone.AvatarEvents`
* @param target the entity being repaired * @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 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 repairValue = Repairable.applyLevelModifier(player, item, RepairToolValue(item)).toInt + target.Definition.RepairMod
val magazine = item.Discharge() val magazine = item.Discharge()
events ! AvatarServiceMessage( events ! MessageEnvelope(
player.Name, player.Name,
AvatarAction.SendResponse( SendResponse(InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong))
Service.defaultPlayerGUID,
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
)
) )
target.LogActivity( target.LogActivity(
RepairFromEquipment( RepairFromEquipment(
@ -108,12 +105,9 @@ trait RepairableEntity extends Repairable {
originalHealth originalHealth
} }
//progress bar remains visible //progress bar remains visible
events ! AvatarServiceMessage( events ! MessageEnvelope(
name, name,
AvatarAction.SendResponse( SendResponse(RepairMessage(target.GUID, updatedHealth * 100 / definition.MaxHealth))
Service.defaultPlayerGUID,
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 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)) { if (target.Zone.Vehicles.exists(_.GUID == target.GUID)) {
@ -146,11 +140,11 @@ trait RepairableEntity extends Repairable {
val newHealth = target.Health = target.Health + amount val newHealth = target.Health = target.Health + amount
if (target.Destroyed) { if (target.Destroyed) {
if (newHealth >= target.Definition.RepairRestoresAt) { if (newHealth >= target.Definition.RepairRestoresAt) {
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth)) events ! MessageEnvelope(zoneId, PlanetsideAttribute(tguid, 0, newHealth))
Restoration(target) Restoration(target)
} }
} else { } else {
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth)) events ! MessageEnvelope(zoneId, PlanetsideAttribute(tguid, 0, newHealth))
} }
newHealth newHealth
} }

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