mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
reorganized files and methods for session actor in preparation for custom spectator implementation
This commit is contained in:
parent
9319f7e7bd
commit
cab41ac0b8
16 changed files with 1816 additions and 1722 deletions
|
|
@ -1,38 +1,20 @@
|
||||||
// Copyright (c) 2016, 2020 PSForever
|
// Copyright (c) 2016, 2020, 2024 PSForever
|
||||||
package net.psforever.actors.session
|
package net.psforever.actors.session
|
||||||
|
|
||||||
import akka.actor.typed.receptionist.Receptionist
|
import akka.actor.{Actor, Cancellable, MDCContextAware, typed}
|
||||||
import akka.actor.typed.scaladsl.adapter._
|
import net.psforever.actors.session.support.NormalUser
|
||||||
import akka.actor.{Actor, MDCContextAware, typed}
|
|
||||||
import org.joda.time.LocalDateTime
|
import org.joda.time.LocalDateTime
|
||||||
import org.log4s.MDC
|
import org.log4s.MDC
|
||||||
import scala.collection.mutable
|
|
||||||
//
|
//
|
||||||
import net.psforever.actors.net.MiddlewareActor
|
import net.psforever.actors.net.MiddlewareActor
|
||||||
import net.psforever.actors.session.support.SessionData
|
import net.psforever.objects.{Default, Player}
|
||||||
import net.psforever.objects._
|
import net.psforever.objects.avatar.Avatar
|
||||||
import net.psforever.objects.avatar._
|
import net.psforever.objects.definition.BasicDefinition
|
||||||
import net.psforever.objects.definition._
|
import net.psforever.packet.PlanetSidePacket
|
||||||
import net.psforever.objects.guid._
|
import net.psforever.packet.game.{FriendsResponse, KeepAliveMessage}
|
||||||
import net.psforever.objects.serverobject.containable.Containable
|
import net.psforever.types.Vector3
|
||||||
import net.psforever.objects.serverobject.deploy.Deployment
|
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import scala.collection.mutable
|
||||||
import net.psforever.objects.serverobject.terminals._
|
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
|
||||||
import net.psforever.objects.zones._
|
|
||||||
import net.psforever.packet._
|
|
||||||
import net.psforever.packet.game._
|
|
||||||
import net.psforever.services.CavernRotationService.SendCavernRotationUpdates
|
|
||||||
import net.psforever.services.ServiceManager.{Lookup, LookupResult}
|
|
||||||
import net.psforever.services.account.{PlayerToken, ReceiveAccountData}
|
|
||||||
import net.psforever.services.avatar.AvatarServiceResponse
|
|
||||||
import net.psforever.services.galaxy.GalaxyServiceResponse
|
|
||||||
import net.psforever.services.local.LocalServiceResponse
|
|
||||||
import net.psforever.services.teamwork.SquadServiceResponse
|
|
||||||
import net.psforever.services.vehicle.VehicleServiceResponse
|
|
||||||
import net.psforever.services.{CavernRotationService, ServiceManager, InterstellarClusterService => ICS}
|
|
||||||
import net.psforever.types._
|
|
||||||
import net.psforever.util.Config
|
|
||||||
|
|
||||||
object SessionActor {
|
object SessionActor {
|
||||||
sealed trait Command
|
sealed trait Command
|
||||||
|
|
@ -86,28 +68,6 @@ object SessionActor {
|
||||||
final case object CharSaved extends Command
|
final case object CharSaved extends Command
|
||||||
|
|
||||||
private[session] case object CharSavedMsg extends Command
|
private[session] case object CharSavedMsg extends Command
|
||||||
|
|
||||||
/**
|
|
||||||
* The message that progresses some form of user-driven activity with a certain eventual outcome
|
|
||||||
* and potential feedback per cycle.
|
|
||||||
* @param delta how much the progress value changes each tick, which will be treated as a percentage;
|
|
||||||
* must be a positive value
|
|
||||||
* @param completionAction a finalizing action performed once the progress reaches 100(%)
|
|
||||||
* @param tickAction an action that is performed for each increase of progress
|
|
||||||
* @param tickTime how long between each `tickAction` (ms);
|
|
||||||
* defaults to 250 milliseconds
|
|
||||||
*/
|
|
||||||
private[session] final case class ProgressEvent(
|
|
||||||
delta: Float,
|
|
||||||
completionAction: () => Unit,
|
|
||||||
tickAction: Float => Boolean,
|
|
||||||
tickTime: Long = 250L
|
|
||||||
)
|
|
||||||
|
|
||||||
private[session] final case class AvatarAwardMessageBundle(
|
|
||||||
bundle: Iterable[Iterable[PlanetSideGamePacket]],
|
|
||||||
delay: Long
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], connectionId: String, sessionId: Long)
|
class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], connectionId: String, sessionId: Long)
|
||||||
|
|
@ -115,493 +75,46 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
||||||
with MDCContextAware {
|
with MDCContextAware {
|
||||||
MDC("connectionId") = connectionId
|
MDC("connectionId") = connectionId
|
||||||
|
|
||||||
|
private var clientKeepAlive: Cancellable = Default.Cancellable
|
||||||
private[this] val buffer: mutable.ListBuffer[Any] = new mutable.ListBuffer[Any]()
|
private[this] val buffer: mutable.ListBuffer[Any] = new mutable.ListBuffer[Any]()
|
||||||
private[this] val sessionFuncs = new SessionData(middlewareActor, context)
|
private[this] val logic = new NormalUser(middlewareActor, context)
|
||||||
|
|
||||||
ServiceManager.serviceManager ! Lookup("accountIntermediary")
|
|
||||||
ServiceManager.serviceManager ! Lookup("accountPersistence")
|
|
||||||
ServiceManager.serviceManager ! Lookup("galaxy")
|
|
||||||
ServiceManager.serviceManager ! Lookup("squad")
|
|
||||||
ServiceManager.receptionist ! Receptionist.Find(ICS.InterstellarClusterServiceKey, context.self)
|
|
||||||
|
|
||||||
override def postStop(): Unit = {
|
override def postStop(): Unit = {
|
||||||
//normally, the player avatar persists a minute or so after disconnect; we are subject to the SessionReaper
|
clientKeepAlive.cancel()
|
||||||
//TODO put any temporary values back into the avatar
|
logic.stop()
|
||||||
sessionFuncs.stop()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def receive: Receive = startup
|
def receive: Receive = startup
|
||||||
|
|
||||||
def startup: Receive = {
|
private def startup: Receive = {
|
||||||
case msg if !sessionFuncs.assignEventBus(msg) =>
|
case msg if !logic.assignEventBus(msg) =>
|
||||||
buffer.addOne(msg)
|
buffer.addOne(msg)
|
||||||
case _ if sessionFuncs.whenAllEventBusesLoaded() =>
|
case _ if logic.whenAllEventBusesLoaded() =>
|
||||||
context.become(inTheGame)
|
context.become(inTheGame)
|
||||||
|
startHeartbeat()
|
||||||
buffer.foreach { self.tell(_, self) } //we forget the original sender, shouldn't be doing callbacks at this point
|
buffer.foreach { self.tell(_, self) } //we forget the original sender, shouldn't be doing callbacks at this point
|
||||||
buffer.clear()
|
buffer.clear()
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
def inTheGame: Receive = {
|
private def startHeartbeat(): Unit = {
|
||||||
/* really common messages (very frequently, every life) */
|
import scala.concurrent.duration._
|
||||||
case packet: PlanetSideGamePacket =>
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
handleGamePkt(packet)
|
clientKeepAlive.cancel()
|
||||||
|
clientKeepAlive = context.system.scheduler.scheduleWithFixedDelay(
|
||||||
case AvatarServiceResponse(toChannel, guid, reply) =>
|
initialDelay = 0.seconds,
|
||||||
sessionFuncs.avatarResponse.handle(toChannel, guid, reply)
|
delay = 500.milliseconds,
|
||||||
|
context.self,
|
||||||
case GalaxyServiceResponse(_, reply) =>
|
SessionActor.PokeClient()
|
||||||
sessionFuncs.galaxyResponseHanders.handle(reply)
|
)
|
||||||
|
|
||||||
case LocalServiceResponse(toChannel, guid, reply) =>
|
|
||||||
sessionFuncs.localResponse.handle(toChannel, guid, reply)
|
|
||||||
|
|
||||||
case Mountable.MountMessages(tplayer, reply) =>
|
|
||||||
sessionFuncs.mountResponse.handle(tplayer, reply)
|
|
||||||
|
|
||||||
case SquadServiceResponse(_, excluded, response) =>
|
|
||||||
sessionFuncs.squad.handle(response, excluded)
|
|
||||||
|
|
||||||
case Terminal.TerminalMessage(tplayer, msg, order) =>
|
|
||||||
sessionFuncs.terminals.handle(tplayer, msg, order)
|
|
||||||
|
|
||||||
case VehicleServiceResponse(toChannel, guid, reply) =>
|
|
||||||
sessionFuncs.vehicleResponseOperations.handle(toChannel, guid, reply)
|
|
||||||
|
|
||||||
case SessionActor.PokeClient() =>
|
|
||||||
sessionFuncs.sendResponse(KeepAliveMessage())
|
|
||||||
|
|
||||||
case SessionActor.SendResponse(packet) =>
|
|
||||||
sessionFuncs.sendResponse(packet)
|
|
||||||
|
|
||||||
case SessionActor.CharSaved =>
|
|
||||||
sessionFuncs.renewCharSavedTimer(
|
|
||||||
Config.app.game.savedMsg.interruptedByAction.fixed,
|
|
||||||
Config.app.game.savedMsg.interruptedByAction.variable
|
|
||||||
)
|
|
||||||
|
|
||||||
case SessionActor.CharSavedMsg =>
|
|
||||||
sessionFuncs.displayCharSavedMsgThenRenewTimer(
|
|
||||||
Config.app.game.savedMsg.renewal.fixed,
|
|
||||||
Config.app.game.savedMsg.renewal.variable
|
|
||||||
)
|
|
||||||
|
|
||||||
/* common messages (maybe once every respawn) */
|
|
||||||
case ICS.SpawnPointResponse(response) =>
|
|
||||||
sessionFuncs.zoning.handleSpawnPointResponse(response)
|
|
||||||
|
|
||||||
case SessionActor.NewPlayerLoaded(tplayer) =>
|
|
||||||
sessionFuncs.zoning.spawn.handleNewPlayerLoaded(tplayer)
|
|
||||||
|
|
||||||
case SessionActor.PlayerLoaded(tplayer) =>
|
|
||||||
sessionFuncs.zoning.spawn.handlePlayerLoaded(tplayer)
|
|
||||||
|
|
||||||
case Zone.Population.PlayerHasLeft(zone, None) =>
|
|
||||||
log.debug(s"PlayerHasLeft: ${sessionFuncs.player.Name} does not have a body on ${zone.id}")
|
|
||||||
|
|
||||||
case Zone.Population.PlayerHasLeft(zone, Some(tplayer)) =>
|
|
||||||
if (tplayer.isAlive) {
|
|
||||||
log.info(s"${tplayer.Name} has left zone ${zone.id}")
|
|
||||||
}
|
|
||||||
|
|
||||||
case Zone.Population.PlayerCanNotSpawn(zone, tplayer) =>
|
|
||||||
log.warning(s"${tplayer.Name} can not spawn in zone ${zone.id}; why?")
|
|
||||||
|
|
||||||
case Zone.Population.PlayerAlreadySpawned(zone, tplayer) =>
|
|
||||||
log.warning(s"${tplayer.Name} is already spawned on zone ${zone.id}; is this a clerical error?")
|
|
||||||
|
|
||||||
case Zone.Vehicle.CanNotSpawn(zone, vehicle, reason) =>
|
|
||||||
log.warning(
|
|
||||||
s"${sessionFuncs.player.Name}'s ${vehicle.Definition.Name} can not spawn in ${zone.id} because $reason"
|
|
||||||
)
|
|
||||||
|
|
||||||
case Zone.Vehicle.CanNotDespawn(zone, vehicle, reason) =>
|
|
||||||
log.warning(
|
|
||||||
s"${sessionFuncs.player.Name}'s ${vehicle.Definition.Name} can not deconstruct in ${zone.id} because $reason"
|
|
||||||
)
|
|
||||||
|
|
||||||
case ICS.ZoneResponse(Some(zone)) =>
|
|
||||||
sessionFuncs.zoning.handleZoneResponse(zone)
|
|
||||||
|
|
||||||
/* uncommon messages (once a session) */
|
|
||||||
case ICS.ZonesResponse(zones) =>
|
|
||||||
sessionFuncs.zoning.handleZonesResponse(zones)
|
|
||||||
|
|
||||||
case SessionActor.SetAvatar(avatar) =>
|
|
||||||
sessionFuncs.handleSetAvatar(avatar)
|
|
||||||
|
|
||||||
case PlayerToken.LoginInfo(name, Zone.Nowhere, _) =>
|
|
||||||
sessionFuncs.zoning.spawn.handleLoginInfoNowhere(name, sender())
|
|
||||||
|
|
||||||
case PlayerToken.LoginInfo(name, inZone, optionalSavedData) =>
|
|
||||||
sessionFuncs.zoning.spawn.handleLoginInfoSomewhere(name, inZone, optionalSavedData, sender())
|
|
||||||
|
|
||||||
case PlayerToken.RestoreInfo(playerName, inZone, pos) =>
|
|
||||||
sessionFuncs.zoning.spawn.handleLoginInfoRestore(playerName, inZone, pos, sender())
|
|
||||||
|
|
||||||
case PlayerToken.CanNotLogin(playerName, reason) =>
|
|
||||||
sessionFuncs.zoning.spawn.handleLoginCanNot(playerName, reason)
|
|
||||||
|
|
||||||
case ReceiveAccountData(account) =>
|
|
||||||
sessionFuncs.handleReceiveAccountData(account)
|
|
||||||
|
|
||||||
case AvatarActor.AvatarResponse(avatar) =>
|
|
||||||
sessionFuncs.handleAvatarResponse(avatar)
|
|
||||||
|
|
||||||
case AvatarActor.AvatarLoginResponse(avatar) =>
|
|
||||||
sessionFuncs.zoning.spawn.avatarLoginResponse(avatar)
|
|
||||||
|
|
||||||
case SessionActor.SetCurrentAvatar(tplayer, max_attempts, attempt) =>
|
|
||||||
sessionFuncs.zoning.spawn.ReadyToSetCurrentAvatar(tplayer, max_attempts, attempt)
|
|
||||||
|
|
||||||
case SessionActor.SetConnectionState(state) =>
|
|
||||||
sessionFuncs.connectionState = state
|
|
||||||
|
|
||||||
case SessionActor.AvatarLoadingSync(state) =>
|
|
||||||
sessionFuncs.zoning.spawn.handleAvatarLoadingSync(state)
|
|
||||||
|
|
||||||
/* uncommon messages (utility, or once in a while) */
|
|
||||||
case SessionActor.AvatarAwardMessageBundle(pkts, delay) =>
|
|
||||||
sessionFuncs.zoning.spawn.performAvatarAwardMessageDelivery(pkts, delay)
|
|
||||||
|
|
||||||
case CommonMessages.Progress(rate, finishedAction, stepAction) =>
|
|
||||||
sessionFuncs.setupProgressChange(rate, finishedAction, stepAction)
|
|
||||||
|
|
||||||
case SessionActor.ProgressEvent(delta, finishedAction, stepAction, tick) =>
|
|
||||||
sessionFuncs.handleProgressChange(delta, finishedAction, stepAction, tick)
|
|
||||||
|
|
||||||
case CavernRotationService.CavernRotationServiceKey.Listing(listings) =>
|
|
||||||
listings.head ! SendCavernRotationUpdates(context.self)
|
|
||||||
|
|
||||||
case LookupResult("propertyOverrideManager", endpoint) =>
|
|
||||||
sessionFuncs.zoning.propertyOverrideManagerLoadOverrides(endpoint)
|
|
||||||
|
|
||||||
case SessionActor.UpdateIgnoredPlayers(msg) =>
|
|
||||||
sessionFuncs.handleUpdateIgnoredPlayers(msg)
|
|
||||||
|
|
||||||
case SessionActor.UseCooldownRenewed(definition, _) =>
|
|
||||||
sessionFuncs.handleUseCooldownRenew(definition)
|
|
||||||
|
|
||||||
case Deployment.CanDeploy(obj, state) =>
|
|
||||||
sessionFuncs.vehicles.handleCanDeploy(obj, state)
|
|
||||||
|
|
||||||
case Deployment.CanUndeploy(obj, state) =>
|
|
||||||
sessionFuncs.vehicles.handleCanUndeploy(obj, state)
|
|
||||||
|
|
||||||
case Deployment.CanNotChangeDeployment(obj, state, reason) =>
|
|
||||||
sessionFuncs.vehicles.handleCanNotChangeDeployment(obj, state, reason)
|
|
||||||
|
|
||||||
/* rare messages */
|
|
||||||
case ProximityUnit.StopAction(term, _) =>
|
|
||||||
sessionFuncs.terminals.LocalStopUsingProximityUnit(term)
|
|
||||||
|
|
||||||
case SessionActor.Suicide() =>
|
|
||||||
sessionFuncs.suicide(sessionFuncs.player)
|
|
||||||
|
|
||||||
case SessionActor.Recall() =>
|
|
||||||
sessionFuncs.zoning.handleRecall()
|
|
||||||
|
|
||||||
case SessionActor.InstantAction() =>
|
|
||||||
sessionFuncs.zoning.handleInstantAction()
|
|
||||||
|
|
||||||
case SessionActor.Quit() =>
|
|
||||||
sessionFuncs.zoning.handleQuit()
|
|
||||||
|
|
||||||
case ICS.DroppodLaunchDenial(errorCode, _) =>
|
|
||||||
sessionFuncs.zoning.handleDroppodLaunchDenial(errorCode)
|
|
||||||
|
|
||||||
case ICS.DroppodLaunchConfirmation(zone, position) =>
|
|
||||||
sessionFuncs.zoning.LoadZoneLaunchDroppod(zone, position)
|
|
||||||
|
|
||||||
case SessionActor.PlayerFailedToLoad(tplayer) =>
|
|
||||||
sessionFuncs.failWithError(s"${tplayer.Name} failed to load anywhere")
|
|
||||||
|
|
||||||
/* csr only */
|
|
||||||
case SessionActor.SetSpeed(speed) =>
|
|
||||||
sessionFuncs.handleSetSpeed(speed)
|
|
||||||
|
|
||||||
case SessionActor.SetFlying(isFlying) =>
|
|
||||||
sessionFuncs.handleSetFlying(isFlying)
|
|
||||||
|
|
||||||
case SessionActor.SetSpectator(isSpectator) =>
|
|
||||||
sessionFuncs.handleSetSpectator(isSpectator)
|
|
||||||
|
|
||||||
case SessionActor.Kick(player, time) =>
|
|
||||||
sessionFuncs.handleKick(player, time)
|
|
||||||
|
|
||||||
case SessionActor.SetZone(zoneId, position) =>
|
|
||||||
sessionFuncs.zoning.handleSetZone(zoneId, position)
|
|
||||||
|
|
||||||
case SessionActor.SetPosition(position) =>
|
|
||||||
sessionFuncs.zoning.spawn.handleSetPosition(position)
|
|
||||||
|
|
||||||
case SessionActor.SetSilenced(silenced) =>
|
|
||||||
sessionFuncs.handleSilenced(silenced)
|
|
||||||
|
|
||||||
/* catch these messages */
|
|
||||||
case _: ProximityUnit.Action => ;
|
|
||||||
|
|
||||||
case _: Zone.Vehicle.HasSpawned => ;
|
|
||||||
|
|
||||||
case _: Zone.Vehicle.HasDespawned => ;
|
|
||||||
|
|
||||||
case Zone.Deployable.IsDismissed(obj: TurretDeployable) => //only if target deployable was never fully introduced
|
|
||||||
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(sessionFuncs.continent.GUID, obj))
|
|
||||||
|
|
||||||
case Zone.Deployable.IsDismissed(obj) => //only if target deployable was never fully introduced
|
|
||||||
TaskWorkflow.execute(GUIDTask.unregisterObject(sessionFuncs.continent.GUID, obj))
|
|
||||||
|
|
||||||
case msg: Containable.ItemPutInSlot =>
|
|
||||||
log.debug(s"ItemPutInSlot: $msg")
|
|
||||||
|
|
||||||
case msg: Containable.CanNotPutItemInSlot =>
|
|
||||||
log.debug(s"CanNotPutItemInSlot: $msg")
|
|
||||||
|
|
||||||
case default =>
|
|
||||||
log.warning(s"Invalid packet class received: $default from ${sender()}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def handleGamePkt: PlanetSideGamePacket => Unit = {
|
private def inTheGame: Receive = {
|
||||||
case packet: ConnectToWorldRequestMessage =>
|
/* used for the game's heartbeat*/
|
||||||
sessionFuncs.handleConnectToWorldRequest(packet)
|
case SessionActor.PokeClient() =>
|
||||||
|
middlewareActor ! MiddlewareActor.Send(KeepAliveMessage())
|
||||||
|
|
||||||
case packet: MountVehicleCargoMsg =>
|
case packet =>
|
||||||
sessionFuncs.vehicles.handleMountVehicleCargo(packet)
|
logic.parse(sender())(packet)
|
||||||
|
|
||||||
case packet: DismountVehicleCargoMsg =>
|
|
||||||
sessionFuncs.vehicles.handleDismountVehicleCargo(packet)
|
|
||||||
|
|
||||||
case packet: CharacterCreateRequestMessage =>
|
|
||||||
sessionFuncs.handleCharacterCreateRequest(packet)
|
|
||||||
|
|
||||||
case packet: CharacterRequestMessage =>
|
|
||||||
sessionFuncs.handleCharacterRequest(packet)
|
|
||||||
|
|
||||||
case _: KeepAliveMessage =>
|
|
||||||
sessionFuncs.keepAliveFunc()
|
|
||||||
|
|
||||||
case packet: BeginZoningMessage =>
|
|
||||||
sessionFuncs.zoning.handleBeginZoning(packet)
|
|
||||||
|
|
||||||
case packet: PlayerStateMessageUpstream =>
|
|
||||||
sessionFuncs.handlePlayerStateUpstream(packet)
|
|
||||||
|
|
||||||
case packet: ChildObjectStateMessage =>
|
|
||||||
sessionFuncs.vehicles.handleChildObjectState(packet)
|
|
||||||
|
|
||||||
case packet: VehicleStateMessage =>
|
|
||||||
sessionFuncs.vehicles.handleVehicleState(packet)
|
|
||||||
|
|
||||||
case packet: VehicleSubStateMessage =>
|
|
||||||
sessionFuncs.vehicles.handleVehicleSubState(packet)
|
|
||||||
|
|
||||||
case packet: FrameVehicleStateMessage =>
|
|
||||||
sessionFuncs.vehicles.handleFrameVehicleState(packet)
|
|
||||||
|
|
||||||
case packet: ProjectileStateMessage =>
|
|
||||||
sessionFuncs.shooting.handleProjectileState(packet)
|
|
||||||
|
|
||||||
case packet: LongRangeProjectileInfoMessage =>
|
|
||||||
sessionFuncs.shooting.handleLongRangeProjectileState(packet)
|
|
||||||
|
|
||||||
case packet: ReleaseAvatarRequestMessage =>
|
|
||||||
sessionFuncs.zoning.spawn.handleReleaseAvatarRequest(packet)
|
|
||||||
|
|
||||||
case packet: SpawnRequestMessage =>
|
|
||||||
sessionFuncs.zoning.spawn.handleSpawnRequest(packet)
|
|
||||||
|
|
||||||
case packet: ChatMsg =>
|
|
||||||
sessionFuncs.handleChat(packet)
|
|
||||||
|
|
||||||
case packet: SetChatFilterMessage =>
|
|
||||||
sessionFuncs.handleChatFilter(packet)
|
|
||||||
|
|
||||||
case packet: VoiceHostRequest =>
|
|
||||||
sessionFuncs.handleVoiceHostRequest(packet)
|
|
||||||
|
|
||||||
case packet: VoiceHostInfo =>
|
|
||||||
sessionFuncs.handleVoiceHostInfo(packet)
|
|
||||||
|
|
||||||
case packet: ChangeAmmoMessage =>
|
|
||||||
sessionFuncs.shooting.handleChangeAmmo(packet)
|
|
||||||
|
|
||||||
case packet: ChangeFireModeMessage =>
|
|
||||||
sessionFuncs.shooting.handleChangeFireMode(packet)
|
|
||||||
|
|
||||||
case packet: ChangeFireStateMessage_Start =>
|
|
||||||
sessionFuncs.shooting.handleChangeFireStateStart(packet)
|
|
||||||
|
|
||||||
case packet: ChangeFireStateMessage_Stop =>
|
|
||||||
sessionFuncs.shooting.handleChangeFireStateStop(packet)
|
|
||||||
|
|
||||||
case packet: EmoteMsg =>
|
|
||||||
sessionFuncs.handleEmote(packet)
|
|
||||||
|
|
||||||
case packet: DropItemMessage =>
|
|
||||||
sessionFuncs.handleDropItem(packet)
|
|
||||||
|
|
||||||
case packet: PickupItemMessage =>
|
|
||||||
sessionFuncs.handlePickupItem(packet)
|
|
||||||
|
|
||||||
case packet: ReloadMessage =>
|
|
||||||
sessionFuncs.shooting.handleReload(packet)
|
|
||||||
|
|
||||||
case packet: ObjectHeldMessage =>
|
|
||||||
sessionFuncs.handleObjectHeld(packet)
|
|
||||||
|
|
||||||
case packet: AvatarJumpMessage =>
|
|
||||||
sessionFuncs.handleAvatarJump(packet)
|
|
||||||
|
|
||||||
case packet: ZipLineMessage =>
|
|
||||||
sessionFuncs.handleZipLine(packet)
|
|
||||||
|
|
||||||
case packet: RequestDestroyMessage =>
|
|
||||||
sessionFuncs.handleRequestDestroy(packet)
|
|
||||||
|
|
||||||
case packet: MoveItemMessage =>
|
|
||||||
sessionFuncs.handleMoveItem(packet)
|
|
||||||
|
|
||||||
case packet: LootItemMessage =>
|
|
||||||
sessionFuncs.handleLootItem(packet)
|
|
||||||
|
|
||||||
case packet: AvatarImplantMessage =>
|
|
||||||
sessionFuncs.handleAvatarImplant(packet)
|
|
||||||
|
|
||||||
case packet: UseItemMessage =>
|
|
||||||
sessionFuncs.handleUseItem(packet)
|
|
||||||
|
|
||||||
case packet: UnuseItemMessage =>
|
|
||||||
sessionFuncs.handleUnuseItem(packet)
|
|
||||||
|
|
||||||
case packet: ProximityTerminalUseMessage =>
|
|
||||||
sessionFuncs.terminals.handleProximityTerminalUse(packet)
|
|
||||||
|
|
||||||
case packet: DeployObjectMessage =>
|
|
||||||
sessionFuncs.handleDeployObject(packet)
|
|
||||||
|
|
||||||
case packet: GenericObjectActionMessage =>
|
|
||||||
sessionFuncs.handleGenericObjectAction(packet)
|
|
||||||
|
|
||||||
case packet: GenericObjectActionAtPositionMessage =>
|
|
||||||
sessionFuncs.handleGenericObjectActionAtPosition(packet)
|
|
||||||
|
|
||||||
case packet: GenericObjectStateMsg =>
|
|
||||||
sessionFuncs.handleGenericObjectState(packet)
|
|
||||||
|
|
||||||
case packet: GenericActionMessage =>
|
|
||||||
sessionFuncs.handleGenericAction(packet)
|
|
||||||
|
|
||||||
case packet: ItemTransactionMessage =>
|
|
||||||
sessionFuncs.terminals.handleItemTransaction(packet)
|
|
||||||
|
|
||||||
case packet: FavoritesRequest =>
|
|
||||||
sessionFuncs.handleFavoritesRequest(packet)
|
|
||||||
|
|
||||||
case packet: WeaponDelayFireMessage =>
|
|
||||||
sessionFuncs.shooting.handleWeaponDelayFire(packet)
|
|
||||||
|
|
||||||
case packet: WeaponDryFireMessage =>
|
|
||||||
sessionFuncs.shooting.handleWeaponDryFire(packet)
|
|
||||||
|
|
||||||
case packet: WeaponFireMessage =>
|
|
||||||
sessionFuncs.shooting.handleWeaponFire(packet)
|
|
||||||
|
|
||||||
case packet: WeaponLazeTargetPositionMessage =>
|
|
||||||
sessionFuncs.shooting.handleWeaponLazeTargetPosition(packet)
|
|
||||||
|
|
||||||
case packet: HitMessage =>
|
|
||||||
sessionFuncs.shooting.handleDirectHit(packet)
|
|
||||||
|
|
||||||
case packet: SplashHitMessage =>
|
|
||||||
sessionFuncs.shooting.handleSplashHit(packet)
|
|
||||||
|
|
||||||
case packet: LashMessage =>
|
|
||||||
sessionFuncs.shooting.handleLashHit(packet)
|
|
||||||
|
|
||||||
case packet: AIDamage =>
|
|
||||||
sessionFuncs.shooting.handleAIDamage(packet)
|
|
||||||
|
|
||||||
case packet: AvatarFirstTimeEventMessage =>
|
|
||||||
sessionFuncs.handleAvatarFirstTimeEvent(packet)
|
|
||||||
|
|
||||||
case packet: WarpgateRequest =>
|
|
||||||
sessionFuncs.zoning.handleWarpgateRequest(packet)
|
|
||||||
|
|
||||||
case packet: MountVehicleMsg =>
|
|
||||||
sessionFuncs.vehicles.handleMountVehicle(packet)
|
|
||||||
|
|
||||||
case packet: DismountVehicleMsg =>
|
|
||||||
sessionFuncs.vehicles.handleDismountVehicle(packet)
|
|
||||||
|
|
||||||
case packet: DeployRequestMessage =>
|
|
||||||
sessionFuncs.vehicles.handleDeployRequest(packet)
|
|
||||||
|
|
||||||
case packet: AvatarGrenadeStateMessage =>
|
|
||||||
sessionFuncs.shooting.handleAvatarGrenadeState(packet)
|
|
||||||
|
|
||||||
case packet: SquadDefinitionActionMessage =>
|
|
||||||
sessionFuncs.squad.handleSquadDefinitionAction(packet)
|
|
||||||
|
|
||||||
case packet: SquadMembershipRequest =>
|
|
||||||
sessionFuncs.squad.handleSquadMemberRequest(packet)
|
|
||||||
|
|
||||||
case packet: SquadWaypointRequest =>
|
|
||||||
sessionFuncs.squad.handleSquadWaypointRequest(packet)
|
|
||||||
|
|
||||||
case packet: GenericCollisionMsg =>
|
|
||||||
sessionFuncs.handleGenericCollision(packet)
|
|
||||||
|
|
||||||
case packet: BugReportMessage =>
|
|
||||||
sessionFuncs.handleBugReport(packet)
|
|
||||||
|
|
||||||
case packet: BindPlayerMessage =>
|
|
||||||
sessionFuncs.handleBindPlayer(packet)
|
|
||||||
|
|
||||||
case packet: PlanetsideAttributeMessage =>
|
|
||||||
sessionFuncs.handlePlanetsideAttribute(packet)
|
|
||||||
|
|
||||||
case packet: FacilityBenefitShieldChargeRequestMessage =>
|
|
||||||
sessionFuncs.handleFacilityBenefitShieldChargeRequest(packet)
|
|
||||||
|
|
||||||
case packet: BattleplanMessage =>
|
|
||||||
sessionFuncs.handleBattleplan(packet)
|
|
||||||
|
|
||||||
case packet: CreateShortcutMessage =>
|
|
||||||
sessionFuncs.handleCreateShortcut(packet)
|
|
||||||
|
|
||||||
case packet: ChangeShortcutBankMessage =>
|
|
||||||
sessionFuncs.handleChangeShortcutBank(packet)
|
|
||||||
|
|
||||||
case packet: FriendsRequest =>
|
|
||||||
sessionFuncs.handleFriendRequest(packet)
|
|
||||||
|
|
||||||
case packet: DroppodLaunchRequestMessage =>
|
|
||||||
sessionFuncs.zoning.handleDroppodLaunchRequest(packet)
|
|
||||||
|
|
||||||
case packet: InvalidTerrainMessage =>
|
|
||||||
sessionFuncs.handleInvalidTerrain(packet)
|
|
||||||
|
|
||||||
case packet: ActionCancelMessage =>
|
|
||||||
sessionFuncs.handleActionCancel(packet)
|
|
||||||
|
|
||||||
case packet: TradeMessage =>
|
|
||||||
sessionFuncs.handleTrade(packet)
|
|
||||||
|
|
||||||
case packet: DisplayedAwardMessage =>
|
|
||||||
sessionFuncs.handleDisplayedAward(packet)
|
|
||||||
|
|
||||||
case packet: ObjectDetectedMessage =>
|
|
||||||
sessionFuncs.handleObjectDetected(packet)
|
|
||||||
|
|
||||||
case packet: TargetingImplantRequest =>
|
|
||||||
sessionFuncs.handleTargetingImplantRequest(packet)
|
|
||||||
|
|
||||||
case packet: HitHint =>
|
|
||||||
sessionFuncs.handleHitHint(packet)
|
|
||||||
|
|
||||||
case _: OutfitRequest => ()
|
|
||||||
|
|
||||||
case pkt =>
|
|
||||||
log.warning(s"Unhandled GamePacket $pkt")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,23 +23,25 @@ trait CommonSessionInterfacingFunctionality {
|
||||||
|
|
||||||
protected def context: ActorContext
|
protected def context: ActorContext
|
||||||
|
|
||||||
protected def sessionData: SessionData
|
protected def sessionLogic: SessionLogic
|
||||||
|
|
||||||
protected def session: Session = sessionData.session
|
protected def session: Session = sessionLogic.session
|
||||||
|
|
||||||
protected def session_=(newsession: Session): Unit = sessionData.session_=(newsession)
|
protected def session_=(newsession: Session): Unit = sessionLogic.session_=(newsession)
|
||||||
|
|
||||||
protected def account: Account = sessionData.account
|
protected def account: Account = sessionLogic.account
|
||||||
|
|
||||||
protected def continent: Zone = sessionData.continent
|
protected def continent: Zone = sessionLogic.continent
|
||||||
|
|
||||||
protected def player: Player = sessionData.player
|
protected def player: Player = sessionLogic.player
|
||||||
|
|
||||||
protected def avatar: Avatar = sessionData.avatar
|
protected def avatar: Avatar = sessionLogic.avatar
|
||||||
|
|
||||||
protected def log: Logger = sessionData.log
|
protected def log: Logger = sessionLogic.log
|
||||||
|
|
||||||
protected def sendResponse(pkt: PlanetSideGamePacket): Unit = sessionData.sendResponse(pkt)
|
protected def sendResponse(pkt: PlanetSideGamePacket): Unit = sessionLogic.sendResponse(pkt)
|
||||||
|
|
||||||
protected[session] def stop(): Unit = { /* to override */ }
|
protected[support] def actionsToCancel(): Unit = { /* to override */ }
|
||||||
|
|
||||||
|
protected[support] def stop(): Unit = { /* to override */ }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,496 @@
|
||||||
|
// Copyright (c) 2024 PSForever
|
||||||
|
package net.psforever.actors.session.support
|
||||||
|
|
||||||
|
import akka.actor.Actor.Receive
|
||||||
|
import akka.actor.{ActorContext, ActorRef, typed}
|
||||||
|
import net.psforever.actors.net.MiddlewareActor
|
||||||
|
import net.psforever.actors.session.{AvatarActor, SessionActor}
|
||||||
|
import net.psforever.objects.TurretDeployable
|
||||||
|
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
|
||||||
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
|
import net.psforever.objects.serverobject.containable.Containable
|
||||||
|
import net.psforever.objects.serverobject.deploy.Deployment
|
||||||
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
|
import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
|
||||||
|
import net.psforever.objects.zones.Zone
|
||||||
|
import net.psforever.packet.PlanetSideGamePacket
|
||||||
|
import net.psforever.packet.game.{AIDamage, ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarGrenadeStateMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BeginZoningMessage, BindPlayerMessage, BugReportMessage, ChangeAmmoMessage, ChangeFireModeMessage, ChangeFireStateMessage_Start, ChangeFireStateMessage_Stop, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, ChatMsg, ChildObjectStateMessage, ConnectToWorldRequestMessage, CreateShortcutMessage, DeployObjectMessage, DeployRequestMessage, DismountVehicleCargoMsg, DismountVehicleMsg, DisplayedAwardMessage, DropItemMessage, DroppodLaunchRequestMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FavoritesRequest, FrameVehicleStateMessage, FriendsRequest, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, HitMessage, InvalidTerrainMessage, ItemTransactionMessage, KeepAliveMessage, LashMessage, LongRangeProjectileInfoMessage, LootItemMessage, MountVehicleCargoMsg, MountVehicleMsg, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, OutfitRequest, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, ProjectileStateMessage, ProximityTerminalUseMessage, ReleaseAvatarRequestMessage, ReloadMessage, RequestDestroyMessage, SetChatFilterMessage, SpawnRequestMessage, SplashHitMessage, SquadDefinitionActionMessage, SquadMembershipRequest, SquadWaypointRequest, TargetingImplantRequest, TradeMessage, UnuseItemMessage, UseItemMessage, VehicleStateMessage, VehicleSubStateMessage, VoiceHostInfo, VoiceHostRequest, WarpgateRequest, WeaponDelayFireMessage, WeaponDryFireMessage, WeaponFireMessage, WeaponLazeTargetPositionMessage, ZipLineMessage}
|
||||||
|
import net.psforever.services.{InterstellarClusterService => ICS}
|
||||||
|
import net.psforever.services.CavernRotationService
|
||||||
|
import net.psforever.services.CavernRotationService.SendCavernRotationUpdates
|
||||||
|
import net.psforever.services.ServiceManager.LookupResult
|
||||||
|
import net.psforever.services.account.{PlayerToken, ReceiveAccountData}
|
||||||
|
import net.psforever.services.avatar.AvatarServiceResponse
|
||||||
|
import net.psforever.services.galaxy.GalaxyServiceResponse
|
||||||
|
import net.psforever.services.local.LocalServiceResponse
|
||||||
|
import net.psforever.services.teamwork.SquadServiceResponse
|
||||||
|
import net.psforever.services.vehicle.VehicleServiceResponse
|
||||||
|
import net.psforever.util.Config
|
||||||
|
|
||||||
|
class NormalUser(
|
||||||
|
val middlewareActor: typed.ActorRef[MiddlewareActor.Command],
|
||||||
|
implicit val context: ActorContext
|
||||||
|
) extends SessionLogic {
|
||||||
|
def parse(sender: ActorRef): Receive = {
|
||||||
|
/* really common messages (very frequently, every life) */
|
||||||
|
case packet: PlanetSideGamePacket =>
|
||||||
|
handleGamePkt(packet)
|
||||||
|
|
||||||
|
case AvatarServiceResponse(toChannel, guid, reply) =>
|
||||||
|
avatarResponse.handle(toChannel, guid, reply)
|
||||||
|
|
||||||
|
case GalaxyServiceResponse(_, reply) =>
|
||||||
|
galaxyResponseHandlers.handle(reply)
|
||||||
|
|
||||||
|
case LocalServiceResponse(toChannel, guid, reply) =>
|
||||||
|
localResponse.handle(toChannel, guid, reply)
|
||||||
|
|
||||||
|
case Mountable.MountMessages(tplayer, reply) =>
|
||||||
|
mountResponse.handle(tplayer, reply)
|
||||||
|
|
||||||
|
case SquadServiceResponse(_, excluded, response) =>
|
||||||
|
squad.handle(response, excluded)
|
||||||
|
|
||||||
|
case Terminal.TerminalMessage(tplayer, msg, order) =>
|
||||||
|
terminals.handle(tplayer, msg, order)
|
||||||
|
|
||||||
|
case VehicleServiceResponse(toChannel, guid, reply) =>
|
||||||
|
vehicleResponseOperations.handle(toChannel, guid, reply)
|
||||||
|
|
||||||
|
case SessionActor.PokeClient() =>
|
||||||
|
sendResponse(KeepAliveMessage())
|
||||||
|
|
||||||
|
case SessionActor.SendResponse(packet) =>
|
||||||
|
sendResponse(packet)
|
||||||
|
|
||||||
|
case SessionActor.CharSaved =>
|
||||||
|
general.renewCharSavedTimer(
|
||||||
|
Config.app.game.savedMsg.interruptedByAction.fixed,
|
||||||
|
Config.app.game.savedMsg.interruptedByAction.variable
|
||||||
|
)
|
||||||
|
|
||||||
|
case SessionActor.CharSavedMsg =>
|
||||||
|
general.displayCharSavedMsgThenRenewTimer(
|
||||||
|
Config.app.game.savedMsg.renewal.fixed,
|
||||||
|
Config.app.game.savedMsg.renewal.variable
|
||||||
|
)
|
||||||
|
|
||||||
|
/* common messages (maybe once every respawn) */
|
||||||
|
case ICS.SpawnPointResponse(response) =>
|
||||||
|
zoning.handleSpawnPointResponse(response)
|
||||||
|
|
||||||
|
case SessionActor.NewPlayerLoaded(tplayer) =>
|
||||||
|
zoning.spawn.handleNewPlayerLoaded(tplayer)
|
||||||
|
|
||||||
|
case SessionActor.PlayerLoaded(tplayer) =>
|
||||||
|
zoning.spawn.handlePlayerLoaded(tplayer)
|
||||||
|
|
||||||
|
case Zone.Population.PlayerHasLeft(zone, None) =>
|
||||||
|
log.debug(s"PlayerHasLeft: ${player.Name} does not have a body on ${zone.id}")
|
||||||
|
|
||||||
|
case Zone.Population.PlayerHasLeft(zone, Some(tplayer)) =>
|
||||||
|
if (tplayer.isAlive) {
|
||||||
|
log.info(s"${tplayer.Name} has left zone ${zone.id}")
|
||||||
|
}
|
||||||
|
|
||||||
|
case Zone.Population.PlayerCanNotSpawn(zone, tplayer) =>
|
||||||
|
log.warn(s"${tplayer.Name} can not spawn in zone ${zone.id}; why?")
|
||||||
|
|
||||||
|
case Zone.Population.PlayerAlreadySpawned(zone, tplayer) =>
|
||||||
|
log.warn(s"${tplayer.Name} is already spawned on zone ${zone.id}; is this a clerical error?")
|
||||||
|
|
||||||
|
case Zone.Vehicle.CanNotSpawn(zone, vehicle, reason) =>
|
||||||
|
log.warn(
|
||||||
|
s"${player.Name}'s ${vehicle.Definition.Name} can not spawn in ${zone.id} because $reason"
|
||||||
|
)
|
||||||
|
|
||||||
|
case Zone.Vehicle.CanNotDespawn(zone, vehicle, reason) =>
|
||||||
|
log.warn(
|
||||||
|
s"${player.Name}'s ${vehicle.Definition.Name} can not deconstruct in ${zone.id} because $reason"
|
||||||
|
)
|
||||||
|
|
||||||
|
case ICS.ZoneResponse(Some(zone)) =>
|
||||||
|
zoning.handleZoneResponse(zone)
|
||||||
|
|
||||||
|
/* uncommon messages (once a session) */
|
||||||
|
case ICS.ZonesResponse(zones) =>
|
||||||
|
zoning.handleZonesResponse(zones)
|
||||||
|
|
||||||
|
case SessionActor.SetAvatar(avatar) =>
|
||||||
|
general.handleSetAvatar(avatar)
|
||||||
|
|
||||||
|
case PlayerToken.LoginInfo(name, Zone.Nowhere, _) =>
|
||||||
|
zoning.spawn.handleLoginInfoNowhere(name, sender)
|
||||||
|
|
||||||
|
case PlayerToken.LoginInfo(name, inZone, optionalSavedData) =>
|
||||||
|
zoning.spawn.handleLoginInfoSomewhere(name, inZone, optionalSavedData, sender)
|
||||||
|
|
||||||
|
case PlayerToken.RestoreInfo(playerName, inZone, pos) =>
|
||||||
|
zoning.spawn.handleLoginInfoRestore(playerName, inZone, pos, sender)
|
||||||
|
|
||||||
|
case PlayerToken.CanNotLogin(playerName, reason) =>
|
||||||
|
zoning.spawn.handleLoginCanNot(playerName, reason)
|
||||||
|
|
||||||
|
case ReceiveAccountData(account) =>
|
||||||
|
general.handleReceiveAccountData(account)
|
||||||
|
|
||||||
|
case AvatarActor.AvatarResponse(avatar) =>
|
||||||
|
general.handleAvatarResponse(avatar)
|
||||||
|
|
||||||
|
case AvatarActor.AvatarLoginResponse(avatar) =>
|
||||||
|
zoning.spawn.avatarLoginResponse(avatar)
|
||||||
|
|
||||||
|
case SessionActor.SetCurrentAvatar(tplayer, max_attempts, attempt) =>
|
||||||
|
zoning.spawn.ReadyToSetCurrentAvatar(tplayer, max_attempts, attempt)
|
||||||
|
|
||||||
|
case SessionActor.SetConnectionState(state) =>
|
||||||
|
connectionState = state
|
||||||
|
|
||||||
|
case SessionActor.AvatarLoadingSync(state) =>
|
||||||
|
zoning.spawn.handleAvatarLoadingSync(state)
|
||||||
|
|
||||||
|
/* uncommon messages (utility, or once in a while) */
|
||||||
|
case ZoningOperations.AvatarAwardMessageBundle(pkts, delay) =>
|
||||||
|
zoning.spawn.performAvatarAwardMessageDelivery(pkts, delay)
|
||||||
|
|
||||||
|
case CommonMessages.ProgressEvent(delta, finishedAction, stepAction, tick) =>
|
||||||
|
general.handleProgressChange(delta, finishedAction, stepAction, tick)
|
||||||
|
|
||||||
|
case CommonMessages.Progress(rate, finishedAction, stepAction) =>
|
||||||
|
general.setupProgressChange(rate, finishedAction, stepAction)
|
||||||
|
|
||||||
|
case CavernRotationService.CavernRotationServiceKey.Listing(listings) =>
|
||||||
|
listings.head ! SendCavernRotationUpdates(context.self)
|
||||||
|
|
||||||
|
case LookupResult("propertyOverrideManager", endpoint) =>
|
||||||
|
zoning.propertyOverrideManagerLoadOverrides(endpoint)
|
||||||
|
|
||||||
|
case SessionActor.UpdateIgnoredPlayers(msg) =>
|
||||||
|
galaxyResponseHandlers.handleUpdateIgnoredPlayers(msg)
|
||||||
|
|
||||||
|
case SessionActor.UseCooldownRenewed(definition, _) =>
|
||||||
|
general.handleUseCooldownRenew(definition)
|
||||||
|
|
||||||
|
case Deployment.CanDeploy(obj, state) =>
|
||||||
|
vehicles.handleCanDeploy(obj, state)
|
||||||
|
|
||||||
|
case Deployment.CanUndeploy(obj, state) =>
|
||||||
|
vehicles.handleCanUndeploy(obj, state)
|
||||||
|
|
||||||
|
case Deployment.CanNotChangeDeployment(obj, state, reason) =>
|
||||||
|
vehicles.handleCanNotChangeDeployment(obj, state, reason)
|
||||||
|
|
||||||
|
/* rare messages */
|
||||||
|
case ProximityUnit.StopAction(term, _) =>
|
||||||
|
terminals.LocalStopUsingProximityUnit(term)
|
||||||
|
|
||||||
|
case SessionActor.Suicide() =>
|
||||||
|
general.suicide(player)
|
||||||
|
|
||||||
|
case SessionActor.Recall() =>
|
||||||
|
zoning.handleRecall()
|
||||||
|
|
||||||
|
case SessionActor.InstantAction() =>
|
||||||
|
zoning.handleInstantAction()
|
||||||
|
|
||||||
|
case SessionActor.Quit() =>
|
||||||
|
zoning.handleQuit()
|
||||||
|
|
||||||
|
case ICS.DroppodLaunchDenial(errorCode, _) =>
|
||||||
|
zoning.handleDroppodLaunchDenial(errorCode)
|
||||||
|
|
||||||
|
case ICS.DroppodLaunchConfirmation(zone, position) =>
|
||||||
|
zoning.LoadZoneLaunchDroppod(zone, position)
|
||||||
|
|
||||||
|
case SessionActor.PlayerFailedToLoad(tplayer) =>
|
||||||
|
failWithError(s"${tplayer.Name} failed to load anywhere")
|
||||||
|
|
||||||
|
/* csr only */
|
||||||
|
case SessionActor.SetSpeed(speed) =>
|
||||||
|
general.handleSetSpeed(speed)
|
||||||
|
|
||||||
|
case SessionActor.SetFlying(isFlying) =>
|
||||||
|
general.handleSetFlying(isFlying)
|
||||||
|
|
||||||
|
case SessionActor.SetSpectator(isSpectator) =>
|
||||||
|
general.handleSetSpectator(isSpectator)
|
||||||
|
|
||||||
|
case SessionActor.Kick(player, time) =>
|
||||||
|
general.handleKick(player, time)
|
||||||
|
|
||||||
|
case SessionActor.SetZone(zoneId, position) =>
|
||||||
|
zoning.handleSetZone(zoneId, position)
|
||||||
|
|
||||||
|
case SessionActor.SetPosition(position) =>
|
||||||
|
zoning.spawn.handleSetPosition(position)
|
||||||
|
|
||||||
|
case SessionActor.SetSilenced(silenced) =>
|
||||||
|
general.handleSilenced(silenced)
|
||||||
|
|
||||||
|
/* catch these messages */
|
||||||
|
case _: ProximityUnit.Action => ;
|
||||||
|
|
||||||
|
case _: Zone.Vehicle.HasSpawned => ;
|
||||||
|
|
||||||
|
case _: Zone.Vehicle.HasDespawned => ;
|
||||||
|
|
||||||
|
case Zone.Deployable.IsDismissed(obj: TurretDeployable) => //only if target deployable was never fully introduced
|
||||||
|
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(continent.GUID, obj))
|
||||||
|
|
||||||
|
case Zone.Deployable.IsDismissed(obj) => //only if target deployable was never fully introduced
|
||||||
|
TaskWorkflow.execute(GUIDTask.unregisterObject(continent.GUID, obj))
|
||||||
|
|
||||||
|
case msg: Containable.ItemPutInSlot =>
|
||||||
|
log.debug(s"ItemPutInSlot: $msg")
|
||||||
|
|
||||||
|
case msg: Containable.CanNotPutItemInSlot =>
|
||||||
|
log.debug(s"CanNotPutItemInSlot: $msg")
|
||||||
|
|
||||||
|
case default =>
|
||||||
|
log.warn(s"Invalid packet class received: $default from $sender")
|
||||||
|
}
|
||||||
|
|
||||||
|
private def handleGamePkt: PlanetSideGamePacket => Unit = {
|
||||||
|
case packet: ConnectToWorldRequestMessage =>
|
||||||
|
general.handleConnectToWorldRequest(packet)
|
||||||
|
|
||||||
|
case packet: MountVehicleCargoMsg =>
|
||||||
|
vehicles.handleMountVehicleCargo(packet)
|
||||||
|
|
||||||
|
case packet: DismountVehicleCargoMsg =>
|
||||||
|
vehicles.handleDismountVehicleCargo(packet)
|
||||||
|
|
||||||
|
case packet: CharacterCreateRequestMessage =>
|
||||||
|
general.handleCharacterCreateRequest(packet)
|
||||||
|
|
||||||
|
case packet: CharacterRequestMessage =>
|
||||||
|
general.handleCharacterRequest(packet)
|
||||||
|
|
||||||
|
case _: KeepAliveMessage =>
|
||||||
|
keepAliveFunc()
|
||||||
|
|
||||||
|
case packet: BeginZoningMessage =>
|
||||||
|
zoning.handleBeginZoning(packet)
|
||||||
|
|
||||||
|
case packet: PlayerStateMessageUpstream =>
|
||||||
|
general.handlePlayerStateUpstream(packet)
|
||||||
|
|
||||||
|
case packet: ChildObjectStateMessage =>
|
||||||
|
vehicles.handleChildObjectState(packet)
|
||||||
|
|
||||||
|
case packet: VehicleStateMessage =>
|
||||||
|
vehicles.handleVehicleState(packet)
|
||||||
|
|
||||||
|
case packet: VehicleSubStateMessage =>
|
||||||
|
vehicles.handleVehicleSubState(packet)
|
||||||
|
|
||||||
|
case packet: FrameVehicleStateMessage =>
|
||||||
|
vehicles.handleFrameVehicleState(packet)
|
||||||
|
|
||||||
|
case packet: ProjectileStateMessage =>
|
||||||
|
shooting.handleProjectileState(packet)
|
||||||
|
|
||||||
|
case packet: LongRangeProjectileInfoMessage =>
|
||||||
|
shooting.handleLongRangeProjectileState(packet)
|
||||||
|
|
||||||
|
case packet: ReleaseAvatarRequestMessage =>
|
||||||
|
zoning.spawn.handleReleaseAvatarRequest(packet)
|
||||||
|
|
||||||
|
case packet: SpawnRequestMessage =>
|
||||||
|
zoning.spawn.handleSpawnRequest(packet)
|
||||||
|
|
||||||
|
case packet: ChatMsg =>
|
||||||
|
general.handleChat(packet)
|
||||||
|
|
||||||
|
case packet: SetChatFilterMessage =>
|
||||||
|
general.handleChatFilter(packet)
|
||||||
|
|
||||||
|
case packet: VoiceHostRequest =>
|
||||||
|
general.handleVoiceHostRequest(packet)
|
||||||
|
|
||||||
|
case packet: VoiceHostInfo =>
|
||||||
|
general.handleVoiceHostInfo(packet)
|
||||||
|
|
||||||
|
case packet: ChangeAmmoMessage =>
|
||||||
|
shooting.handleChangeAmmo(packet)
|
||||||
|
|
||||||
|
case packet: ChangeFireModeMessage =>
|
||||||
|
shooting.handleChangeFireMode(packet)
|
||||||
|
|
||||||
|
case packet: ChangeFireStateMessage_Start =>
|
||||||
|
shooting.handleChangeFireStateStart(packet)
|
||||||
|
|
||||||
|
case packet: ChangeFireStateMessage_Stop =>
|
||||||
|
shooting.handleChangeFireStateStop(packet)
|
||||||
|
|
||||||
|
case packet: EmoteMsg =>
|
||||||
|
general.handleEmote(packet)
|
||||||
|
|
||||||
|
case packet: DropItemMessage =>
|
||||||
|
general.handleDropItem(packet)
|
||||||
|
|
||||||
|
case packet: PickupItemMessage =>
|
||||||
|
general.handlePickupItem(packet)
|
||||||
|
|
||||||
|
case packet: ReloadMessage =>
|
||||||
|
shooting.handleReload(packet)
|
||||||
|
|
||||||
|
case packet: ObjectHeldMessage =>
|
||||||
|
general.handleObjectHeld(packet)
|
||||||
|
|
||||||
|
case packet: AvatarJumpMessage =>
|
||||||
|
general.handleAvatarJump(packet)
|
||||||
|
|
||||||
|
case packet: ZipLineMessage =>
|
||||||
|
general.handleZipLine(packet)
|
||||||
|
|
||||||
|
case packet: RequestDestroyMessage =>
|
||||||
|
general.handleRequestDestroy(packet)
|
||||||
|
|
||||||
|
case packet: MoveItemMessage =>
|
||||||
|
general.handleMoveItem(packet)
|
||||||
|
|
||||||
|
case packet: LootItemMessage =>
|
||||||
|
general.handleLootItem(packet)
|
||||||
|
|
||||||
|
case packet: AvatarImplantMessage =>
|
||||||
|
general.handleAvatarImplant(packet)
|
||||||
|
|
||||||
|
case packet: UseItemMessage =>
|
||||||
|
general.handleUseItem(packet)
|
||||||
|
|
||||||
|
case packet: UnuseItemMessage =>
|
||||||
|
general.handleUnuseItem(packet)
|
||||||
|
|
||||||
|
case packet: ProximityTerminalUseMessage =>
|
||||||
|
terminals.handleProximityTerminalUse(packet)
|
||||||
|
|
||||||
|
case packet: DeployObjectMessage =>
|
||||||
|
general.handleDeployObject(packet)
|
||||||
|
|
||||||
|
case packet: GenericObjectActionMessage =>
|
||||||
|
general.handleGenericObjectAction(packet)
|
||||||
|
|
||||||
|
case packet: GenericObjectActionAtPositionMessage =>
|
||||||
|
general.handleGenericObjectActionAtPosition(packet)
|
||||||
|
|
||||||
|
case packet: GenericObjectStateMsg =>
|
||||||
|
general.handleGenericObjectState(packet)
|
||||||
|
|
||||||
|
case packet: GenericActionMessage =>
|
||||||
|
general.handleGenericAction(packet)
|
||||||
|
|
||||||
|
case packet: ItemTransactionMessage =>
|
||||||
|
terminals.handleItemTransaction(packet)
|
||||||
|
|
||||||
|
case packet: FavoritesRequest =>
|
||||||
|
general.handleFavoritesRequest(packet)
|
||||||
|
|
||||||
|
case packet: WeaponDelayFireMessage =>
|
||||||
|
shooting.handleWeaponDelayFire(packet)
|
||||||
|
|
||||||
|
case packet: WeaponDryFireMessage =>
|
||||||
|
shooting.handleWeaponDryFire(packet)
|
||||||
|
|
||||||
|
case packet: WeaponFireMessage =>
|
||||||
|
shooting.handleWeaponFire(packet)
|
||||||
|
|
||||||
|
case packet: WeaponLazeTargetPositionMessage =>
|
||||||
|
shooting.handleWeaponLazeTargetPosition(packet)
|
||||||
|
|
||||||
|
case packet: HitMessage =>
|
||||||
|
shooting.handleDirectHit(packet)
|
||||||
|
|
||||||
|
case packet: SplashHitMessage =>
|
||||||
|
shooting.handleSplashHit(packet)
|
||||||
|
|
||||||
|
case packet: LashMessage =>
|
||||||
|
shooting.handleLashHit(packet)
|
||||||
|
|
||||||
|
case packet: AIDamage =>
|
||||||
|
shooting.handleAIDamage(packet)
|
||||||
|
|
||||||
|
case packet: AvatarFirstTimeEventMessage =>
|
||||||
|
general.handleAvatarFirstTimeEvent(packet)
|
||||||
|
|
||||||
|
case packet: WarpgateRequest =>
|
||||||
|
zoning.handleWarpgateRequest(packet)
|
||||||
|
|
||||||
|
case packet: MountVehicleMsg =>
|
||||||
|
vehicles.handleMountVehicle(packet)
|
||||||
|
|
||||||
|
case packet: DismountVehicleMsg =>
|
||||||
|
vehicles.handleDismountVehicle(packet)
|
||||||
|
|
||||||
|
case packet: DeployRequestMessage =>
|
||||||
|
vehicles.handleDeployRequest(packet)
|
||||||
|
|
||||||
|
case packet: AvatarGrenadeStateMessage =>
|
||||||
|
shooting.handleAvatarGrenadeState(packet)
|
||||||
|
|
||||||
|
case packet: SquadDefinitionActionMessage =>
|
||||||
|
squad.handleSquadDefinitionAction(packet)
|
||||||
|
|
||||||
|
case packet: SquadMembershipRequest =>
|
||||||
|
squad.handleSquadMemberRequest(packet)
|
||||||
|
|
||||||
|
case packet: SquadWaypointRequest =>
|
||||||
|
squad.handleSquadWaypointRequest(packet)
|
||||||
|
|
||||||
|
case packet: GenericCollisionMsg =>
|
||||||
|
general.handleGenericCollision(packet)
|
||||||
|
|
||||||
|
case packet: BugReportMessage =>
|
||||||
|
general.handleBugReport(packet)
|
||||||
|
|
||||||
|
case packet: BindPlayerMessage =>
|
||||||
|
general.handleBindPlayer(packet)
|
||||||
|
|
||||||
|
case packet: PlanetsideAttributeMessage =>
|
||||||
|
general.handlePlanetsideAttribute(packet)
|
||||||
|
|
||||||
|
case packet: FacilityBenefitShieldChargeRequestMessage =>
|
||||||
|
general.handleFacilityBenefitShieldChargeRequest(packet)
|
||||||
|
|
||||||
|
case packet: BattleplanMessage =>
|
||||||
|
general.handleBattleplan(packet)
|
||||||
|
|
||||||
|
case packet: CreateShortcutMessage =>
|
||||||
|
general.handleCreateShortcut(packet)
|
||||||
|
|
||||||
|
case packet: ChangeShortcutBankMessage =>
|
||||||
|
general.handleChangeShortcutBank(packet)
|
||||||
|
|
||||||
|
case packet: FriendsRequest =>
|
||||||
|
general.handleFriendRequest(packet)
|
||||||
|
|
||||||
|
case packet: DroppodLaunchRequestMessage =>
|
||||||
|
zoning.handleDroppodLaunchRequest(packet)
|
||||||
|
|
||||||
|
case packet: InvalidTerrainMessage =>
|
||||||
|
general.handleInvalidTerrain(packet)
|
||||||
|
|
||||||
|
case packet: ActionCancelMessage =>
|
||||||
|
general.handleActionCancel(packet)
|
||||||
|
|
||||||
|
case packet: TradeMessage =>
|
||||||
|
general.handleTrade(packet)
|
||||||
|
|
||||||
|
case packet: DisplayedAwardMessage =>
|
||||||
|
general.handleDisplayedAward(packet)
|
||||||
|
|
||||||
|
case packet: ObjectDetectedMessage =>
|
||||||
|
general.handleObjectDetected(packet)
|
||||||
|
|
||||||
|
case packet: TargetingImplantRequest =>
|
||||||
|
general.handleTargetingImplantRequest(packet)
|
||||||
|
|
||||||
|
case packet: HitHint =>
|
||||||
|
general.handleHitHint(packet)
|
||||||
|
|
||||||
|
case _: OutfitRequest => ()
|
||||||
|
|
||||||
|
case pkt =>
|
||||||
|
log.warn(s"Unhandled GamePacket $pkt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.typed.scaladsl.adapter._
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
|
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry}
|
||||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.objects.zones.exp
|
import net.psforever.objects.zones.exp
|
||||||
|
|
@ -29,7 +30,7 @@ import net.psforever.util.Config
|
||||||
import net.psforever.zones.Zones
|
import net.psforever.zones.Zones
|
||||||
|
|
||||||
class SessionAvatarHandlers(
|
class SessionAvatarHandlers(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
chatActor: typed.ActorRef[ChatActor.Command],
|
chatActor: typed.ActorRef[ChatActor.Command],
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
|
|
@ -86,7 +87,7 @@ class SessionAvatarHandlers(
|
||||||
val inDrawableRange = currentDistance <= maxRange
|
val inDrawableRange = currentDistance <= maxRange
|
||||||
val now = System.currentTimeMillis() //ms
|
val now = System.currentTimeMillis() //ms
|
||||||
if (
|
if (
|
||||||
sessionData.zoning.zoningStatus != Zoning.Status.Deconstructing &&
|
sessionLogic.zoning.zoningStatus != Zoning.Status.Deconstructing &&
|
||||||
!isNotRendered && inDrawableRange
|
!isNotRendered && inDrawableRange
|
||||||
) {
|
) {
|
||||||
//conditions where visibility is assured
|
//conditions where visibility is assured
|
||||||
|
|
@ -95,7 +96,7 @@ class SessionAvatarHandlers(
|
||||||
lazy val targetDelay = {
|
lazy val targetDelay = {
|
||||||
val populationOver = math.max(
|
val populationOver = math.max(
|
||||||
0,
|
0,
|
||||||
sessionData.localSector.livePlayerList.size - drawConfig.populationThreshold
|
sessionLogic.localSector.livePlayerList.size - drawConfig.populationThreshold
|
||||||
)
|
)
|
||||||
val distanceAdjustment = math.pow(populationOver / drawConfig.populationStep * drawConfig.rangeStep, 2) //sq.m
|
val distanceAdjustment = math.pow(populationOver / drawConfig.populationStep * drawConfig.rangeStep, 2) //sq.m
|
||||||
val adjustedDistance = currentDistance + distanceAdjustment //sq.m
|
val adjustedDistance = currentDistance + distanceAdjustment //sq.m
|
||||||
|
|
@ -110,7 +111,7 @@ class SessionAvatarHandlers(
|
||||||
(!lastMsg.contains(pstateToSave) &&
|
(!lastMsg.contains(pstateToSave) &&
|
||||||
(canSeeReallyFar ||
|
(canSeeReallyFar ||
|
||||||
currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
|
currentDistance < drawConfig.rangeMin * drawConfig.rangeMin ||
|
||||||
sessionData.canSeeReallyFar ||
|
sessionLogic.general.canSeeReallyFar ||
|
||||||
durationSince > targetDelay
|
durationSince > targetDelay
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -164,11 +165,11 @@ class SessionAvatarHandlers(
|
||||||
if isSameTarget && player.VisibleSlots.contains(slot) =>
|
if isSameTarget && player.VisibleSlots.contains(slot) =>
|
||||||
sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
|
sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
|
||||||
//Stop using proximity terminals if player unholsters a weapon
|
//Stop using proximity terminals if player unholsters a weapon
|
||||||
continent.GUID(sessionData.terminals.usingMedicalTerminal).collect {
|
continent.GUID(sessionLogic.terminals.usingMedicalTerminal).collect {
|
||||||
case term: Terminal with ProximityUnit => sessionData.terminals.StopUsingProximityUnit(term)
|
case term: Terminal with ProximityUnit => sessionLogic.terminals.StopUsingProximityUnit(term)
|
||||||
}
|
}
|
||||||
if (sessionData.zoning.zoningStatus == Zoning.Status.Deconstructing) {
|
if (sessionLogic.zoning.zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
sessionData.stopDeconstructing()
|
sessionLogic.zoning.spawn.stopDeconstructing()
|
||||||
}
|
}
|
||||||
|
|
||||||
case AvatarResponse.ObjectHeld(slot, _)
|
case AvatarResponse.ObjectHeld(slot, _)
|
||||||
|
|
@ -221,32 +222,28 @@ class SessionAvatarHandlers(
|
||||||
|
|
||||||
case AvatarResponse.HitHint(sourceGuid) if player.isAlive =>
|
case AvatarResponse.HitHint(sourceGuid) if player.isAlive =>
|
||||||
sendResponse(HitHint(sourceGuid, guid))
|
sendResponse(HitHint(sourceGuid, guid))
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
||||||
|
|
||||||
case AvatarResponse.DestroyDisplay(killer, victim, method, unk)
|
|
||||||
if killer.CharId == avatar.id && killer.Faction != victim.Faction =>
|
|
||||||
sendResponse(sessionData.destroyDisplayMessage(killer, victim, method, unk))
|
|
||||||
|
|
||||||
case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
|
case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
|
||||||
// guid = victim // killer = killer
|
// guid = victim // killer = killer
|
||||||
sendResponse(DestroyMessage(victim, killer, weapon, pos))
|
sendResponse(DestroyMessage(victim, killer, weapon, pos))
|
||||||
|
|
||||||
case AvatarResponse.DestroyDisplay(killer, victim, method, unk) =>
|
case AvatarResponse.DestroyDisplay(killer, victim, method, unk) =>
|
||||||
sendResponse(sessionData.destroyDisplayMessage(killer, victim, method, unk))
|
sendResponse(destroyDisplayMessage(killer, victim, method, unk))
|
||||||
|
|
||||||
case AvatarResponse.TerminalOrderResult(terminalGuid, action, result)
|
case AvatarResponse.TerminalOrderResult(terminalGuid, action, result)
|
||||||
if result && (action == TransactionType.Buy || action == TransactionType.Loadout) =>
|
if result && (action == TransactionType.Buy || action == TransactionType.Loadout) =>
|
||||||
sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
|
sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
|
||||||
sessionData.terminals.lastTerminalOrderFulfillment = true
|
sessionLogic.terminals.lastTerminalOrderFulfillment = true
|
||||||
AvatarActor.savePlayerData(player)
|
AvatarActor.savePlayerData(player)
|
||||||
sessionData.renewCharSavedTimer(
|
sessionLogic.general.renewCharSavedTimer(
|
||||||
Config.app.game.savedMsg.interruptedByAction.fixed,
|
Config.app.game.savedMsg.interruptedByAction.fixed,
|
||||||
Config.app.game.savedMsg.interruptedByAction.variable
|
Config.app.game.savedMsg.interruptedByAction.variable
|
||||||
)
|
)
|
||||||
|
|
||||||
case AvatarResponse.TerminalOrderResult(terminalGuid, action, result) =>
|
case AvatarResponse.TerminalOrderResult(terminalGuid, action, result) =>
|
||||||
sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
|
sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
|
||||||
sessionData.terminals.lastTerminalOrderFulfillment = true
|
sessionLogic.terminals.lastTerminalOrderFulfillment = true
|
||||||
|
|
||||||
case AvatarResponse.ChangeExosuit(
|
case AvatarResponse.ChangeExosuit(
|
||||||
target,
|
target,
|
||||||
|
|
@ -358,7 +355,7 @@ class SessionAvatarHandlers(
|
||||||
slot = 0
|
slot = 0
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
sessionData.applyPurchaseTimersBeforePackingLoadout(player, player, holsters ++ inventory)
|
sessionLogic.general.applyPurchaseTimersBeforePackingLoadout(player, player, holsters ++ inventory)
|
||||||
DropLeftovers(player)(drops)
|
DropLeftovers(player)(drops)
|
||||||
|
|
||||||
case AvatarResponse.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
|
case AvatarResponse.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
|
||||||
|
|
@ -389,10 +386,10 @@ class SessionAvatarHandlers(
|
||||||
sendResponse(ObjectDeleteMessage(kguid, unk1=0))
|
sendResponse(ObjectDeleteMessage(kguid, unk1=0))
|
||||||
|
|
||||||
case AvatarResponse.KitNotUsed(_, "") =>
|
case AvatarResponse.KitNotUsed(_, "") =>
|
||||||
sessionData.kitToBeUsed = None
|
sessionLogic.general.kitToBeUsed = None
|
||||||
|
|
||||||
case AvatarResponse.KitNotUsed(_, msg) =>
|
case AvatarResponse.KitNotUsed(_, msg) =>
|
||||||
sessionData.kitToBeUsed = None
|
sessionLogic.general.kitToBeUsed = None
|
||||||
sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
|
sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
|
||||||
|
|
||||||
case AvatarResponse.UpdateKillsDeathsAssists(_, kda) =>
|
case AvatarResponse.UpdateKillsDeathsAssists(_, kda) =>
|
||||||
|
|
@ -439,40 +436,40 @@ class SessionAvatarHandlers(
|
||||||
adversarial.map {_.Name }.orElse { Some(s"a ${reason.getClass.getSimpleName}") }
|
adversarial.map {_.Name }.orElse { Some(s"a ${reason.getClass.getSimpleName}") }
|
||||||
}.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
|
}.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
|
||||||
log.info(s"${player.Name} has died, killed by $cause")
|
log.info(s"${player.Name} has died, killed by $cause")
|
||||||
if (sessionData.shooting.shotsWhileDead > 0) {
|
if (sessionLogic.shooting.shotsWhileDead > 0) {
|
||||||
log.warn(
|
log.warn(
|
||||||
s"SHOTS_WHILE_DEAD: client of ${avatar.name} fired ${sessionData.shooting.shotsWhileDead} rounds while character was dead on server"
|
s"SHOTS_WHILE_DEAD: client of ${avatar.name} fired ${sessionLogic.shooting.shotsWhileDead} rounds while character was dead on server"
|
||||||
)
|
)
|
||||||
sessionData.shooting.shotsWhileDead = 0
|
sessionLogic.shooting.shotsWhileDead = 0
|
||||||
}
|
}
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason(msg = "cancel")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason(msg = "cancel")
|
||||||
sessionData.renewCharSavedTimer(fixedLen = 1800L, varLen = 0L)
|
sessionLogic.general.renewCharSavedTimer(fixedLen = 1800L, varLen = 0L)
|
||||||
|
|
||||||
//player state changes
|
//player state changes
|
||||||
AvatarActor.updateToolDischargeFor(avatar)
|
AvatarActor.updateToolDischargeFor(avatar)
|
||||||
player.FreeHand.Equipment.foreach { item =>
|
player.FreeHand.Equipment.foreach { item =>
|
||||||
DropEquipmentFromInventory(player)(item)
|
DropEquipmentFromInventory(player)(item)
|
||||||
}
|
}
|
||||||
sessionData.dropSpecialSlotItem()
|
sessionLogic.general.dropSpecialSlotItem()
|
||||||
sessionData.toggleMaxSpecialState(enable = false)
|
sessionLogic.general.toggleMaxSpecialState(enable = false)
|
||||||
sessionData.keepAliveFunc = sessionData.zoning.NormalKeepAlive
|
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
|
||||||
sessionData.zoning.zoningStatus = Zoning.Status.None
|
sessionLogic.zoning.zoningStatus = Zoning.Status.None
|
||||||
sessionData.zoning.spawn.deadState = DeadState.Dead
|
sessionLogic.zoning.spawn.deadState = DeadState.Dead
|
||||||
continent.GUID(mount).collect { case obj: Vehicle =>
|
continent.GUID(mount).collect { case obj: Vehicle =>
|
||||||
sessionData.vehicles.ConditionalDriverVehicleControl(obj)
|
sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
|
||||||
sessionData.unaccessContainer(obj)
|
sessionLogic.general.unaccessContainer(obj)
|
||||||
}
|
}
|
||||||
sessionData.playerActionsToCancel()
|
sessionLogic.actionsToCancel()
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
AvatarActor.savePlayerLocation(player)
|
AvatarActor.savePlayerLocation(player)
|
||||||
sessionData.zoning.spawn.shiftPosition = Some(player.Position)
|
sessionLogic.zoning.spawn.shiftPosition = Some(player.Position)
|
||||||
|
|
||||||
//respawn
|
//respawn
|
||||||
val respawnTimer = 300.seconds
|
val respawnTimer = 300.seconds
|
||||||
sessionData.zoning.spawn.reviveTimer.cancel()
|
sessionLogic.zoning.spawn.reviveTimer.cancel()
|
||||||
if (player.death_by == 0) {
|
if (player.death_by == 0) {
|
||||||
sessionData.zoning.spawn.reviveTimer = context.system.scheduler.scheduleOnce(respawnTimer) {
|
sessionLogic.zoning.spawn.reviveTimer = context.system.scheduler.scheduleOnce(respawnTimer) {
|
||||||
sessionData.cluster ! ICS.GetRandomSpawnPoint(
|
sessionLogic.cluster ! ICS.GetRandomSpawnPoint(
|
||||||
Zones.sanctuaryZoneNumber(player.Faction),
|
Zones.sanctuaryZoneNumber(player.Faction),
|
||||||
player.Faction,
|
player.Faction,
|
||||||
Seq(SpawnGroup.Sanctuary),
|
Seq(SpawnGroup.Sanctuary),
|
||||||
|
|
@ -480,16 +477,16 @@ class SessionAvatarHandlers(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sessionData.zoning.spawn.HandleReleaseAvatar(player, continent)
|
sessionLogic.zoning.spawn.HandleReleaseAvatar(player, continent)
|
||||||
}
|
}
|
||||||
|
|
||||||
case AvatarResponse.Release(tplayer) if isNotSameTarget =>
|
case AvatarResponse.Release(tplayer) if isNotSameTarget =>
|
||||||
sessionData.zoning.spawn.DepictPlayerAsCorpse(tplayer)
|
sessionLogic.zoning.spawn.DepictPlayerAsCorpse(tplayer)
|
||||||
|
|
||||||
case AvatarResponse.Revive(revivalTargetGuid) if resolvedPlayerGuid == revivalTargetGuid =>
|
case AvatarResponse.Revive(revivalTargetGuid) if resolvedPlayerGuid == revivalTargetGuid =>
|
||||||
log.info(s"No time for rest, ${player.Name}. Back on your feet!")
|
log.info(s"No time for rest, ${player.Name}. Back on your feet!")
|
||||||
sessionData.zoning.spawn.reviveTimer.cancel()
|
sessionLogic.zoning.spawn.reviveTimer.cancel()
|
||||||
sessionData.zoning.spawn.deadState = DeadState.Alive
|
sessionLogic.zoning.spawn.deadState = DeadState.Alive
|
||||||
player.Revive
|
player.Revive
|
||||||
val health = player.Health
|
val health = player.Health
|
||||||
sendResponse(PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
|
sendResponse(PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
|
||||||
|
|
@ -517,7 +514,7 @@ class SessionAvatarHandlers(
|
||||||
|
|
||||||
case AvatarResponse.EnvironmentalDamage(_, _, _) =>
|
case AvatarResponse.EnvironmentalDamage(_, _, _) =>
|
||||||
//TODO damage marker?
|
//TODO damage marker?
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
||||||
|
|
||||||
case AvatarResponse.DropItem(pkt) if isNotSameTarget =>
|
case AvatarResponse.DropItem(pkt) if isNotSameTarget =>
|
||||||
sendResponse(pkt)
|
sendResponse(pkt)
|
||||||
|
|
@ -530,7 +527,7 @@ class SessionAvatarHandlers(
|
||||||
sendResponse(SetEmpireMessage(objectGuid, faction))
|
sendResponse(SetEmpireMessage(objectGuid, faction))
|
||||||
|
|
||||||
case AvatarResponse.DropSpecialItem() =>
|
case AvatarResponse.DropSpecialItem() =>
|
||||||
sessionData.dropSpecialSlotItem()
|
sessionLogic.general.dropSpecialSlotItem()
|
||||||
|
|
||||||
case AvatarResponse.OxygenState(player, vehicle) =>
|
case AvatarResponse.OxygenState(player, vehicle) =>
|
||||||
sendResponse(OxygenStateMessage(
|
sendResponse(OxygenStateMessage(
|
||||||
|
|
@ -612,7 +609,7 @@ class SessionAvatarHandlers(
|
||||||
//TODO squad services deactivated, participation trophy rewards for now - 11-20-2023
|
//TODO squad services deactivated, participation trophy rewards for now - 11-20-2023
|
||||||
//must be in a squad to earn experience
|
//must be in a squad to earn experience
|
||||||
val charId = player.CharId
|
val charId = player.CharId
|
||||||
val squadUI = sessionData.squad.squadUI
|
val squadUI = sessionLogic.squad.squadUI
|
||||||
val participation = continent
|
val participation = continent
|
||||||
.Building(buildingId)
|
.Building(buildingId)
|
||||||
.map { building =>
|
.map { building =>
|
||||||
|
|
@ -672,6 +669,45 @@ class SessionAvatarHandlers(
|
||||||
Some(modifiedExp)
|
Some(modifiedExp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properly format a `DestroyDisplayMessage` packet
|
||||||
|
* given sufficient information about a target (victim) and an actor (killer).
|
||||||
|
* For the packet, the `charId` field is important for determining distinction between players.
|
||||||
|
* @param killer the killer's entry
|
||||||
|
* @param victim the victim's entry
|
||||||
|
* @param method the manner of death
|
||||||
|
* @param unk na;
|
||||||
|
* defaults to 121, the object id of `avatar`
|
||||||
|
* @return a `DestroyDisplayMessage` packet that is properly formatted
|
||||||
|
*/
|
||||||
|
def destroyDisplayMessage(
|
||||||
|
killer: SourceEntry,
|
||||||
|
victim: SourceEntry,
|
||||||
|
method: Int,
|
||||||
|
unk: Int = 121
|
||||||
|
): DestroyDisplayMessage = {
|
||||||
|
val killerSeated = killer match {
|
||||||
|
case obj: PlayerSource => obj.Seated
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
val victimSeated = victim match {
|
||||||
|
case obj: PlayerSource => obj.Seated
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
new DestroyDisplayMessage(
|
||||||
|
killer.Name,
|
||||||
|
killer.CharId,
|
||||||
|
killer.Faction,
|
||||||
|
killerSeated,
|
||||||
|
unk,
|
||||||
|
method,
|
||||||
|
victim.Name,
|
||||||
|
victim.CharId,
|
||||||
|
victim.Faction,
|
||||||
|
victimSeated
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object SessionAvatarHandlers {
|
object SessionAvatarHandlers {
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,34 @@
|
||||||
package net.psforever.actors.session.support
|
package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.{ActorContext, ActorRef, typed}
|
import akka.actor.{ActorContext, ActorRef, typed}
|
||||||
import scala.concurrent.duration._
|
import net.psforever.packet.PlanetSideGamePacket
|
||||||
|
import net.psforever.packet.game.FriendsResponse
|
||||||
|
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
|
||||||
//
|
//
|
||||||
import net.psforever.actors.session.AvatarActor
|
import net.psforever.actors.session.AvatarActor
|
||||||
import net.psforever.objects.Vehicle
|
import net.psforever.packet.game.{BroadcastWarpgateUpdateMessage, HotSpotInfo => PacketHotSpotInfo, HotSpotUpdateMessage, ZoneInfoMessage, ZonePopulationUpdateMessage}
|
||||||
import net.psforever.packet.game.{AvatarDeadStateMessage, BroadcastWarpgateUpdateMessage, DeadState, HotSpotInfo => PacketHotSpotInfo, HotSpotUpdateMessage, ZoneInfoMessage, ZonePopulationUpdateMessage}
|
|
||||||
import net.psforever.services.Service
|
|
||||||
import net.psforever.services.galaxy.GalaxyResponse
|
import net.psforever.services.galaxy.GalaxyResponse
|
||||||
import net.psforever.types.{MemberAction, PlanetSideEmpire}
|
import net.psforever.types.{MemberAction, PlanetSideEmpire}
|
||||||
|
|
||||||
class SessionGalaxyHandlers(
|
class SessionGalaxyHandlers(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
galaxyService: ActorRef,
|
galaxyService: ActorRef,
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality {
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
|
/* packets */
|
||||||
|
|
||||||
|
def handleUpdateIgnoredPlayers: PlanetSideGamePacket => Unit = {
|
||||||
|
case msg: FriendsResponse =>
|
||||||
|
sendResponse(msg)
|
||||||
|
msg.friends.foreach { f =>
|
||||||
|
galaxyService ! GalaxyServiceMessage(GalaxyAction.LogStatusChange(f.name))
|
||||||
|
}
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* response handlers */
|
||||||
|
|
||||||
def handle(reply: GalaxyResponse.Response): Unit = {
|
def handle(reply: GalaxyResponse.Response): Unit = {
|
||||||
reply match {
|
reply match {
|
||||||
case GalaxyResponse.HotSpotUpdate(zone_index, priority, hot_spot_info) =>
|
case GalaxyResponse.HotSpotUpdate(zone_index, priority, hot_spot_info) =>
|
||||||
|
|
@ -45,7 +58,7 @@ class SessionGalaxyHandlers(
|
||||||
sendResponse(msg)
|
sendResponse(msg)
|
||||||
|
|
||||||
case GalaxyResponse.TransferPassenger(temp_channel, vehicle, _, manifest) =>
|
case GalaxyResponse.TransferPassenger(temp_channel, vehicle, _, manifest) =>
|
||||||
sessionData.zoning.handleTransferPassenger(temp_channel, vehicle, manifest)
|
sessionLogic.zoning.handleTransferPassenger(temp_channel, vehicle, manifest)
|
||||||
|
|
||||||
case GalaxyResponse.LockedZoneUpdate(zone, time) =>
|
case GalaxyResponse.LockedZoneUpdate(zone, time) =>
|
||||||
sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
|
sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
|
||||||
|
|
@ -58,7 +71,7 @@ class SessionGalaxyHandlers(
|
||||||
val popVS = zone.Players.count(_.faction == PlanetSideEmpire.VS)
|
val popVS = zone.Players.count(_.faction == PlanetSideEmpire.VS)
|
||||||
sendResponse(ZonePopulationUpdateMessage(zone.Number, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
|
sendResponse(ZonePopulationUpdateMessage(zone.Number, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
|
||||||
|
|
||||||
case GalaxyResponse.LogStatusChange(name) if (avatar.people.friend.exists { _.name.equals(name) }) =>
|
case GalaxyResponse.LogStatusChange(name) if avatar.people.friend.exists(_.name.equals(name)) =>
|
||||||
avatarActor ! AvatarActor.MemberListRequest(MemberAction.UpdateFriend, name)
|
avatarActor ! AvatarActor.MemberListRequest(MemberAction.UpdateFriend, name)
|
||||||
|
|
||||||
case GalaxyResponse.SendResponse(msg) =>
|
case GalaxyResponse.SendResponse(msg) =>
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,13 @@ import akka.actor.ActorContext
|
||||||
import net.psforever.objects.ce.Deployable
|
import net.psforever.objects.ce.Deployable
|
||||||
import net.psforever.objects.vehicles.MountableWeapons
|
import net.psforever.objects.vehicles.MountableWeapons
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
|
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.services.Service
|
import net.psforever.services.Service
|
||||||
import net.psforever.services.local.LocalResponse
|
import net.psforever.services.local.LocalResponse
|
||||||
import net.psforever.types.{ChatMessageType, PlanetSideGUID, Vector3}
|
import net.psforever.types.{ChatMessageType, PlanetSideGUID, Vector3}
|
||||||
|
|
||||||
class SessionLocalHandlers(
|
class SessionLocalHandlers(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality {
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
/**
|
/**
|
||||||
|
|
@ -33,7 +32,7 @@ class SessionLocalHandlers(
|
||||||
sendResponse(DeployableObjectsInfoMessage(behavior, deployInfo))
|
sendResponse(DeployableObjectsInfoMessage(behavior, deployInfo))
|
||||||
|
|
||||||
case LocalResponse.DeployableUIFor(item) =>
|
case LocalResponse.DeployableUIFor(item) =>
|
||||||
sessionData.updateDeployableUIElements(avatar.deployables.UpdateUIElement(item))
|
sessionLogic.general.updateDeployableUIElements(avatar.deployables.UpdateUIElement(item))
|
||||||
|
|
||||||
case LocalResponse.Detonate(dguid, _: BoomerDeployable) =>
|
case LocalResponse.Detonate(dguid, _: BoomerDeployable) =>
|
||||||
sendResponse(TriggerEffectMessage(dguid, "detonate_boomer"))
|
sendResponse(TriggerEffectMessage(dguid, "detonate_boomer"))
|
||||||
|
|
@ -112,10 +111,10 @@ class SessionLocalHandlers(
|
||||||
sendResponse(HackMessage(unk1=0, targetGuid, guid, progress=0, unk1, HackState.HackCleared, unk2))
|
sendResponse(HackMessage(unk1=0, targetGuid, guid, progress=0, unk1, HackState.HackCleared, unk2))
|
||||||
|
|
||||||
case LocalResponse.HackObject(targetGuid, unk1, unk2) =>
|
case LocalResponse.HackObject(targetGuid, unk1, unk2) =>
|
||||||
HackObject(targetGuid, unk1, unk2)
|
sessionLogic.general.hackObject(targetGuid, unk1, unk2)
|
||||||
|
|
||||||
case LocalResponse.PlanetsideAttribute(targetGuid, attributeType, attributeValue) =>
|
case LocalResponse.PlanetsideAttribute(targetGuid, attributeType, attributeValue) =>
|
||||||
SendPlanetsideAttributeMessage(targetGuid, attributeType, attributeValue)
|
sessionLogic.general.sendPlanetsideAttributeMessage(targetGuid, attributeType, attributeValue)
|
||||||
|
|
||||||
case LocalResponse.GenericObjectAction(targetGuid, actionNumber) =>
|
case LocalResponse.GenericObjectAction(targetGuid, actionNumber) =>
|
||||||
sendResponse(GenericObjectActionMessage(targetGuid, actionNumber))
|
sendResponse(GenericObjectActionMessage(targetGuid, actionNumber))
|
||||||
|
|
@ -142,8 +141,8 @@ class SessionLocalHandlers(
|
||||||
sendResponse(TriggerSoundMessage(TriggeredSound.LLUDeconstruct, position, unk=20, volume=0.8000001f))
|
sendResponse(TriggerSoundMessage(TriggeredSound.LLUDeconstruct, position, unk=20, volume=0.8000001f))
|
||||||
sendResponse(ObjectDeleteMessage(lluGuid, unk1=0))
|
sendResponse(ObjectDeleteMessage(lluGuid, unk1=0))
|
||||||
// If the player was holding the LLU, remove it from their tracked special item slot
|
// If the player was holding the LLU, remove it from their tracked special item slot
|
||||||
sessionData.specialItemSlotGuid.collect { case guid if guid == lluGuid =>
|
sessionLogic.general.specialItemSlotGuid.collect { case guid if guid == lluGuid =>
|
||||||
sessionData.specialItemSlotGuid = None
|
sessionLogic.general.specialItemSlotGuid = None
|
||||||
player.Carrying = None
|
player.Carrying = None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,13 +154,13 @@ class SessionLocalHandlers(
|
||||||
|
|
||||||
case LocalResponse.ProximityTerminalEffect(objectGuid, false) =>
|
case LocalResponse.ProximityTerminalEffect(objectGuid, false) =>
|
||||||
sendResponse(ProximityTerminalUseMessage(Service.defaultPlayerGUID, objectGuid, unk=false))
|
sendResponse(ProximityTerminalUseMessage(Service.defaultPlayerGUID, objectGuid, unk=false))
|
||||||
sessionData.terminals.ForgetAllProximityTerminals(objectGuid)
|
sessionLogic.terminals.ForgetAllProximityTerminals(objectGuid)
|
||||||
|
|
||||||
case LocalResponse.RouterTelepadMessage(msg) =>
|
case LocalResponse.RouterTelepadMessage(msg) =>
|
||||||
sendResponse(ChatMsg(ChatMessageType.UNK_229, wideContents=false, recipient="", msg, note=None))
|
sendResponse(ChatMsg(ChatMessageType.UNK_229, wideContents=false, recipient="", msg, note=None))
|
||||||
|
|
||||||
case LocalResponse.RouterTelepadTransport(passengerGuid, srcGuid, destGuid) =>
|
case LocalResponse.RouterTelepadTransport(passengerGuid, srcGuid, destGuid) =>
|
||||||
sessionData.useRouterTelepadEffect(passengerGuid, srcGuid, destGuid)
|
sessionLogic.general.useRouterTelepadEffect(passengerGuid, srcGuid, destGuid)
|
||||||
|
|
||||||
case LocalResponse.SendResponse(msg) =>
|
case LocalResponse.SendResponse(msg) =>
|
||||||
sendResponse(msg)
|
sendResponse(msg)
|
||||||
|
|
@ -190,7 +189,7 @@ class SessionLocalHandlers(
|
||||||
sendResponse(VehicleStateMessage(sguid, unk1=0, pos, orient, vel=None, Some(state), unk3=0, unk4=0, wheel_direction=15, is_decelerating=false, is_cloaked=false))
|
sendResponse(VehicleStateMessage(sguid, unk1=0, pos, orient, vel=None, Some(state), unk3=0, unk4=0, wheel_direction=15, is_decelerating=false, is_cloaked=false))
|
||||||
|
|
||||||
case LocalResponse.ToggleTeleportSystem(router, systemPlan) =>
|
case LocalResponse.ToggleTeleportSystem(router, systemPlan) =>
|
||||||
sessionData.toggleTeleportSystem(router, systemPlan)
|
sessionLogic.general.toggleTeleportSystem(router, systemPlan)
|
||||||
|
|
||||||
case LocalResponse.TriggerEffect(targetGuid, effect, effectInfo, triggerLocation) =>
|
case LocalResponse.TriggerEffect(targetGuid, effect, effectInfo, triggerLocation) =>
|
||||||
sendResponse(TriggerEffectMessage(targetGuid, effect, effectInfo, triggerLocation))
|
sendResponse(TriggerEffectMessage(targetGuid, effect, effectInfo, triggerLocation))
|
||||||
|
|
@ -236,28 +235,4 @@ class SessionLocalHandlers(
|
||||||
sendResponse(PlanetsideAttributeMessage(guid, 29, 1)) //make deployable vanish
|
sendResponse(PlanetsideAttributeMessage(guid, 29, 1)) //make deployable vanish
|
||||||
sendResponse(ObjectDeleteMessage(guid, deletionType))
|
sendResponse(ObjectDeleteMessage(guid, deletionType))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* na
|
|
||||||
* @param targetGuid na
|
|
||||||
* @param unk1 na
|
|
||||||
* @param unk2 na
|
|
||||||
*/
|
|
||||||
def HackObject(targetGuid: PlanetSideGUID, unk1: Long, unk2: Long): Unit = {
|
|
||||||
sendResponse(HackMessage(unk1=0, targetGuid, player_guid=Service.defaultPlayerGUID, progress=100, unk1, HackState.Hacked, unk2))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a PlanetsideAttributeMessage packet to the client
|
|
||||||
* @param targetGuid The target of the attribute
|
|
||||||
* @param attributeType The attribute number
|
|
||||||
* @param attributeValue The attribute value
|
|
||||||
*/
|
|
||||||
def SendPlanetsideAttributeMessage(
|
|
||||||
targetGuid: PlanetSideGUID,
|
|
||||||
attributeType: PlanetsideAttributeEnum,
|
|
||||||
attributeValue: Long
|
|
||||||
): Unit = {
|
|
||||||
sendResponse(PlanetsideAttributeMessage(targetGuid, attributeType, attributeValue))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,573 @@
|
||||||
|
// Copyright (c) 2023 PSForever
|
||||||
|
package net.psforever.actors.session.support
|
||||||
|
|
||||||
|
import akka.actor.Actor.Receive
|
||||||
|
import akka.actor.typed.receptionist.Receptionist
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
import akka.actor.{ActorContext, ActorRef, typed}
|
||||||
|
import net.psforever.objects.zones.blockmap.{SectorGroup, SectorPopulation}
|
||||||
|
import net.psforever.services.ServiceManager
|
||||||
|
import net.psforever.services.ServiceManager.Lookup
|
||||||
|
|
||||||
|
import scala.collection.mutable
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
//
|
||||||
|
import net.psforever.actors.net.MiddlewareActor
|
||||||
|
import net.psforever.actors.session.{AvatarActor, ChatActor}
|
||||||
|
import net.psforever.actors.zone.ZoneActor
|
||||||
|
import net.psforever.objects._
|
||||||
|
import net.psforever.objects.avatar._
|
||||||
|
import net.psforever.objects.ce._
|
||||||
|
import net.psforever.objects.equipment._
|
||||||
|
import net.psforever.objects.inventory.{Container, InventoryItem}
|
||||||
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
|
import net.psforever.objects.vehicles._
|
||||||
|
import net.psforever.objects.vital._
|
||||||
|
import net.psforever.objects.vital.interaction.DamageInteraction
|
||||||
|
import net.psforever.objects.zones._
|
||||||
|
import net.psforever.objects.zones.blockmap.{BlockMap, BlockMapEntity}
|
||||||
|
import net.psforever.packet._
|
||||||
|
import net.psforever.packet.game._
|
||||||
|
import net.psforever.services.account.AccountPersistenceService
|
||||||
|
import net.psforever.services.ServiceManager.LookupResult
|
||||||
|
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
import net.psforever.services.{Service, InterstellarClusterService => ICS}
|
||||||
|
import net.psforever.types._
|
||||||
|
import net.psforever.util.Config
|
||||||
|
|
||||||
|
object SessionLogic {
|
||||||
|
//noinspection ScalaUnusedSymbol
|
||||||
|
private def NoTurnCounterYet(guid: PlanetSideGUID): Unit = { }
|
||||||
|
|
||||||
|
private def updateOldRefsMap(inventory: net.psforever.objects.inventory.GridInventory): IterableOnce[(PlanetSideGUID, String)] = {
|
||||||
|
inventory.Items.flatMap {
|
||||||
|
case InventoryItem(o, _) => updateOldRefsMap(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def updateOldRefsMap(item: PlanetSideGameObject): IterableOnce[(PlanetSideGUID, String)] = {
|
||||||
|
item match {
|
||||||
|
case t: Tool =>
|
||||||
|
t.AmmoSlots.map { slot =>
|
||||||
|
val box = slot.Box
|
||||||
|
box.GUID -> box.Definition.Name
|
||||||
|
} :+ (t.GUID -> t.Definition.Name)
|
||||||
|
case _ =>
|
||||||
|
Seq(item.GUID -> item.Definition.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SessionLogic {
|
||||||
|
def middlewareActor: typed.ActorRef[MiddlewareActor.Command]
|
||||||
|
|
||||||
|
implicit def context: ActorContext
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hardwire an implicit `sender` to be the same as `context.self` of the `SessionActor` actor class
|
||||||
|
* for which this support class was initialized.
|
||||||
|
* Allows for proper use for `ActorRef.tell` or an actor's `!` in the support class,
|
||||||
|
* one where the result is always directed back to the same `SessionActor` instance.
|
||||||
|
* If there is a different packet "sender" that has to be respected by a given method,
|
||||||
|
* pass that `ActorRef` into the method as a parameter.
|
||||||
|
* @see `ActorRef.!(Any)(ActorRef)`
|
||||||
|
* @see `ActorRef.tell(Any)(ActorRef)`
|
||||||
|
*/
|
||||||
|
private[this] implicit val sender: ActorRef = context.self
|
||||||
|
|
||||||
|
private val avatarActor: typed.ActorRef[AvatarActor.Command] = context.spawnAnonymous(AvatarActor(context.self))
|
||||||
|
private val chatActor: typed.ActorRef[ChatActor.Command] = context.spawnAnonymous(ChatActor(context.self, avatarActor))
|
||||||
|
|
||||||
|
private[support] val log = org.log4s.getLogger
|
||||||
|
private[support] var theSession: Session = Session()
|
||||||
|
private[support] var accountIntermediary: ActorRef = Default.Actor
|
||||||
|
private[support] var accountPersistence: ActorRef = Default.Actor
|
||||||
|
private[support] var galaxyService: ActorRef = Default.Actor
|
||||||
|
private[support] var squadService: ActorRef = Default.Actor
|
||||||
|
private[support] var cluster: typed.ActorRef[ICS.Command] = Default.typed.Actor
|
||||||
|
private[session] var connectionState: Int = 25
|
||||||
|
private[support] var persistFunc: () => Unit = noPersistence
|
||||||
|
private[support] var persist: () => Unit = updatePersistenceOnly
|
||||||
|
private[session] var keepAliveFunc: () => Unit = keepAlivePersistenceInitial
|
||||||
|
private[support] var turnCounterFunc: PlanetSideGUID => Unit = SessionLogic.NoTurnCounterYet
|
||||||
|
private[support] val oldRefsMap: mutable.HashMap[PlanetSideGUID, String] = new mutable.HashMap[PlanetSideGUID, String]()
|
||||||
|
private var contextSafeEntity: PlanetSideGUID = PlanetSideGUID(0)
|
||||||
|
|
||||||
|
val general: GeneralOperations =
|
||||||
|
new GeneralOperations(sessionLogic=this, avatarActor, chatActor, context)
|
||||||
|
val shooting: WeaponAndProjectileOperations =
|
||||||
|
new WeaponAndProjectileOperations(sessionLogic=this, avatarActor, chatActor, context)
|
||||||
|
val vehicles: VehicleOperations =
|
||||||
|
new VehicleOperations(sessionLogic=this, avatarActor, context)
|
||||||
|
val avatarResponse: SessionAvatarHandlers =
|
||||||
|
new SessionAvatarHandlers(sessionLogic=this, avatarActor, chatActor, context)
|
||||||
|
val localResponse: SessionLocalHandlers =
|
||||||
|
new SessionLocalHandlers(sessionLogic=this, context)
|
||||||
|
val mountResponse: SessionMountHandlers =
|
||||||
|
new SessionMountHandlers(sessionLogic=this, avatarActor, context)
|
||||||
|
val terminals: SessionTerminalHandlers =
|
||||||
|
new SessionTerminalHandlers(sessionLogic=this, avatarActor, context)
|
||||||
|
private var vehicleResponseOpt: Option[SessionVehicleHandlers] = None
|
||||||
|
private var galaxyResponseOpt: Option[SessionGalaxyHandlers] = None
|
||||||
|
private var squadResponseOpt: Option[SessionSquadHandlers] = None
|
||||||
|
private var zoningOpt: Option[ZoningOperations] = None
|
||||||
|
def vehicleResponseOperations: SessionVehicleHandlers = vehicleResponseOpt.orNull
|
||||||
|
def galaxyResponseHandlers: SessionGalaxyHandlers = galaxyResponseOpt.orNull
|
||||||
|
def squad: SessionSquadHandlers = squadResponseOpt.orNull
|
||||||
|
def zoning: ZoningOperations = zoningOpt.orNull
|
||||||
|
|
||||||
|
ServiceManager.serviceManager ! Lookup("accountIntermediary")
|
||||||
|
ServiceManager.serviceManager ! Lookup("accountPersistence")
|
||||||
|
ServiceManager.serviceManager ! Lookup("galaxy")
|
||||||
|
ServiceManager.serviceManager ! Lookup("squad")
|
||||||
|
ServiceManager.receptionist ! Receptionist.Find(ICS.InterstellarClusterServiceKey, context.self)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updated when an upstream packet arrives;
|
||||||
|
* allow to be a little stale for a short while
|
||||||
|
*/
|
||||||
|
private[support] var localSector: SectorPopulation = SectorGroup(Nil)
|
||||||
|
|
||||||
|
def session: Session = theSession
|
||||||
|
|
||||||
|
def session_=(session: Session): Unit = {
|
||||||
|
chatActor ! ChatActor.SetSession(session)
|
||||||
|
avatarActor ! AvatarActor.SetSession(session)
|
||||||
|
theSession = session
|
||||||
|
}
|
||||||
|
|
||||||
|
def account: Account = theSession.account
|
||||||
|
|
||||||
|
def continent: Zone = theSession.zone
|
||||||
|
|
||||||
|
def player: Player = theSession.player
|
||||||
|
|
||||||
|
def avatar: Avatar = theSession.avatar
|
||||||
|
|
||||||
|
/* setup functions */
|
||||||
|
|
||||||
|
def assignEventBus(msg: Any): Boolean = {
|
||||||
|
msg match {
|
||||||
|
case LookupResult("accountIntermediary", endpoint) =>
|
||||||
|
accountIntermediary = endpoint
|
||||||
|
true
|
||||||
|
case LookupResult("accountPersistence", endpoint) =>
|
||||||
|
accountPersistence = endpoint
|
||||||
|
true
|
||||||
|
case LookupResult("galaxy", endpoint) =>
|
||||||
|
galaxyService = endpoint
|
||||||
|
buildDependentOperationsForGalaxy(endpoint)
|
||||||
|
buildDependentOperations(endpoint, cluster)
|
||||||
|
true
|
||||||
|
case LookupResult("squad", endpoint) =>
|
||||||
|
squadService = endpoint
|
||||||
|
buildDependentOperationsForSquad(endpoint)
|
||||||
|
true
|
||||||
|
case ICS.InterstellarClusterServiceKey.Listing(listings) =>
|
||||||
|
cluster = listings.head
|
||||||
|
buildDependentOperations(galaxyService, cluster)
|
||||||
|
true
|
||||||
|
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildDependentOperationsForGalaxy(galaxyActor: ActorRef): Unit = {
|
||||||
|
if (vehicleResponseOpt.isEmpty && galaxyActor != Default.Actor) {
|
||||||
|
galaxyResponseOpt = Some(new SessionGalaxyHandlers(sessionLogic=this, avatarActor, galaxyActor, context))
|
||||||
|
vehicleResponseOpt = Some(new SessionVehicleHandlers(sessionLogic=this, avatarActor, galaxyActor, context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildDependentOperations(galaxyActor: ActorRef, clusterActor: typed.ActorRef[ICS.Command]): Unit = {
|
||||||
|
if (zoningOpt.isEmpty && galaxyActor != Default.Actor && clusterActor != Default.typed.Actor) {
|
||||||
|
zoningOpt = Some(new ZoningOperations(sessionLogic=this, avatarActor, galaxyActor, clusterActor, context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildDependentOperationsForSquad(squadActor: ActorRef): Unit = {
|
||||||
|
if (squadResponseOpt.isEmpty && squadActor != Default.Actor) {
|
||||||
|
squadResponseOpt = Some(new SessionSquadHandlers(sessionLogic=this, avatarActor, chatActor, squadActor, context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def whenAllEventBusesLoaded(): Boolean = {
|
||||||
|
accountIntermediary != Default.Actor &&
|
||||||
|
accountPersistence != Default.Actor &&
|
||||||
|
vehicleResponseOpt.nonEmpty &&
|
||||||
|
galaxyResponseOpt.nonEmpty &&
|
||||||
|
squadResponseOpt.nonEmpty &&
|
||||||
|
zoningOpt.nonEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
/* message processing */
|
||||||
|
|
||||||
|
def parse(sender: ActorRef): Receive
|
||||||
|
|
||||||
|
/* support functions */
|
||||||
|
|
||||||
|
def validObject(id: Int): Option[PlanetSideGameObject] = validObject(Some(PlanetSideGUID(id)), decorator = "")
|
||||||
|
|
||||||
|
def validObject(id: Int, decorator: String): Option[PlanetSideGameObject] = validObject(Some(PlanetSideGUID(id)), decorator)
|
||||||
|
|
||||||
|
def validObject(id: PlanetSideGUID): Option[PlanetSideGameObject] = validObject(Some(id), decorator = "")
|
||||||
|
|
||||||
|
def validObject(id: PlanetSideGUID, decorator: String): Option[PlanetSideGameObject] = validObject(Some(id), decorator)
|
||||||
|
|
||||||
|
def validObject(id: Option[PlanetSideGUID]): Option[PlanetSideGameObject] = validObject(id, decorator = "")
|
||||||
|
|
||||||
|
def validObject(id: Option[PlanetSideGUID], decorator: String): Option[PlanetSideGameObject] = {
|
||||||
|
val elevatedDecorator = if (decorator.nonEmpty) decorator else "ValidObject"
|
||||||
|
id match {
|
||||||
|
case Some(guid) =>
|
||||||
|
val hint = oldRefsMap.getOrElse(guid, "thing")
|
||||||
|
continent.GUID(guid) match {
|
||||||
|
case Some(_: LocalProjectile) =>
|
||||||
|
shooting.FindProjectileEntry(guid)
|
||||||
|
|
||||||
|
case Some(_: LocalLockerItem) =>
|
||||||
|
player.avatar.locker.Inventory.hasItem(guid) match {
|
||||||
|
case out @ Some(_) =>
|
||||||
|
contextSafeEntity = guid
|
||||||
|
out
|
||||||
|
case None if contextSafeEntity == guid =>
|
||||||
|
//safeguard
|
||||||
|
None
|
||||||
|
case None =>
|
||||||
|
//delete stale entity reference from client
|
||||||
|
log.warn(
|
||||||
|
s"$elevatedDecorator: ${player.Name} is looking for an invalid GUID $guid, believing it a $hint in ${player.Sex.possessive} locker"
|
||||||
|
)
|
||||||
|
sendResponse(ObjectDeleteMessage(guid, 0))
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
case Some(obj) if obj.HasGUID && obj.GUID != guid =>
|
||||||
|
log.error(
|
||||||
|
s"$elevatedDecorator: ${player.Name} found a ${obj.Definition.Name} that isn't the $hint ${player.Sex.pronounSubject} thought it was in zone ${continent.id}"
|
||||||
|
)
|
||||||
|
log.debug(
|
||||||
|
s"$elevatedDecorator: potentially fatal error in ${continent.id} - requested $hint with $guid, got ${obj.Definition.Name} with ${obj.GUID}; mismatch"
|
||||||
|
)
|
||||||
|
None
|
||||||
|
|
||||||
|
case out @ Some(obj) if obj.HasGUID =>
|
||||||
|
out
|
||||||
|
|
||||||
|
case None if !id.contains(PlanetSideGUID(0)) =>
|
||||||
|
//delete stale entity reference from client
|
||||||
|
//deleting guid=0 will cause BAD things to happen
|
||||||
|
log.error(s"$elevatedDecorator: ${player.Name} has an invalid reference to $hint with GUID $guid in zone ${continent.id}")
|
||||||
|
sendResponse(ObjectDeleteMessage(guid, 0))
|
||||||
|
None
|
||||||
|
|
||||||
|
case None if contextSafeEntity == guid =>
|
||||||
|
//safeguard
|
||||||
|
None
|
||||||
|
|
||||||
|
case _ =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update this player avatar for persistence.
|
||||||
|
* Set to `persist` initially.
|
||||||
|
*/
|
||||||
|
def updatePersistenceOnly(): Unit = {
|
||||||
|
persistFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not update this player avatar for persistence.
|
||||||
|
* Set to `persistFunc` initially.
|
||||||
|
*/
|
||||||
|
def noPersistence(): Unit = { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check two locations for a controlled piece of equipment that is associated with the `player`.<br>
|
||||||
|
* <br>
|
||||||
|
* The first location is dependent on whether the avatar is in a vehicle.
|
||||||
|
* Some vehicle seats may have a "controlled weapon" which counts as the first location to be checked.
|
||||||
|
* The second location is dependent on whether the avatar has a raised hand.
|
||||||
|
* That is only possible if the player has something in their hand at the moment, hence the second location.
|
||||||
|
* Players do have a concept called a "last drawn slot" (hand) but that former location is not eligible.<br>
|
||||||
|
* <br>
|
||||||
|
* Along with any discovered item, a containing object such that the statement:<br>
|
||||||
|
* `container.Find(object) = Some(slot)`<br>
|
||||||
|
* ... will return a proper result.
|
||||||
|
* For a mount controlled weapon, the vehicle is returned.
|
||||||
|
* For the player's hand, the player is returned.
|
||||||
|
* @return a `Tuple` of the returned values;
|
||||||
|
* the first value is a `Container` object;
|
||||||
|
* the second value is an `Equipment` object in the former
|
||||||
|
*/
|
||||||
|
def findContainedEquipment(): (Option[PlanetSideGameObject with Container], Set[Equipment]) = {
|
||||||
|
continent.GUID(player.VehicleSeated) match {
|
||||||
|
case Some(vehicle: Mountable with MountableWeapons with Container) =>
|
||||||
|
vehicle.PassengerInSeat(player) match {
|
||||||
|
case Some(seatNum) =>
|
||||||
|
(Some(vehicle), vehicle.WeaponControlledFromSeat(seatNum))
|
||||||
|
case None =>
|
||||||
|
(None, Set.empty)
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
player.Slot(player.DrawnSlot).Equipment match {
|
||||||
|
case Some(a) =>
|
||||||
|
(Some(player), Set(a))
|
||||||
|
case _ =>
|
||||||
|
(None, Set.empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check two locations for a controlled piece of equipment that is associated with the `player`
|
||||||
|
* and has the specified global unique identifier number.
|
||||||
|
*/
|
||||||
|
def findContainedEquipment(
|
||||||
|
guid: PlanetSideGUID
|
||||||
|
): (Option[PlanetSideGameObject with Container], Set[Equipment]) = {
|
||||||
|
val (o, equipment) = findContainedEquipment()
|
||||||
|
equipment.find { _.GUID == guid } match {
|
||||||
|
case Some(equip) => (o, Set(equip))
|
||||||
|
case None => (None, Set.empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs `FindContainedEquipment` but ignores the `Container` object output.
|
||||||
|
* @return an `Equipment` object
|
||||||
|
*/
|
||||||
|
def findEquipment(): Set[Equipment] = findContainedEquipment()._2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs `FindContainedEquipment` but ignores the `Container` object output
|
||||||
|
* and only discovers `Equipment` with the specified global unique identifier number.
|
||||||
|
* @return an `Equipment` object
|
||||||
|
*/
|
||||||
|
def findEquipment(guid: PlanetSideGUID): Option[Equipment] = findEquipment().find { _.GUID == guid }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event has occurred that would cause the player character to stop certain stateful activities.
|
||||||
|
* These activities include shooting, the weapon being drawn, hacking, accessing (a container), flying, and running.
|
||||||
|
* Other players in the same zone must be made aware that the player has stopped as well.<br>
|
||||||
|
* <br>
|
||||||
|
* Things whose configuration should not be changed:<br>
|
||||||
|
* - if the player is seated<br>
|
||||||
|
* - if the player is anchored<br>
|
||||||
|
* This is not a complete list but, for the purpose of enforcement, some pointers will be documented here.
|
||||||
|
*/
|
||||||
|
def actionsToCancel(): Unit = {
|
||||||
|
general.actionsToCancel()
|
||||||
|
shooting.actionsToCancel()
|
||||||
|
terminals.actionsToCancel()
|
||||||
|
if (session.flying) {
|
||||||
|
session = session.copy(flying = false)
|
||||||
|
chatActor ! ChatActor.Message(ChatMsg(ChatMessageType.CMT_FLY, wideContents=false, "", "off", None))
|
||||||
|
}
|
||||||
|
if (session.speed > 1) {
|
||||||
|
session = session.copy(speed = 1)
|
||||||
|
chatActor ! ChatActor.Message(ChatMsg(ChatMessageType.CMT_SPEED, wideContents=false, "", "1.000", None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the amount of damage to be dealt to an active `target`
|
||||||
|
* using the information reconstructed from a `ResolvedProjectile`
|
||||||
|
* and affect the `target` in a synchronized manner.
|
||||||
|
* The active `target` and the target of the `DamageResult` do not have be the same.
|
||||||
|
* While the "tell" for being able to sustain damage is an entity of type `Vitality`,
|
||||||
|
* only specific `Vitality` entity types are being screened for sustaining damage.
|
||||||
|
* @see `DamageResistanceModel`
|
||||||
|
* @see `Vitality`
|
||||||
|
* @param target a valid game object that is known to the server
|
||||||
|
* @param data a projectile that will affect the target
|
||||||
|
*/
|
||||||
|
def handleDealingDamage(target: PlanetSideGameObject with Vitality, data: DamageInteraction): Unit = {
|
||||||
|
val func = data.calculate()
|
||||||
|
target match {
|
||||||
|
case obj: Player if obj.CanDamage && obj.Actor != Default.Actor =>
|
||||||
|
if (obj.CharId != player.CharId) {
|
||||||
|
log.info(s"${player.Name} is attacking ${obj.Name}")
|
||||||
|
} else {
|
||||||
|
log.info(s"${player.Name} hurt ${player.Sex.pronounObject}self")
|
||||||
|
}
|
||||||
|
// auto kick players damaging spectators
|
||||||
|
if (obj.spectator && obj != player) {
|
||||||
|
administrativeKick(player)
|
||||||
|
} else {
|
||||||
|
obj.Actor ! Vitality.Damage(func)
|
||||||
|
}
|
||||||
|
|
||||||
|
case obj: Vehicle if obj.CanDamage =>
|
||||||
|
val name = player.Name
|
||||||
|
val ownerName = obj.OwnerName.getOrElse("someone")
|
||||||
|
if (ownerName.equals(name)) {
|
||||||
|
log.info(s"$name is damaging ${player.Sex.possessive} own ${obj.Definition.Name}")
|
||||||
|
} else {
|
||||||
|
log.info(s"$name is attacking $ownerName's ${obj.Definition.Name}")
|
||||||
|
}
|
||||||
|
obj.Actor ! Vitality.Damage(func)
|
||||||
|
|
||||||
|
case obj: Amenity if obj.CanDamage =>
|
||||||
|
obj.Actor ! Vitality.Damage(func)
|
||||||
|
|
||||||
|
case obj: Deployable if obj.CanDamage =>
|
||||||
|
val name = player.Name
|
||||||
|
val ownerName = obj.OwnerName.getOrElse("someone")
|
||||||
|
if (ownerName.equals(name)) {
|
||||||
|
log.info(s"$name is damaging ${player.Sex.possessive} own ${obj.Definition.Name}")
|
||||||
|
} else {
|
||||||
|
log.info(s"$name is attacking $ownerName's ${obj.Definition.Name}")
|
||||||
|
}
|
||||||
|
obj.Actor ! Vitality.Damage(func)
|
||||||
|
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The atypical response to receiving a `KeepAliveMessage` packet from the client.<br>
|
||||||
|
* <br>
|
||||||
|
* `KeepAliveMessage` packets are the primary vehicle for persistence due to client reporting
|
||||||
|
* in the case where the player's avatar is riding in a vehicle in a mount with no weapon to control.
|
||||||
|
* @see `KeepAliveMessage`
|
||||||
|
* @see `keepAliveFunc`
|
||||||
|
* @see `turnCounterFunc`
|
||||||
|
* @see `persist`
|
||||||
|
*/
|
||||||
|
def keepAlivePersistence(): Unit = {
|
||||||
|
zoning.spawn.interimUngunnedVehicle = None
|
||||||
|
persist()
|
||||||
|
if (player.HasGUID) {
|
||||||
|
turnCounterFunc(player.GUID)
|
||||||
|
} else {
|
||||||
|
turnCounterFunc(PlanetSideGUID(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A really atypical response to receiving a `KeepAliveMessage` packet from the client
|
||||||
|
* that applies only during the character select portion and part of the first zone load activity.
|
||||||
|
*/
|
||||||
|
def keepAlivePersistenceInitial(): Unit = {
|
||||||
|
persist()
|
||||||
|
if (player != null && player.HasGUID) {
|
||||||
|
keepAliveFunc = keepAlivePersistence
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateBlockMap(target: BlockMapEntity, newCoords: Vector3): Unit = {
|
||||||
|
target.blockMapEntry.foreach { entry =>
|
||||||
|
val sectorIndices = BlockMap.findSectorIndices(continent.blockMap, newCoords, entry.rangeX, entry.rangeY).toSet
|
||||||
|
if (sectorIndices.equals(entry.sectors)) {
|
||||||
|
target.updateBlockMapEntry(newCoords) //soft update
|
||||||
|
localSector = continent.blockMap.sector(sectorIndices, Config.app.game.playerDraw.rangeMax.toFloat)
|
||||||
|
} else {
|
||||||
|
continent.actor ! ZoneActor.UpdateBlockMap(target, newCoords) //hard update
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateLocalBlockMap(pos: Vector3): Unit = {
|
||||||
|
localSector = continent.blockMap.sector(pos, Config.app.game.playerDraw.rangeMax.toFloat)
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateOldRefsMap(): Unit = {
|
||||||
|
if(player.HasGUID) {
|
||||||
|
oldRefsMap.addAll(
|
||||||
|
(continent.GUID(player.VehicleSeated) match {
|
||||||
|
case Some(v : Vehicle) =>
|
||||||
|
v.Weapons.toList.collect {
|
||||||
|
case (_, slot : EquipmentSlot) if slot.Equipment.nonEmpty => SessionLogic.updateOldRefsMap(slot.Equipment.get)
|
||||||
|
}.flatten ++
|
||||||
|
SessionLogic.updateOldRefsMap(v.Inventory)
|
||||||
|
case _ =>
|
||||||
|
Map.empty[PlanetSideGUID, String]
|
||||||
|
}) ++
|
||||||
|
(general.accessedContainer match {
|
||||||
|
case Some(cont) => SessionLogic.updateOldRefsMap(cont.Inventory)
|
||||||
|
case None => Map.empty[PlanetSideGUID, String]
|
||||||
|
}) ++
|
||||||
|
player.Holsters().toList.collect {
|
||||||
|
case slot if slot.Equipment.nonEmpty => SessionLogic.updateOldRefsMap(slot.Equipment.get)
|
||||||
|
}.flatten ++
|
||||||
|
SessionLogic.updateOldRefsMap(player.Inventory) ++
|
||||||
|
SessionLogic.updateOldRefsMap(player.avatar.locker.Inventory)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def administrativeKick(tplayer: Player): Unit = {
|
||||||
|
log.warn(s"${tplayer.Name} has been kicked by ${player.Name}")
|
||||||
|
tplayer.death_by = -1
|
||||||
|
accountPersistence ! AccountPersistenceService.Kick(tplayer.Name)
|
||||||
|
//get out of that vehicle
|
||||||
|
vehicles.GetMountableAndSeat(None, tplayer, continent) match {
|
||||||
|
case (Some(obj), Some(seatNum)) =>
|
||||||
|
tplayer.VehicleSeated = None
|
||||||
|
obj.Seats(seatNum).unmount(tplayer)
|
||||||
|
continent.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
continent.id,
|
||||||
|
VehicleAction.KickPassenger(tplayer.GUID, seatNum, unk2=false, obj.GUID)
|
||||||
|
)
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def kickedByAdministration(): Unit = {
|
||||||
|
sendResponse(DisconnectMessage("@kick_w"))
|
||||||
|
context.system.scheduler.scheduleOnce(
|
||||||
|
delay = 300.milliseconds,
|
||||||
|
middlewareActor.toClassic,
|
||||||
|
MiddlewareActor.Teardown()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def immediateDisconnect(): Unit = {
|
||||||
|
if (avatar != null) {
|
||||||
|
accountPersistence ! AccountPersistenceService.Logout(avatar.name)
|
||||||
|
}
|
||||||
|
middlewareActor ! MiddlewareActor.Teardown()
|
||||||
|
}
|
||||||
|
|
||||||
|
def failWithError(error: String): Unit = {
|
||||||
|
log.error(error)
|
||||||
|
middlewareActor ! MiddlewareActor.Teardown()
|
||||||
|
}
|
||||||
|
|
||||||
|
def sendResponse(packet: PlanetSidePacket): Unit = {
|
||||||
|
middlewareActor ! MiddlewareActor.Send(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
def stop(): Unit = {
|
||||||
|
context.stop(avatarActor)
|
||||||
|
context.stop(chatActor)
|
||||||
|
general.stop()
|
||||||
|
shooting.stop()
|
||||||
|
vehicles.stop()
|
||||||
|
avatarResponse.stop()
|
||||||
|
localResponse.stop()
|
||||||
|
mountResponse.stop()
|
||||||
|
terminals.stop()
|
||||||
|
vehicleResponseOpt.foreach(_.stop())
|
||||||
|
galaxyResponseOpt.foreach(_.stop())
|
||||||
|
squadResponseOpt.foreach(_.stop())
|
||||||
|
zoningOpt.foreach(_.stop())
|
||||||
|
continent.AvatarEvents ! Service.Leave()
|
||||||
|
continent.LocalEvents ! Service.Leave()
|
||||||
|
continent.VehicleEvents ! Service.Leave()
|
||||||
|
galaxyService ! Service.Leave()
|
||||||
|
if (avatar != null && squadService != Default.Actor) {
|
||||||
|
squadService ! Service.Leave()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,12 @@
|
||||||
package net.psforever.actors.session.support
|
package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
|
import net.psforever.objects.Tool
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.serverobject.environment.interaction.ResetAllEnvironmentInteractions
|
import net.psforever.objects.serverobject.environment.interaction.ResetAllEnvironmentInteractions
|
||||||
|
import net.psforever.objects.vehicles.MountableWeapons
|
||||||
import net.psforever.objects.vital.InGameHistory
|
import net.psforever.objects.vital.InGameHistory
|
||||||
|
import net.psforever.packet.game.InventoryStateMessage
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
//
|
//
|
||||||
|
|
@ -24,7 +27,7 @@ import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
|
import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
|
||||||
|
|
||||||
class SessionMountHandlers(
|
class SessionMountHandlers(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality {
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
|
|
@ -37,82 +40,82 @@ class SessionMountHandlers(
|
||||||
def handle(tplayer: Player, reply: Mountable.Exchange): Unit = {
|
def handle(tplayer: Player, reply: Mountable.Exchange): Unit = {
|
||||||
reply match {
|
reply match {
|
||||||
case Mountable.CanMount(obj: ImplantTerminalMech, seatNumber, _) =>
|
case Mountable.CanMount(obj: ImplantTerminalMech, seatNumber, _) =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||||
log.info(s"${player.Name} mounts an implant terminal")
|
log.info(s"${player.Name} mounts an implant terminal")
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
sessionLogic.keepAliveFunc = sessionLogic.keepAlivePersistence
|
||||||
|
|
||||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||||
if obj.Definition == GlobalDefinitions.orbital_shuttle =>
|
if obj.Definition == GlobalDefinitions.orbital_shuttle =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the orbital shuttle")
|
log.info(s"${player.Name} mounts the orbital shuttle")
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
sessionLogic.keepAliveFunc = sessionLogic.keepAlivePersistence
|
||||||
|
|
||||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||||
if obj.Definition == GlobalDefinitions.ant =>
|
if obj.Definition == GlobalDefinitions.ant =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
||||||
val obj_guid: PlanetSideGUID = obj.GUID
|
val obj_guid: PlanetSideGUID = obj.GUID
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=45, obj.NtuCapacitorScaled))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=45, obj.NtuCapacitorScaled))
|
||||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||||
sessionData.accessContainer(obj)
|
sessionLogic.general.accessContainer(obj)
|
||||||
tplayer.Actor ! ResetAllEnvironmentInteractions
|
tplayer.Actor ! ResetAllEnvironmentInteractions
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||||
if obj.Definition == GlobalDefinitions.quadstealth =>
|
if obj.Definition == GlobalDefinitions.quadstealth =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
||||||
val obj_guid: PlanetSideGUID = obj.GUID
|
val obj_guid: PlanetSideGUID = obj.GUID
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||||
//exclusive to the wraith, cloak state matches the cloak state of the driver
|
//exclusive to the wraith, cloak state matches the cloak state of the driver
|
||||||
//phantasm doesn't uncloak if the driver is uncloaked and no other vehicle cloaks
|
//phantasm doesn't uncloak if the driver is uncloaked and no other vehicle cloaks
|
||||||
obj.Cloaked = tplayer.Cloaked
|
obj.Cloaked = tplayer.Cloaked
|
||||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||||
sessionData.accessContainer(obj)
|
sessionLogic.general.accessContainer(obj)
|
||||||
tplayer.Actor ! ResetAllEnvironmentInteractions
|
tplayer.Actor ! ResetAllEnvironmentInteractions
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||||
if seatNumber == 0 && obj.Definition.MaxCapacitor > 0 =>
|
if seatNumber == 0 && obj.Definition.MaxCapacitor > 0 =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
||||||
val obj_guid: PlanetSideGUID = obj.GUID
|
val obj_guid: PlanetSideGUID = obj.GUID
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=113, obj.Capacitor))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=113, obj.Capacitor))
|
||||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||||
sessionData.accessContainer(obj)
|
sessionLogic.general.accessContainer(obj)
|
||||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
updateWeaponAtSeatPosition(obj, seatNumber)
|
||||||
tplayer.Actor ! ResetAllEnvironmentInteractions
|
tplayer.Actor ! ResetAllEnvironmentInteractions
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||||
if seatNumber == 0 =>
|
if seatNumber == 0 =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
||||||
val obj_guid: PlanetSideGUID = obj.GUID
|
val obj_guid: PlanetSideGUID = obj.GUID
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||||
sessionData.accessContainer(obj)
|
sessionLogic.general.accessContainer(obj)
|
||||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
updateWeaponAtSeatPosition(obj, seatNumber)
|
||||||
tplayer.Actor ! ResetAllEnvironmentInteractions
|
tplayer.Actor ! ResetAllEnvironmentInteractions
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||||
if obj.Definition.MaxCapacitor > 0 =>
|
if obj.Definition.MaxCapacitor > 0 =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts ${
|
log.info(s"${player.Name} mounts ${
|
||||||
obj.SeatPermissionGroup(seatNumber) match {
|
obj.SeatPermissionGroup(seatNumber) match {
|
||||||
case Some(seatType) => s"a $seatType seat (#$seatNumber)"
|
case Some(seatType) => s"a $seatType seat (#$seatNumber)"
|
||||||
|
|
@ -120,18 +123,18 @@ class SessionMountHandlers(
|
||||||
}
|
}
|
||||||
} of the ${obj.Definition.Name}")
|
} of the ${obj.Definition.Name}")
|
||||||
val obj_guid: PlanetSideGUID = obj.GUID
|
val obj_guid: PlanetSideGUID = obj.GUID
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=113, obj.Capacitor))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=113, obj.Capacitor))
|
||||||
sessionData.accessContainer(obj)
|
sessionLogic.general.accessContainer(obj)
|
||||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
updateWeaponAtSeatPosition(obj, seatNumber)
|
||||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
sessionLogic.keepAliveFunc = sessionLogic.keepAlivePersistence
|
||||||
tplayer.Actor ! ResetAllEnvironmentInteractions
|
tplayer.Actor ! ResetAllEnvironmentInteractions
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _) =>
|
case Mountable.CanMount(obj: Vehicle, seatNumber, _) =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the ${
|
log.info(s"${player.Name} mounts the ${
|
||||||
obj.SeatPermissionGroup(seatNumber) match {
|
obj.SeatPermissionGroup(seatNumber) match {
|
||||||
case Some(seatType) => s"a $seatType seat (#$seatNumber)"
|
case Some(seatType) => s"a $seatType seat (#$seatNumber)"
|
||||||
|
|
@ -139,44 +142,44 @@ class SessionMountHandlers(
|
||||||
}
|
}
|
||||||
} of the ${obj.Definition.Name}")
|
} of the ${obj.Definition.Name}")
|
||||||
val obj_guid: PlanetSideGUID = obj.GUID
|
val obj_guid: PlanetSideGUID = obj.GUID
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||||
sessionData.accessContainer(obj)
|
sessionLogic.general.accessContainer(obj)
|
||||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
updateWeaponAtSeatPosition(obj, seatNumber)
|
||||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
sessionLogic.keepAliveFunc = sessionLogic.keepAlivePersistence
|
||||||
tplayer.Actor ! ResetAllEnvironmentInteractions
|
tplayer.Actor ! ResetAllEnvironmentInteractions
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
||||||
if obj.Definition == GlobalDefinitions.vanu_sentry_turret =>
|
if obj.Definition == GlobalDefinitions.vanu_sentry_turret =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
||||||
obj.Zone.LocalEvents ! LocalServiceMessage(obj.Zone.id, LocalAction.SetEmpire(obj.GUID, player.Faction))
|
obj.Zone.LocalEvents ! LocalServiceMessage(obj.Zone.id, LocalAction.SetEmpire(obj.GUID, player.Faction))
|
||||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
||||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
updateWeaponAtSeatPosition(obj, seatNumber)
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
||||||
if !obj.isUpgrading || System.currentTimeMillis() - getTurretUpgradeTime >= 1500L =>
|
if !obj.isUpgrading || System.currentTimeMillis() - getTurretUpgradeTime >= 1500L =>
|
||||||
obj.setMiddleOfUpgrade(false)
|
obj.setMiddleOfUpgrade(false)
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
||||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
||||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
updateWeaponAtSeatPosition(obj, seatNumber)
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: FacilityTurret, _, _) =>
|
case Mountable.CanMount(obj: FacilityTurret, _, _) =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.warn(
|
log.warn(
|
||||||
s"MountVehicleMsg: ${tplayer.Name} wants to mount turret ${obj.GUID.guid}, but needs to wait until it finishes updating"
|
s"MountVehicleMsg: ${tplayer.Name} wants to mount turret ${obj.GUID.guid}, but needs to wait until it finishes updating"
|
||||||
)
|
)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: PlanetSideGameObject with FactionAffinity with WeaponTurret with InGameHistory, seatNumber, _) =>
|
case Mountable.CanMount(obj: PlanetSideGameObject with FactionAffinity with WeaponTurret with InGameHistory, seatNumber, _) =>
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||||
log.info(s"${player.Name} mounts the ${obj.Definition.asInstanceOf[BasicDefinition].Name}")
|
log.info(s"${player.Name} mounts the ${obj.Definition.asInstanceOf[BasicDefinition].Name}")
|
||||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
||||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
updateWeaponAtSeatPosition(obj, seatNumber)
|
||||||
MountingAction(tplayer, obj, seatNumber)
|
MountingAction(tplayer, obj, seatNumber)
|
||||||
|
|
||||||
case Mountable.CanMount(obj: Mountable, _, _) =>
|
case Mountable.CanMount(obj: Mountable, _, _) =>
|
||||||
|
|
@ -199,7 +202,7 @@ class SessionMountHandlers(
|
||||||
continent.id,
|
continent.id,
|
||||||
LocalAction.SendResponse(ObjectDetachMessage(sguid, pguid, pos, roll=0, pitch=0, zang))
|
LocalAction.SendResponse(ObjectDetachMessage(sguid, pguid, pos, roll=0, pitch=0, zang))
|
||||||
)
|
)
|
||||||
sessionData.keepAliveFunc = sessionData.zoning.NormalKeepAlive
|
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
|
||||||
|
|
||||||
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
|
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
|
||||||
if obj.Definition == GlobalDefinitions.orbital_shuttle =>
|
if obj.Definition == GlobalDefinitions.orbital_shuttle =>
|
||||||
|
|
@ -229,12 +232,12 @@ class SessionMountHandlers(
|
||||||
continent.id,
|
continent.id,
|
||||||
VehicleAction.SendResponse(pguid, GenericObjectActionMessage(pguid, code=9)) //conceal the player
|
VehicleAction.SendResponse(pguid, GenericObjectActionMessage(pguid, code=9)) //conceal the player
|
||||||
)
|
)
|
||||||
sessionData.keepAliveFunc = sessionData.zoning.NormalKeepAlive
|
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
|
||||||
|
|
||||||
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
|
case Mountable.CanDismount(obj: Vehicle, seatNum, _)
|
||||||
if obj.Definition == GlobalDefinitions.droppod =>
|
if obj.Definition == GlobalDefinitions.droppod =>
|
||||||
log.info(s"${tplayer.Name} has landed on ${continent.id}")
|
log.info(s"${tplayer.Name} has landed on ${continent.id}")
|
||||||
sessionData.unaccessContainer(obj)
|
sessionLogic.general.unaccessContainer(obj)
|
||||||
DismountAction(tplayer, obj, seatNum)
|
DismountAction(tplayer, obj, seatNum)
|
||||||
obj.Actor ! Vehicle.Deconstruct()
|
obj.Actor ! Vehicle.Deconstruct()
|
||||||
|
|
||||||
|
|
@ -248,8 +251,8 @@ class SessionMountHandlers(
|
||||||
case None => "seat"
|
case None => "seat"
|
||||||
}
|
}
|
||||||
}")
|
}")
|
||||||
sessionData.vehicles.ConditionalDriverVehicleControl(obj)
|
sessionLogic.vehicles.ConditionalDriverVehicleControl(obj)
|
||||||
sessionData.unaccessContainer(obj)
|
sessionLogic.general.unaccessContainer(obj)
|
||||||
DismountVehicleAction(tplayer, obj, seatNum)
|
DismountVehicleAction(tplayer, obj, seatNum)
|
||||||
|
|
||||||
case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
|
case Mountable.CanDismount(obj: Vehicle, seat_num, _) =>
|
||||||
|
|
@ -291,7 +294,7 @@ class SessionMountHandlers(
|
||||||
def MountingAction(tplayer: Player, obj: PlanetSideGameObject with FactionAffinity with InGameHistory, seatNum: Int): Unit = {
|
def MountingAction(tplayer: Player, obj: PlanetSideGameObject with FactionAffinity with InGameHistory, seatNum: Int): Unit = {
|
||||||
val playerGuid: PlanetSideGUID = tplayer.GUID
|
val playerGuid: PlanetSideGUID = tplayer.GUID
|
||||||
val objGuid: PlanetSideGUID = obj.GUID
|
val objGuid: PlanetSideGUID = obj.GUID
|
||||||
sessionData.playerActionsToCancel()
|
sessionLogic.actionsToCancel()
|
||||||
avatarActor ! AvatarActor.DeactivateActiveImplants()
|
avatarActor ! AvatarActor.DeactivateActiveImplants()
|
||||||
avatarActor ! AvatarActor.SuspendStaminaRegeneration(3.seconds)
|
avatarActor ! AvatarActor.SuspendStaminaRegeneration(3.seconds)
|
||||||
sendResponse(ObjectAttachMessage(objGuid, playerGuid, seatNum))
|
sendResponse(ObjectAttachMessage(objGuid, playerGuid, seatNum))
|
||||||
|
|
@ -313,8 +316,8 @@ class SessionMountHandlers(
|
||||||
obj match {
|
obj match {
|
||||||
case v: Vehicle
|
case v: Vehicle
|
||||||
if seatNum == 0 && Vector3.MagnitudeSquared(v.Velocity.getOrElse(Vector3.Zero)) > 0f =>
|
if seatNum == 0 && Vector3.MagnitudeSquared(v.Velocity.getOrElse(Vector3.Zero)) > 0f =>
|
||||||
sessionData.vehicles.serverVehicleControlVelocity.collect { _ =>
|
sessionLogic.vehicles.serverVehicleControlVelocity.collect { _ =>
|
||||||
sessionData.vehicles.ServerVehicleOverrideStop(v)
|
sessionLogic.vehicles.ServerVehicleOverrideStop(v)
|
||||||
}
|
}
|
||||||
v.Velocity = Vector3.Zero
|
v.Velocity = Vector3.Zero
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(
|
continent.VehicleEvents ! VehicleServiceMessage(
|
||||||
|
|
@ -347,7 +350,7 @@ class SessionMountHandlers(
|
||||||
def DismountAction(tplayer: Player, obj: PlanetSideGameObject with FactionAffinity with InGameHistory, seatNum: Int): Unit = {
|
def DismountAction(tplayer: Player, obj: PlanetSideGameObject with FactionAffinity with InGameHistory, seatNum: Int): Unit = {
|
||||||
val playerGuid: PlanetSideGUID = tplayer.GUID
|
val playerGuid: PlanetSideGUID = tplayer.GUID
|
||||||
tplayer.ContributionFrom(obj)
|
tplayer.ContributionFrom(obj)
|
||||||
sessionData.keepAliveFunc = sessionData.zoning.NormalKeepAlive
|
sessionLogic.keepAliveFunc = sessionLogic.zoning.NormalKeepAlive
|
||||||
val bailType = if (tplayer.BailProtection) {
|
val bailType = if (tplayer.BailProtection) {
|
||||||
BailType.Bailed
|
BailType.Bailed
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -359,4 +362,22 @@ class SessionMountHandlers(
|
||||||
VehicleAction.DismountVehicle(playerGuid, bailType, unk2 = false)
|
VehicleAction.DismountVehicle(playerGuid, bailType, unk2 = false)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From a mount, find the weapon controlled from it, and update the ammunition counts for that weapon's magazines.
|
||||||
|
* @param objWithSeat the object that owns seats (and weaponry)
|
||||||
|
* @param seatNum the mount
|
||||||
|
*/
|
||||||
|
def updateWeaponAtSeatPosition(objWithSeat: MountableWeapons, seatNum: Int): Unit = {
|
||||||
|
objWithSeat.WeaponControlledFromSeat(seatNum) foreach {
|
||||||
|
case weapon: Tool =>
|
||||||
|
//update mounted weapon belonging to mount
|
||||||
|
weapon.AmmoSlots.foreach(slot => {
|
||||||
|
//update the magazine(s) in the weapon, specifically
|
||||||
|
val magazine = slot.Box
|
||||||
|
sendResponse(InventoryStateMessage(magazine.GUID, weapon.GUID, magazine.Capacity.toLong))
|
||||||
|
})
|
||||||
|
case _ => () //no weapons to update
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ object SessionSquadHandlers {
|
||||||
}
|
}
|
||||||
|
|
||||||
class SessionSquadHandlers(
|
class SessionSquadHandlers(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
chatActor: typed.ActorRef[ChatActor.Command],
|
chatActor: typed.ActorRef[ChatActor.Command],
|
||||||
squadService: ActorRef,
|
squadService: ActorRef,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
package net.psforever.actors.session.support
|
package net.psforever.actors.session.support
|
||||||
|
|
||||||
import akka.actor.{ActorContext, typed}
|
import akka.actor.{ActorContext, typed}
|
||||||
|
import net.psforever.objects.guid.GUIDTask
|
||||||
import net.psforever.objects.sourcing.AmenitySource
|
import net.psforever.objects.sourcing.AmenitySource
|
||||||
import net.psforever.objects.vital.TerminalUsedActivity
|
import net.psforever.objects.vital.TerminalUsedActivity
|
||||||
|
|
||||||
|
|
@ -21,7 +22,7 @@ import net.psforever.packet.game.{ItemTransactionMessage, ItemTransactionResultM
|
||||||
import net.psforever.types.{PlanetSideGUID, TransactionType, Vector3}
|
import net.psforever.types.{PlanetSideGUID, TransactionType, Vector3}
|
||||||
|
|
||||||
class SessionTerminalHandlers(
|
class SessionTerminalHandlers(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality {
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
|
|
@ -37,7 +38,7 @@ class SessionTerminalHandlers(
|
||||||
val msg: String = if (itemName.nonEmpty) s" of $itemName" else ""
|
val msg: String = if (itemName.nonEmpty) s" of $itemName" else ""
|
||||||
log.info(s"${player.Name} is submitting an order - a $transactionType from a ${term.Definition.Name}$msg")
|
log.info(s"${player.Name} is submitting an order - a $transactionType from a ${term.Definition.Name}$msg")
|
||||||
lastTerminalOrderFulfillment = false
|
lastTerminalOrderFulfillment = false
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||||
term.Actor ! Terminal.Request(player, pkt)
|
term.Actor ! Terminal.Request(player, pkt)
|
||||||
case Some(_: Terminal) =>
|
case Some(_: Terminal) =>
|
||||||
log.warn(s"Please Wait until your previous order has been fulfilled, ${player.Name}")
|
log.warn(s"Please Wait until your previous order has been fulfilled, ${player.Name}")
|
||||||
|
|
@ -203,7 +204,7 @@ class SessionTerminalHandlers(
|
||||||
Future(true)
|
Future(true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
List(sessionData.registerVehicle(vehicle))
|
List(registerVehicle(vehicle))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,7 +294,7 @@ class SessionTerminalHandlers(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cease all current interactions with proximity-based units.
|
* Cease all current interactions with proximity-based units.
|
||||||
* Pair with `PlayerActionsToCancel`, except when logging out (stopping).
|
* Pair with `actionsToCancel`, except when logging out (stopping).
|
||||||
* This operations may invoke callback messages.
|
* This operations may invoke callback messages.
|
||||||
* @see `postStop`
|
* @see `postStop`
|
||||||
*/
|
*/
|
||||||
|
|
@ -303,7 +304,7 @@ class SessionTerminalHandlers(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cease all current interactions with proximity-based units.
|
* Cease all current interactions with proximity-based units.
|
||||||
* Pair with `PlayerActionsToCancel`, except when logging out (stopping).
|
* Pair with `actionsToCancel`, except when logging out (stopping).
|
||||||
* This operations may invoke callback messages.
|
* This operations may invoke callback messages.
|
||||||
* @param guid globally unique identifier for a proximity terminal
|
* @param guid globally unique identifier for a proximity terminal
|
||||||
* @see `postStop`
|
* @see `postStop`
|
||||||
|
|
@ -326,4 +327,28 @@ class SessionTerminalHandlers(
|
||||||
usingMedicalTerminal = None
|
usingMedicalTerminal = None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that adds a completed and registered vehicle into the scene.
|
||||||
|
* Use this function to renew the globally unique identifiers on a vehicle that has already been added to the scene once.
|
||||||
|
* @param vehicle the `Vehicle` object
|
||||||
|
* @see `RegisterVehicleFromSpawnPad`
|
||||||
|
* @return a `TaskBundle` message
|
||||||
|
*/
|
||||||
|
private[session] def registerVehicle(vehicle: Vehicle): TaskBundle = {
|
||||||
|
TaskBundle(
|
||||||
|
new StraightforwardTask() {
|
||||||
|
private val localVehicle = vehicle
|
||||||
|
|
||||||
|
override def description(): String = s"register a ${localVehicle.Definition.Name}"
|
||||||
|
|
||||||
|
def action(): Future[Any] = Future(true)
|
||||||
|
},
|
||||||
|
List(GUIDTask.registerVehicle(continent.GUID, vehicle))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected[support] def actionsToCancel(): Unit = {
|
||||||
|
lastTerminalOrderFulfillment = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import net.psforever.types.{BailType, ChatMessageType, PlanetSideGUID, Vector3}
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
class SessionVehicleHandlers(
|
class SessionVehicleHandlers(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
galaxyService: ActorRef,
|
galaxyService: ActorRef,
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
|
|
@ -55,7 +55,7 @@ class SessionVehicleHandlers(
|
||||||
player.Position = pos
|
player.Position = pos
|
||||||
player.Orientation = orient
|
player.Orientation = orient
|
||||||
player.Velocity = vel
|
player.Velocity = vel
|
||||||
sessionData.updateLocalBlockMap(pos)
|
sessionLogic.updateLocalBlockMap(pos)
|
||||||
|
|
||||||
case VehicleResponse.VehicleState(
|
case VehicleResponse.VehicleState(
|
||||||
vehicleGuid,
|
vehicleGuid,
|
||||||
|
|
@ -165,7 +165,7 @@ class SessionVehicleHandlers(
|
||||||
sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
|
sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
|
||||||
val typeOfRide = continent.GUID(vehicleGuid) match {
|
val typeOfRide = continent.GUID(vehicleGuid) match {
|
||||||
case Some(obj: Vehicle) =>
|
case Some(obj: Vehicle) =>
|
||||||
sessionData.unaccessContainer(obj)
|
sessionLogic.general.unaccessContainer(obj)
|
||||||
s"the ${obj.Definition.Name}'s seat by ${obj.OwnerName.getOrElse("the pilot")}"
|
s"the ${obj.Definition.Name}'s seat by ${obj.OwnerName.getOrElse("the pilot")}"
|
||||||
case _ =>
|
case _ =>
|
||||||
s"${player.Sex.possessive} ride"
|
s"${player.Sex.possessive} ride"
|
||||||
|
|
@ -217,22 +217,22 @@ class SessionVehicleHandlers(
|
||||||
sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
|
sendResponse(ObjectDeleteMessage(itemGuid, unk1=0))
|
||||||
|
|
||||||
case VehicleResponse.UpdateAmsSpawnPoint(list) =>
|
case VehicleResponse.UpdateAmsSpawnPoint(list) =>
|
||||||
sessionData.zoning.spawn.amsSpawnPoints = list.filter(tube => tube.Faction == player.Faction)
|
sessionLogic.zoning.spawn.amsSpawnPoints = list.filter(tube => tube.Faction == player.Faction)
|
||||||
sessionData.zoning.spawn.DrawCurrentAmsSpawnPoint()
|
sessionLogic.zoning.spawn.DrawCurrentAmsSpawnPoint()
|
||||||
|
|
||||||
case VehicleResponse.TransferPassengerChannel(oldChannel, tempChannel, vehicle, vehicleToDelete) if isNotSameTarget =>
|
case VehicleResponse.TransferPassengerChannel(oldChannel, tempChannel, vehicle, vehicleToDelete) if isNotSameTarget =>
|
||||||
sessionData.zoning.interstellarFerry = Some(vehicle)
|
sessionLogic.zoning.interstellarFerry = Some(vehicle)
|
||||||
sessionData.zoning.interstellarFerryTopLevelGUID = Some(vehicleToDelete)
|
sessionLogic.zoning.interstellarFerryTopLevelGUID = Some(vehicleToDelete)
|
||||||
continent.VehicleEvents ! Service.Leave(Some(oldChannel)) //old vehicle-specific channel (was s"${vehicle.Actor}")
|
continent.VehicleEvents ! Service.Leave(Some(oldChannel)) //old vehicle-specific channel (was s"${vehicle.Actor}")
|
||||||
galaxyService ! Service.Join(tempChannel) //temporary vehicle-specific channel
|
galaxyService ! Service.Join(tempChannel) //temporary vehicle-specific channel
|
||||||
log.debug(s"TransferPassengerChannel: ${player.Name} now subscribed to $tempChannel for vehicle gating")
|
log.debug(s"TransferPassengerChannel: ${player.Name} now subscribed to $tempChannel for vehicle gating")
|
||||||
|
|
||||||
case VehicleResponse.KickCargo(vehicle, speed, delay)
|
case VehicleResponse.KickCargo(vehicle, speed, delay)
|
||||||
if player.VehicleSeated.nonEmpty && sessionData.zoning.spawn.deadState == DeadState.Alive && speed > 0 =>
|
if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive && speed > 0 =>
|
||||||
val strafe = 1 + Vehicles.CargoOrientation(vehicle)
|
val strafe = 1 + Vehicles.CargoOrientation(vehicle)
|
||||||
val reverseSpeed = if (strafe > 1) { 0 } else { speed }
|
val reverseSpeed = if (strafe > 1) { 0 } else { speed }
|
||||||
//strafe or reverse, not both
|
//strafe or reverse, not both
|
||||||
sessionData.vehicles.ServerVehicleOverrideWithPacket(
|
sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
|
||||||
vehicle,
|
vehicle,
|
||||||
ServerVehicleOverrideMsg(
|
ServerVehicleOverrideMsg(
|
||||||
lock_accelerator=true,
|
lock_accelerator=true,
|
||||||
|
|
@ -253,8 +253,8 @@ class SessionVehicleHandlers(
|
||||||
)
|
)
|
||||||
|
|
||||||
case VehicleResponse.KickCargo(cargo, _, _)
|
case VehicleResponse.KickCargo(cargo, _, _)
|
||||||
if player.VehicleSeated.nonEmpty && sessionData.zoning.spawn.deadState == DeadState.Alive =>
|
if player.VehicleSeated.nonEmpty && sessionLogic.zoning.spawn.deadState == DeadState.Alive =>
|
||||||
sessionData.vehicles.TotalDriverVehicleControl(cargo)
|
sessionLogic.vehicles.TotalDriverVehicleControl(cargo)
|
||||||
|
|
||||||
case VehicleResponse.StartPlayerSeatedInVehicle(vehicle, _)
|
case VehicleResponse.StartPlayerSeatedInVehicle(vehicle, _)
|
||||||
if player.VisibleSlots.contains(player.DrawnSlot) =>
|
if player.VisibleSlots.contains(player.DrawnSlot) =>
|
||||||
|
|
@ -266,7 +266,7 @@ class SessionVehicleHandlers(
|
||||||
|
|
||||||
case VehicleResponse.PlayerSeatedInVehicle(vehicle, _) =>
|
case VehicleResponse.PlayerSeatedInVehicle(vehicle, _) =>
|
||||||
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
Vehicles.ReloadAccessPermissions(vehicle, player.Name)
|
||||||
sessionData.vehicles.ServerVehicleOverrideWithPacket(
|
sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
|
||||||
vehicle,
|
vehicle,
|
||||||
ServerVehicleOverrideMsg(
|
ServerVehicleOverrideMsg(
|
||||||
lock_accelerator=true,
|
lock_accelerator=true,
|
||||||
|
|
@ -279,11 +279,11 @@ class SessionVehicleHandlers(
|
||||||
unk8=Some(0)
|
unk8=Some(0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
sessionData.vehicles.serverVehicleControlVelocity = Some(0)
|
sessionLogic.vehicles.serverVehicleControlVelocity = Some(0)
|
||||||
|
|
||||||
case VehicleResponse.ServerVehicleOverrideStart(vehicle, _) =>
|
case VehicleResponse.ServerVehicleOverrideStart(vehicle, _) =>
|
||||||
val vdef = vehicle.Definition
|
val vdef = vehicle.Definition
|
||||||
sessionData.vehicles.ServerVehicleOverrideWithPacket(
|
sessionLogic.vehicles.ServerVehicleOverrideWithPacket(
|
||||||
vehicle,
|
vehicle,
|
||||||
ServerVehicleOverrideMsg(
|
ServerVehicleOverrideMsg(
|
||||||
lock_accelerator=true,
|
lock_accelerator=true,
|
||||||
|
|
@ -298,7 +298,7 @@ class SessionVehicleHandlers(
|
||||||
)
|
)
|
||||||
|
|
||||||
case VehicleResponse.ServerVehicleOverrideEnd(vehicle, _) =>
|
case VehicleResponse.ServerVehicleOverrideEnd(vehicle, _) =>
|
||||||
sessionData.vehicles.ServerVehicleOverrideStop(vehicle)
|
sessionLogic.vehicles.ServerVehicleOverrideStop(vehicle)
|
||||||
|
|
||||||
case VehicleResponse.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, data) =>
|
case VehicleResponse.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, data) =>
|
||||||
sendResponse(ChatMsg(
|
sendResponse(ChatMsg(
|
||||||
|
|
@ -328,7 +328,7 @@ class SessionVehicleHandlers(
|
||||||
sendResponse(ObjectDeleteMessage(eguid, unk1=0))
|
sendResponse(ObjectDeleteMessage(eguid, unk1=0))
|
||||||
TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
|
TaskWorkflow.execute(GUIDTask.unregisterEquipment(continent.GUID, obj))
|
||||||
}
|
}
|
||||||
sessionData.applyPurchaseTimersBeforePackingLoadout(player, vehicle, addedWeapons ++ newInventory)
|
sessionLogic.general.applyPurchaseTimersBeforePackingLoadout(player, vehicle, addedWeapons ++ newInventory)
|
||||||
//jammer or unjamm new weapons based on vehicle status
|
//jammer or unjamm new weapons based on vehicle status
|
||||||
val vehicleJammered = vehicle.Jammed
|
val vehicleJammered = vehicle.Jammed
|
||||||
addedWeapons
|
addedWeapons
|
||||||
|
|
@ -342,7 +342,7 @@ class SessionVehicleHandlers(
|
||||||
}
|
}
|
||||||
|
|
||||||
case VehicleResponse.ChangeLoadout(target, oldWeapons, _, oldInventory, _)
|
case VehicleResponse.ChangeLoadout(target, oldWeapons, _, oldInventory, _)
|
||||||
if sessionData.accessedContainer.map { _.GUID }.contains(target) =>
|
if sessionLogic.general.accessedContainer.map(_.GUID).contains(target) =>
|
||||||
//TODO when vehicle weapons can be changed without visual glitches, rewrite this
|
//TODO when vehicle weapons can be changed without visual glitches, rewrite this
|
||||||
continent.GUID(target).collect { case vehicle: Vehicle =>
|
continent.GUID(target).collect { case vehicle: Vehicle =>
|
||||||
//external participant: observe changes to equipment
|
//external participant: observe changes to equipment
|
||||||
|
|
@ -371,7 +371,7 @@ class SessionVehicleHandlers(
|
||||||
(oldWeapons ++ oldInventory).foreach {
|
(oldWeapons ++ oldInventory).foreach {
|
||||||
case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0))
|
case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0))
|
||||||
}
|
}
|
||||||
sessionData.updateWeaponAtSeatPosition(vehicle, seatNum)
|
sessionLogic.mountResponse.updateWeaponAtSeatPosition(vehicle, seatNum)
|
||||||
case None =>
|
case None =>
|
||||||
//observer: observe changes to external equipment
|
//observer: observe changes to external equipment
|
||||||
oldWeapons.foreach { case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0)) }
|
oldWeapons.foreach { case (_, eguid) => sendResponse(ObjectDeleteMessage(eguid, unk1=0)) }
|
||||||
|
|
@ -380,9 +380,9 @@ class SessionVehicleHandlers(
|
||||||
|
|
||||||
private def startPlayerSeatedInVehicle(vehicle: Vehicle): Unit = {
|
private def startPlayerSeatedInVehicle(vehicle: Vehicle): Unit = {
|
||||||
val vehicle_guid = vehicle.GUID
|
val vehicle_guid = vehicle.GUID
|
||||||
sessionData.playerActionsToCancel()
|
sessionLogic.actionsToCancel()
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sessionData.vehicles.serverVehicleControlVelocity = Some(0)
|
sessionLogic.vehicles.serverVehicleControlVelocity = Some(0)
|
||||||
sendResponse(PlanetsideAttributeMessage(vehicle_guid, attribute_type=22, attribute_value=1L)) //mount points off
|
sendResponse(PlanetsideAttributeMessage(vehicle_guid, attribute_type=22, attribute_value=1L)) //mount points off
|
||||||
sendResponse(PlanetsideAttributeMessage(player.GUID, attribute_type=21, vehicle_guid)) //ownership
|
sendResponse(PlanetsideAttributeMessage(player.GUID, attribute_type=21, vehicle_guid)) //ownership
|
||||||
vehicle.MountPoints.find { case (_, mp) => mp.seatIndex == 0 }.collect {
|
vehicle.MountPoints.find { case (_, mp) => mp.seatIndex == 0 }.collect {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
import net.psforever.types.{BailType, DriveState, Vector3}
|
import net.psforever.types.{BailType, DriveState, Vector3}
|
||||||
|
|
||||||
class VehicleOperations(
|
class VehicleOperations(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality {
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
|
|
@ -40,11 +40,11 @@ class VehicleOperations(
|
||||||
GetVehicleAndSeat() match {
|
GetVehicleAndSeat() match {
|
||||||
case (Some(obj), Some(0)) =>
|
case (Some(obj), Some(0)) =>
|
||||||
//we're driving the vehicle
|
//we're driving the vehicle
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
sessionData.turnCounterFunc(player.GUID)
|
sessionLogic.turnCounterFunc(player.GUID)
|
||||||
sessionData.fallHeightTracker(pos.z)
|
sessionLogic.general.fallHeightTracker(pos.z)
|
||||||
if (obj.MountedIn.isEmpty) {
|
if (obj.MountedIn.isEmpty) {
|
||||||
sessionData.updateBlockMap(obj, pos)
|
sessionLogic.updateBlockMap(obj, pos)
|
||||||
}
|
}
|
||||||
player.Position = pos //convenient
|
player.Position = pos //convenient
|
||||||
if (obj.WeaponControlledFromSeat(0).isEmpty) {
|
if (obj.WeaponControlledFromSeat(0).isEmpty) {
|
||||||
|
|
@ -87,7 +87,7 @@ class VehicleOperations(
|
||||||
obj.Cloaked
|
obj.Cloaked
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
sessionData.squad.updateSquad()
|
sessionLogic.squad.updateSquad()
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
case (None, _) =>
|
case (None, _) =>
|
||||||
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone")
|
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone")
|
||||||
|
|
@ -99,7 +99,7 @@ class VehicleOperations(
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
if (player.death_by == -1) {
|
if (player.death_by == -1) {
|
||||||
sessionData.kickedByAdministration()
|
sessionLogic.kickedByAdministration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,11 +123,11 @@ class VehicleOperations(
|
||||||
GetVehicleAndSeat() match {
|
GetVehicleAndSeat() match {
|
||||||
case (Some(obj), Some(0)) =>
|
case (Some(obj), Some(0)) =>
|
||||||
//we're driving the vehicle
|
//we're driving the vehicle
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
sessionData.turnCounterFunc(player.GUID)
|
sessionLogic.turnCounterFunc(player.GUID)
|
||||||
val (position, angle, velocity, notMountedState) = continent.GUID(obj.MountedIn) match {
|
val (position, angle, velocity, notMountedState) = continent.GUID(obj.MountedIn) match {
|
||||||
case Some(v: Vehicle) =>
|
case Some(v: Vehicle) =>
|
||||||
sessionData.updateBlockMap(obj, pos)
|
sessionLogic.updateBlockMap(obj, pos)
|
||||||
(pos, v.Orientation - Vector3.z(value = 90f) * Vehicles.CargoOrientation(obj).toFloat, v.Velocity, false)
|
(pos, v.Orientation - Vector3.z(value = 90f) * Vehicles.CargoOrientation(obj).toFloat, v.Velocity, false)
|
||||||
case _ =>
|
case _ =>
|
||||||
(pos, ang, vel, true)
|
(pos, ang, vel, true)
|
||||||
|
|
@ -186,7 +186,7 @@ class VehicleOperations(
|
||||||
unkA
|
unkA
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
sessionData.squad.updateSquad()
|
sessionLogic.squad.updateSquad()
|
||||||
case (None, _) =>
|
case (None, _) =>
|
||||||
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone")
|
//log.error(s"VehicleState: no vehicle $vehicle_guid found in zone")
|
||||||
//TODO placing a "not driving" warning here may trigger as we are disembarking the vehicle
|
//TODO placing a "not driving" warning here may trigger as we are disembarking the vehicle
|
||||||
|
|
@ -197,13 +197,13 @@ class VehicleOperations(
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
if (player.death_by == -1) {
|
if (player.death_by == -1) {
|
||||||
sessionData.kickedByAdministration()
|
sessionLogic.kickedByAdministration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleChildObjectState(pkt: ChildObjectStateMessage): Unit = {
|
def handleChildObjectState(pkt: ChildObjectStateMessage): Unit = {
|
||||||
val ChildObjectStateMessage(object_guid, pitch, yaw) = pkt
|
val ChildObjectStateMessage(object_guid, pitch, yaw) = pkt
|
||||||
val (o, tools) = sessionData.shooting.FindContainedWeapon
|
val (o, tools) = sessionLogic.shooting.FindContainedWeapon
|
||||||
//is COSM our primary upstream packet?
|
//is COSM our primary upstream packet?
|
||||||
(o match {
|
(o match {
|
||||||
case Some(mount: Mountable) => (o, mount.PassengerInSeat(player))
|
case Some(mount: Mountable) => (o, mount.PassengerInSeat(player))
|
||||||
|
|
@ -211,8 +211,8 @@ class VehicleOperations(
|
||||||
}) match {
|
}) match {
|
||||||
case (None, None) | (_, None) | (Some(_: Vehicle), Some(0)) => ;
|
case (None, None) | (_, None) | (Some(_: Vehicle), Some(0)) => ;
|
||||||
case _ =>
|
case _ =>
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
sessionData.turnCounterFunc(player.GUID)
|
sessionLogic.turnCounterFunc(player.GUID)
|
||||||
}
|
}
|
||||||
//the majority of the following check retrieves information to determine if we are in control of the child
|
//the majority of the following check retrieves information to determine if we are in control of the child
|
||||||
tools.find { _.GUID == object_guid } match {
|
tools.find { _.GUID == object_guid } match {
|
||||||
|
|
@ -231,19 +231,19 @@ class VehicleOperations(
|
||||||
}
|
}
|
||||||
//TODO status condition of "playing getting out of vehicle to allow for late packets without warning
|
//TODO status condition of "playing getting out of vehicle to allow for late packets without warning
|
||||||
if (player.death_by == -1) {
|
if (player.death_by == -1) {
|
||||||
sessionData.kickedByAdministration()
|
sessionLogic.kickedByAdministration()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleVehicleSubState(pkt: VehicleSubStateMessage): Unit = {
|
def handleVehicleSubState(pkt: VehicleSubStateMessage): Unit = {
|
||||||
val VehicleSubStateMessage(vehicle_guid, _, pos, ang, vel, unk1, _) = pkt
|
val VehicleSubStateMessage(vehicle_guid, _, pos, ang, vel, unk1, _) = pkt
|
||||||
sessionData.validObject(vehicle_guid, decorator = "VehicleSubState") match {
|
sessionLogic.validObject(vehicle_guid, decorator = "VehicleSubState") match {
|
||||||
case Some(obj: Vehicle) =>
|
case Some(obj: Vehicle) =>
|
||||||
import net.psforever.login.WorldSession.boolToInt
|
import net.psforever.login.WorldSession.boolToInt
|
||||||
obj.Position = pos
|
obj.Position = pos
|
||||||
obj.Orientation = ang
|
obj.Orientation = ang
|
||||||
obj.Velocity = vel
|
obj.Velocity = vel
|
||||||
sessionData.updateBlockMap(obj, pos)
|
sessionLogic.updateBlockMap(obj, pos)
|
||||||
obj.zoneInteractions()
|
obj.zoneInteractions()
|
||||||
continent.VehicleEvents ! VehicleServiceMessage(
|
continent.VehicleEvents ! VehicleServiceMessage(
|
||||||
continent.id,
|
continent.id,
|
||||||
|
|
@ -268,7 +268,7 @@ class VehicleOperations(
|
||||||
|
|
||||||
def handleMountVehicle(pkt: MountVehicleMsg): Unit = {
|
def handleMountVehicle(pkt: MountVehicleMsg): Unit = {
|
||||||
val MountVehicleMsg(_, mountable_guid, entry_point) = pkt
|
val MountVehicleMsg(_, mountable_guid, entry_point) = pkt
|
||||||
sessionData.validObject(mountable_guid, decorator = "MountVehicle").collect {
|
sessionLogic.validObject(mountable_guid, decorator = "MountVehicle").collect {
|
||||||
case obj: Mountable =>
|
case obj: Mountable =>
|
||||||
obj.Actor ! Mountable.TryMount(player, entry_point)
|
obj.Actor ! Mountable.TryMount(player, entry_point)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -283,7 +283,7 @@ class VehicleOperations(
|
||||||
//common warning for this section
|
//common warning for this section
|
||||||
if (player.GUID == player_guid) {
|
if (player.GUID == player_guid) {
|
||||||
//normally disembarking from a mount
|
//normally disembarking from a mount
|
||||||
(sessionData.zoning.interstellarFerry.orElse(continent.GUID(player.VehicleSeated)) match {
|
(sessionLogic.zoning.interstellarFerry.orElse(continent.GUID(player.VehicleSeated)) match {
|
||||||
case out @ Some(obj: Vehicle) =>
|
case out @ Some(obj: Vehicle) =>
|
||||||
continent.GUID(obj.MountedIn) match {
|
continent.GUID(obj.MountedIn) match {
|
||||||
case Some(_: Vehicle) => None //cargo vehicle
|
case Some(_: Vehicle) => None //cargo vehicle
|
||||||
|
|
@ -300,7 +300,7 @@ class VehicleOperations(
|
||||||
case Some(seat_num) =>
|
case Some(seat_num) =>
|
||||||
obj.Actor ! Mountable.TryDismount(player, seat_num, bailType)
|
obj.Actor ! Mountable.TryDismount(player, seat_num, bailType)
|
||||||
//short-circuit the temporary channel for transferring between zones, the player is no longer doing that
|
//short-circuit the temporary channel for transferring between zones, the player is no longer doing that
|
||||||
sessionData.zoning.interstellarFerry = None
|
sessionLogic.zoning.interstellarFerry = None
|
||||||
// Deconstruct the vehicle if the driver has bailed out and the vehicle is capable of flight
|
// Deconstruct the vehicle if the driver has bailed out and the vehicle is capable of flight
|
||||||
//todo: implement auto landing procedure if the pilot bails but passengers are still present instead of deconstructing the vehicle
|
//todo: implement auto landing procedure if the pilot bails but passengers are still present instead of deconstructing the vehicle
|
||||||
//todo: continue flight path until aircraft crashes if no passengers present (or no passenger seats), then deconstruct.
|
//todo: continue flight path until aircraft crashes if no passengers present (or no passenger seats), then deconstruct.
|
||||||
|
|
@ -327,8 +327,8 @@ class VehicleOperations(
|
||||||
case Some(obj_guid) =>
|
case Some(obj_guid) =>
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
sessionData.validObject(obj_guid, decorator = "DismountVehicle/Vehicle"),
|
sessionLogic.validObject(obj_guid, decorator = "DismountVehicle/Vehicle"),
|
||||||
sessionData.validObject(player_guid, decorator = "DismountVehicle/Player")
|
sessionLogic.validObject(player_guid, decorator = "DismountVehicle/Player")
|
||||||
) match {
|
) match {
|
||||||
case (vehicle @ Some(obj: Vehicle), tplayer) =>
|
case (vehicle @ Some(obj: Vehicle), tplayer) =>
|
||||||
if (obj.MountedIn.isEmpty) (vehicle, tplayer) else (None, None)
|
if (obj.MountedIn.isEmpty) (vehicle, tplayer) else (None, None)
|
||||||
|
|
@ -508,7 +508,7 @@ class VehicleOperations(
|
||||||
* `(None, None)`, otherwise (even if the vehicle can be determined)
|
* `(None, None)`, otherwise (even if the vehicle can be determined)
|
||||||
*/
|
*/
|
||||||
def GetKnownVehicleAndSeat(): (Option[Vehicle], Option[Int]) =
|
def GetKnownVehicleAndSeat(): (Option[Vehicle], Option[Int]) =
|
||||||
GetMountableAndSeat(sessionData.zoning.interstellarFerry, player, continent) match {
|
GetMountableAndSeat(sessionLogic.zoning.interstellarFerry, player, continent) match {
|
||||||
case (Some(v: Vehicle), Some(seat)) => (Some(v), Some(seat))
|
case (Some(v: Vehicle), Some(seat)) => (Some(v), Some(seat))
|
||||||
case _ => (None, None)
|
case _ => (None, None)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
import scala.concurrent.Future
|
import scala.concurrent.Future
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
//
|
//
|
||||||
import net.psforever.actors.session.{AvatarActor, ChatActor, SessionActor}
|
import net.psforever.actors.session.{AvatarActor, ChatActor}
|
||||||
import net.psforever.login.WorldSession.{CountAmmunition, CountGrenades, FindAmmoBoxThatUses, FindEquipmentStock, FindToolThatUses, PutEquipmentInInventoryOrDrop, PutNewEquipmentInInventoryOrDrop, RemoveOldEquipmentFromInventory}
|
import net.psforever.login.WorldSession.{CountAmmunition, CountGrenades, FindAmmoBoxThatUses, FindEquipmentStock, FindToolThatUses, PutEquipmentInInventoryOrDrop, PutNewEquipmentInInventoryOrDrop, RemoveOldEquipmentFromInventory}
|
||||||
import net.psforever.objects.avatar.scoring.EquipmentStat
|
import net.psforever.objects.avatar.scoring.EquipmentStat
|
||||||
import net.psforever.objects.ballistics.{Projectile, ProjectileQuality}
|
import net.psforever.objects.ballistics.{Projectile, ProjectileQuality}
|
||||||
|
|
@ -42,10 +42,10 @@ import net.psforever.types.{ExoSuitType, PlanetSideGUID, Vector3}
|
||||||
import net.psforever.util.Config
|
import net.psforever.util.Config
|
||||||
|
|
||||||
private[support] class WeaponAndProjectileOperations(
|
private[support] class WeaponAndProjectileOperations(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
chatActor: typed.ActorRef[ChatActor.Command],
|
chatActor: typed.ActorRef[ChatActor.Command],
|
||||||
implicit val context: ActorContext
|
implicit val context: ActorContext
|
||||||
) extends CommonSessionInterfacingFunctionality {
|
) extends CommonSessionInterfacingFunctionality {
|
||||||
var shooting: mutable.Set[PlanetSideGUID] = mutable.Set.empty //ChangeFireStateMessage_Start
|
var shooting: mutable.Set[PlanetSideGUID] = mutable.Set.empty //ChangeFireStateMessage_Start
|
||||||
var prefire: mutable.Set[PlanetSideGUID] = mutable.Set.empty //if WeaponFireMessage precedes ChangeFireStateMessage_Start
|
var prefire: mutable.Set[PlanetSideGUID] = mutable.Set.empty //if WeaponFireMessage precedes ChangeFireStateMessage_Start
|
||||||
|
|
@ -111,8 +111,8 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
val WeaponLazeTargetPositionMessage(_, _, _) = pkt
|
val WeaponLazeTargetPositionMessage(_, _, _) = pkt
|
||||||
//do not need to handle the progress bar animation/state on the server
|
//do not need to handle the progress bar animation/state on the server
|
||||||
//laze waypoint is requested by client upon completion (see SquadWaypointRequest)
|
//laze waypoint is requested by client upon completion (see SquadWaypointRequest)
|
||||||
val purpose = if (sessionData.squad.squad_supplement_id > 0) {
|
val purpose = if (sessionLogic.squad.squad_supplement_id > 0) {
|
||||||
s" for ${player.Sex.possessive} squad (#${sessionData.squad.squad_supplement_id -1})"
|
s" for ${player.Sex.possessive} squad (#${sessionLogic.squad.squad_supplement_id -1})"
|
||||||
} else {
|
} else {
|
||||||
" ..."
|
" ..."
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +128,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
def handleChangeFireStateStart(pkt: ChangeFireStateMessage_Start)(implicit context: ActorContext): Unit = {
|
def handleChangeFireStateStart(pkt: ChangeFireStateMessage_Start)(implicit context: ActorContext): Unit = {
|
||||||
val ChangeFireStateMessage_Start(item_guid) = pkt
|
val ChangeFireStateMessage_Start(item_guid) = pkt
|
||||||
if (shooting.isEmpty) {
|
if (shooting.isEmpty) {
|
||||||
sessionData.findEquipment(item_guid) match {
|
sessionLogic.findEquipment(item_guid) match {
|
||||||
case Some(tool: Tool) if player.VehicleSeated.isEmpty =>
|
case Some(tool: Tool) if player.VehicleSeated.isEmpty =>
|
||||||
fireStateStartWhenPlayer(tool, item_guid)
|
fireStateStartWhenPlayer(tool, item_guid)
|
||||||
case Some(tool: Tool) =>
|
case Some(tool: Tool) =>
|
||||||
|
|
@ -151,7 +151,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
prefire -= item_guid
|
prefire -= item_guid
|
||||||
shootingStop += item_guid -> now
|
shootingStop += item_guid -> now
|
||||||
shooting -= item_guid
|
shooting -= item_guid
|
||||||
sessionData.findEquipment(item_guid) match {
|
sessionLogic.findEquipment(item_guid) match {
|
||||||
case Some(tool: Tool) if player.VehicleSeated.isEmpty =>
|
case Some(tool: Tool) if player.VehicleSeated.isEmpty =>
|
||||||
fireStateStopWhenPlayer(tool, item_guid)
|
fireStateStopWhenPlayer(tool, item_guid)
|
||||||
case Some(tool: Tool) =>
|
case Some(tool: Tool) =>
|
||||||
|
|
@ -169,8 +169,8 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
case _ =>
|
case _ =>
|
||||||
log.warn(s"ChangeFireState_Stop: can not find $item_guid")
|
log.warn(s"ChangeFireState_Stop: can not find $item_guid")
|
||||||
}
|
}
|
||||||
sessionData.progressBarUpdate.cancel()
|
sessionLogic.general.progressBarUpdate.cancel()
|
||||||
sessionData.progressBarValue = None
|
sessionLogic.general.progressBarValue = None
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleReload(pkt: ReloadMessage): Unit = {
|
def handleReload(pkt: ReloadMessage): Unit = {
|
||||||
|
|
@ -187,7 +187,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
|
|
||||||
def handleChangeAmmo(pkt: ChangeAmmoMessage): Unit = {
|
def handleChangeAmmo(pkt: ChangeAmmoMessage): Unit = {
|
||||||
val ChangeAmmoMessage(item_guid, _) = pkt
|
val ChangeAmmoMessage(item_guid, _) = pkt
|
||||||
val (thing, equipment) = sessionData.findContainedEquipment()
|
val (thing, equipment) = sessionLogic.findContainedEquipment()
|
||||||
if (equipment.isEmpty) {
|
if (equipment.isEmpty) {
|
||||||
log.warn(s"ChangeAmmo: either can not find $item_guid or the object found was not Equipment")
|
log.warn(s"ChangeAmmo: either can not find $item_guid or the object found was not Equipment")
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -216,7 +216,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
|
|
||||||
def handleChangeFireMode(pkt: ChangeFireModeMessage): Unit = {
|
def handleChangeFireMode(pkt: ChangeFireModeMessage): Unit = {
|
||||||
val ChangeFireModeMessage(item_guid, _/*fire_mode*/) = pkt
|
val ChangeFireModeMessage(item_guid, _/*fire_mode*/) = pkt
|
||||||
sessionData.findEquipment(item_guid) match {
|
sessionLogic.findEquipment(item_guid) match {
|
||||||
case Some(obj: PlanetSideGameObject with FireModeSwitch[_]) =>
|
case Some(obj: PlanetSideGameObject with FireModeSwitch[_]) =>
|
||||||
val originalModeIndex = obj.FireModeIndex
|
val originalModeIndex = obj.FireModeIndex
|
||||||
if (obj match {
|
if (obj match {
|
||||||
|
|
@ -306,7 +306,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
(hit_info match {
|
(hit_info match {
|
||||||
case Some(hitInfo) =>
|
case Some(hitInfo) =>
|
||||||
val hitPos = hitInfo.hit_pos
|
val hitPos = hitInfo.hit_pos
|
||||||
sessionData.validObject(hitInfo.hitobject_guid, decorator = "Hit/hitInfo") match {
|
sessionLogic.validObject(hitInfo.hitobject_guid, decorator = "Hit/hitInfo") match {
|
||||||
case _ if projectile.profile == GlobalDefinitions.flail_projectile =>
|
case _ if projectile.profile == GlobalDefinitions.flail_projectile =>
|
||||||
val radius = projectile.profile.DamageRadius * projectile.profile.DamageRadius
|
val radius = projectile.profile.DamageRadius * projectile.profile.DamageRadius
|
||||||
val targets = Zone.findAllTargets(continent, player, hitPos, projectile.profile)
|
val targets = Zone.findAllTargets(continent, player, hitPos, projectile.profile)
|
||||||
|
|
@ -340,7 +340,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
) =>
|
) =>
|
||||||
ResolveProjectileInteraction(proj, DamageResolution.Hit, target, hitPos).collect { resprojectile =>
|
ResolveProjectileInteraction(proj, DamageResolution.Hit, target, hitPos).collect { resprojectile =>
|
||||||
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
||||||
sessionData.handleDealingDamage(target, resprojectile)
|
sessionLogic.handleDealingDamage(target, resprojectile)
|
||||||
}
|
}
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
@ -371,23 +371,23 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
(DamageResolution.Splash, DamageResolution.Splash)
|
(DamageResolution.Splash, DamageResolution.Splash)
|
||||||
}
|
}
|
||||||
//direct_victim_uid
|
//direct_victim_uid
|
||||||
sessionData.validObject(direct_victim_uid, decorator = "SplashHit/direct_victim") match {
|
sessionLogic.validObject(direct_victim_uid, decorator = "SplashHit/direct_victim") match {
|
||||||
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
CheckForHitPositionDiscrepancy(projectile_guid, explosion_pos, target)
|
CheckForHitPositionDiscrepancy(projectile_guid, explosion_pos, target)
|
||||||
ResolveProjectileInteraction(projectile, resolution1, target, target.Position).collect { resprojectile =>
|
ResolveProjectileInteraction(projectile, resolution1, target, target.Position).collect { resprojectile =>
|
||||||
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
||||||
sessionData.handleDealingDamage(target, resprojectile)
|
sessionLogic.handleDealingDamage(target, resprojectile)
|
||||||
}
|
}
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
//other victims
|
//other victims
|
||||||
targets.foreach(elem => {
|
targets.foreach(elem => {
|
||||||
sessionData.validObject(elem.uid, decorator = "SplashHit/other_victims") match {
|
sessionLogic.validObject(elem.uid, decorator = "SplashHit/other_victims") match {
|
||||||
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
CheckForHitPositionDiscrepancy(projectile_guid, explosion_pos, target)
|
CheckForHitPositionDiscrepancy(projectile_guid, explosion_pos, target)
|
||||||
ResolveProjectileInteraction(projectile, resolution2, target, explosion_pos).collect { resprojectile =>
|
ResolveProjectileInteraction(projectile, resolution2, target, explosion_pos).collect { resprojectile =>
|
||||||
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
||||||
sessionData.handleDealingDamage(target, resprojectile)
|
sessionLogic.handleDealingDamage(target, resprojectile)
|
||||||
}
|
}
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
@ -421,13 +421,13 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
|
|
||||||
def handleLashHit(pkt: LashMessage): Unit = {
|
def handleLashHit(pkt: LashMessage): Unit = {
|
||||||
val LashMessage(_, _, victim_guid, projectile_guid, hit_pos, _) = pkt
|
val LashMessage(_, _, victim_guid, projectile_guid, hit_pos, _) = pkt
|
||||||
sessionData.validObject(victim_guid, decorator = "Lash") match {
|
sessionLogic.validObject(victim_guid, decorator = "Lash") match {
|
||||||
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
case Some(target: PlanetSideGameObject with FactionAffinity with Vitality) =>
|
||||||
CheckForHitPositionDiscrepancy(projectile_guid, hit_pos, target)
|
CheckForHitPositionDiscrepancy(projectile_guid, hit_pos, target)
|
||||||
ResolveProjectileInteraction(projectile_guid, DamageResolution.Lash, target, hit_pos).foreach {
|
ResolveProjectileInteraction(projectile_guid, DamageResolution.Lash, target, hit_pos).foreach {
|
||||||
resprojectile =>
|
resprojectile =>
|
||||||
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
||||||
sessionData.handleDealingDamage(target, resprojectile)
|
sessionLogic.handleDealingDamage(target, resprojectile)
|
||||||
}
|
}
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
@ -454,7 +454,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
None
|
None
|
||||||
}).collect {
|
}).collect {
|
||||||
case target: AutomatedTurret.Target =>
|
case target: AutomatedTurret.Target =>
|
||||||
sessionData.validObject(attackerGuid, decorator = "AIDamage/AutomatedTurret")
|
sessionLogic.validObject(attackerGuid, decorator = "AIDamage/AutomatedTurret")
|
||||||
.collect {
|
.collect {
|
||||||
case turret: AutomatedTurret if turret.Target.isEmpty =>
|
case turret: AutomatedTurret if turret.Target.isEmpty =>
|
||||||
turret.Actor ! AutomatedTurretBehavior.ConfirmShot(target)
|
turret.Actor ! AutomatedTurretBehavior.ConfirmShot(target)
|
||||||
|
|
@ -468,10 +468,10 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
}
|
}
|
||||||
.orElse {
|
.orElse {
|
||||||
//occasionally, something that is not technically a turret's natural target may be attacked
|
//occasionally, something that is not technically a turret's natural target may be attacked
|
||||||
sessionData.validObject(targetGuid, decorator = "AIDamage/Target")
|
sessionLogic.validObject(targetGuid, decorator = "AIDamage/Target")
|
||||||
.collect {
|
.collect {
|
||||||
case target: PlanetSideServerObject with FactionAffinity with Vitality =>
|
case target: PlanetSideServerObject with FactionAffinity with Vitality =>
|
||||||
sessionData.validObject(attackerGuid, decorator = "AIDamage/Attacker")
|
sessionLogic.validObject(attackerGuid, decorator = "AIDamage/Attacker")
|
||||||
.collect {
|
.collect {
|
||||||
case turret: AutomatedTurret if turret.Target.nonEmpty =>
|
case turret: AutomatedTurret if turret.Target.nonEmpty =>
|
||||||
//the turret must be shooting at something (else) first
|
//the turret must be shooting at something (else) first
|
||||||
|
|
@ -587,11 +587,11 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
projectileGUID: PlanetSideGUID
|
projectileGUID: PlanetSideGUID
|
||||||
): (Option[PlanetSideGameObject with Container], Option[Tool]) = {
|
): (Option[PlanetSideGameObject with Container], Option[Tool]) = {
|
||||||
if (player.ZoningRequest != Zoning.Method.None) {
|
if (player.ZoningRequest != Zoning.Method.None) {
|
||||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_fire")
|
sessionLogic.zoning.CancelZoningProcessWithDescriptiveReason("cancel_fire")
|
||||||
}
|
}
|
||||||
if (player.isShielded) {
|
if (player.isShielded) {
|
||||||
// Cancel NC MAX shield if it's active
|
// Cancel NC MAX shield if it's active
|
||||||
sessionData.toggleMaxSpecialState(enable = false)
|
sessionLogic.general.toggleMaxSpecialState(enable = false)
|
||||||
}
|
}
|
||||||
val (o, tools) = FindContainedWeapon
|
val (o, tools) = FindContainedWeapon
|
||||||
val (_, enabledTools) = FindEnabledWeaponsToHandleWeaponFireAccountability(o, tools)
|
val (_, enabledTools) = FindEnabledWeaponsToHandleWeaponFireAccountability(o, tools)
|
||||||
|
|
@ -893,7 +893,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
stowFunc(previousBox)
|
stowFunc(previousBox)
|
||||||
case None =>
|
case None =>
|
||||||
sessionData.normalItemDrop(player, continent)(previousBox)
|
sessionLogic.general.normalItemDrop(player, continent)(previousBox)
|
||||||
}
|
}
|
||||||
AmmoBox.Split(previousBox) match {
|
AmmoBox.Split(previousBox) match {
|
||||||
case Nil | List(_) => () //done (the former case is technically not possible)
|
case Nil | List(_) => () //done (the former case is technically not possible)
|
||||||
|
|
@ -919,7 +919,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
*/
|
*/
|
||||||
def FindDetectedProjectileTargets(targets: Iterable[PlanetSideGUID]): Iterable[String] = {
|
def FindDetectedProjectileTargets(targets: Iterable[PlanetSideGUID]): Iterable[String] = {
|
||||||
targets
|
targets
|
||||||
.map { sessionData.validObject(_, decorator="FindDetectedProjectileTargets") }
|
.map { sessionLogic.validObject(_, decorator="FindDetectedProjectileTargets") }
|
||||||
.flatMap {
|
.flatMap {
|
||||||
case Some(obj: Vehicle) if !obj.Cloaked =>
|
case Some(obj: Vehicle) if !obj.Cloaked =>
|
||||||
//TODO hint: vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.ProjectileAutoLockAwareness(mode))
|
//TODO hint: vehicleService ! VehicleServiceMessage(s"${obj.Actor}", VehicleAction.ProjectileAutoLockAwareness(mode))
|
||||||
|
|
@ -1163,7 +1163,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
* the second value is an `Tool` object in the former
|
* the second value is an `Tool` object in the former
|
||||||
*/
|
*/
|
||||||
def FindContainedWeapon: (Option[PlanetSideGameObject with Container], Set[Tool]) = {
|
def FindContainedWeapon: (Option[PlanetSideGameObject with Container], Set[Tool]) = {
|
||||||
sessionData.findContainedEquipment() match {
|
sessionLogic.findContainedEquipment() match {
|
||||||
case (container, equipment) =>
|
case (container, equipment) =>
|
||||||
(container, equipment collect { case t: Tool => t })
|
(container, equipment collect { case t: Tool => t })
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -1207,11 +1207,11 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
//charge ammunition drain
|
//charge ammunition drain
|
||||||
tool.FireMode match {
|
tool.FireMode match {
|
||||||
case mode: ChargeFireModeDefinition =>
|
case mode: ChargeFireModeDefinition =>
|
||||||
sessionData.progressBarValue = Some(0f)
|
sessionLogic.general.progressBarValue = Some(0f)
|
||||||
sessionData.progressBarUpdate = context.system.scheduler.scheduleOnce(
|
sessionLogic.general.progressBarUpdate = context.system.scheduler.scheduleOnce(
|
||||||
(mode.Time + mode.DrainInterval) milliseconds,
|
(mode.Time + mode.DrainInterval) milliseconds,
|
||||||
context.self,
|
context.self,
|
||||||
SessionActor.ProgressEvent(1f, () => {}, Tools.ChargeFireMode(player, tool), mode.DrainInterval)
|
CommonMessages.ProgressEvent(1f, () => {}, Tools.ChargeFireMode(player, tool), mode.DrainInterval)
|
||||||
)
|
)
|
||||||
case _ => ()
|
case _ => ()
|
||||||
}
|
}
|
||||||
|
|
@ -1225,7 +1225,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
private def fireStateStartMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
private def fireStateStartMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||||
sessionData.findContainedEquipment()._1.collect {
|
sessionLogic.findContainedEquipment()._1.collect {
|
||||||
case turret: FacilityTurret if continent.map.cavern =>
|
case turret: FacilityTurret if continent.map.cavern =>
|
||||||
turret.Actor ! VanuSentry.ChangeFireStart
|
turret.Actor ! VanuSentry.ChangeFireStart
|
||||||
}
|
}
|
||||||
|
|
@ -1291,7 +1291,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
private def fireStateStopMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
private def fireStateStopMountedMessages(itemGuid: PlanetSideGUID): Unit = {
|
||||||
sessionData.findContainedEquipment()._1.collect {
|
sessionLogic.findContainedEquipment()._1.collect {
|
||||||
case turret: FacilityTurret if continent.map.cavern =>
|
case turret: FacilityTurret if continent.map.cavern =>
|
||||||
turret.Actor ! VanuSentry.ChangeFireStop
|
turret.Actor ! VanuSentry.ChangeFireStop
|
||||||
}
|
}
|
||||||
|
|
@ -1498,7 +1498,7 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
val hitPos = target.Position + Vector3.z(value = 1f)
|
val hitPos = target.Position + Vector3.z(value = 1f)
|
||||||
ResolveProjectileInteraction(proj, DamageResolution.Hit, target, hitPos).collect { resprojectile =>
|
ResolveProjectileInteraction(proj, DamageResolution.Hit, target, hitPos).collect { resprojectile =>
|
||||||
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
addShotsLanded(resprojectile.cause.attribution, shots = 1)
|
||||||
sessionData.handleDealingDamage(target, resprojectile)
|
sessionLogic.handleDealingDamage(target, resprojectile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1585,7 +1585,21 @@ private[support] class WeaponAndProjectileOperations(
|
||||||
}.filter(p => Vector3.DistanceSquared(start, p) <= a)
|
}.filter(p => Vector3.DistanceSquared(start, p) <= a)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected[session] def stop(): Unit = {
|
override protected[support] def actionsToCancel(): Unit = {
|
||||||
|
shootingStart.clear()
|
||||||
|
shootingStop.clear()
|
||||||
|
(prefire ++ shooting).foreach { guid =>
|
||||||
|
sendResponse(ChangeFireStateMessage_Stop(guid))
|
||||||
|
continent.AvatarEvents ! AvatarServiceMessage(
|
||||||
|
continent.id,
|
||||||
|
AvatarAction.ChangeFireState_Stop(player.GUID, guid)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
prefire.clear()
|
||||||
|
shooting.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected[support] def stop(): Unit = {
|
||||||
if (player != null && player.HasGUID) {
|
if (player != null && player.HasGUID) {
|
||||||
(prefire ++ shooting).foreach { guid =>
|
(prefire ++ shooting).foreach { guid =>
|
||||||
//do I need to do this? (maybe)
|
//do I need to do this? (maybe)
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,11 @@ import net.psforever.util.{Config, DefinitionUtil}
|
||||||
import net.psforever.zones.Zones
|
import net.psforever.zones.Zones
|
||||||
|
|
||||||
object ZoningOperations {
|
object ZoningOperations {
|
||||||
|
private[support] final case class AvatarAwardMessageBundle(
|
||||||
|
bundle: Iterable[Iterable[PlanetSideGamePacket]],
|
||||||
|
delay: Long
|
||||||
|
)
|
||||||
|
|
||||||
private final val zoningCountdownMessages: Seq[Int] = Seq(5, 10, 20)
|
private final val zoningCountdownMessages: Seq[Int] = Seq(5, 10, 20)
|
||||||
|
|
||||||
def reportProgressionSystem(sessionActor: ActorRef): Unit = {
|
def reportProgressionSystem(sessionActor: ActorRef): Unit = {
|
||||||
|
|
@ -101,7 +106,7 @@ object ZoningOperations {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ZoningOperations(
|
class ZoningOperations(
|
||||||
val sessionData: SessionData,
|
val sessionLogic: SessionLogic,
|
||||||
avatarActor: typed.ActorRef[AvatarActor.Command],
|
avatarActor: typed.ActorRef[AvatarActor.Command],
|
||||||
galaxyService: ActorRef,
|
galaxyService: ActorRef,
|
||||||
cluster: typed.ActorRef[ICS.Command],
|
cluster: typed.ActorRef[ICS.Command],
|
||||||
|
|
@ -147,7 +152,7 @@ class ZoningOperations(
|
||||||
CancelZoningProcessWithDescriptiveReason("cancel_use")
|
CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||||
if (spawn.deadState != DeadState.RespawnTime) {
|
if (spawn.deadState != DeadState.RespawnTime) {
|
||||||
continent.Buildings.values.find(_.GUID == building_guid) match {
|
continent.Buildings.values.find(_.GUID == building_guid) match {
|
||||||
case Some(wg: WarpGate) if wg.Active && (sessionData.vehicles.GetKnownVehicleAndSeat() match {
|
case Some(wg: WarpGate) if wg.Active && (sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
|
||||||
case (Some(vehicle), _) =>
|
case (Some(vehicle), _) =>
|
||||||
wg.Definition.VehicleAllowance && !wg.Definition.NoWarp.contains(vehicle.Definition)
|
wg.Definition.VehicleAllowance && !wg.Definition.NoWarp.contains(vehicle.Definition)
|
||||||
case _ =>
|
case _ =>
|
||||||
|
|
@ -202,7 +207,7 @@ class ZoningOperations(
|
||||||
continent.VehicleEvents ! Service.Join(name)
|
continent.VehicleEvents ! Service.Join(name)
|
||||||
continent.VehicleEvents ! Service.Join(continentId)
|
continent.VehicleEvents ! Service.Join(continentId)
|
||||||
continent.VehicleEvents ! Service.Join(factionChannel)
|
continent.VehicleEvents ! Service.Join(factionChannel)
|
||||||
if (sessionData.connectionState != 100) configZone(continent)
|
if (sessionLogic.connectionState != 100) configZone(continent)
|
||||||
sendResponse(TimeOfDayMessage(1191182336))
|
sendResponse(TimeOfDayMessage(1191182336))
|
||||||
//custom
|
//custom
|
||||||
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
sendResponse(ReplicationStreamMessage(5, Some(6), Vector.empty)) //clear squad list
|
||||||
|
|
@ -487,7 +492,7 @@ class ZoningOperations(
|
||||||
//the router won't work if it doesn't completely deploy
|
//the router won't work if it doesn't completely deploy
|
||||||
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deploying, 0, unk3=false, Vector3.Zero))
|
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deploying, 0, unk3=false, Vector3.Zero))
|
||||||
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deployed, 0, unk3=false, Vector3.Zero))
|
sendResponse(DeployRequestMessage(player.GUID, obj.GUID, DriveState.Deployed, 0, unk3=false, Vector3.Zero))
|
||||||
sessionData.toggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent))
|
sessionLogic.general.toggleTeleportSystem(obj, TelepadLike.AppraiseTeleportationSystem(obj, continent))
|
||||||
}
|
}
|
||||||
ServiceManager.serviceManager
|
ServiceManager.serviceManager
|
||||||
.ask(Lookup("hart"))(Timeout(2 seconds))
|
.ask(Lookup("hart"))(Timeout(2 seconds))
|
||||||
|
|
@ -656,8 +661,8 @@ class ZoningOperations(
|
||||||
//the following subscriptions last until character switch/logout
|
//the following subscriptions last until character switch/logout
|
||||||
galaxyService ! Service.Join("galaxy") //for galaxy-wide messages
|
galaxyService ! Service.Join("galaxy") //for galaxy-wide messages
|
||||||
galaxyService ! Service.Join(s"${avatar.faction}") //for hotspots, etc.
|
galaxyService ! Service.Join(s"${avatar.faction}") //for hotspots, etc.
|
||||||
sessionData.squadService ! Service.Join(s"${avatar.faction}") //channel will be player.Faction
|
sessionLogic.squadService ! Service.Join(s"${avatar.faction}") //channel will be player.Faction
|
||||||
sessionData.squadService ! Service.Join(s"${avatar.id}") //channel will be player.CharId (in order to work with packets)
|
sessionLogic.squadService ! Service.Join(s"${avatar.id}") //channel will be player.CharId (in order to work with packets)
|
||||||
player.Zone match {
|
player.Zone match {
|
||||||
case Zone.Nowhere =>
|
case Zone.Nowhere =>
|
||||||
RandomSanctuarySpawnPosition(player)
|
RandomSanctuarySpawnPosition(player)
|
||||||
|
|
@ -669,7 +674,7 @@ class ZoningOperations(
|
||||||
session = session.copy(zone = zone)
|
session = session.copy(zone = zone)
|
||||||
//the only zone-level event system subscription necessary before BeginZoningMessage (for persistence purposes)
|
//the only zone-level event system subscription necessary before BeginZoningMessage (for persistence purposes)
|
||||||
zone.AvatarEvents ! Service.Join(player.Name)
|
zone.AvatarEvents ! Service.Join(player.Name)
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
oldZone.AvatarEvents ! Service.Leave()
|
oldZone.AvatarEvents ! Service.Leave()
|
||||||
oldZone.LocalEvents ! Service.Leave()
|
oldZone.LocalEvents ! Service.Leave()
|
||||||
oldZone.VehicleEvents ! Service.Leave()
|
oldZone.VehicleEvents ! Service.Leave()
|
||||||
|
|
@ -699,7 +704,7 @@ class ZoningOperations(
|
||||||
loadConfZone = true
|
loadConfZone = true
|
||||||
val oldZone = session.zone
|
val oldZone = session.zone
|
||||||
session = session.copy(zone = foundZone)
|
session = session.copy(zone = foundZone)
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
oldZone.AvatarEvents ! Service.Leave()
|
oldZone.AvatarEvents ! Service.Leave()
|
||||||
oldZone.LocalEvents ! Service.Leave()
|
oldZone.LocalEvents ! Service.Leave()
|
||||||
oldZone.VehicleEvents ! Service.Leave()
|
oldZone.VehicleEvents ! Service.Leave()
|
||||||
|
|
@ -709,9 +714,9 @@ class ZoningOperations(
|
||||||
player.avatar = avatar
|
player.avatar = avatar
|
||||||
interstellarFerry match {
|
interstellarFerry match {
|
||||||
case Some(vehicle) if vehicle.PassengerInSeat(player).contains(0) =>
|
case Some(vehicle) if vehicle.PassengerInSeat(player).contains(0) =>
|
||||||
TaskWorkflow.execute(sessionData.registerDrivenVehicle(vehicle, player))
|
TaskWorkflow.execute(registerDrivenVehicle(vehicle, player))
|
||||||
case _ =>
|
case _ =>
|
||||||
TaskWorkflow.execute(sessionData.registerNewAvatar(player))
|
TaskWorkflow.execute(registerNewAvatar(player))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -749,9 +754,9 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
val previousZoningType = ztype
|
val previousZoningType = ztype
|
||||||
CancelZoningProcess()
|
CancelZoningProcess()
|
||||||
sessionData.playerActionsToCancel()
|
sessionLogic.actionsToCancel()
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sessionData.dropSpecialSlotItem()
|
sessionLogic.general.dropSpecialSlotItem()
|
||||||
continent.Population ! Zone.Population.Release(avatar)
|
continent.Population ! Zone.Population.Release(avatar)
|
||||||
spawn.resolveZoningSpawnPointLoad(response, previousZoningType)
|
spawn.resolveZoningSpawnPointLoad(response, previousZoningType)
|
||||||
}
|
}
|
||||||
|
|
@ -859,13 +864,13 @@ class ZoningOperations(
|
||||||
zoningStatus = Zoning.Status.Request
|
zoningStatus = Zoning.Status.Request
|
||||||
beginZoningCountdown(() => {
|
beginZoningCountdown(() => {
|
||||||
log.info(s"Good-bye, ${player.Name}")
|
log.info(s"Good-bye, ${player.Name}")
|
||||||
sessionData.immediateDisconnect()
|
sessionLogic.immediateDisconnect()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleSetZone(zoneId: String, position: Vector3): Unit = {
|
def handleSetZone(zoneId: String, position: Vector3): Unit = {
|
||||||
if (sessionData.vehicles.serverVehicleControlVelocity.isEmpty) {
|
if (sessionLogic.vehicles.serverVehicleControlVelocity.isEmpty) {
|
||||||
sessionData.playerActionsToCancel()
|
sessionLogic.actionsToCancel()
|
||||||
continent.GUID(player.VehicleSeated) match {
|
continent.GUID(player.VehicleSeated) match {
|
||||||
case Some(vehicle: Vehicle) if vehicle.MountedIn.isEmpty =>
|
case Some(vehicle: Vehicle) if vehicle.MountedIn.isEmpty =>
|
||||||
vehicle.PassengerInSeat(player) match {
|
vehicle.PassengerInSeat(player) match {
|
||||||
|
|
@ -1143,13 +1148,13 @@ class ZoningOperations(
|
||||||
//sync hack state
|
//sync hack state
|
||||||
amenity.Definition match {
|
amenity.Definition match {
|
||||||
case GlobalDefinitions.capture_terminal =>
|
case GlobalDefinitions.capture_terminal =>
|
||||||
sessionData.sendPlanetsideAttributeMessage(
|
sessionLogic.general.sendPlanetsideAttributeMessage(
|
||||||
amenity.GUID,
|
amenity.GUID,
|
||||||
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
|
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
|
||||||
HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false)
|
HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false)
|
||||||
)
|
)
|
||||||
case _ =>
|
case _ =>
|
||||||
sessionData.hackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object
|
sessionLogic.general.hackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync capture flags
|
// sync capture flags
|
||||||
|
|
@ -1216,7 +1221,7 @@ class ZoningOperations(
|
||||||
if (!zoneReload && zoneId.equals(continent.id)) {
|
if (!zoneReload && zoneId.equals(continent.id)) {
|
||||||
if (player.isBackpack) { // important! test the actor-wide player ref, not the parameter
|
if (player.isBackpack) { // important! test the actor-wide player ref, not the parameter
|
||||||
// respawning from unregistered player
|
// respawning from unregistered player
|
||||||
TaskWorkflow.execute(sessionData.registerAvatar(targetPlayer))
|
TaskWorkflow.execute(registerAvatar(targetPlayer))
|
||||||
} else {
|
} else {
|
||||||
// move existing player; this is the one case where the original GUID is retained by the player
|
// move existing player; this is the one case where the original GUID is retained by the player
|
||||||
context.self ! SessionActor.PlayerLoaded(targetPlayer)
|
context.self ! SessionActor.PlayerLoaded(targetPlayer)
|
||||||
|
|
@ -1336,7 +1341,7 @@ class ZoningOperations(
|
||||||
ICS.FindZone(_.id == zoneId, context.self)
|
ICS.FindZone(_.id == zoneId, context.self)
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
sessionData.unaccessContainer(vehicle)
|
sessionLogic.general.unaccessContainer(vehicle)
|
||||||
LoadZoneCommonTransferActivity()
|
LoadZoneCommonTransferActivity()
|
||||||
player.VehicleSeated = vehicle.GUID
|
player.VehicleSeated = vehicle.GUID
|
||||||
player.Continent = zoneId //forward-set the continent id to perform a test
|
player.Continent = zoneId //forward-set the continent id to perform a test
|
||||||
|
|
@ -1354,7 +1359,7 @@ class ZoningOperations(
|
||||||
//unregister vehicle and driver whole + GiveWorld
|
//unregister vehicle and driver whole + GiveWorld
|
||||||
continent.Transport ! Zone.Vehicle.Despawn(vehicle)
|
continent.Transport ! Zone.Vehicle.Despawn(vehicle)
|
||||||
TaskWorkflow.execute(taskThenZoneChange(
|
TaskWorkflow.execute(taskThenZoneChange(
|
||||||
sessionData.unregisterDrivenVehicle(vehicle, player),
|
unregisterDrivenVehicle(vehicle, player),
|
||||||
ICS.FindZone(_.id == zoneId, context.self)
|
ICS.FindZone(_.id == zoneId, context.self)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
@ -1480,9 +1485,9 @@ class ZoningOperations(
|
||||||
// allow AMS, ANT and Router to remain deployed when owner leaves the zone
|
// allow AMS, ANT and Router to remain deployed when owner leaves the zone
|
||||||
vehicle.Definition match {
|
vehicle.Definition match {
|
||||||
case GlobalDefinitions.ams | GlobalDefinitions.ant | GlobalDefinitions.router
|
case GlobalDefinitions.ams | GlobalDefinitions.ant | GlobalDefinitions.router
|
||||||
=> sessionData.vehicles.ConditionalDriverVehicleControl(vehicle)
|
=> sessionLogic.vehicles.ConditionalDriverVehicleControl(vehicle)
|
||||||
|
|
||||||
case _ => sessionData.vehicles.TotalDriverVehicleControl(vehicle)
|
case _ => sessionLogic.vehicles.TotalDriverVehicleControl(vehicle)
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove owner
|
// remove owner
|
||||||
|
|
@ -1492,12 +1497,12 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
avatarActor ! AvatarActor.SetVehicle(None)
|
avatarActor ! AvatarActor.SetVehicle(None)
|
||||||
}
|
}
|
||||||
sessionData.removeBoomerTriggersFromInventory().foreach(obj => {
|
spawn.removeBoomerTriggersFromInventory().foreach(obj => {
|
||||||
TaskWorkflow.execute(GUIDTask.unregisterObject(continent.GUID, obj))
|
TaskWorkflow.execute(GUIDTask.unregisterObject(continent.GUID, obj))
|
||||||
})
|
})
|
||||||
Deployables.Disown(continent, avatar, context.self)
|
Deployables.Disown(continent, avatar, context.self)
|
||||||
spawn.drawDeloyableIcon = spawn.RedrawDeployableIcons //important for when SetCurrentAvatar initializes the UI next zone
|
spawn.drawDeloyableIcon = spawn.RedrawDeployableIcons //important for when SetCurrentAvatar initializes the UI next zone
|
||||||
sessionData.squad.squadSetup = sessionData.squad.ZoneChangeSquadSetup
|
sessionLogic.squad.squadSetup = sessionLogic.squad.ZoneChangeSquadSetup
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1514,7 +1519,7 @@ class ZoningOperations(
|
||||||
if (currentZone == Zones.sanctuaryZoneNumber(tplayer.Faction)) {
|
if (currentZone == Zones.sanctuaryZoneNumber(tplayer.Faction)) {
|
||||||
log.error(s"RequestSanctuaryZoneSpawn: ${player.Name} is already in faction sanctuary zone.")
|
log.error(s"RequestSanctuaryZoneSpawn: ${player.Name} is already in faction sanctuary zone.")
|
||||||
sendResponse(DisconnectMessage("RequestSanctuaryZoneSpawn: player is already in sanctuary."))
|
sendResponse(DisconnectMessage("RequestSanctuaryZoneSpawn: player is already in sanctuary."))
|
||||||
sessionData.immediateDisconnect()
|
sessionLogic.immediateDisconnect()
|
||||||
} else {
|
} else {
|
||||||
continent.GUID(player.VehicleSeated) match {
|
continent.GUID(player.VehicleSeated) match {
|
||||||
case Some(obj: Vehicle) if !obj.Destroyed =>
|
case Some(obj: Vehicle) if !obj.Destroyed =>
|
||||||
|
|
@ -1547,8 +1552,8 @@ class ZoningOperations(
|
||||||
def LoadZoneLaunchDroppod(zone: Zone, spawnPosition: Vector3): Unit = {
|
def LoadZoneLaunchDroppod(zone: Zone, spawnPosition: Vector3): Unit = {
|
||||||
log.info(s"${player.Name} is launching to ${zone.id} in ${player.Sex.possessive} droppod")
|
log.info(s"${player.Name} is launching to ${zone.id} in ${player.Sex.possessive} droppod")
|
||||||
CancelZoningProcess()
|
CancelZoningProcess()
|
||||||
sessionData.playerActionsToCancel()
|
sessionLogic.actionsToCancel()
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
//droppod action
|
//droppod action
|
||||||
val droppod = Vehicle(GlobalDefinitions.droppod)
|
val droppod = Vehicle(GlobalDefinitions.droppod)
|
||||||
droppod.GUID = PlanetSideGUID(0) //droppod is not registered, we must jury-rig this
|
droppod.GUID = PlanetSideGUID(0) //droppod is not registered, we must jury-rig this
|
||||||
|
|
@ -1596,6 +1601,88 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that registers all aspects of a `Player` avatar
|
||||||
|
* as if that player was already introduced and is just being renewed.
|
||||||
|
* `Players` are complex objects that contain a variety of other register-able objects and each of these objects much be handled.
|
||||||
|
* @param tplayer the avatar `Player`
|
||||||
|
* @return a `TaskBundle` message
|
||||||
|
*/
|
||||||
|
private[session] def registerAvatar(tplayer: Player): TaskBundle = {
|
||||||
|
TaskBundle(
|
||||||
|
new StraightforwardTask() {
|
||||||
|
private val localPlayer = tplayer
|
||||||
|
private val localAnnounce = context.self
|
||||||
|
|
||||||
|
override def description(): String = s"register player avatar ${localPlayer.Name}"
|
||||||
|
|
||||||
|
def action(): Future[Any] = {
|
||||||
|
localAnnounce ! SessionActor.PlayerLoaded(localPlayer)
|
||||||
|
Future(true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
List(GUIDTask.registerPlayer(continent.GUID, tplayer))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that registers all aspects of a `Player` avatar
|
||||||
|
* as if that player is only just being introduced.
|
||||||
|
* `Players` are complex objects that contain a variety of other register-able objects and each of these objects much be handled.
|
||||||
|
* @param tplayer the avatar `Player`
|
||||||
|
* @return a `TaskBundle` message
|
||||||
|
*/
|
||||||
|
private[session] def registerNewAvatar(tplayer: Player): TaskBundle = {
|
||||||
|
TaskBundle(
|
||||||
|
new StraightforwardTask() {
|
||||||
|
private val localPlayer = tplayer
|
||||||
|
private val localAnnounce = context.self
|
||||||
|
|
||||||
|
override def description(): String = s"register new player avatar ${localPlayer.Name}"
|
||||||
|
|
||||||
|
def action(): Future[Any] = {
|
||||||
|
localAnnounce ! SessionActor.NewPlayerLoaded(localPlayer)
|
||||||
|
Future(true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
List(GUIDTask.registerAvatar(continent.GUID, tplayer))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private[session] def registerDrivenVehicle(vehicle: Vehicle, driver: Player): TaskBundle = {
|
||||||
|
TaskBundle(
|
||||||
|
new StraightforwardTask() {
|
||||||
|
private val localVehicle = vehicle
|
||||||
|
private val localDriver = driver
|
||||||
|
private val localAnnounce = context.self
|
||||||
|
|
||||||
|
override def description(): String = s"register a ${localVehicle.Definition.Name} driven by ${localDriver.Name}"
|
||||||
|
|
||||||
|
def action(): Future[Any] = {
|
||||||
|
localDriver.VehicleSeated = localVehicle.GUID
|
||||||
|
Vehicles.Own(localVehicle, localDriver)
|
||||||
|
localAnnounce ! SessionActor.NewPlayerLoaded(localDriver)
|
||||||
|
Future(true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
List(GUIDTask.registerAvatar(continent.GUID, driver), GUIDTask.registerVehicle(continent.GUID, vehicle))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private[session] def unregisterDrivenVehicle(vehicle: Vehicle, driver: Player): TaskBundle = {
|
||||||
|
TaskBundle(
|
||||||
|
new StraightforwardTask() {
|
||||||
|
private val localVehicle = vehicle
|
||||||
|
private val localDriver = driver
|
||||||
|
|
||||||
|
override def description(): String = s"unregister a ${localVehicle.Definition.Name} driven by ${localDriver.Name}"
|
||||||
|
|
||||||
|
def action(): Future[Any] = Future(true)
|
||||||
|
},
|
||||||
|
List(GUIDTask.unregisterAvatar(continent.GUID, driver), GUIDTask.unregisterVehicle(continent.GUID, vehicle))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this function to facilitate registering a droppod for a globally unique identifier
|
* Use this function to facilitate registering a droppod for a globally unique identifier
|
||||||
* in the event that the user has instigated an instant action event to a destination within the current zone.<br>
|
* in the event that the user has instigated an instant action event to a destination within the current zone.<br>
|
||||||
|
|
@ -1730,7 +1817,7 @@ class ZoningOperations(
|
||||||
|
|
||||||
def handleLoginInfoNowhere(name: String, from: ActorRef): Unit = {
|
def handleLoginInfoNowhere(name: String, from: ActorRef): Unit = {
|
||||||
log.info(s"LoginInfo: player $name is considered a fresh character")
|
log.info(s"LoginInfo: player $name is considered a fresh character")
|
||||||
sessionData.persistFunc = UpdatePersistence(from)
|
sessionLogic.persistFunc = UpdatePersistence(from)
|
||||||
deadState = DeadState.RespawnTime
|
deadState = DeadState.RespawnTime
|
||||||
val tplayer = new Player(avatar)
|
val tplayer = new Player(avatar)
|
||||||
session = session.copy(player = tplayer)
|
session = session.copy(player = tplayer)
|
||||||
|
|
@ -1742,7 +1829,7 @@ class ZoningOperations(
|
||||||
|
|
||||||
def handleLoginInfoSomewhere(name: String, inZone: Zone, optionalSavedData: Option[Savedplayer], from: ActorRef): Unit = {
|
def handleLoginInfoSomewhere(name: String, inZone: Zone, optionalSavedData: Option[Savedplayer], from: ActorRef): Unit = {
|
||||||
log.info(s"LoginInfo: player $name is considered a fresh character")
|
log.info(s"LoginInfo: player $name is considered a fresh character")
|
||||||
sessionData.persistFunc = UpdatePersistence(from)
|
sessionLogic.persistFunc = UpdatePersistence(from)
|
||||||
deadState = DeadState.RespawnTime
|
deadState = DeadState.RespawnTime
|
||||||
session = session.copy(player = new Player(avatar))
|
session = session.copy(player = new Player(avatar))
|
||||||
player.Zone = inZone
|
player.Zone = inZone
|
||||||
|
|
@ -1836,7 +1923,7 @@ class ZoningOperations(
|
||||||
|
|
||||||
def handleLoginInfoRestore(name: String, inZone: Zone, pos: Vector3, from: ActorRef): Unit = {
|
def handleLoginInfoRestore(name: String, inZone: Zone, pos: Vector3, from: ActorRef): Unit = {
|
||||||
log.info(s"RestoreInfo: player $name is already logged in zone ${inZone.id}; rejoining that character")
|
log.info(s"RestoreInfo: player $name is already logged in zone ${inZone.id}; rejoining that character")
|
||||||
sessionData.persistFunc = UpdatePersistence(from)
|
sessionLogic.persistFunc = UpdatePersistence(from)
|
||||||
//tell the old WorldSessionActor to kill itself by using its own subscriptions against itself
|
//tell the old WorldSessionActor to kill itself by using its own subscriptions against itself
|
||||||
inZone.AvatarEvents ! AvatarServiceMessage(name, AvatarAction.TeardownConnection())
|
inZone.AvatarEvents ! AvatarServiceMessage(name, AvatarAction.TeardownConnection())
|
||||||
spawn.switchAvatarStatisticsFieldToRefreshAfterRespawn()
|
spawn.switchAvatarStatisticsFieldToRefreshAfterRespawn()
|
||||||
|
|
@ -1847,14 +1934,14 @@ class ZoningOperations(
|
||||||
) match {
|
) match {
|
||||||
case (_, Some(p)) if p.death_by == -1 =>
|
case (_, Some(p)) if p.death_by == -1 =>
|
||||||
//player is not allowed
|
//player is not allowed
|
||||||
sessionData.kickedByAdministration()
|
sessionLogic.kickedByAdministration()
|
||||||
|
|
||||||
case (Some(a), Some(p)) if p.isAlive =>
|
case (Some(a), Some(p)) if p.isAlive =>
|
||||||
//rejoin current avatar/player
|
//rejoin current avatar/player
|
||||||
log.info(s"RestoreInfo: player $name is alive")
|
log.info(s"RestoreInfo: player $name is alive")
|
||||||
deadState = DeadState.Alive
|
deadState = DeadState.Alive
|
||||||
session = session.copy(player = p, avatar = a)
|
session = session.copy(player = p, avatar = a)
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
setupAvatarFunc = AvatarRejoin
|
setupAvatarFunc = AvatarRejoin
|
||||||
dropMedicalApplicators(p)
|
dropMedicalApplicators(p)
|
||||||
avatarActor ! AvatarActor.ReplaceAvatar(a)
|
avatarActor ! AvatarActor.ReplaceAvatar(a)
|
||||||
|
|
@ -1865,7 +1952,7 @@ class ZoningOperations(
|
||||||
log.info(s"RestoreInfo: player $name is dead")
|
log.info(s"RestoreInfo: player $name is dead")
|
||||||
deadState = DeadState.Dead
|
deadState = DeadState.Dead
|
||||||
session = session.copy(player = p, avatar = a)
|
session = session.copy(player = p, avatar = a)
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
dropMedicalApplicators(p)
|
dropMedicalApplicators(p)
|
||||||
HandleReleaseAvatar(p, inZone)
|
HandleReleaseAvatar(p, inZone)
|
||||||
avatarActor ! AvatarActor.ReplaceAvatar(a)
|
avatarActor ! AvatarActor.ReplaceAvatar(a)
|
||||||
|
|
@ -1900,7 +1987,7 @@ class ZoningOperations(
|
||||||
def handleLoginCanNot(name: String, reason: PlayerToken.DeniedLoginReason.Value): Unit = {
|
def handleLoginCanNot(name: String, reason: PlayerToken.DeniedLoginReason.Value): Unit = {
|
||||||
log.warn(s"LoginInfo: $name is denied login for reason - $reason")
|
log.warn(s"LoginInfo: $name is denied login for reason - $reason")
|
||||||
reason match {
|
reason match {
|
||||||
case PlayerToken.DeniedLoginReason.Kicked => sessionData.kickedByAdministration()
|
case PlayerToken.DeniedLoginReason.Kicked => sessionLogic.kickedByAdministration()
|
||||||
case _ => sendResponse(DisconnectMessage("You will be logged out."))
|
case _ => sendResponse(DisconnectMessage("You will be logged out."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1939,9 +2026,9 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
val previousZoningType = ztype
|
val previousZoningType = ztype
|
||||||
CancelZoningProcess()
|
CancelZoningProcess()
|
||||||
sessionData.playerActionsToCancel()
|
sessionLogic.actionsToCancel()
|
||||||
sessionData.terminals.CancelAllProximityUnits()
|
sessionLogic.terminals.CancelAllProximityUnits()
|
||||||
sessionData.dropSpecialSlotItem()
|
sessionLogic.general.dropSpecialSlotItem()
|
||||||
continent.Population ! Zone.Population.Release(avatar)
|
continent.Population ! Zone.Population.Release(avatar)
|
||||||
resolveZoningSpawnPointLoad(response, previousZoningType)
|
resolveZoningSpawnPointLoad(response, previousZoningType)
|
||||||
}
|
}
|
||||||
|
|
@ -1954,8 +2041,8 @@ class ZoningOperations(
|
||||||
val map = zone.map
|
val map = zone.map
|
||||||
val mapName = map.name
|
val mapName = map.name
|
||||||
log.info(s"${tplayer.Name} has spawned into $id")
|
log.info(s"${tplayer.Name} has spawned into $id")
|
||||||
sessionData.oldRefsMap.clear()
|
sessionLogic.oldRefsMap.clear()
|
||||||
sessionData.persist = UpdatePersistenceAndRefs
|
sessionLogic.persist = UpdatePersistenceAndRefs
|
||||||
tplayer.avatar = avatar
|
tplayer.avatar = avatar
|
||||||
session = session.copy(player = tplayer)
|
session = session.copy(player = tplayer)
|
||||||
avatarActor ! AvatarActor.CreateImplants()
|
avatarActor ! AvatarActor.CreateImplants()
|
||||||
|
|
@ -1967,7 +2054,7 @@ class ZoningOperations(
|
||||||
//important! the LoadMapMessage must be processed by the client before the avatar is created
|
//important! the LoadMapMessage must be processed by the client before the avatar is created
|
||||||
setupAvatarFunc()
|
setupAvatarFunc()
|
||||||
//interimUngunnedVehicle should have been setup by setupAvatarFunc, if it is applicable
|
//interimUngunnedVehicle should have been setup by setupAvatarFunc, if it is applicable
|
||||||
sessionData.turnCounterFunc = interimUngunnedVehicle match {
|
sessionLogic.turnCounterFunc = interimUngunnedVehicle match {
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
TurnCounterDuringInterimWhileInPassengerSeat
|
TurnCounterDuringInterimWhileInPassengerSeat
|
||||||
case None if zoningType == Zoning.Method.Login || zoningType == Zoning.Method.Reset =>
|
case None if zoningType == Zoning.Method.Login || zoningType == Zoning.Method.Reset =>
|
||||||
|
|
@ -1975,14 +2062,14 @@ class ZoningOperations(
|
||||||
case None =>
|
case None =>
|
||||||
TurnCounterDuringInterim
|
TurnCounterDuringInterim
|
||||||
}
|
}
|
||||||
sessionData.keepAliveFunc = NormalKeepAlive
|
sessionLogic.keepAliveFunc = NormalKeepAlive
|
||||||
if (zoningStatus == Zoning.Status.Deconstructing) {
|
if (zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
sessionData.stopDeconstructing()
|
stopDeconstructing()
|
||||||
}
|
}
|
||||||
sessionData.avatarResponse.lastSeenStreamMessage.clear()
|
sessionLogic.avatarResponse.lastSeenStreamMessage.clear()
|
||||||
upstreamMessageCount = 0
|
upstreamMessageCount = 0
|
||||||
setAvatar = false
|
setAvatar = false
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
} else {
|
} else {
|
||||||
//look for different spawn point in same zone
|
//look for different spawn point in same zone
|
||||||
cluster ! ICS.GetNearbySpawnPoint(
|
cluster ! ICS.GetNearbySpawnPoint(
|
||||||
|
|
@ -2004,20 +2091,20 @@ class ZoningOperations(
|
||||||
//try this spawn point
|
//try this spawn point
|
||||||
setupAvatarFunc()
|
setupAvatarFunc()
|
||||||
//interimUngunnedVehicle should have been setup by setupAvatarFunc, if it is applicable
|
//interimUngunnedVehicle should have been setup by setupAvatarFunc, if it is applicable
|
||||||
sessionData.turnCounterFunc = interimUngunnedVehicle match {
|
sessionLogic.turnCounterFunc = interimUngunnedVehicle match {
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
TurnCounterDuringInterimWhileInPassengerSeat
|
TurnCounterDuringInterimWhileInPassengerSeat
|
||||||
case None =>
|
case None =>
|
||||||
TurnCounterDuringInterim
|
TurnCounterDuringInterim
|
||||||
}
|
}
|
||||||
sessionData.keepAliveFunc = NormalKeepAlive
|
sessionLogic.keepAliveFunc = NormalKeepAlive
|
||||||
if (zoningStatus == Zoning.Status.Deconstructing) {
|
if (zoningStatus == Zoning.Status.Deconstructing) {
|
||||||
sessionData.stopDeconstructing()
|
stopDeconstructing()
|
||||||
}
|
}
|
||||||
sessionData.avatarResponse.lastSeenStreamMessage.clear()
|
sessionLogic.avatarResponse.lastSeenStreamMessage.clear()
|
||||||
upstreamMessageCount = 0
|
upstreamMessageCount = 0
|
||||||
setAvatar = false
|
setAvatar = false
|
||||||
sessionData.persist()
|
sessionLogic.persist()
|
||||||
} else {
|
} else {
|
||||||
//look for different spawn point in same zone
|
//look for different spawn point in same zone
|
||||||
cluster ! ICS.GetNearbySpawnPoint(
|
cluster ! ICS.GetNearbySpawnPoint(
|
||||||
|
|
@ -2087,7 +2174,7 @@ class ZoningOperations(
|
||||||
* @param zone na
|
* @param zone na
|
||||||
*/
|
*/
|
||||||
def HandleReleaseAvatar(tplayer: Player, zone: Zone): Unit = {
|
def HandleReleaseAvatar(tplayer: Player, zone: Zone): Unit = {
|
||||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
sessionLogic.keepAliveFunc = sessionLogic.keepAlivePersistence
|
||||||
tplayer.Release
|
tplayer.Release
|
||||||
tplayer.VehicleSeated match {
|
tplayer.VehicleSeated match {
|
||||||
case None =>
|
case None =>
|
||||||
|
|
@ -2101,8 +2188,8 @@ class ZoningOperations(
|
||||||
}
|
}
|
||||||
|
|
||||||
def handleSetPosition(position: Vector3): Unit = {
|
def handleSetPosition(position: Vector3): Unit = {
|
||||||
if (sessionData.vehicles.serverVehicleControlVelocity.isEmpty) {
|
if (sessionLogic.vehicles.serverVehicleControlVelocity.isEmpty) {
|
||||||
sessionData.playerActionsToCancel()
|
sessionLogic.actionsToCancel()
|
||||||
continent.GUID(player.VehicleSeated) match {
|
continent.GUID(player.VehicleSeated) match {
|
||||||
case Some(vehicle: Vehicle) if vehicle.MountedIn.isEmpty =>
|
case Some(vehicle: Vehicle) if vehicle.MountedIn.isEmpty =>
|
||||||
vehicle.PassengerInSeat(player) match {
|
vehicle.PassengerInSeat(player) match {
|
||||||
|
|
@ -2147,7 +2234,7 @@ class ZoningOperations(
|
||||||
player.Armor = armor
|
player.Armor = armor
|
||||||
}
|
}
|
||||||
player.death_by = math.min(player.death_by, 0)
|
player.death_by = math.min(player.death_by, 0)
|
||||||
sessionData.vehicles.GetKnownVehicleAndSeat() match {
|
sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
|
||||||
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
||||||
//if the vehicle is the cargo of another vehicle in this zone
|
//if the vehicle is the cargo of another vehicle in this zone
|
||||||
val carrierInfo = continent.GUID(vehicle.MountedIn) match {
|
val carrierInfo = continent.GUID(vehicle.MountedIn) match {
|
||||||
|
|
@ -2254,7 +2341,7 @@ class ZoningOperations(
|
||||||
* Neither the player avatar nor the vehicle should be reconstructed before the next zone load operation
|
* Neither the player avatar nor the vehicle should be reconstructed before the next zone load operation
|
||||||
* to avoid damaging the critical setup of this function.
|
* to avoid damaging the critical setup of this function.
|
||||||
* @see `AccessContainer`
|
* @see `AccessContainer`
|
||||||
* @see `UpdateWeaponAtSeatPosition`
|
* @see `SessionMountHandlers.updateWeaponAtSeatPosition`
|
||||||
* @param tplayer the player avatar seated in the vehicle's mount
|
* @param tplayer the player avatar seated in the vehicle's mount
|
||||||
* @param vehicle the vehicle the player is riding
|
* @param vehicle the vehicle the player is riding
|
||||||
* @param seat the mount index
|
* @param seat the mount index
|
||||||
|
|
@ -2271,8 +2358,8 @@ class ZoningOperations(
|
||||||
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
|
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
|
||||||
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
||||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||||
sessionData.accessContainer(vehicle)
|
sessionLogic.general.accessContainer(vehicle)
|
||||||
sessionData.updateWeaponAtSeatPosition(vehicle, seat)
|
sessionLogic.mountResponse.updateWeaponAtSeatPosition(vehicle, seat)
|
||||||
} else {
|
} else {
|
||||||
interimUngunnedVehicle = Some(vguid)
|
interimUngunnedVehicle = Some(vguid)
|
||||||
interimUngunnedVehicleSeat = Some(seat)
|
interimUngunnedVehicleSeat = Some(seat)
|
||||||
|
|
@ -2317,7 +2404,7 @@ class ZoningOperations(
|
||||||
* to avoid damaging the critical setup of this function.
|
* to avoid damaging the critical setup of this function.
|
||||||
*/
|
*/
|
||||||
def AvatarRejoin(): Unit = {
|
def AvatarRejoin(): Unit = {
|
||||||
sessionData.vehicles.GetKnownVehicleAndSeat() match {
|
sessionLogic.vehicles.GetKnownVehicleAndSeat() match {
|
||||||
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
case (Some(vehicle: Vehicle), Some(seat: Int)) =>
|
||||||
//vehicle and driver/passenger
|
//vehicle and driver/passenger
|
||||||
val vdef = vehicle.Definition
|
val vdef = vehicle.Definition
|
||||||
|
|
@ -2336,8 +2423,8 @@ class ZoningOperations(
|
||||||
log.debug(s"AvatarRejoin: ${player.Name} - $pguid -> $pdata")
|
log.debug(s"AvatarRejoin: ${player.Name} - $pguid -> $pdata")
|
||||||
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
if (seat == 0 || vehicle.WeaponControlledFromSeat(seat).nonEmpty) {
|
||||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||||
sessionData.accessContainer(vehicle)
|
sessionLogic.general.accessContainer(vehicle)
|
||||||
sessionData.updateWeaponAtSeatPosition(vehicle, seat)
|
sessionLogic.mountResponse.updateWeaponAtSeatPosition(vehicle, seat)
|
||||||
} else {
|
} else {
|
||||||
interimUngunnedVehicle = Some(vguid)
|
interimUngunnedVehicle = Some(vguid)
|
||||||
interimUngunnedVehicleSeat = Some(seat)
|
interimUngunnedVehicleSeat = Some(seat)
|
||||||
|
|
@ -2406,10 +2493,37 @@ class ZoningOperations(
|
||||||
case Some(_) | None => ;
|
case Some(_) | None => ;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
sessionData.removeBoomerTriggersFromInventory().foreach(trigger => { sessionData.normalItemDrop(obj, continent)(trigger) })
|
removeBoomerTriggersFromInventory().foreach(trigger => { sessionLogic.general.normalItemDrop(obj, continent)(trigger) })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search through the player's holsters and their inventory space
|
||||||
|
* and remove all `BoomerTrigger` objects, both functionally and visually.
|
||||||
|
* @return all discovered `BoomTrigger` objects
|
||||||
|
*/
|
||||||
|
def removeBoomerTriggersFromInventory(): List[BoomerTrigger] = {
|
||||||
|
val events = continent.AvatarEvents
|
||||||
|
val zoneId = continent.id
|
||||||
|
(player.Inventory.Items ++ player.HolsterItems())
|
||||||
|
.collect { case InventoryItem(obj: BoomerTrigger, index) =>
|
||||||
|
player.Slot(index).Equipment = None
|
||||||
|
continent.GUID(obj.Companion) match {
|
||||||
|
case Some(mine: BoomerDeployable) => mine.Actor ! Deployable.Ownership(None)
|
||||||
|
case _ => ()
|
||||||
|
}
|
||||||
|
if (player.VisibleSlots.contains(index)) {
|
||||||
|
events ! AvatarServiceMessage(
|
||||||
|
zoneId,
|
||||||
|
AvatarAction.ObjectDelete(Service.defaultPlayerGUID, obj.GUID)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
sendResponse(ObjectDeleteMessage(obj.GUID, 0))
|
||||||
|
}
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a player that has the characteristics of a corpse
|
* Creates a player that has the characteristics of a corpse
|
||||||
* so long as the player has items in their knapsack or their holsters.
|
* so long as the player has items in their knapsack or their holsters.
|
||||||
|
|
@ -2762,10 +2876,10 @@ class ZoningOperations(
|
||||||
SessionActor.SetCurrentAvatar(player, max_attempts, attempt + max_attempts / 3)
|
SessionActor.SetCurrentAvatar(player, max_attempts, attempt + max_attempts / 3)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
sessionData.keepAliveFunc = sessionData.vehicles.GetMountableAndSeat(None, player, continent) match {
|
sessionLogic.keepAliveFunc = sessionLogic.vehicles.GetMountableAndSeat(None, player, continent) match {
|
||||||
case (Some(v: Vehicle), Some(seatNumber))
|
case (Some(v: Vehicle), Some(seatNumber))
|
||||||
if seatNumber > 0 && v.WeaponControlledFromSeat(seatNumber).isEmpty =>
|
if seatNumber > 0 && v.WeaponControlledFromSeat(seatNumber).isEmpty =>
|
||||||
sessionData.keepAlivePersistence
|
sessionLogic.keepAlivePersistence
|
||||||
case _ =>
|
case _ =>
|
||||||
NormalKeepAlive
|
NormalKeepAlive
|
||||||
}
|
}
|
||||||
|
|
@ -2792,7 +2906,7 @@ class ZoningOperations(
|
||||||
log.trace(s"HandleSetCurrentAvatar - ${tplayer.Name}")
|
log.trace(s"HandleSetCurrentAvatar - ${tplayer.Name}")
|
||||||
session = session.copy(player = tplayer)
|
session = session.copy(player = tplayer)
|
||||||
val guid = tplayer.GUID
|
val guid = tplayer.GUID
|
||||||
sessionData.updateDeployableUIElements(Deployables.InitializeDeployableUIElements(avatar))
|
sessionLogic.general.updateDeployableUIElements(Deployables.InitializeDeployableUIElements(avatar))
|
||||||
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 75, 0))
|
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 75, 0))
|
||||||
sendResponse(SetCurrentAvatarMessage(guid, 0, 0))
|
sendResponse(SetCurrentAvatarMessage(guid, 0, 0))
|
||||||
sendResponse(ChatMsg(ChatMessageType.CMT_EXPANSIONS, wideContents=true, "", "1 on", None)) //CC on //TODO once per respawn?
|
sendResponse(ChatMsg(ChatMessageType.CMT_EXPANSIONS, wideContents=true, "", "1 on", None)) //CC on //TODO once per respawn?
|
||||||
|
|
@ -2851,7 +2965,7 @@ class ZoningOperations(
|
||||||
|
|
||||||
sendResponse(PlanetsideStringAttributeMessage(guid, 0, "Outfit Name"))
|
sendResponse(PlanetsideStringAttributeMessage(guid, 0, "Outfit Name"))
|
||||||
//squad stuff (loadouts, assignment)
|
//squad stuff (loadouts, assignment)
|
||||||
sessionData.squad.squadSetup()
|
sessionLogic.squad.squadSetup()
|
||||||
//MapObjectStateBlockMessage and ObjectCreateMessage?
|
//MapObjectStateBlockMessage and ObjectCreateMessage?
|
||||||
//TacticsMessage?
|
//TacticsMessage?
|
||||||
//change the owner on our deployables (re-draw the icons for our deployables too)
|
//change the owner on our deployables (re-draw the icons for our deployables too)
|
||||||
|
|
@ -2875,7 +2989,7 @@ class ZoningOperations(
|
||||||
case _ =>
|
case _ =>
|
||||||
avatarActor ! AvatarActor.SetVehicle(None)
|
avatarActor ! AvatarActor.SetVehicle(None)
|
||||||
}
|
}
|
||||||
sessionData.vehicles.GetVehicleAndSeat() match {
|
sessionLogic.vehicles.GetVehicleAndSeat() match {
|
||||||
case (Some(vehicle), _) if vehicle.Definition == GlobalDefinitions.droppod =>
|
case (Some(vehicle), _) if vehicle.Definition == GlobalDefinitions.droppod =>
|
||||||
//we're falling
|
//we're falling
|
||||||
sendResponse(
|
sendResponse(
|
||||||
|
|
@ -2923,7 +3037,7 @@ class ZoningOperations(
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
interstellarFerryTopLevelGUID = None
|
interstellarFerryTopLevelGUID = None
|
||||||
if (loadConfZone && sessionData.connectionState == 100) {
|
if (loadConfZone && sessionLogic.connectionState == 100) {
|
||||||
configZone(continent)
|
configZone(continent)
|
||||||
loadConfZone = false
|
loadConfZone = false
|
||||||
}
|
}
|
||||||
|
|
@ -2934,7 +3048,7 @@ class ZoningOperations(
|
||||||
player.Actor ! Player.Die()
|
player.Actor ! Player.Die()
|
||||||
} else {
|
} else {
|
||||||
AvatarActor.savePlayerData(player)
|
AvatarActor.savePlayerData(player)
|
||||||
sessionData.displayCharSavedMsgThenRenewTimer(
|
sessionLogic.general.displayCharSavedMsgThenRenewTimer(
|
||||||
Config.app.game.savedMsg.short.fixed,
|
Config.app.game.savedMsg.short.fixed,
|
||||||
Config.app.game.savedMsg.short.variable
|
Config.app.game.savedMsg.short.variable
|
||||||
)
|
)
|
||||||
|
|
@ -3167,7 +3281,7 @@ class ZoningOperations(
|
||||||
def TurnCounterDuringInterim(guid: PlanetSideGUID): Unit = {
|
def TurnCounterDuringInterim(guid: PlanetSideGUID): Unit = {
|
||||||
upstreamMessageCount = 0
|
upstreamMessageCount = 0
|
||||||
if (player != null && player.HasGUID && player.GUID == guid && player.Zone == continent) {
|
if (player != null && player.HasGUID && player.GUID == guid && player.Zone == continent) {
|
||||||
sessionData.turnCounterFunc = NormalTurnCounter
|
sessionLogic.turnCounterFunc = NormalTurnCounter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3201,15 +3315,15 @@ class ZoningOperations(
|
||||||
case (Some(vehicle: Vehicle), Some(vguid), Some(seat)) =>
|
case (Some(vehicle: Vehicle), Some(vguid), Some(seat)) =>
|
||||||
//sit down
|
//sit down
|
||||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||||
sessionData.accessContainer(vehicle)
|
sessionLogic.general.accessContainer(vehicle)
|
||||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
sessionLogic.keepAliveFunc = sessionLogic.keepAlivePersistence
|
||||||
case _ => ;
|
case _ => ;
|
||||||
//we can't find a vehicle? and we're still here? that's bad
|
//we can't find a vehicle? and we're still here? that's bad
|
||||||
player.VehicleSeated = None
|
player.VehicleSeated = None
|
||||||
}
|
}
|
||||||
interimUngunnedVehicle = None
|
interimUngunnedVehicle = None
|
||||||
interimUngunnedVehicleSeat = None
|
interimUngunnedVehicleSeat = None
|
||||||
sessionData.turnCounterFunc = NormalTurnCounter
|
sessionLogic.turnCounterFunc = NormalTurnCounter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|
@ -3226,7 +3340,7 @@ class ZoningOperations(
|
||||||
loginChatMessage.foreach { msg => sendResponse(ChatMsg(zoningChatMessageType, wideContents=false, "", msg, None)) }
|
loginChatMessage.foreach { msg => sendResponse(ChatMsg(zoningChatMessageType, wideContents=false, "", msg, None)) }
|
||||||
loginChatMessage.clear()
|
loginChatMessage.clear()
|
||||||
CancelZoningProcess()
|
CancelZoningProcess()
|
||||||
sessionData.turnCounterFunc = NormalTurnCounter
|
sessionLogic.turnCounterFunc = NormalTurnCounter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -3403,7 +3517,7 @@ class ZoningOperations(
|
||||||
context.system.scheduler.scheduleOnce(
|
context.system.scheduler.scheduleOnce(
|
||||||
delay.milliseconds,
|
delay.milliseconds,
|
||||||
context.self,
|
context.self,
|
||||||
SessionActor.AvatarAwardMessageBundle(xs, delay)
|
ZoningOperations.AvatarAwardMessageBundle(xs, delay)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3413,8 +3527,8 @@ class ZoningOperations(
|
||||||
* Set to `persist` when (new) player is loaded.
|
* Set to `persist` when (new) player is loaded.
|
||||||
*/
|
*/
|
||||||
def UpdatePersistenceAndRefs(): Unit = {
|
def UpdatePersistenceAndRefs(): Unit = {
|
||||||
sessionData.persistFunc()
|
sessionLogic.persistFunc()
|
||||||
sessionData.updateOldRefsMap()
|
sessionLogic.updateOldRefsMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -3425,6 +3539,34 @@ class ZoningOperations(
|
||||||
def UpdatePersistence(persistRef: ActorRef)(): Unit = {
|
def UpdatePersistence(persistRef: ActorRef)(): Unit = {
|
||||||
persistRef ! AccountPersistenceService.Update(player.Name, continent, player.Position)
|
persistRef ! AccountPersistenceService.Update(player.Name, continent, player.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def startDeconstructing(obj: SpawnTube): Unit = {
|
||||||
|
log.info(s"${player.Name} is deconstructing at the ${obj.Owner.Definition.Name}'s spawns")
|
||||||
|
avatar.implants.collect {
|
||||||
|
case Some(implant) if implant.active && !implant.definition.Passive =>
|
||||||
|
avatarActor ! AvatarActor.DeactivateImplant(implant.definition.implantType)
|
||||||
|
}
|
||||||
|
if (player.ExoSuit != ExoSuitType.MAX) {
|
||||||
|
player.Actor ! PlayerControl.ObjectHeld(Player.HandsDownSlot, updateMyHolsterArm = true)
|
||||||
|
}
|
||||||
|
nextSpawnPoint = Some(obj) //set fallback
|
||||||
|
zoningStatus = Zoning.Status.Deconstructing
|
||||||
|
player.allowInteraction = false
|
||||||
|
if (player.death_by == 0) {
|
||||||
|
player.death_by = 1
|
||||||
|
}
|
||||||
|
GoToDeploymentMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
def stopDeconstructing(): Unit = {
|
||||||
|
zoningStatus = Zoning.Status.None
|
||||||
|
player.death_by = math.min(player.death_by, 0)
|
||||||
|
player.allowInteraction = true
|
||||||
|
nextSpawnPoint.foreach { tube =>
|
||||||
|
sendResponse(PlayerStateShiftMessage(ShiftState(0, tube.Position, tube.Orientation.z)))
|
||||||
|
nextSpawnPoint = None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected[session] def stop(): Unit = {
|
override protected[session] def stop(): Unit = {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,23 @@ object CommonMessages {
|
||||||
final case class Hack(player: Player, obj: PlanetSideServerObject with Hackable, data: Option[Any] = None)
|
final case class Hack(player: Player, obj: PlanetSideServerObject with Hackable, data: Option[Any] = None)
|
||||||
final case class ClearHack()
|
final case class ClearHack()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The message that progresses some form of user-driven activity with a certain eventual outcome
|
||||||
|
* and potential feedback per cycle.
|
||||||
|
* @param delta how much the progress value changes each tick, which will be treated as a percentage;
|
||||||
|
* must be a positive value
|
||||||
|
* @param completionAction a finalizing action performed once the progress reaches 100(%)
|
||||||
|
* @param tickAction an action that is performed for each increase of progress
|
||||||
|
* @param tickTime how long between each `tickAction` (ms);
|
||||||
|
* defaults to 250 milliseconds
|
||||||
|
*/
|
||||||
|
final case class ProgressEvent(
|
||||||
|
delta: Float,
|
||||||
|
completionAction: () => Unit,
|
||||||
|
tickAction: Float => Boolean,
|
||||||
|
tickTime: Long = 250L
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message that initializes a process -
|
* The message that initializes a process -
|
||||||
* some form of user-driven activity with a certain eventual outcome and potential feedback per cycle.
|
* some form of user-driven activity with a certain eventual outcome and potential feedback per cycle.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue