mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-11 14:34:44 +00:00
extract common messages into a common handler endpoint; created an interface for handlers thus that all handler endpoints can be polled if a specific handler endpoint does not support a message
This commit is contained in:
parent
7e1e0e3016
commit
b39f95354a
21 changed files with 2391 additions and 2480 deletions
|
|
@ -3,7 +3,7 @@ package net.psforever.actors.session
|
|||
|
||||
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware, typed}
|
||||
import net.psforever.actors.session.normal.NormalMode
|
||||
import net.psforever.actors.session.support.ZoningOperations
|
||||
import net.psforever.actors.session.support.{CommonHandlerFunctions, CommonHandlerLogic, HandlerFilter, ZoningOperations}
|
||||
import net.psforever.objects.TurretDeployable
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.containable.Containable
|
||||
|
|
@ -108,6 +108,21 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
private[this] var mode: PlayerMode = NormalMode
|
||||
private[this] var logic: ModeLogic = _
|
||||
|
||||
private val commonHandlerLogic: CommonHandlerLogic = new CommonHandlerLogic(data, context)
|
||||
private def listOfHandlers: Seq[CommonHandlerFunctions] = {
|
||||
if (logic == null) {
|
||||
List.empty
|
||||
} else {
|
||||
List(
|
||||
logic.avatarResponse,
|
||||
logic.local,
|
||||
logic.vehicleResponse,
|
||||
logic.galaxy,
|
||||
commonHandlerLogic
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override def postStop(): Unit = {
|
||||
clientKeepAlive.cancel()
|
||||
data.stop()
|
||||
|
|
@ -175,21 +190,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
logic.squad.handle(reply, excluded)
|
||||
|
||||
case envelope: GenericResponseEnvelope =>
|
||||
val GenericResponseEnvelope(toChannel, guid, reply) = envelope
|
||||
envelope.stamp match {
|
||||
case AvatarStamp =>
|
||||
logic.avatarResponse.handle(toChannel, guid, reply)
|
||||
case LocalStamp =>
|
||||
logic.local.handle(toChannel, guid, reply)
|
||||
case VehicleStamp =>
|
||||
logic.vehicleResponse.handle(toChannel, guid, reply)
|
||||
case GalaxyStamp =>
|
||||
logic.galaxy.handle(reply)
|
||||
case Undelivered =>
|
||||
log.error(s"received a message's response that was not delivered by an event system - $reply")
|
||||
case unknownStamp =>
|
||||
log.error(s"received a message's response from an unknown event system - stamp: $unknownStamp")
|
||||
}
|
||||
handleGenericResponseEnvelope(envelope)
|
||||
|
||||
case Mountable.MountMessages(tplayer, reply) =>
|
||||
logic.mountResponse.handle(tplayer, reply)
|
||||
|
|
@ -375,6 +376,43 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
logic.general.handleReceiveDefaultMessage(default, sender)
|
||||
}
|
||||
|
||||
private def handleGenericResponseEnvelope(envelope: GenericResponseEnvelope): Unit = {
|
||||
val GenericResponseEnvelope(_, guid, reply) = envelope
|
||||
//try use the stamp to match the specific handler
|
||||
val primaryHandler = envelope.stamp match {
|
||||
case Undelivered =>
|
||||
log.error(s"received a message's response that was not processed by an event system - $reply")
|
||||
CommonHandlerFunctions.HandleAnything
|
||||
case AvatarStamp =>
|
||||
logic.avatarResponse
|
||||
case LocalStamp =>
|
||||
logic.local
|
||||
case VehicleStamp =>
|
||||
logic.vehicleResponse
|
||||
case GalaxyStamp =>
|
||||
logic.galaxy
|
||||
case unknownStamp =>
|
||||
log.error(s"received a message's response from an unknown event system - stamp: $unknownStamp")
|
||||
CommonHandlerFunctions.HandleNothing
|
||||
}
|
||||
//try the handler on the input message
|
||||
lazy val alwaysAllowFilter = HandlerFilter.Allow(guid)
|
||||
if (primaryHandler.handleWith(guid).isDefinedAt(reply)) {
|
||||
primaryHandler.receive.apply(reply)
|
||||
} else if (!primaryHandler.handleWith(alwaysAllowFilter).isDefinedAt(reply)) {
|
||||
//check a list of all handlers for any potentially valid case
|
||||
val potentiallyValidHandlers = listOfHandlers.filter(_.handleWith(alwaysAllowFilter).isDefinedAt(reply))
|
||||
if (potentiallyValidHandlers.nonEmpty) {
|
||||
potentiallyValidHandlers
|
||||
.find(_.handleWith(guid).isDefinedAt(reply))
|
||||
.foreach(_.receive.apply(reply))
|
||||
//arrive here without processing input, the guard for a handler blocked a case; not gonna fault
|
||||
} else {
|
||||
log.error(s"received completely unhandled response message - $envelope")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def handleGamePkt: PlanetSideGamePacket => Unit = {
|
||||
case packet: ConnectToWorldRequestMessage =>
|
||||
logic.general.handleConnectToWorldRequest(packet)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,14 +1,15 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.actors.session.normal
|
||||
|
||||
import akka.actor.Actor.Receive
|
||||
import akka.actor.{ActorContext, ActorRef, typed}
|
||||
import net.psforever.actors.session.AvatarActor
|
||||
import net.psforever.actors.session.support.{GalaxyHandlerFunctions, SessionData, SessionGalaxyHandlers}
|
||||
import net.psforever.packet.game.{BroadcastWarpgateUpdateMessage, FriendsResponse, HotSpotUpdateMessage, ZoneInfoMessage, ZonePopulationUpdateMessage, HotSpotInfo => PacketHotSpotInfo}
|
||||
import net.psforever.services.base.envelope.MessageEnvelope
|
||||
import net.psforever.services.base.message.{EventResponse, SendResponse}
|
||||
import net.psforever.services.base.message.EventResponse
|
||||
import net.psforever.services.galaxy.GalaxyAction
|
||||
import net.psforever.types.{MemberAction, PlanetSideEmpire}
|
||||
import net.psforever.types.{MemberAction, PlanetSideEmpire, PlanetSideGUID}
|
||||
|
||||
object GalaxyHandlerLogic {
|
||||
def apply(ops: SessionGalaxyHandlers): GalaxyHandlerLogic = {
|
||||
|
|
@ -34,62 +35,59 @@ class GalaxyHandlerLogic(val ops: SessionGalaxyHandlers, implicit val context: A
|
|||
|
||||
/* response handlers */
|
||||
|
||||
def handle(reply: EventResponse): Unit = {
|
||||
reply match {
|
||||
case GalaxyAction.HotSpotUpdate(zone_index, priority, hot_spot_info) =>
|
||||
sendResponse(
|
||||
HotSpotUpdateMessage(
|
||||
zone_index,
|
||||
priority,
|
||||
hot_spot_info.map { spot => PacketHotSpotInfo(spot.DisplayLocation.x, spot.DisplayLocation.y, 40) }
|
||||
)
|
||||
override def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit = {
|
||||
receive.apply(reply)
|
||||
}
|
||||
|
||||
def receive: Receive = {
|
||||
case GalaxyAction.HotSpotUpdate(zone_index, priority, hot_spot_info) =>
|
||||
sendResponse(
|
||||
HotSpotUpdateMessage(
|
||||
zone_index,
|
||||
priority,
|
||||
hot_spot_info.map { spot => PacketHotSpotInfo(spot.DisplayLocation.x, spot.DisplayLocation.y, 40) }
|
||||
)
|
||||
)
|
||||
|
||||
case GalaxyAction.MapUpdate(msg) =>
|
||||
sendResponse(msg)
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.zones.Zones
|
||||
Zones.zones.find(_.Number == msg.continent_id) match {
|
||||
case Some(zone) =>
|
||||
zone.actor ! ZoneActor.BuildingInfoState(msg)
|
||||
case None =>
|
||||
}
|
||||
case GalaxyAction.MapUpdate(msg) =>
|
||||
sendResponse(msg)
|
||||
import net.psforever.actors.zone.ZoneActor
|
||||
import net.psforever.zones.Zones
|
||||
Zones.zones.find(_.Number == msg.continent_id) match {
|
||||
case Some(zone) =>
|
||||
zone.actor ! ZoneActor.BuildingInfoState(msg)
|
||||
case None =>
|
||||
}
|
||||
|
||||
case GalaxyAction.UpdateBroadcastPrivileges(zoneId, gateMapId, fromFactions, toFactions) =>
|
||||
val faction = player.Faction
|
||||
val from = fromFactions.contains(faction)
|
||||
val to = toFactions.contains(faction)
|
||||
if (from && !to) {
|
||||
sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, PlanetSideEmpire.NEUTRAL))
|
||||
} else if (!from && to) {
|
||||
sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, faction))
|
||||
}
|
||||
case GalaxyAction.UpdateBroadcastPrivileges(zoneId, gateMapId, fromFactions, toFactions) =>
|
||||
val faction = player.Faction
|
||||
val from = fromFactions.contains(faction)
|
||||
val to = toFactions.contains(faction)
|
||||
if (from && !to) {
|
||||
sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, PlanetSideEmpire.NEUTRAL))
|
||||
} else if (!from && to) {
|
||||
sendResponse(BroadcastWarpgateUpdateMessage(zoneId, gateMapId, faction))
|
||||
}
|
||||
|
||||
case GalaxyAction.FlagMapUpdate(msg) =>
|
||||
sendResponse(msg)
|
||||
case GalaxyAction.FlagMapUpdate(msg) =>
|
||||
sendResponse(msg)
|
||||
|
||||
case GalaxyAction.TransferPassenger(_, temp_channel, vehicle, _, manifest) =>
|
||||
sessionLogic.zoning.handleTransferPassenger(temp_channel, vehicle, manifest)
|
||||
case GalaxyAction.TransferPassenger(_, temp_channel, vehicle, _, manifest) =>
|
||||
sessionLogic.zoning.handleTransferPassenger(temp_channel, vehicle, manifest)
|
||||
|
||||
case GalaxyAction.LockedZoneUpdate(zone, time) =>
|
||||
sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
|
||||
case GalaxyAction.LockedZoneUpdate(zone, time) =>
|
||||
sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
|
||||
|
||||
case GalaxyAction.UnlockedZoneUpdate(zone) =>
|
||||
sendResponse(ZoneInfoMessage(zone.Number, empire_status=true, lock_time=0L))
|
||||
val popBO = 0
|
||||
val pop = zone.LivePlayers.distinctBy(_.CharId)
|
||||
val popTR = pop.count(_.Faction == PlanetSideEmpire.TR)
|
||||
val popNC = pop.count(_.Faction == PlanetSideEmpire.NC)
|
||||
val popVS = pop.count(_.Faction == PlanetSideEmpire.VS)
|
||||
sendResponse(ZonePopulationUpdateMessage(zone.Number, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
|
||||
case GalaxyAction.UnlockedZoneUpdate(zone) =>
|
||||
sendResponse(ZoneInfoMessage(zone.Number, empire_status=true, lock_time=0L))
|
||||
val popBO = 0
|
||||
val pop = zone.LivePlayers.distinctBy(_.CharId)
|
||||
val popTR = pop.count(_.Faction == PlanetSideEmpire.TR)
|
||||
val popNC = pop.count(_.Faction == PlanetSideEmpire.NC)
|
||||
val popVS = pop.count(_.Faction == PlanetSideEmpire.VS)
|
||||
sendResponse(ZonePopulationUpdateMessage(zone.Number, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
|
||||
|
||||
case GalaxyAction.LogStatusChange(name) if avatar.people.friend.exists(_.name.equals(name)) =>
|
||||
avatarActor ! AvatarActor.MemberListRequest(MemberAction.UpdateFriend, name)
|
||||
|
||||
case SendResponse(msgs) =>
|
||||
msgs.foreach(sendResponse)
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
case GalaxyAction.LogStatusChange(name) if avatar.people.friend.exists(_.name.equals(name)) =>
|
||||
avatarActor ! AvatarActor.MemberListRequest(MemberAction.UpdateFriend, name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.actors.session.normal
|
||||
|
||||
import akka.actor.Actor.Receive
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.actors.session.support.SpawnOperations.ActivityQueuedTask
|
||||
import net.psforever.actors.session.support.{LocalHandlerFunctions, SessionData, SessionLocalHandlers, SpawnOperations}
|
||||
|
|
@ -8,11 +9,11 @@ import net.psforever.objects.ce.Deployable
|
|||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.vehicles.MountableWeapons
|
||||
import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable}
|
||||
import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, HackState1, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage}
|
||||
import net.psforever.services.base.message.{EventResponse, GenericObjectAction, ObjectDelete, PlanetsideAttribute, SendResponse, SetEmpire}
|
||||
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.{GenericObjectAction, PlanetsideAttribute, SendResponse}
|
||||
import net.psforever.services.{InterstellarClusterService, Service}
|
||||
import net.psforever.services.local.LocalAction
|
||||
import net.psforever.types.{ChatMessageType, PlanetSideGUID, SpawnGroup}
|
||||
import net.psforever.types.{ChatMessageType, SpawnGroup}
|
||||
|
||||
object LocalHandlerLogic {
|
||||
def apply(ops: SessionLocalHandlers): LocalHandlerLogic = {
|
||||
|
|
@ -35,238 +36,213 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act
|
|||
|
||||
/* response handlers */
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param toChannel na
|
||||
* @param guid na
|
||||
* @param reply na
|
||||
*/
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit = {
|
||||
val resolvedPlayerGuid = if (player.HasGUID) {
|
||||
player.GUID
|
||||
} else {
|
||||
Service.defaultPlayerGUID
|
||||
}
|
||||
val isNotSameTarget = resolvedPlayerGuid != guid
|
||||
reply match {
|
||||
case LocalAction.DeployableMapIcon(behavior, deployInfo) if isNotSameTarget =>
|
||||
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 isNotSameTarget =>
|
||||
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 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 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 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 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 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 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, guid, progress=0, unk1.toFloat, HackState.HackCleared, unk2))
|
||||
|
||||
case LocalAction.HackObject(targetGuid, unk1, unk2) =>
|
||||
sessionLogic.general.hackObject(targetGuid, unk1, unk2)
|
||||
|
||||
case PlanetsideAttribute(targetGuid, attributeType, attributeValue) =>
|
||||
sessionLogic.general.sendPlanetsideAttributeMessage(targetGuid, attributeType, attributeValue)
|
||||
|
||||
case GenericObjectAction(targetGuid, actionNumber) =>
|
||||
sendResponse(GenericObjectActionMessage(targetGuid, actionNumber))
|
||||
|
||||
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 ObjectDelete(objectGuid, unk) if isNotSameTarget =>
|
||||
sendResponse(ObjectDeleteMessage(objectGuid, unk))
|
||||
|
||||
case LocalAction.ProximityTerminalEffect(object_guid, true) =>
|
||||
sendResponse(ProximityTerminalUseMessage(Service.defaultPlayerGUID, object_guid, unk=true))
|
||||
|
||||
case LocalAction.ProximityTerminalEffect(objectGuid, false) =>
|
||||
sendResponse(ProximityTerminalUseMessage(Service.defaultPlayerGUID, 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 SendResponse(msgs) =>
|
||||
msgs.foreach {
|
||||
case msg @ (m: GenericObjectActionMessage)
|
||||
if (m.code == 58 || m.code == 60 || m.code == 61) && !sessionLogic.zoning.spawn.startEnqueueSquadMessages =>
|
||||
// delay building virus alert if player is dead/respawning
|
||||
sessionLogic.zoning.spawn.enqueueNewActivity(ActivityQueuedTask(
|
||||
SpawnOperations.delaySendGenericObjectActionMessage(msg), 1)
|
||||
)
|
||||
case msg =>
|
||||
sendResponse(msg)
|
||||
}
|
||||
|
||||
case SetEmpire(objectGuid, empire) =>
|
||||
sendResponse(SetEmpireMessage(objectGuid, empire))
|
||||
|
||||
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 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 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
|
||||
def receive: Receive = {
|
||||
case SendResponse(msgs) =>
|
||||
msgs.foreach {
|
||||
case msg @ (m: GenericObjectActionMessage)
|
||||
if (m.code == 58 || m.code == 60 || m.code == 61) && !sessionLogic.zoning.spawn.startEnqueueSquadMessages =>
|
||||
// delay building virus alert if player is dead/respawning
|
||||
sessionLogic.zoning.spawn.enqueueNewActivity(ActivityQueuedTask(
|
||||
SpawnOperations.delaySendGenericObjectActionMessage(msg), 1)
|
||||
)
|
||||
case msg =>
|
||||
sendResponse(msg)
|
||||
}
|
||||
|
||||
case LocalAction.DeployableMapIcon(behavior, deployInfo) if filter.isNotSameTarget =>
|
||||
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 filter.isNotSameTarget =>
|
||||
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 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 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 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 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 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 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, filter.resolvedPlayerGuid, progress=0, unk1.toFloat, HackState.HackCleared, unk2))
|
||||
|
||||
case LocalAction.HackObject(targetGuid, unk1, unk2) =>
|
||||
sessionLogic.general.hackObject(targetGuid, unk1, unk2)
|
||||
|
||||
case PlanetsideAttribute(targetGuid, attributeType, attributeValue) =>
|
||||
sessionLogic.general.sendPlanetsideAttributeMessage(targetGuid, attributeType, attributeValue)
|
||||
|
||||
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(Service.defaultPlayerGUID, object_guid, unk=true))
|
||||
|
||||
case LocalAction.ProximityTerminalEffect(objectGuid, false) =>
|
||||
sendResponse(ProximityTerminalUseMessage(Service.defaultPlayerGUID, 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 filter.isSameTarget /*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 _ => ()
|
||||
}
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.actors.session.normal
|
||||
|
||||
import akka.actor.Actor.Receive
|
||||
import akka.actor.{ActorContext, ActorRef, typed}
|
||||
import net.psforever.actors.session.AvatarActor
|
||||
import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions}
|
||||
|
|
@ -15,7 +16,7 @@ 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.services.Service
|
||||
import net.psforever.services.base.envelope.GenericResponseEnvelope
|
||||
import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, EventResponse, GenericObjectAction, HintsAtAttacker, ObjectDelete, PlanetsideAttribute, ReloadTool, SendResponse, WeaponDryFire}
|
||||
import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, GenericObjectAction, HintsAtAttacker, ObjectDelete, PlanetsideAttribute, ReloadTool, SendResponse, WeaponDryFire}
|
||||
import net.psforever.services.local.support.CaptureFlagManager
|
||||
import net.psforever.services.vehicle.{VehicleAction, VehicleStamp}
|
||||
import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
|
||||
|
|
@ -33,367 +34,305 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
|
|||
|
||||
private val galaxyService: ActorRef = ops.galaxyService
|
||||
|
||||
/**
|
||||
* na
|
||||
*
|
||||
* @param toChannel na
|
||||
* @param guid na
|
||||
* @param reply na
|
||||
*/
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit = {
|
||||
val resolvedPlayerGuid = if (player.HasGUID) {
|
||||
player.GUID
|
||||
} else {
|
||||
PlanetSideGUID(-1)
|
||||
}
|
||||
val isNotSameTarget = resolvedPlayerGuid != guid
|
||||
reply match {
|
||||
case VehicleAction.VehicleState(
|
||||
vehicleGuid,
|
||||
unk1,
|
||||
pos,
|
||||
orient,
|
||||
vel,
|
||||
unk2,
|
||||
unk3,
|
||||
unk4,
|
||||
wheelDirection,
|
||||
unk5,
|
||||
unk6
|
||||
) if isNotSameTarget && player.VehicleSeated.contains(vehicleGuid) =>
|
||||
//player who is also in the vehicle (not driver)
|
||||
sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, orient, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
|
||||
player.Position = pos
|
||||
player.Orientation = orient
|
||||
player.Velocity = vel
|
||||
sessionLogic.updateLocalBlockMap(pos)
|
||||
//llu destruction check
|
||||
if (player.Carrying.contains(SpecialCarry.CaptureFlag)) {
|
||||
continent
|
||||
.GUID(player.VehicleSeated)
|
||||
.collect { case vehicle: Vehicle =>
|
||||
CaptureFlagManager.ReasonToLoseFlagViolently(continent, sessionLogic.general.specialItemSlotGuid, vehicle)
|
||||
}
|
||||
}
|
||||
|
||||
case VehicleAction.VehicleState(
|
||||
vehicleGuid,
|
||||
unk1,
|
||||
pos,
|
||||
ang,
|
||||
vel,
|
||||
unk2,
|
||||
unk3,
|
||||
unk4,
|
||||
wheelDirection,
|
||||
unk5,
|
||||
unk6
|
||||
) if isNotSameTarget =>
|
||||
//player who is watching the vehicle from the outside
|
||||
sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
|
||||
|
||||
case VehicleAction.ChildObjectState(objectGuid, pitch, yaw) if isNotSameTarget =>
|
||||
sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
|
||||
|
||||
case VehicleAction.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 ChangeFireState_Start(weaponGuid) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Start(weaponGuid))
|
||||
|
||||
case ChangeFireState_Stop(weaponGuid) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||
|
||||
case ReloadTool(itemGuid) if isNotSameTarget =>
|
||||
sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
|
||||
|
||||
case 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 WeaponDryFire(weaponGuid) if isNotSameTarget =>
|
||||
continent.GUID(weaponGuid).collect {
|
||||
case tool: Tool if tool.Magazine == 0 =>
|
||||
// check that the magazine is still empty before sending WeaponDryFireMessage
|
||||
// if it has been reloaded since then, other clients will not see it firing
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
}
|
||||
|
||||
case VehicleAction.DismountVehicle(bailType, wasKickedByDriver) if isNotSameTarget =>
|
||||
sendResponse(DismountVehicleMsg(guid, bailType, wasKickedByDriver))
|
||||
|
||||
case VehicleAction.MountVehicle(vehicleGuid, seat) if isNotSameTarget =>
|
||||
sendResponse(ObjectAttachMessage(vehicleGuid, guid, seat))
|
||||
|
||||
case VehicleAction.DeployRequest(objectGuid, state, unk1, unk2, pos) if isNotSameTarget =>
|
||||
sendResponse(DeployRequestMessage(guid, objectGuid, state, unk1, unk2, pos))
|
||||
|
||||
case SendResponse(msgs) =>
|
||||
msgs.foreach(sendResponse)
|
||||
|
||||
case VehicleAction.EquipmentCreatedInSlot(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case GenericObjectAction(objectGuid, action) if isNotSameTarget =>
|
||||
sendResponse(GenericObjectActionMessage(objectGuid, action))
|
||||
|
||||
case HintsAtAttacker(sourceGuid) if player.isAlive =>
|
||||
sendResponse(HitHint(sourceGuid, player.GUID))
|
||||
|
||||
case VehicleAction.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 VehicleAction.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 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(guid, BailType.Kicked, wasKickedByDriver))
|
||||
|
||||
case VehicleAction.InventoryState2(objGuid, parentGuid, value) if isNotSameTarget =>
|
||||
sendResponse(InventoryStateMessage(objGuid, unk=0, parentGuid, value))
|
||||
|
||||
case VehicleAction.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 ObjectDelete(itemGuid, _) if isNotSameTarget =>
|
||||
sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
|
||||
|
||||
case VehicleAction.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 VehicleAction.LoseOwnership(_, vehicleGuid) =>
|
||||
ops.announceAmsDecay(vehicleGuid,msg = "@ams_decaystarted")
|
||||
|
||||
case PlanetsideAttribute(vehicleGuid, attributeType, attributeValue) if isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, attributeType, attributeValue))
|
||||
|
||||
case VehicleAction.SeatPermissions(vehicleGuid, seatGroup, permission) if isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, seatGroup, permission))
|
||||
|
||||
case VehicleAction.StowCreatedEquipment(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 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 isNotSameTarget =>
|
||||
//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 isNotSameTarget =>
|
||||
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 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,
|
||||
toChannel,
|
||||
PlanetSideGUID(0),
|
||||
VehicleAction.KickCargo(vehicle, speed=0, delay)
|
||||
)
|
||||
context.system.scheduler.scheduleOnce(delay milliseconds, context.self, resp)
|
||||
|
||||
case VehicleAction.KickCargo(cargo, _, _)
|
||||
if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive =>
|
||||
sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
|
||||
|
||||
case VehicleAction.ChangeLoadout(target, oldWeapons, addedWeapons, oldInventory, newInventory)
|
||||
if player.avatar.vehicle.contains(target) =>
|
||||
//TODO when vehicle weapons can be changed without visual glitches, rewrite this
|
||||
continent.GUID(target).collect { case vehicle: Vehicle =>
|
||||
import net.psforever.login.WorldSession.boolToInt
|
||||
//owner: must unregister old equipment, and register and install new equipment
|
||||
(oldWeapons ++ oldInventory).foreach {
|
||||
case (obj, eguid) =>
|
||||
sendResponse(ObjectDeleteMessage(eguid, unk1=0))
|
||||
TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
|
||||
def receive: Receive = {
|
||||
case VehicleAction.VehicleState(
|
||||
vehicleGuid,
|
||||
unk1,
|
||||
pos,
|
||||
orient,
|
||||
vel,
|
||||
unk2,
|
||||
unk3,
|
||||
unk4,
|
||||
wheelDirection,
|
||||
unk5,
|
||||
unk6
|
||||
) if filter.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)
|
||||
}
|
||||
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 sessionLogic.general.accessedContainer.map(_.GUID).contains(target) =>
|
||||
//TODO when vehicle weapons can be changed without visual glitches, rewrite this
|
||||
continent.GUID(target).collect { case vehicle: Vehicle =>
|
||||
//external participant: observe changes to equipment
|
||||
(oldWeapons ++ oldInventory).foreach { case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0)) }
|
||||
changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
|
||||
}
|
||||
case VehicleAction.VehicleState(
|
||||
vehicleGuid,
|
||||
unk1,
|
||||
pos,
|
||||
ang,
|
||||
vel,
|
||||
unk2,
|
||||
unk3,
|
||||
unk4,
|
||||
wheelDirection,
|
||||
unk5,
|
||||
unk6
|
||||
) if filter.isNotSameTarget =>
|
||||
//player who is watching the vehicle from the outside
|
||||
sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
|
||||
|
||||
case VehicleAction.ChangeLoadout(target, oldWeapons, _, oldInventory, _) =>
|
||||
//TODO when vehicle weapons can be changed without visual glitches, rewrite this
|
||||
continent.GUID(target).collect { case vehicle: Vehicle =>
|
||||
changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
|
||||
}
|
||||
case VehicleAction.ChildObjectState(objectGuid, pitch, yaw) if filter.isNotSameTarget =>
|
||||
sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
|
||||
|
||||
case VehicleSpawnPad.AttachToRails(vehicle, pad) =>
|
||||
sendResponse(ObjectAttachMessage(pad.GUID, vehicle.GUID, slot=3))
|
||||
case VehicleAction.FrameVehicleState(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)
|
||||
if filter.isNotSameTarget =>
|
||||
sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
|
||||
|
||||
case VehicleSpawnPad.ConcealPlayer(playerGuid) =>
|
||||
sendResponse(GenericObjectActionMessage(playerGuid, code=9))
|
||||
case VehicleAction.DismountVehicle(bailType, wasKickedByDriver) if filter.isNotSameTarget =>
|
||||
sendResponse(DismountVehicleMsg(filter.resolvedPlayerGuid, bailType, wasKickedByDriver))
|
||||
|
||||
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 VehicleAction.MountVehicle(vehicleGuid, seat) if filter.isNotSameTarget =>
|
||||
sendResponse(ObjectAttachMessage(vehicleGuid, filter.resolvedPlayerGuid, seat))
|
||||
|
||||
case VehicleAction.DeployRequest(objectGuid, state, unk1, unk2, pos) if filter.isNotSameTarget =>
|
||||
sendResponse(DeployRequestMessage(filter.resolvedPlayerGuid, objectGuid, state, unk1, unk2, pos))
|
||||
|
||||
case VehicleAction.EquipmentCreatedInSlot(pkt) if filter.isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case VehicleAction.InventoryState(obj, parentGuid, start, conData) if filter.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 VehicleAction.KickPassenger(_, wasKickedByDriver, vehicleGuid) if filter.isSameTarget /*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(filter.resolvedPlayerGuid, 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(filter.resolvedPlayerGuid, BailType.Kicked, wasKickedByDriver))
|
||||
|
||||
case VehicleAction.InventoryState2(objGuid, parentGuid, value) if filter.isNotSameTarget =>
|
||||
sendResponse(InventoryStateMessage(objGuid, unk=0, parentGuid, value))
|
||||
|
||||
case VehicleAction.LoadVehicle(vehicle, vtype, vguid, vdata) if filter.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 VehicleAction.Ownership(vehicleGuid) if filter.isSameTarget /*resolvedPlayerGuid == guid*/ =>
|
||||
//Only the player that owns this vehicle needs the ownership packet
|
||||
avatarActor ! AvatarActor.SetVehicle(Some(vehicleGuid))
|
||||
sendResponse(PlanetsideAttributeMessage(filter.resolvedPlayerGuid, attribute_type=21, vehicleGuid))
|
||||
|
||||
case VehicleAction.LoseOwnership(_, vehicleGuid) =>
|
||||
ops.announceAmsDecay(vehicleGuid,msg = "@ams_decaystarted")
|
||||
|
||||
case VehicleAction.SeatPermissions(vehicleGuid, seatGroup, permission) if filter.isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, seatGroup, permission))
|
||||
|
||||
case VehicleAction.StowCreatedEquipment(vehicleGuid, slot, itemType, itemGuid, itemData) if filter.isNotSameTarget =>
|
||||
//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 filter.isNotSameTarget =>
|
||||
//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 filter.isNotSameTarget =>
|
||||
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 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 VehicleSpawnPad.ResetSpawnPad(pad) =>
|
||||
sendResponse(GenericObjectActionMessage(pad.GUID, code=23))
|
||||
case VehicleAction.KickCargo(cargo, _, _)
|
||||
if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive =>
|
||||
sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
|
||||
|
||||
case VehicleSpawnPad.RevealPlayer(playerGuid) =>
|
||||
sendResponse(GenericObjectActionMessage(playerGuid, code=10))
|
||||
|
||||
case VehicleSpawnPad.StartPlayerSeatedInVehicle(vehicle, _)
|
||||
if 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)
|
||||
case VehicleAction.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))
|
||||
}
|
||||
sendResponse(msg)
|
||||
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 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))
|
||||
case VehicleAction.ChangeLoadout(target, oldWeapons, _, oldInventory, _)
|
||||
if sessionLogic.general.accessedContainer.map(_.GUID).contains(target) =>
|
||||
//TODO when vehicle weapons can be changed without visual glitches, rewrite this
|
||||
continent.GUID(target).collect { case vehicle: Vehicle =>
|
||||
//external participant: observe changes to equipment
|
||||
(oldWeapons ++ oldInventory).foreach { case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0)) }
|
||||
changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
|
||||
}
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
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 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(
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2024 PSForever
|
||||
package net.psforever.actors.session.spectator
|
||||
|
||||
import akka.actor.Actor.Receive
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.actors.session.support.{SessionData, SessionVehicleHandlers, VehicleHandlerFunctions}
|
||||
import net.psforever.objects.{Tool, Vehicle, Vehicles}
|
||||
|
|
@ -9,7 +10,7 @@ import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
|||
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
||||
import net.psforever.packet.game.{ChangeAmmoMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChildObjectStateMessage, DeadState, DeployRequestMessage, DismountVehicleMsg, FrameVehicleStateMessage, GenericObjectActionMessage, InventoryStateMessage, ObjectAttachMessage, ObjectCreateDetailedMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, PlanetsideAttributeMessage, ReloadMessage, ServerVehicleOverrideMsg, VehicleStateMessage, WeaponDryFireMessage}
|
||||
import net.psforever.services.base.envelope.GenericResponseEnvelope
|
||||
import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, EventResponse, GenericObjectAction, ObjectDelete, PlanetsideAttribute, ReloadTool, SendResponse, WeaponDryFire}
|
||||
import net.psforever.services.base.message.{ChangeAmmo, ChangeFireState_Start, ChangeFireState_Stop, GenericObjectAction, ObjectDelete, PlanetsideAttribute, ReloadTool, SendResponse, WeaponDryFire}
|
||||
import net.psforever.services.vehicle.{VehicleAction, VehicleStamp}
|
||||
import net.psforever.types.{BailType, PlanetSideGUID, Vector3}
|
||||
|
||||
|
|
@ -26,232 +27,173 @@ class VehicleHandlerLogic(val ops: SessionVehicleHandlers, implicit val context:
|
|||
|
||||
//private val galaxyService: ActorRef = ops.galaxyService
|
||||
|
||||
/**
|
||||
* na
|
||||
*
|
||||
* @param toChannel na
|
||||
* @param guid na
|
||||
* @param reply na
|
||||
*/
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit = {
|
||||
val resolvedPlayerGuid = if (player.HasGUID) {
|
||||
player.GUID
|
||||
} else {
|
||||
PlanetSideGUID(-1)
|
||||
}
|
||||
val isNotSameTarget = resolvedPlayerGuid != guid
|
||||
reply match {
|
||||
case VehicleAction.VehicleState(
|
||||
vehicleGuid,
|
||||
unk1,
|
||||
pos,
|
||||
orient,
|
||||
vel,
|
||||
unk2,
|
||||
unk3,
|
||||
unk4,
|
||||
wheelDirection,
|
||||
unk5,
|
||||
unk6
|
||||
) if isNotSameTarget && player.VehicleSeated.contains(vehicleGuid) =>
|
||||
//player who is also in the vehicle (not driver)
|
||||
sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, orient, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
|
||||
player.Position = pos
|
||||
player.Orientation = orient
|
||||
player.Velocity = vel
|
||||
sessionLogic.updateLocalBlockMap(pos)
|
||||
def receive: Receive = {
|
||||
case VehicleAction.VehicleState(
|
||||
vehicleGuid,
|
||||
unk1,
|
||||
pos,
|
||||
orient,
|
||||
vel,
|
||||
unk2,
|
||||
unk3,
|
||||
unk4,
|
||||
wheelDirection,
|
||||
unk5,
|
||||
unk6
|
||||
) if filter.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 VehicleAction.VehicleState(
|
||||
vehicleGuid,
|
||||
unk1,
|
||||
pos,
|
||||
ang,
|
||||
vel,
|
||||
unk2,
|
||||
unk3,
|
||||
unk4,
|
||||
wheelDirection,
|
||||
unk5,
|
||||
unk6
|
||||
) if isNotSameTarget =>
|
||||
//player who is watching the vehicle from the outside
|
||||
sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
|
||||
case VehicleAction.VehicleState(
|
||||
vehicleGuid,
|
||||
unk1,
|
||||
pos,
|
||||
ang,
|
||||
vel,
|
||||
unk2,
|
||||
unk3,
|
||||
unk4,
|
||||
wheelDirection,
|
||||
unk5,
|
||||
unk6
|
||||
) if filter.isNotSameTarget =>
|
||||
//player who is watching the vehicle from the outside
|
||||
sendResponse(VehicleStateMessage(vehicleGuid, unk1, pos, ang, vel, unk2, unk3, unk4, wheelDirection, unk5, unk6))
|
||||
|
||||
case VehicleAction.ChildObjectState(objectGuid, pitch, yaw) if isNotSameTarget =>
|
||||
sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
|
||||
case VehicleAction.ChildObjectState(objectGuid, pitch, yaw) if filter.isNotSameTarget =>
|
||||
sendResponse(ChildObjectStateMessage(objectGuid, pitch, yaw))
|
||||
|
||||
case VehicleAction.FrameVehicleState(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)
|
||||
if isNotSameTarget =>
|
||||
sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
|
||||
case VehicleAction.FrameVehicleState(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA)
|
||||
if filter.isNotSameTarget =>
|
||||
sendResponse(FrameVehicleStateMessage(vguid, u1, pos, oient, vel, u2, u3, u4, is_crouched, u6, u7, u8, u9, uA))
|
||||
|
||||
case ChangeFireState_Start(weaponGuid) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Start(weaponGuid))
|
||||
case VehicleAction.DismountVehicle(bailType, wasKickedByDriver) if filter.isNotSameTarget =>
|
||||
sendResponse(DismountVehicleMsg(filter.resolvedPlayerGuid, bailType, wasKickedByDriver))
|
||||
|
||||
case ChangeFireState_Stop(weaponGuid) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||
case VehicleAction.MountVehicle(vehicleGuid, seat) if filter.isNotSameTarget =>
|
||||
sendResponse(ObjectAttachMessage(vehicleGuid, filter.resolvedPlayerGuid, seat))
|
||||
|
||||
case ReloadTool(itemGuid) if isNotSameTarget =>
|
||||
sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
|
||||
case VehicleAction.DeployRequest(objectGuid, state, unk1, unk2, pos) if filter.isNotSameTarget =>
|
||||
sendResponse(DeployRequestMessage(filter.resolvedPlayerGuid, objectGuid, state, unk1, unk2, pos))
|
||||
|
||||
case ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data) if isNotSameTarget =>
|
||||
sendResponse(ObjectDetachMessage(weapon_guid, previous_guid, Vector3.Zero, 0))
|
||||
//TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
ammo_id,
|
||||
ammo_guid,
|
||||
ObjectCreateMessageParent(weapon_guid, weapon_slot),
|
||||
ammo_data
|
||||
)
|
||||
case VehicleAction.EquipmentCreatedInSlot(pkt) if filter.isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case VehicleAction.InventoryState(obj, parentGuid, start, conData) if filter.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 VehicleAction.KickPassenger(_, wasKickedByDriver, vehicleGuid) if filter.isSameTarget =>
|
||||
//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(filter.resolvedPlayerGuid, 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(filter.resolvedPlayerGuid, BailType.Kicked, wasKickedByDriver))
|
||||
|
||||
case VehicleAction.InventoryState2(objGuid, parentGuid, value) if filter.isNotSameTarget =>
|
||||
sendResponse(InventoryStateMessage(objGuid, unk=0, parentGuid, value))
|
||||
|
||||
case VehicleAction.LoadVehicle(vehicle, vtype, vguid, vdata) if filter.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 VehicleAction.SeatPermissions(vehicleGuid, seatGroup, permission) if filter.isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, seatGroup, permission))
|
||||
|
||||
case VehicleAction.UnloadVehicle(_, vehicleGuid) =>
|
||||
sendResponse(ObjectDeleteMessage(vehicleGuid, unk1=1))
|
||||
|
||||
case VehicleAction.UnstowEquipment(itemGuid) if filter.isNotSameTarget =>
|
||||
//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 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 WeaponDryFire(weaponGuid) if isNotSameTarget =>
|
||||
continent.GUID(weaponGuid).collect {
|
||||
case tool: Tool if tool.Magazine == 0 =>
|
||||
// check that the magazine is still empty before sending WeaponDryFireMessage
|
||||
// if it has been reloaded since then, other clients will not see it firing
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
}
|
||||
case VehicleAction.KickCargo(cargo, _, _)
|
||||
if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive =>
|
||||
sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
|
||||
|
||||
case VehicleAction.DismountVehicle(bailType, wasKickedByDriver) if isNotSameTarget =>
|
||||
sendResponse(DismountVehicleMsg(guid, bailType, wasKickedByDriver))
|
||||
case VehicleSpawnPad.AttachToRails(vehicle, pad) =>
|
||||
sendResponse(ObjectAttachMessage(pad.GUID, vehicle.GUID, slot=3))
|
||||
|
||||
case VehicleAction.MountVehicle(vehicleGuid, seat) if isNotSameTarget =>
|
||||
sendResponse(ObjectAttachMessage(vehicleGuid, guid, seat))
|
||||
case VehicleSpawnPad.ConcealPlayer(playerGuid) =>
|
||||
sendResponse(GenericObjectActionMessage(playerGuid, code=9))
|
||||
|
||||
case VehicleAction.DeployRequest(objectGuid, state, unk1, unk2, pos) if isNotSameTarget =>
|
||||
sendResponse(DeployRequestMessage(guid, objectGuid, state, unk1, unk2, pos))
|
||||
|
||||
case SendResponse(msgs) =>
|
||||
msgs.foreach(sendResponse)
|
||||
|
||||
case VehicleAction.EquipmentCreatedInSlot(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case GenericObjectAction(objectGuid, action) if isNotSameTarget =>
|
||||
sendResponse(GenericObjectActionMessage(objectGuid, action))
|
||||
|
||||
case VehicleAction.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 VehicleAction.KickPassenger(_, wasKickedByDriver, vehicleGuid) if resolvedPlayerGuid == guid =>
|
||||
//seat number (first field) seems to be correct if passenger is kicked manually by driver
|
||||
//but always seems to return 4 if user is kicked by mount permissions changing
|
||||
sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
|
||||
continent.GUID(vehicleGuid) match {
|
||||
case Some(obj: Vehicle) =>
|
||||
sessionLogic.general.unaccessContainer(obj)
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
case 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(guid, BailType.Kicked, wasKickedByDriver))
|
||||
|
||||
case VehicleAction.InventoryState2(objGuid, parentGuid, value) if isNotSameTarget =>
|
||||
sendResponse(InventoryStateMessage(objGuid, unk=0, parentGuid, value))
|
||||
|
||||
case VehicleAction.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 ObjectDelete(itemGuid, _) if isNotSameTarget =>
|
||||
sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
|
||||
|
||||
case PlanetsideAttribute(vehicleGuid, attributeType, attributeValue) if isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, attributeType, attributeValue))
|
||||
|
||||
case VehicleAction.SeatPermissions(vehicleGuid, seatGroup, permission) if isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, seatGroup, permission))
|
||||
|
||||
case VehicleAction.UnloadVehicle(_, vehicleGuid) =>
|
||||
sendResponse(ObjectDeleteMessage(vehicleGuid, unk1=1))
|
||||
|
||||
case VehicleAction.UnstowEquipment(itemGuid) if isNotSameTarget =>
|
||||
//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 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)
|
||||
)
|
||||
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
|
||||
)
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration._
|
||||
val resp = GenericResponseEnvelope(
|
||||
VehicleStamp,
|
||||
toChannel,
|
||||
PlanetSideGUID(0),
|
||||
VehicleAction.KickCargo(vehicle, speed=0, delay)
|
||||
)
|
||||
context.system.scheduler.scheduleOnce(delay milliseconds, context.self, resp)
|
||||
)
|
||||
|
||||
case VehicleAction.KickCargo(cargo, _, _)
|
||||
if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive =>
|
||||
sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
|
||||
case VehicleSpawnPad.ResetSpawnPad(pad) =>
|
||||
sendResponse(GenericObjectActionMessage(pad.GUID, code=23))
|
||||
|
||||
case VehicleSpawnPad.AttachToRails(vehicle, pad) =>
|
||||
sendResponse(ObjectAttachMessage(pad.GUID, vehicle.GUID, slot=3))
|
||||
case VehicleSpawnPad.RevealPlayer(playerGuid) =>
|
||||
sendResponse(GenericObjectActionMessage(playerGuid, code=10))
|
||||
|
||||
case VehicleSpawnPad.ConcealPlayer(playerGuid) =>
|
||||
sendResponse(GenericObjectActionMessage(playerGuid, code=9))
|
||||
case VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, _) =>
|
||||
sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
|
||||
|
||||
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.ServerVehicleOverrideEnd(vehicle, _) =>
|
||||
sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
|
||||
|
||||
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 _ => ()
|
||||
}
|
||||
case VehicleAction.ChangeLoadout(target, oldWeapons, _, oldInventory, _) =>
|
||||
//TODO when vehicle weapons can be changed without visual glitches, rewrite this
|
||||
continent.GUID(target).collect { case vehicle: Vehicle =>
|
||||
changeLoadoutDeleteOldEquipment(vehicle, oldWeapons, oldInventory)
|
||||
}
|
||||
}
|
||||
|
||||
private def changeLoadoutDeleteOldEquipment(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) 2026 PSForever
|
||||
package net.psforever.actors.session.support
|
||||
|
||||
import akka.actor.Actor.Receive
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.base.message.EventResponse
|
||||
import net.psforever.types.PlanetSideGUID
|
||||
|
||||
trait HandlerFilter {
|
||||
def resolvedPlayerGuid: PlanetSideGUID
|
||||
def isNotSameTarget: Boolean
|
||||
def isSameTarget: Boolean = !isNotSameTarget
|
||||
}
|
||||
|
||||
class HandlerFilterClass(guid1: PlanetSideGUID, guid2: PlanetSideGUID) extends HandlerFilter {
|
||||
val resolvedPlayerGuid: PlanetSideGUID = guid2
|
||||
val isNotSameTarget: Boolean = resolvedPlayerGuid != guid1
|
||||
}
|
||||
|
||||
object HandlerFilter {
|
||||
def apply(guid1: PlanetSideGUID, guid2: PlanetSideGUID): HandlerFilter = {
|
||||
new HandlerFilterClass(guid1, guid2)
|
||||
}
|
||||
|
||||
def apply(guid: PlanetSideGUID, player: Player): HandlerFilter = {
|
||||
this(guid, if (player != null && player.HasGUID) {
|
||||
player.GUID
|
||||
} else {
|
||||
Service.defaultPlayerGUID
|
||||
})
|
||||
}
|
||||
|
||||
final val NeverAllow: HandlerFilter = new HandlerFilter {
|
||||
def resolvedPlayerGuid: PlanetSideGUID = PlanetSideGUID(-1)
|
||||
def isNotSameTarget: Boolean = false
|
||||
override def isSameTarget: Boolean = false
|
||||
}
|
||||
|
||||
final def Allow(guid: PlanetSideGUID): HandlerFilter = new HandlerFilter {
|
||||
def resolvedPlayerGuid: PlanetSideGUID = guid
|
||||
def isNotSameTarget: Boolean = true
|
||||
override def isSameTarget: Boolean = true
|
||||
}
|
||||
}
|
||||
|
||||
trait CommonHandlerFunctionsBase {
|
||||
/**
|
||||
* na
|
||||
* @param toChannel na
|
||||
* @param guid na
|
||||
* @param reply na
|
||||
*/
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit
|
||||
|
||||
def handleWith(guid: PlanetSideGUID): Receive
|
||||
|
||||
def handleWith(filter: HandlerFilter): Receive
|
||||
|
||||
def receive: Receive
|
||||
}
|
||||
|
||||
trait CommonHandlerFunctions extends CommonHandlerFunctionsBase {
|
||||
_: CommonSessionInterfacingFunctionality =>
|
||||
protected var filter: HandlerFilter = HandlerFilter.NeverAllow
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param toChannel na
|
||||
* @param guid na
|
||||
* @param reply na
|
||||
*/
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit = {
|
||||
filter = HandlerFilter(guid, player)
|
||||
receive.apply(reply)
|
||||
}
|
||||
|
||||
def handleWith(guid: PlanetSideGUID): Receive = {
|
||||
filter = HandlerFilter(guid, player)
|
||||
receive
|
||||
}
|
||||
|
||||
def handleWith(giveFilter: HandlerFilter): Receive = {
|
||||
filter = giveFilter
|
||||
receive
|
||||
}
|
||||
|
||||
def receive: Receive
|
||||
}
|
||||
|
||||
object CommonHandlerFunctions {
|
||||
val HandleNothing: CommonHandlerFunctionsBase = new CommonHandlerFunctionsBase {
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit = { }
|
||||
def handleWith(guid: PlanetSideGUID): Receive = receive
|
||||
def handleWith(filter: HandlerFilter): Receive = receive
|
||||
def receive: Receive = { case _: CommonHandlerFunctions => () }
|
||||
}
|
||||
|
||||
val HandleAnything: CommonHandlerFunctionsBase = new CommonHandlerFunctionsBase {
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit = receive.apply(reply)
|
||||
def handleWith(guid: PlanetSideGUID): Receive = receive
|
||||
def handleWith(filter: HandlerFilter): Receive = receive
|
||||
def receive: Receive = { case _ => () }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// 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 filter.isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(target_guid, attributeType, attributeValue))
|
||||
|
||||
case GenericObjectAction(objectGuid, actionCode)
|
||||
if filter.isNotSameTarget =>
|
||||
sendResponse(GenericObjectActionMessage(objectGuid, actionCode))
|
||||
|
||||
case ObjectDelete(itemGuid, unk)
|
||||
if filter.isNotSameTarget =>
|
||||
sendResponse(ObjectDeleteMessage(itemGuid, unk))
|
||||
|
||||
case ChangeFireState_Start(weaponGuid)
|
||||
if filter.isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Start(weaponGuid))
|
||||
|
||||
case ChangeFireState_Stop(weaponGuid)
|
||||
if filter.isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||
|
||||
case ReloadTool(itemGuid)
|
||||
if filter.isNotSameTarget =>
|
||||
sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
|
||||
|
||||
case ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
|
||||
if filter.isNotSameTarget =>
|
||||
sessionLogic.avatarResponse.changeAmmoProcedure(weapon_guid, previous_guid, ammo_id, ammo_guid, weapon_slot, ammo_data)
|
||||
sendResponse(ChangeAmmoMessage(weapon_guid, 1))
|
||||
|
||||
case WeaponDryFire(weaponGuid)
|
||||
if filter.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 HintsAtAttacker(sourceGuid)
|
||||
if player.isAlive =>
|
||||
sendResponse(HitHint(sourceGuid, filter.resolvedPlayerGuid))
|
||||
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
||||
|
||||
case SetEmpire(objectGuid, faction)
|
||||
if filter.isNotSameTarget =>
|
||||
sendResponse(SetEmpireMessage(objectGuid, faction))
|
||||
|
||||
case ConcealPlayer(_) =>
|
||||
sendResponse(GenericObjectActionMessage(filter.resolvedPlayerGuid, code=9))
|
||||
|
||||
case SendResponse(msgs) =>
|
||||
msgs.foreach(sendResponse)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import net.psforever.objects.zones.exp
|
|||
import net.psforever.services.Service
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarStamp}
|
||||
import net.psforever.services.base.envelope.{GenericResponseEnvelope, MessageEnvelope}
|
||||
import net.psforever.services.base.message.{EventResponse, SendResponse}
|
||||
import net.psforever.services.base.message.SendResponse
|
||||
import net.psforever.services.chat.OutfitChannel
|
||||
|
||||
import scala.collection.mutable
|
||||
|
|
@ -21,10 +21,8 @@ import net.psforever.packet.game._
|
|||
import net.psforever.types._
|
||||
import net.psforever.util.Config
|
||||
|
||||
trait AvatarHandlerFunctions extends CommonSessionInterfacingFunctionality {
|
||||
trait AvatarHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
|
||||
val ops: SessionAvatarHandlers
|
||||
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit
|
||||
}
|
||||
|
||||
class SessionAvatarHandlers(
|
||||
|
|
@ -37,7 +35,7 @@ class SessionAvatarHandlers(
|
|||
mutable.LongMap[SessionAvatarHandlers.LastUpstream]()
|
||||
private[session] val hidingPlayerRandomizer = new scala.util.Random
|
||||
|
||||
def changeAmmoProcedures(
|
||||
def changeAmmoProcedure(
|
||||
weaponGuid: PlanetSideGUID,
|
||||
previousAmmoGuid: PlanetSideGUID,
|
||||
ammoTypeId: Int,
|
||||
|
|
@ -46,7 +44,7 @@ class SessionAvatarHandlers(
|
|||
ammoData: ConstructorData
|
||||
): Unit = {
|
||||
sendResponse(ObjectDetachMessage(weaponGuid, previousAmmoGuid, Vector3.Zero, 0))
|
||||
//TODO? sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
|
||||
sendResponse(ObjectDeleteMessage(previousAmmoGuid, 0))
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
ammoTypeId,
|
||||
|
|
|
|||
|
|
@ -3,18 +3,13 @@ package net.psforever.actors.session.support
|
|||
|
||||
import akka.actor.{ActorContext, ActorRef, typed}
|
||||
import net.psforever.packet.game.FriendsResponse
|
||||
import net.psforever.services.base.message.EventResponse
|
||||
|
||||
import scala.annotation.unused
|
||||
//
|
||||
import net.psforever.actors.session.AvatarActor
|
||||
|
||||
trait GalaxyHandlerFunctions extends CommonSessionInterfacingFunctionality {
|
||||
trait GalaxyHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
|
||||
def ops: SessionGalaxyHandlers
|
||||
|
||||
def handleUpdateIgnoredPlayers(pkt: FriendsResponse): Unit
|
||||
|
||||
def handle(@unused reply: EventResponse): Unit
|
||||
}
|
||||
|
||||
class SessionGalaxyHandlers(
|
||||
|
|
|
|||
|
|
@ -7,17 +7,14 @@ import net.psforever.objects.ce.Deployable
|
|||
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||
import net.psforever.objects.serverobject.interior.Sidedness
|
||||
import net.psforever.packet.game.{GenericObjectActionMessage, ObjectDeleteMessage, PlanetsideAttributeMessage, TriggerEffectMessage}
|
||||
import net.psforever.services.base.message.EventResponse
|
||||
import net.psforever.types.{PlanetSideGUID, Vector3}
|
||||
|
||||
trait LocalHandlerFunctions extends CommonSessionInterfacingFunctionality {
|
||||
trait LocalHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
|
||||
def ops: SessionLocalHandlers
|
||||
|
||||
def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit
|
||||
|
||||
def handleDeployableIsDismissed(obj: Deployable): Unit
|
||||
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit
|
||||
}
|
||||
|
||||
class SessionLocalHandlers(
|
||||
|
|
|
|||
|
|
@ -5,13 +5,10 @@ import akka.actor.{ActorContext, ActorRef, typed}
|
|||
import net.psforever.actors.session.AvatarActor
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.packet.game.ChatMsg
|
||||
import net.psforever.services.base.message.EventResponse
|
||||
import net.psforever.types.{ChatMessageType, DriveState, PlanetSideGUID}
|
||||
|
||||
trait VehicleHandlerFunctions extends CommonSessionInterfacingFunctionality {
|
||||
trait VehicleHandlerFunctions extends CommonSessionInterfacingFunctionality with CommonHandlerFunctions {
|
||||
def ops: SessionVehicleHandlers
|
||||
|
||||
def handle(toChannel: String, guid: PlanetSideGUID, reply: EventResponse): Unit
|
||||
}
|
||||
|
||||
class SessionVehicleHandlers(
|
||||
|
|
|
|||
|
|
@ -2195,7 +2195,7 @@ class ZoningOperations(
|
|||
log.info(s"RestoreInfo: player $name is already logged in zone ${inZone.id}; rejoining that character")
|
||||
sessionLogic.persistFunc = UpdatePersistence(from)
|
||||
//tell the old WorldSessionActor to kill itself by using its own subscriptions against itself
|
||||
inZone.AvatarEvents ! MessageEnvelope(name, AvatarAction.TeardownConnection())
|
||||
inZone.AvatarEvents ! MessageEnvelope(name, AvatarAction.TeardownConnection)
|
||||
spawn.switchAvatarStatisticsFieldToRefreshAfterRespawn()
|
||||
//find and reload previous player
|
||||
(
|
||||
|
|
|
|||
|
|
@ -279,7 +279,6 @@ object Vehicles {
|
|||
if (GlobalDefinitions.isBattleFrameVehicle(target.Definition) && target.Seat(0).isDefined) {
|
||||
zone.LocalEvents ! MessageEnvelope(
|
||||
zoneid,
|
||||
PlanetSideGUID(-1),
|
||||
GenericObjectAction(target.GUID, GenericObjectActionEnum.BFRShieldsDown.id)
|
||||
)
|
||||
zone.LocalEvents ! MessageEnvelope(
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
val zone = building.Zone
|
||||
building.Zone.AvatarEvents ! MessageEnvelope(
|
||||
zone.id,
|
||||
building.GUID,
|
||||
PlanetsideAttribute(building.GUID, 47, if (resourceSilo.LowNtuWarningOn) 1 else 0)
|
||||
)
|
||||
}
|
||||
|
|
@ -133,7 +132,6 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
)
|
||||
zone.AvatarEvents ! MessageEnvelope(
|
||||
zone.id,
|
||||
resourceSilo.GUID,
|
||||
PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)
|
||||
)
|
||||
building.Actor ! BuildingActor.MapUpdate()
|
||||
|
|
|
|||
|
|
@ -201,5 +201,5 @@ object AvatarAction {
|
|||
|
||||
final case class RemoveFromOutfitChat(outfit_id: Long) extends SelfRespondingEvent
|
||||
|
||||
final case class TeardownConnection() extends SelfRespondingEvent
|
||||
final case object TeardownConnection extends SelfRespondingEvent
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import akka.actor.{ActorContext, ActorRef, Props}
|
|||
import net.psforever.objects.guid.{GUIDTask, TaskBundle}
|
||||
import net.psforever.objects.Player
|
||||
import net.psforever.types.{ExoSuitType, PlanetSideGUID}
|
||||
import net.psforever.services.Service
|
||||
import net.psforever.services.avatar.AvatarAction.Release
|
||||
import net.psforever.services.base.envelope.MessageEnvelope
|
||||
import net.psforever.services.base.{EventServiceSupport, GenericSupportEnvelope, GenericSupportEnvelopeOnly}
|
||||
|
|
@ -37,7 +36,7 @@ final case class ReleaseEnvelope(
|
|||
|
||||
object ReleaseEnvelope {
|
||||
def apply(channel: String, actionMessage: Release): ReleaseEnvelope =
|
||||
ReleaseEnvelope(channel, Service.defaultPlayerGUID, actionMessage)
|
||||
ReleaseEnvelope(channel, actionMessage.player.GUID, actionMessage)
|
||||
}
|
||||
|
||||
final case class CorpseEnvelope(supportMessage: Any)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ class CaptureFlagManager(zone: Zone) extends Actor {
|
|||
// Override CC message when looked at
|
||||
zone.LocalEvents ! MessageEnvelope(
|
||||
zone.id,
|
||||
PlanetSideGUID(-1),
|
||||
GenericObjectAction(
|
||||
capture_terminal.GUID,
|
||||
GenericObjectActionEnum.FlagSpawned.id
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ class HackCaptureActor extends Actor {
|
|||
// Notify all clients that CC has had its hack state changed
|
||||
terminal.Zone.LocalEvents ! MessageEnvelope(
|
||||
terminal.Zone.id,
|
||||
PlanetSideGUID(-1),
|
||||
PlanetSideGUID(-1), /*what is this?, says the person who wrote it*/
|
||||
PlanetsideAttribute(
|
||||
terminal.GUID,
|
||||
PlanetsideAttributeEnum.ControlConsoleHackUpdate.id,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue