reviewing logic and operations pairs to ensure that functionality should have been retained from parent structure; moving handling case from individual player modes to session actor, which makes it much closer to the pattern

This commit is contained in:
Fate-JH 2024-05-21 12:43:59 -04:00
parent 450c35af72
commit 1847b4bedf
23 changed files with 732 additions and 1202 deletions

View file

@ -1,8 +1,29 @@
// Copyright (c) 2016, 2020, 2024 PSForever
package net.psforever.actors.session
import akka.actor.{Actor, Cancellable, MDCContextAware, typed}
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware, typed}
import net.psforever.actors.session.normal.NormalMode
import net.psforever.actors.session.support.ZoningOperations
import net.psforever.objects.TurretDeployable
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, 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, UplinkRequest, 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.chat.ChatService
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 org.joda.time.LocalDateTime
import org.log4s.MDC
@ -105,8 +126,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
}
private def inTheGame: Receive = {
/* used for the game's heartbeat */
case SessionActor.StartHeartbeat =>
//used for the game's heartbeat
startHeartbeat()
case SessionActor.PokeClient =>
@ -115,13 +136,13 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case SessionActor.SetMode(newMode) =>
if (mode != newMode) {
logic.switchFrom(data.session)
mode = newMode
logic = mode.setup(data)
}
mode = newMode
logic = mode.setup(data)
logic.switchTo(data.session)
case packet =>
logic.parse(sender())(packet)
parse(sender())(packet)
}
private def startHeartbeat(): Unit = {
@ -135,4 +156,454 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
SessionActor.PokeClient
)
}
private def parse(sender: ActorRef): Receive = {
/* really common messages (very frequently, every life) */
case packet: PlanetSideGamePacket =>
handleGamePkt(packet)
case AvatarServiceResponse(toChannel, guid, reply) =>
logic.avatarResponse.handle(toChannel, guid, reply)
case GalaxyServiceResponse(_, reply) =>
logic.galaxy.handle(reply)
case LocalServiceResponse(toChannel, guid, reply) =>
logic.local.handle(toChannel, guid, reply)
case Mountable.MountMessages(tplayer, reply) =>
logic.mountResponse.handle(tplayer, reply)
case SquadServiceResponse(_, excluded, response) =>
logic.squad.handle(response, excluded)
case Terminal.TerminalMessage(tplayer, msg, order) =>
logic.terminals.handle(tplayer, msg, order)
case VehicleServiceResponse(toChannel, guid, reply) =>
logic.vehicleResponse.handle(toChannel, guid, reply)
case ChatService.MessageResponse(fromSession, message, _) =>
logic.chat.handleIncomingMessage(message, fromSession)
case SessionActor.SendResponse(packet) =>
data.sendResponse(packet)
case SessionActor.CharSaved =>
logic.general.handleRenewCharSavedTimer()
case SessionActor.CharSavedMsg =>
logic.general.handleRenewCharSavedTimerMsg()
/* common messages (maybe once every respawn) */
case ICS.SpawnPointResponse(response) =>
data.zoning.handleSpawnPointResponse(response)
case SessionActor.NewPlayerLoaded(tplayer) =>
data.zoning.spawn.handleNewPlayerLoaded(tplayer)
case SessionActor.PlayerLoaded(tplayer) =>
data.zoning.spawn.handlePlayerLoaded(tplayer)
case Zone.Population.PlayerHasLeft(zone, playerOpt) =>
data.zoning.spawn.handlePlayerHasLeft(zone, playerOpt)
case Zone.Population.PlayerCanNotSpawn(zone, tplayer) =>
data.zoning.spawn.handlePlayerCanNotSpawn(zone, tplayer)
case Zone.Population.PlayerAlreadySpawned(zone, tplayer) =>
data.zoning.spawn.handlePlayerAlreadySpawned(zone, tplayer)
case Zone.Vehicle.CanNotSpawn(zone, vehicle, reason) =>
data.zoning.spawn.handleCanNotSpawn(zone, vehicle, reason)
case Zone.Vehicle.CanNotDespawn(zone, vehicle, reason) =>
data.zoning.spawn.handleCanNotDespawn(zone, vehicle, reason)
case ICS.ZoneResponse(Some(zone)) =>
data.zoning.handleZoneResponse(zone)
/* uncommon messages (once a session) */
case ICS.ZonesResponse(zones) =>
data.zoning.handleZonesResponse(zones)
case SessionActor.SetAvatar(avatar) =>
logic.general.handleSetAvatar(avatar)
case PlayerToken.LoginInfo(name, Zone.Nowhere, _) =>
data.zoning.spawn.handleLoginInfoNowhere(name, sender)
case PlayerToken.LoginInfo(name, inZone, optionalSavedData) =>
data.zoning.spawn.handleLoginInfoSomewhere(name, inZone, optionalSavedData, sender)
case PlayerToken.RestoreInfo(playerName, inZone, pos) =>
data.zoning.spawn.handleLoginInfoRestore(playerName, inZone, pos, sender)
case PlayerToken.CanNotLogin(playerName, reason) =>
data.zoning.spawn.handleLoginCanNot(playerName, reason)
case ReceiveAccountData(account) =>
logic.general.handleReceiveAccountData(account)
case AvatarActor.AvatarResponse(avatar) =>
logic.general.handleAvatarResponse(avatar)
case AvatarActor.AvatarLoginResponse(avatar) =>
data.zoning.spawn.avatarLoginResponse(avatar)
case SessionActor.SetCurrentAvatar(tplayer, max_attempts, attempt) =>
data.zoning.spawn.ReadyToSetCurrentAvatar(tplayer, max_attempts, attempt)
case SessionActor.SetConnectionState(state) =>
data.connectionState = state
case SessionActor.AvatarLoadingSync(state) =>
data.zoning.spawn.handleAvatarLoadingSync(state)
/* uncommon messages (utility, or once in a while) */
case ZoningOperations.AvatarAwardMessageBundle(pkts, delay) =>
data.zoning.spawn.performAvatarAwardMessageDelivery(pkts, delay)
case CommonMessages.ProgressEvent(delta, finishedAction, stepAction, tick) =>
data.general.handleProgressChange(delta, finishedAction, stepAction, tick)
case CommonMessages.Progress(rate, finishedAction, stepAction) =>
data.general.setupProgressChange(rate, finishedAction, stepAction)
case CavernRotationService.CavernRotationServiceKey.Listing(listings) =>
listings.head ! SendCavernRotationUpdates(data.context.self)
case LookupResult("propertyOverrideManager", endpoint) =>
data.zoning.propertyOverrideManagerLoadOverrides(endpoint)
case SessionActor.UpdateIgnoredPlayers(msg) =>
logic.galaxy.handleUpdateIgnoredPlayers(msg)
case SessionActor.UseCooldownRenewed(definition, _) =>
logic.general.handleUseCooldownRenew(definition)
case Deployment.CanDeploy(obj, state) =>
logic.vehicles.handleCanDeploy(obj, state)
case Deployment.CanUndeploy(obj, state) =>
logic.vehicles.handleCanUndeploy(obj, state)
case Deployment.CanNotChangeDeployment(obj, state, reason) =>
logic.vehicles.handleCanNotChangeDeployment(obj, state, reason)
/* rare messages */
case ProximityUnit.StopAction(term, _) =>
logic.terminals.ops.LocalStopUsingProximityUnit(term)
case SessionActor.Suicide() =>
data.general.suicide(data.player)
case SessionActor.Recall() =>
data.zoning.handleRecall()
case SessionActor.InstantAction() =>
data.zoning.handleInstantAction()
case SessionActor.Quit() =>
data.zoning.handleQuit()
case ICS.DroppodLaunchDenial(errorCode, _) =>
data.zoning.handleDroppodLaunchDenial(errorCode)
case ICS.DroppodLaunchConfirmation(zone, position) =>
data.zoning.LoadZoneLaunchDroppod(zone, position)
case SessionActor.PlayerFailedToLoad(tplayer) =>
data.zoning.spawn.handlePlayerFailedToLoad(tplayer)
/* csr only */
case SessionActor.SetSpeed(speed) =>
logic.general.handleSetSpeed(speed)
case SessionActor.SetFlying(isFlying) =>
logic.general.handleSetFlying(isFlying)
case SessionActor.SetSpectator(isSpectator) =>
logic.general.handleSetSpectator(isSpectator)
case SessionActor.Kick(player, time) =>
logic.general.handleKick(player, time)
case SessionActor.SetZone(zoneId, position) =>
data.zoning.handleSetZone(zoneId, position)
case SessionActor.SetPosition(position) =>
data.zoning.spawn.handleSetPosition(position)
case SessionActor.SetSilenced(silenced) =>
logic.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
logic.local.handleTurretDeployableIsDismissed(obj)
case Zone.Deployable.IsDismissed(obj) => //only if target deployable was never fully introduced
logic.local.handleDeployableIsDismissed(obj)
case msg: Containable.ItemPutInSlot =>
logic.general.handleItemPutInSlot(msg)
case msg: Containable.CanNotPutItemInSlot =>
logic.general.handleCanNotPutItemInSlot(msg)
case default =>
logic.general.handleReceiveDefaultMessage(default, sender)
}
private def handleGamePkt: PlanetSideGamePacket => Unit = {
case packet: ConnectToWorldRequestMessage =>
logic.general.handleConnectToWorldRequest(packet)
case packet: MountVehicleCargoMsg =>
logic.mountResponse.handleMountVehicleCargo(packet)
case packet: DismountVehicleCargoMsg =>
logic.mountResponse.handleDismountVehicleCargo(packet)
case packet: CharacterCreateRequestMessage =>
logic.general.handleCharacterCreateRequest(packet)
case packet: CharacterRequestMessage =>
logic.general.handleCharacterRequest(packet)
case _: KeepAliveMessage =>
data.keepAliveFunc()
case packet: BeginZoningMessage =>
data.zoning.handleBeginZoning(packet)
case packet: PlayerStateMessageUpstream =>
logic.general.handlePlayerStateUpstream(packet)
case packet: ChildObjectStateMessage =>
logic.vehicles.handleChildObjectState(packet)
case packet: VehicleStateMessage =>
logic.vehicles.handleVehicleState(packet)
case packet: VehicleSubStateMessage =>
logic.vehicles.handleVehicleSubState(packet)
case packet: FrameVehicleStateMessage =>
logic.vehicles.handleFrameVehicleState(packet)
case packet: ProjectileStateMessage =>
logic.shooting.handleProjectileState(packet)
case packet: LongRangeProjectileInfoMessage =>
logic.shooting.handleLongRangeProjectileState(packet)
case packet: ReleaseAvatarRequestMessage =>
data.zoning.spawn.handleReleaseAvatarRequest(packet)
case packet: SpawnRequestMessage =>
data.zoning.spawn.handleSpawnRequest(packet)
case packet: ChatMsg =>
logic.chat.handleChatMsg(packet)
case packet: SetChatFilterMessage =>
logic.chat.handleChatFilter(packet)
case packet: VoiceHostRequest =>
logic.general.handleVoiceHostRequest(packet)
case packet: VoiceHostInfo =>
logic.general.handleVoiceHostInfo(packet)
case packet: ChangeAmmoMessage =>
logic.shooting.handleChangeAmmo(packet)
case packet: ChangeFireModeMessage =>
logic.shooting.handleChangeFireMode(packet)
case packet: ChangeFireStateMessage_Start =>
logic.shooting.handleChangeFireStateStart(packet)
case packet: ChangeFireStateMessage_Stop =>
logic.shooting.handleChangeFireStateStop(packet)
case packet: EmoteMsg =>
logic.general.handleEmote(packet)
case packet: DropItemMessage =>
logic.general.handleDropItem(packet)
case packet: PickupItemMessage =>
logic.general.handlePickupItem(packet)
case packet: ReloadMessage =>
logic.shooting.handleReload(packet)
case packet: ObjectHeldMessage =>
logic.general.handleObjectHeld(packet)
case packet: AvatarJumpMessage =>
logic.general.handleAvatarJump(packet)
case packet: ZipLineMessage =>
logic.general.handleZipLine(packet)
case packet: RequestDestroyMessage =>
logic.general.handleRequestDestroy(packet)
case packet: MoveItemMessage =>
logic.general.handleMoveItem(packet)
case packet: LootItemMessage =>
logic.general.handleLootItem(packet)
case packet: AvatarImplantMessage =>
logic.general.handleAvatarImplant(packet)
case packet: UseItemMessage =>
logic.general.handleUseItem(packet)
case packet: UnuseItemMessage =>
logic.general.handleUnuseItem(packet)
case packet: ProximityTerminalUseMessage =>
logic.terminals.handleProximityTerminalUse(packet)
case packet: DeployObjectMessage =>
logic.general.handleDeployObject(packet)
case packet: GenericObjectActionMessage =>
logic.general.handleGenericObjectAction(packet)
case packet: GenericObjectActionAtPositionMessage =>
logic.general.handleGenericObjectActionAtPosition(packet)
case packet: GenericObjectStateMsg =>
logic.general.handleGenericObjectState(packet)
case packet: GenericActionMessage =>
logic.general.handleGenericAction(packet)
case packet: ItemTransactionMessage =>
logic.terminals.handleItemTransaction(packet)
case packet: FavoritesRequest =>
logic.terminals.handleFavoritesRequest(packet)
case packet: WeaponDelayFireMessage =>
logic.shooting.handleWeaponDelayFire(packet)
case packet: WeaponDryFireMessage =>
logic.shooting.handleWeaponDryFire(packet)
case packet: WeaponFireMessage =>
logic.shooting.handleWeaponFire(packet)
case packet: WeaponLazeTargetPositionMessage =>
logic.shooting.handleWeaponLazeTargetPosition(packet)
case _: UplinkRequest => ()
case packet: HitMessage =>
logic.shooting.handleDirectHit(packet)
case packet: SplashHitMessage =>
logic.shooting.handleSplashHit(packet)
case packet: LashMessage =>
logic.shooting.handleLashHit(packet)
case packet: AIDamage =>
logic.shooting.handleAIDamage(packet)
case packet: AvatarFirstTimeEventMessage =>
logic.general.handleAvatarFirstTimeEvent(packet)
case packet: WarpgateRequest =>
data.zoning.handleWarpgateRequest(packet)
case packet: MountVehicleMsg =>
logic.mountResponse.handleMountVehicle(packet)
case packet: DismountVehicleMsg =>
logic.mountResponse.handleDismountVehicle(packet)
case packet: DeployRequestMessage =>
logic.vehicles.handleDeployRequest(packet)
case packet: AvatarGrenadeStateMessage =>
logic.shooting.handleAvatarGrenadeState(packet)
case packet: SquadDefinitionActionMessage =>
logic.squad.handleSquadDefinitionAction(packet)
case packet: SquadMembershipRequest =>
logic.squad.handleSquadMemberRequest(packet)
case packet: SquadWaypointRequest =>
logic.squad.handleSquadWaypointRequest(packet)
case packet: GenericCollisionMsg =>
logic.general.handleGenericCollision(packet)
case packet: BugReportMessage =>
logic.general.handleBugReport(packet)
case packet: BindPlayerMessage =>
logic.general.handleBindPlayer(packet)
case packet: PlanetsideAttributeMessage =>
logic.general.handlePlanetsideAttribute(packet)
case packet: FacilityBenefitShieldChargeRequestMessage =>
logic.general.handleFacilityBenefitShieldChargeRequest(packet)
case packet: BattleplanMessage =>
logic.general.handleBattleplan(packet)
case packet: CreateShortcutMessage =>
logic.general.handleCreateShortcut(packet)
case packet: ChangeShortcutBankMessage =>
logic.general.handleChangeShortcutBank(packet)
case packet: FriendsRequest =>
logic.general.handleFriendRequest(packet)
case packet: DroppodLaunchRequestMessage =>
data.zoning.handleDroppodLaunchRequest(packet)
case packet: InvalidTerrainMessage =>
logic.general.handleInvalidTerrain(packet)
case packet: ActionCancelMessage =>
logic.general.handleActionCancel(packet)
case packet: TradeMessage =>
logic.general.handleTrade(packet)
case packet: DisplayedAwardMessage =>
logic.general.handleDisplayedAward(packet)
case packet: ObjectDetectedMessage =>
logic.general.handleObjectDetected(packet)
case packet: TargetingImplantRequest =>
logic.general.handleTargetingImplantRequest(packet)
case packet: HitHint =>
logic.general.handleHitHint(packet)
case _: OutfitRequest => ()
case pkt =>
data.log.warn(s"Unhandled GamePacket $pkt")
}
}

View file

@ -395,7 +395,7 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
avatarActor ! AvatarActor.AwardBep(bep, expType)
}
case AvatarResponse.AwardCep(charId, cep) =>
case AvatarResponse.AwardCep(charId, cep) =>
//if the target player, always award (some) CEP
if (charId == player.CharId) {
avatarActor ! AvatarActor.AwardCep(cep)
@ -469,7 +469,8 @@ class AvatarHandlerLogic(val ops: SessionAvatarHandlers, implicit val context: A
case AvatarResponse.Release(tplayer) if isNotSameTarget =>
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!")
sessionLogic.zoning.spawn.reviveTimer.cancel()
sessionLogic.zoning.spawn.deadState = DeadState.Alive

View file

@ -65,12 +65,13 @@ class GalaxyHandlerLogic(val ops: SessionGalaxyHandlers, implicit val context: A
case GalaxyResponse.LockedZoneUpdate(zone, time) =>
sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
case GalaxyResponse.UnlockedZoneUpdate(zone) => ;
case GalaxyResponse.UnlockedZoneUpdate(zone) =>
sendResponse(ZoneInfoMessage(zone.Number, empire_status=true, lock_time=0L))
val popBO = 0
val popTR = zone.Players.count(_.faction == PlanetSideEmpire.TR)
val popNC = zone.Players.count(_.faction == PlanetSideEmpire.NC)
val popVS = zone.Players.count(_.faction == PlanetSideEmpire.VS)
val pop = zone.LivePlayers.distinctBy(_.CharId)
val popTR = pop.count(_.Faction == PlanetSideEmpire.TR)
val popNC = pop.count(_.Faction == PlanetSideEmpire.NC)
val popVS = pop.count(_.Faction == PlanetSideEmpire.VS)
sendResponse(ZonePopulationUpdateMessage(zone.Number, 414, 138, popTR, 138, popNC, 138, popVS, 138, popBO))
case GalaxyResponse.LogStatusChange(name) if avatar.people.friend.exists(_.name.equals(name)) =>

View file

@ -2,7 +2,7 @@
package net.psforever.actors.session.normal
import akka.actor.typed.scaladsl.adapter._
import akka.actor.{ActorContext, typed}
import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.{AvatarActor, SessionActor}
import net.psforever.actors.session.support.{GeneralFunctions, GeneralOperations, SessionData}
import net.psforever.login.WorldSession.{CallBackForTask, ContainableMoveItem, DropEquipmentFromInventory, PickUpEquipmentFromGround, RemoveOldEquipmentFromInventory}
@ -17,6 +17,7 @@ import net.psforever.objects.guid.{GUIDTask, TaskBundle, TaskWorkflow}
import net.psforever.objects.inventory.Container
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject, ServerObject}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.containable.Containable
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.generator.Generator
import net.psforever.objects.serverobject.llu.CaptureFlag
@ -39,7 +40,7 @@ import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.zones.{Zone, ZoneProjectile, Zoning}
import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.objectcreate.ObjectClass
import net.psforever.packet.game.{ActionCancelMessage, ActionResultMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BindStatus, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestAction, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, ItemTransactionMessage, LootItemMessage, MoveItemMessage, ObjectDeleteMessage, ObjectDetectedMessage, ObjectHeldMessage, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, PlayerStateShiftMessage, RequestDestroyMessage, ShiftState, TargetInfo, TargetingImplantRequest, TargetingInfoMessage, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostKill, VoiceHostRequest, ZipLineMessage}
import net.psforever.packet.game.{ActionCancelMessage, ActionResultMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BindStatus, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestAction, CharacterRequestMessage, ChatMsg, CollisionIs, ConnectToWorldRequestMessage, CreateShortcutMessage, DeadState, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, ItemTransactionMessage, LootItemMessage, MoveItemMessage, ObjectDeleteMessage, ObjectDetectedMessage, ObjectHeldMessage, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, PlayerStateShiftMessage, RequestDestroyMessage, ShiftState, TargetInfo, TargetingImplantRequest, TargetingInfoMessage, TerrainCondition, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage}
import net.psforever.services.RemoverActor
import net.psforever.services.account.{AccountPersistenceService, RetrieveAccountData}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
@ -190,19 +191,11 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
}
def handleVoiceHostRequest(pkt: VoiceHostRequest): Unit = {
log.debug(s"$pkt")
sendResponse(VoiceHostKill())
sendResponse(
ChatMsg(ChatMessageType.CMT_OPEN, wideContents=false, "", "Try our Discord at https://discord.gg/0nRe5TNbTYoUruA4", None)
)
ops.noVoicedChat(pkt)
}
def handleVoiceHostInfo(pkt: VoiceHostInfo): Unit = {
log.debug(s"$pkt")
sendResponse(VoiceHostKill())
sendResponse(
ChatMsg(ChatMessageType.CMT_OPEN, wideContents=false, "", "Try our Discord at https://discord.gg/0nRe5TNbTYoUruA4", None)
)
ops.noVoicedChat(pkt)
}
def handleEmote(pkt: EmoteMsg): Unit = {
@ -269,7 +262,7 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
//travel along the zipline in the direction specified
sendResponse(ZipLineMessage(playerGuid, forwards, action, pathId, pos))
case 1 =>
//disembark from zipline at destination!
//disembark from zipline at destination
sendResponse(ZipLineMessage(playerGuid, forwards, action, 0, pos))
case 2 =>
//get off by force
@ -572,11 +565,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
//aphelion_laser discharge (no target)
sessionLogic.shooting.HandleWeaponFireAccountability(objectGuid, PlanetSideGUID(Projectile.baseUID))
} else {
sessionLogic.validObject(player.VehicleSeated, decorator = "GenericObjectAction/Vehicle") match {
case Some(vehicle: Vehicle)
sessionLogic.validObject(player.VehicleSeated, decorator = "GenericObjectAction/Vehicle") collect {
case vehicle: Vehicle
if vehicle.OwnerName.contains(player.Name) =>
vehicle.Actor ! ServerObject.GenericObjectAction(objectGuid, code, Some(tool))
case _ =>
}
}
case _ =>
@ -946,6 +938,20 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
/* messages */
def handleRenewCharSavedTimer(): Unit = {
ops.renewCharSavedTimer(
Config.app.game.savedMsg.interruptedByAction.fixed,
Config.app.game.savedMsg.interruptedByAction.variable
)
}
def handleRenewCharSavedTimerMsg(): Unit = {
ops.displayCharSavedMsgThenRenewTimer(
Config.app.game.savedMsg.interruptedByAction.fixed,
Config.app.game.savedMsg.interruptedByAction.variable
)
}
def handleSetAvatar(avatar: Avatar): Unit = {
session = session.copy(avatar = avatar)
if (session.player != null) {
@ -991,6 +997,18 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
player.silenced = isSilenced
}
def handleItemPutInSlot(msg: Containable.ItemPutInSlot): Unit = {
log.debug(s"ItemPutInSlot: $msg")
}
def handleCanNotPutItemInSlot(msg: Containable.CanNotPutItemInSlot): Unit = {
log.debug(s"CanNotPutItemInSlot: $msg")
}
def handleReceiveDefaultMessage(default: Any, sender: ActorRef): Unit = {
log.warn(s"Invalid packet class received: $default from $sender")
}
/* supporting functions */
private def handleUseDoor(door: Door, equipment: Option[Equipment]): Unit = {

View file

@ -20,6 +20,16 @@ object LocalHandlerLogic {
class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: ActorContext) extends LocalHandlerFunctions {
def sessionLogic: SessionData = ops.sessionLogic
/* messages */
def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit = {
ops.handleTurretDeployableIsDismissed(obj)
}
def handleDeployableIsDismissed(obj: Deployable): Unit = {
ops.handleDeployableIsDismissed(obj)
}
/* response handlers */
/**

View file

@ -81,7 +81,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
v.SeatPermissionGroup(seat_num).contains(AccessPermissionGroup.Driver) &&
v.isFlying =>
v.Actor ! Vehicle.Deconstruct(None) //immediate deconstruction
case _ => ;
case _ => ()
}
case None =>

View file

@ -1,36 +1,8 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.normal
import akka.actor.Actor.Receive
import akka.actor.ActorRef
import net.psforever.actors.session.support.{ChatFunctions, GeneralFunctions, LocalHandlerFunctions, MountHandlerFunctions, SquadHandlerFunctions, TerminalHandlerFunctions, VehicleFunctions, VehicleHandlerFunctions, WeaponAndProjectileFunctions}
import net.psforever.objects.Players
import net.psforever.packet.game.UplinkRequest
import net.psforever.services.chat.ChatService
//
import net.psforever.actors.session.{AvatarActor, SessionActor}
import net.psforever.actors.session.support.{ModeLogic, PlayerMode, SessionData, ZoningOperations}
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
import net.psforever.actors.session.support.{ModeLogic, PlayerMode, SessionData}
class NormalModeLogic(data: SessionData) extends ModeLogic {
val avatarResponse: AvatarHandlerLogic = AvatarHandlerLogic(data.avatarResponse)
@ -44,473 +16,6 @@ class NormalModeLogic(data: SessionData) extends ModeLogic {
val terminals: TerminalHandlerFunctions = TerminalHandlerLogic(data.terminals)
val vehicles: VehicleFunctions = VehicleLogic(data.vehicles)
val vehicleResponse: VehicleHandlerFunctions = VehicleHandlerLogic(data.vehicleResponseOperations)
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) =>
galaxy.handle(reply)
case LocalServiceResponse(toChannel, guid, reply) =>
local.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) =>
vehicleResponse.handle(toChannel, guid, reply)
case ChatService.MessageResponse(fromSession, message, _) =>
chat.handleIncomingMessage(message, fromSession)
case SessionActor.SendResponse(packet) =>
data.sendResponse(packet)
case SessionActor.CharSaved =>
general.ops.renewCharSavedTimer(
Config.app.game.savedMsg.interruptedByAction.fixed,
Config.app.game.savedMsg.interruptedByAction.variable
)
case SessionActor.CharSavedMsg =>
general.ops.displayCharSavedMsgThenRenewTimer(
Config.app.game.savedMsg.renewal.fixed,
Config.app.game.savedMsg.renewal.variable
)
/* common messages (maybe once every respawn) */
case ICS.SpawnPointResponse(response) =>
data.zoning.handleSpawnPointResponse(response)
case SessionActor.NewPlayerLoaded(tplayer) =>
data.zoning.spawn.handleNewPlayerLoaded(tplayer)
case SessionActor.PlayerLoaded(tplayer) =>
data.zoning.spawn.handlePlayerLoaded(tplayer)
case Zone.Population.PlayerHasLeft(zone, None) =>
data.log.debug(s"PlayerHasLeft: ${data.player.Name} does not have a body on ${zone.id}")
case Zone.Population.PlayerHasLeft(zone, Some(tplayer)) =>
if (tplayer.isAlive) {
data.log.info(s"${tplayer.Name} has left zone ${zone.id}")
}
case Zone.Population.PlayerCanNotSpawn(zone, tplayer) =>
data.log.warn(s"${tplayer.Name} can not spawn in zone ${zone.id}; why?")
case Zone.Population.PlayerAlreadySpawned(zone, tplayer) =>
data.log.warn(s"${tplayer.Name} is already spawned on zone ${zone.id}; is this a clerical error?")
case Zone.Vehicle.CanNotSpawn(zone, vehicle, reason) =>
data.log.warn(
s"${data.player.Name}'s ${vehicle.Definition.Name} can not spawn in ${zone.id} because $reason"
)
case Zone.Vehicle.CanNotDespawn(zone, vehicle, reason) =>
data.log.warn(
s"${data.player.Name}'s ${vehicle.Definition.Name} can not deconstruct in ${zone.id} because $reason"
)
case ICS.ZoneResponse(Some(zone)) =>
data.zoning.handleZoneResponse(zone)
/* uncommon messages (once a session) */
case ICS.ZonesResponse(zones) =>
data.zoning.handleZonesResponse(zones)
case SessionActor.SetAvatar(avatar) =>
general.handleSetAvatar(avatar)
case PlayerToken.LoginInfo(name, Zone.Nowhere, _) =>
data.zoning.spawn.handleLoginInfoNowhere(name, sender)
case PlayerToken.LoginInfo(name, inZone, optionalSavedData) =>
data.zoning.spawn.handleLoginInfoSomewhere(name, inZone, optionalSavedData, sender)
case PlayerToken.RestoreInfo(playerName, inZone, pos) =>
data.zoning.spawn.handleLoginInfoRestore(playerName, inZone, pos, sender)
case PlayerToken.CanNotLogin(playerName, reason) =>
data.zoning.spawn.handleLoginCanNot(playerName, reason)
case ReceiveAccountData(account) =>
general.handleReceiveAccountData(account)
case AvatarActor.AvatarResponse(avatar) =>
general.handleAvatarResponse(avatar)
case AvatarActor.AvatarLoginResponse(avatar) =>
data.zoning.spawn.avatarLoginResponse(avatar)
case SessionActor.SetCurrentAvatar(tplayer, max_attempts, attempt) =>
data.zoning.spawn.ReadyToSetCurrentAvatar(tplayer, max_attempts, attempt)
case SessionActor.SetConnectionState(state) =>
data.connectionState = state
case SessionActor.AvatarLoadingSync(state) =>
data.zoning.spawn.handleAvatarLoadingSync(state)
/* uncommon messages (utility, or once in a while) */
case ZoningOperations.AvatarAwardMessageBundle(pkts, delay) =>
data.zoning.spawn.performAvatarAwardMessageDelivery(pkts, delay)
case CommonMessages.ProgressEvent(delta, finishedAction, stepAction, tick) =>
general.ops.handleProgressChange(delta, finishedAction, stepAction, tick)
case CommonMessages.Progress(rate, finishedAction, stepAction) =>
general.ops.setupProgressChange(rate, finishedAction, stepAction)
case CavernRotationService.CavernRotationServiceKey.Listing(listings) =>
listings.head ! SendCavernRotationUpdates(data.context.self)
case LookupResult("propertyOverrideManager", endpoint) =>
data.zoning.propertyOverrideManagerLoadOverrides(endpoint)
case SessionActor.UpdateIgnoredPlayers(msg) =>
galaxy.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.ops.LocalStopUsingProximityUnit(term)
case SessionActor.Suicide() =>
general.ops.suicide(data.player)
case SessionActor.Recall() =>
data.zoning.handleRecall()
case SessionActor.InstantAction() =>
data.zoning.handleInstantAction()
case SessionActor.Quit() =>
data.zoning.handleQuit()
case ICS.DroppodLaunchDenial(errorCode, _) =>
data.zoning.handleDroppodLaunchDenial(errorCode)
case ICS.DroppodLaunchConfirmation(zone, position) =>
data.zoning.LoadZoneLaunchDroppod(zone, position)
case SessionActor.PlayerFailedToLoad(tplayer) =>
data.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) =>
data.zoning.handleSetZone(zoneId, position)
case SessionActor.SetPosition(position) =>
data.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
Players.buildCooldownReset(data.continent, data.player.Name, obj)
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(data.continent.GUID, obj))
case Zone.Deployable.IsDismissed(obj) => //only if target deployable was never fully introduced
Players.buildCooldownReset(data.continent, data.player.Name, obj)
TaskWorkflow.execute(GUIDTask.unregisterObject(data.continent.GUID, obj))
case msg: Containable.ItemPutInSlot =>
data.log.debug(s"ItemPutInSlot: $msg")
case msg: Containable.CanNotPutItemInSlot =>
data.log.debug(s"CanNotPutItemInSlot: $msg")
case default =>
data.log.warn(s"Invalid packet class received: $default from $sender")
}
private def handleGamePkt: PlanetSideGamePacket => Unit = {
case packet: ConnectToWorldRequestMessage =>
general.handleConnectToWorldRequest(packet)
case packet: MountVehicleCargoMsg =>
mountResponse.handleMountVehicleCargo(packet)
case packet: DismountVehicleCargoMsg =>
mountResponse.handleDismountVehicleCargo(packet)
case packet: CharacterCreateRequestMessage =>
general.handleCharacterCreateRequest(packet)
case packet: CharacterRequestMessage =>
general.handleCharacterRequest(packet)
case _: KeepAliveMessage =>
data.keepAliveFunc()
case packet: BeginZoningMessage =>
data.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 =>
data.zoning.spawn.handleReleaseAvatarRequest(packet)
case packet: SpawnRequestMessage =>
data.zoning.spawn.handleSpawnRequest(packet)
case packet: ChatMsg =>
chat.handleChatMsg(packet)
case packet: SetChatFilterMessage =>
chat.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 =>
terminals.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 _: UplinkRequest => ()
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 =>
data.zoning.handleWarpgateRequest(packet)
case packet: MountVehicleMsg =>
mountResponse.handleMountVehicle(packet)
case packet: DismountVehicleMsg =>
mountResponse.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 =>
data.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 =>
data.log.warn(s"Unhandled GamePacket $pkt")
}
}
case object NormalMode extends PlayerMode {

View file

@ -112,7 +112,7 @@ class TerminalHandlerLogic(val ops: SessionTerminalHandlers, implicit val contex
ops.lastTerminalOrderFulfillment = true
case Terminal.BuyVehicle(vehicle, _, _)
if tplayer.avatar.purchaseCooldown(vehicle.Definition).nonEmpty || tplayer.spectator =>
if tplayer.avatar.purchaseCooldown(vehicle.Definition).nonEmpty =>
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, success = false))
ops.lastTerminalOrderFulfillment = true

View file

@ -5,7 +5,7 @@ import akka.actor.{ActorContext, typed}
import net.psforever.actors.session.AvatarActor
import net.psforever.actors.session.support.{SessionData, VehicleFunctions, VehicleOperations}
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle, Vehicles}
import net.psforever.objects.{Vehicle, Vehicles}
import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.vehicles.control.BfrFlight
@ -41,7 +41,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
is_decelerating,
is_cloaked
) = pkt
GetVehicleAndSeat() match {
ops.GetVehicleAndSeat() match {
case (Some(obj), Some(0)) =>
//we're driving the vehicle
sessionLogic.persist()
@ -100,7 +100,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
log.error(
s"VehicleState: ${player.Name} should not be dispatching this kind of packet from vehicle ${vehicle_guid.guid} when not the driver (actually, seat $index)"
)
case _ => ;
case _ => ()
}
if (player.death_by == -1) {
sessionLogic.kickedByAdministration()
@ -124,7 +124,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
unk9,
unkA
) = pkt
GetVehicleAndSeat() match {
ops.GetVehicleAndSeat() match {
case (Some(obj), Some(0)) =>
//we're driving the vehicle
sessionLogic.persist()
@ -198,7 +198,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
log.error(
s"VehicleState: ${player.Name} should not be dispatching this kind of packet from vehicle ${vehicle_guid.guid} when not the driver (actually, seat $index)"
)
case _ => ;
case _ => ()
}
if (player.death_by == -1) {
sessionLogic.kickedByAdministration()
@ -213,7 +213,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
case Some(mount: Mountable) => (o, mount.PassengerInSeat(player))
case _ => (None, None)
}) match {
case (None, None) | (_, None) | (Some(_: Vehicle), Some(0)) => ;
case (None, None) | (_, None) | (Some(_: Vehicle), Some(0)) => ()
case _ =>
sessionLogic.persist()
sessionLogic.turnCounterFunc(player.GUID)
@ -241,33 +241,33 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
def handleVehicleSubState(pkt: VehicleSubStateMessage): Unit = {
val VehicleSubStateMessage(vehicle_guid, _, pos, ang, vel, unk1, _) = pkt
sessionLogic.validObject(vehicle_guid, decorator = "VehicleSubState") match {
case Some(obj: Vehicle) =>
import net.psforever.login.WorldSession.boolToInt
obj.Position = pos
obj.Orientation = ang
obj.Velocity = vel
sessionLogic.updateBlockMap(obj, pos)
obj.zoneInteractions()
continent.VehicleEvents ! VehicleServiceMessage(
continent.id,
VehicleAction.VehicleState(
player.GUID,
vehicle_guid,
unk1,
pos,
ang,
obj.Velocity,
obj.Flying,
0,
0,
15,
unk5 = false,
obj.Cloaked
sessionLogic.validObject(vehicle_guid, decorator = "VehicleSubState")
.collect {
case obj: Vehicle =>
import net.psforever.login.WorldSession.boolToInt
obj.Position = pos
obj.Orientation = ang
obj.Velocity = vel
sessionLogic.updateBlockMap(obj, pos)
obj.zoneInteractions()
continent.VehicleEvents ! VehicleServiceMessage(
continent.id,
VehicleAction.VehicleState(
player.GUID,
vehicle_guid,
unk1,
pos,
ang,
obj.Velocity,
obj.Flying,
0,
0,
15,
unk5 = false,
obj.Cloaked
)
)
)
case _ => ()
}
}
}
def handleDeployRequest(pkt: DeployRequestMessage): Unit = {
@ -329,46 +329,6 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
/* support functions */
/**
* If the player is mounted in some entity, find that entity and get the mount index number at which the player is sat.
* The priority of object confirmation is `direct` then `occupant.VehicleSeated`.
* Once an object is found, the remainder are ignored.
* @param direct a game object in which the player may be sat
* @param occupant the player who is sat and may have specified the game object in which mounted
* @return a tuple consisting of a vehicle reference and a mount index
* if and only if the vehicle is known to this client and the `WorldSessioNActor`-global `player` occupies it;
* `(None, None)`, otherwise (even if the vehicle can be determined)
*/
private def GetMountableAndSeat(
direct: Option[PlanetSideGameObject with Mountable],
occupant: Player,
zone: Zone
): (Option[PlanetSideGameObject with Mountable], Option[Int]) =
direct.orElse(zone.GUID(occupant.VehicleSeated)) match {
case Some(obj: PlanetSideGameObject with Mountable) =>
obj.PassengerInSeat(occupant) match {
case index @ Some(_) =>
(Some(obj), index)
case None =>
(None, None)
}
case _ =>
(None, None)
}
/**
* If the player is seated in a vehicle, find that vehicle and get the mount index number at which the player is sat.
* @see `GetMountableAndSeat`
* @return a tuple consisting of a vehicle reference and a mount index
* if and only if the vehicle is known to this client and the `WorldSessioNActor`-global `player` occupies it;
* `(None, None)`, otherwise (even if the vehicle can be determined)
*/
private def GetVehicleAndSeat(): (Option[Vehicle], Option[Int]) =
GetMountableAndSeat(None, player, continent) match {
case (Some(v: Vehicle), Some(seat)) => (Some(v), Some(seat))
case _ => (None, None)
}
/**
* Common reporting behavior when a `Deployment` object fails to properly transition between states.
* @param obj the game object that could not

View file

@ -88,6 +88,7 @@ object WeaponAndProjectileLogic {
Seq(start + endStart * (sqrt - b), start + endStart * (b + sqrt) * -1f)
}.filter(p => Vector3.DistanceSquared(start, p) <= a)
}
/**
* Preparation for explosion damage that utilizes the Scorpion's little buddy sub-projectiles.
* The main difference from "normal" server-side explosion
@ -497,9 +498,7 @@ class WeaponAndProjectileLogic(val ops: WeaponAndProjectileOperations, implicit
}
if (profile.ExistsOnRemoteClients && projectile.HasGUID) {
//cleanup
if (projectile.HasGUID) {
continent.Projectile ! ZoneProjectile.Remove(projectile.GUID)
}
continent.Projectile ! ZoneProjectile.Remove(projectile.GUID)
}
case None => ()
}

View file

@ -65,7 +65,7 @@ class GalaxyHandlerLogic(val ops: SessionGalaxyHandlers, implicit val context: A
case GalaxyResponse.LockedZoneUpdate(zone, time) =>
sendResponse(ZoneInfoMessage(zone.Number, empire_status=false, lock_time=time))
case GalaxyResponse.UnlockedZoneUpdate(zone) => ;
case GalaxyResponse.UnlockedZoneUpdate(zone) =>
sendResponse(ZoneInfoMessage(zone.Number, empire_status=true, lock_time=0L))
val popBO = 0
val popTR = zone.Players.count(_.faction == PlanetSideEmpire.TR)

View file

@ -1,7 +1,7 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.spectator
import akka.actor.{ActorContext, typed}
import akka.actor.{ActorContext, ActorRef, typed}
import net.psforever.actors.session.AvatarActor
import net.psforever.actors.session.support.{GeneralFunctions, GeneralOperations, SessionData}
import net.psforever.objects.{Account, GlobalDefinitions, LivePlayerList, PlanetSideGameObject, Player, TelepadDeployable, Tool, Vehicle}
@ -11,15 +11,16 @@ import net.psforever.objects.ce.{Deployable, TelepadLike}
import net.psforever.objects.definition.{BasicDefinition, KitDefinition, SpecialExoSuitDefinition}
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.containable.Containable
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.vehicles.{Utility, UtilityType}
import net.psforever.objects.vehicles.Utility.InternalTelepad
import net.psforever.objects.zones.ZoneProjectile
import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.{ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, ChatMsg, ConnectToWorldRequestMessage, CreateShortcutMessage, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, PlayerStateShiftMessage, RequestDestroyMessage, ShiftState, TargetInfo, TargetingImplantRequest, TargetingInfoMessage, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostKill, VoiceHostRequest, ZipLineMessage}
import net.psforever.packet.game.{ActionCancelMessage, AvatarFirstTimeEventMessage, AvatarImplantMessage, AvatarJumpMessage, BattleplanMessage, BindPlayerMessage, BugReportMessage, ChangeFireModeMessage, ChangeShortcutBankMessage, CharacterCreateRequestMessage, CharacterRequestMessage, ConnectToWorldRequestMessage, CreateShortcutMessage, DeployObjectMessage, DisplayedAwardMessage, DropItemMessage, EmoteMsg, FacilityBenefitShieldChargeRequestMessage, FriendsRequest, GenericAction, GenericActionMessage, GenericCollisionMsg, GenericObjectActionAtPositionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HitHint, ImplantAction, InvalidTerrainMessage, LootItemMessage, MoveItemMessage, ObjectDetectedMessage, ObjectHeldMessage, PickupItemMessage, PlanetsideAttributeMessage, PlayerStateMessageUpstream, PlayerStateShiftMessage, RequestDestroyMessage, ShiftState, TargetInfo, TargetingImplantRequest, TargetingInfoMessage, TradeMessage, UnuseItemMessage, UseItemMessage, VoiceHostInfo, VoiceHostRequest, ZipLineMessage}
import net.psforever.services.account.AccountPersistenceService
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.types.{ChatMessageType, DriveState, ExoSuitType, PlanetSideGUID, Vector3}
import net.psforever.types.{DriveState, ExoSuitType, PlanetSideGUID, Vector3}
import net.psforever.util.Config
object GeneralLogic {
@ -79,19 +80,11 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
}
def handleVoiceHostRequest(pkt: VoiceHostRequest): Unit = {
log.debug(s"$pkt")
sendResponse(VoiceHostKill())
sendResponse(
ChatMsg(ChatMessageType.CMT_OPEN, wideContents=false, "", "Try our Discord at https://discord.gg/0nRe5TNbTYoUruA4", None)
)
ops.noVoicedChat(pkt)
}
def handleVoiceHostInfo(pkt: VoiceHostInfo): Unit = {
log.debug(s"$pkt")
sendResponse(VoiceHostKill())
sendResponse(
ChatMsg(ChatMessageType.CMT_OPEN, wideContents=false, "", "Try our Discord at https://discord.gg/0nRe5TNbTYoUruA4", None)
)
ops.noVoicedChat(pkt)
}
def handleEmote(pkt: EmoteMsg): Unit = {
@ -410,6 +403,10 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
/* messages */
def handleRenewCharSavedTimer(): Unit = { /* intentionally blank */ }
def handleRenewCharSavedTimerMsg(): Unit = { /* intentionally blank */ }
def handleSetAvatar(avatar: Avatar): Unit = {
session = session.copy(avatar = avatar)
if (session.player != null) {
@ -455,6 +452,12 @@ class GeneralLogic(val ops: GeneralOperations, implicit val context: ActorContex
player.silenced = isSilenced
}
def handleItemPutInSlot(msg: Containable.ItemPutInSlot): Unit = { /* intentionally blank */ }
def handleCanNotPutItemInSlot(msg: Containable.CanNotPutItemInSlot): Unit = { /* intentionally blank */ }
def handleReceiveDefaultMessage(default: Any, sender: ActorRef): Unit = { /* intentionally blank */ }
/* supporting functions */
private def handleUseDoor(door: Door, equipment: Option[Equipment]): Unit = {

View file

@ -4,6 +4,7 @@ package net.psforever.actors.session.spectator
import akka.actor.ActorContext
import net.psforever.actors.session.support.{LocalHandlerFunctions, SessionData, SessionLocalHandlers}
import net.psforever.objects.ce.Deployable
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects.vehicles.MountableWeapons
import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable}
import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage}
@ -20,6 +21,16 @@ object LocalHandlerLogic {
class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: ActorContext) extends LocalHandlerFunctions {
def sessionLogic: SessionData = ops.sessionLogic
/* messages */
def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit = {
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(continent.GUID, obj))
}
def handleDeployableIsDismissed(obj: Deployable): Unit = {
TaskWorkflow.execute(GUIDTask.unregisterObject(continent.GUID, obj))
}
/* response handlers */
/**

View file

@ -66,7 +66,7 @@ class MountHandlerLogic(val ops: SessionMountHandlers, implicit val context: Act
v.SeatPermissionGroup(seat_num).contains(AccessPermissionGroup.Driver) &&
v.isFlying =>
v.Actor ! Vehicle.Deconstruct(None) //immediate deconstruction
case _ => ;
case _ => ()
}
case None =>

View file

@ -1,8 +1,6 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.spectator
import akka.actor.Actor.Receive
import akka.actor.ActorRef
import net.psforever.actors.session.support.{AvatarHandlerFunctions, ChatFunctions, GalaxyHandlerFunctions, GeneralFunctions, LocalHandlerFunctions, MountHandlerFunctions, SquadHandlerFunctions, TerminalHandlerFunctions, VehicleFunctions, VehicleHandlerFunctions, WeaponAndProjectileFunctions}
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.{BattleRank, CommandRank, DeployableToolbox, FirstTimeEvents, Implant, ProgressDecoration, Shortcut => AvatarShortcut}
@ -14,32 +12,14 @@ import net.psforever.packet.game.{DeployableInfo, DeployableObjectsInfoMessage,
import net.psforever.packet.game.objectcreate.{ObjectClass, ObjectCreateMessageParent, RibbonBars}
import net.psforever.services.Service
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.chat.{ChatService, SpectatorChannel}
import net.psforever.services.chat.SpectatorChannel
import net.psforever.services.teamwork.{SquadAction, SquadServiceMessage}
import net.psforever.types.{CapacitorStateType, ChatMessageType, ExoSuitType, MeritCommendation, SquadRequestType}
//
import net.psforever.actors.session.{AvatarActor, SessionActor}
import net.psforever.actors.session.support.{ModeLogic, PlayerMode, SessionData, ZoningOperations}
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.actors.session.AvatarActor
import net.psforever.actors.session.support.{ModeLogic, PlayerMode, SessionData}
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, UplinkRequest, 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.packet.game.{ChatMsg, CreateShortcutMessage, UnuseItemMessage}
class SpectatorModeLogic(data: SessionData) extends ModeLogic {
val avatarResponse: AvatarHandlerFunctions = AvatarHandlerLogic(data.avatarResponse)
@ -186,463 +166,6 @@ class SpectatorModeLogic(data: SessionData) extends ModeLogic {
zoning.zoneReload = true
zoning.spawn.randomRespawn(0.seconds) //to sanctuary
}
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) =>
galaxy.handle(reply)
case LocalServiceResponse(toChannel, guid, reply) =>
local.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) =>
vehicleResponse.handle(toChannel, guid, reply)
case ChatService.MessageResponse(fromSession, message, _) =>
chat.handleIncomingMessage(message, fromSession)
case SessionActor.SendResponse(packet) =>
data.sendResponse(packet)
case SessionActor.CharSaved => ()
case SessionActor.CharSavedMsg => ()
/* common messages (maybe once every respawn) */
case ICS.SpawnPointResponse(response) =>
data.zoning.handleSpawnPointResponse(response)
case SessionActor.NewPlayerLoaded(tplayer) =>
data.zoning.spawn.handleNewPlayerLoaded(tplayer)
case SessionActor.PlayerLoaded(tplayer) =>
data.zoning.spawn.handlePlayerLoaded(tplayer)
case Zone.Population.PlayerHasLeft(zone, None) =>
data.log.debug(s"PlayerHasLeft: ${data.player.Name} does not have a body on ${zone.id}")
case Zone.Population.PlayerHasLeft(zone, Some(tplayer)) =>
if (tplayer.isAlive) {
data.log.info(s"${tplayer.Name} has left zone ${zone.id}")
}
case Zone.Population.PlayerCanNotSpawn(zone, tplayer) =>
data.log.warn(s"${tplayer.Name} can not spawn in zone ${zone.id}; why?")
case Zone.Population.PlayerAlreadySpawned(zone, tplayer) =>
data.log.warn(s"${tplayer.Name} is already spawned on zone ${zone.id}; is this a clerical error?")
case Zone.Vehicle.CanNotSpawn(zone, vehicle, reason) =>
data.log.warn(
s"${data.player.Name}'s ${vehicle.Definition.Name} can not spawn in ${zone.id} because $reason"
)
case Zone.Vehicle.CanNotDespawn(zone, vehicle, reason) =>
data.log.warn(
s"${data.player.Name}'s ${vehicle.Definition.Name} can not deconstruct in ${zone.id} because $reason"
)
case ICS.ZoneResponse(Some(zone)) =>
data.zoning.handleZoneResponse(zone)
/* uncommon messages (once a session) */
case ICS.ZonesResponse(zones) =>
data.zoning.handleZonesResponse(zones)
case SessionActor.SetAvatar(avatar) =>
general.handleSetAvatar(avatar)
case PlayerToken.LoginInfo(name, Zone.Nowhere, _) =>
data.zoning.spawn.handleLoginInfoNowhere(name, sender)
case PlayerToken.LoginInfo(name, inZone, optionalSavedData) =>
data.zoning.spawn.handleLoginInfoSomewhere(name, inZone, optionalSavedData, sender)
case PlayerToken.RestoreInfo(playerName, inZone, pos) =>
data.zoning.spawn.handleLoginInfoRestore(playerName, inZone, pos, sender)
case PlayerToken.CanNotLogin(playerName, reason) =>
data.zoning.spawn.handleLoginCanNot(playerName, reason)
case ReceiveAccountData(account) =>
general.handleReceiveAccountData(account)
case AvatarActor.AvatarResponse(avatar) =>
general.handleAvatarResponse(avatar)
case AvatarActor.AvatarLoginResponse(avatar) =>
data.zoning.spawn.avatarLoginResponse(avatar)
case SessionActor.SetCurrentAvatar(tplayer, max_attempts, attempt) =>
data.zoning.spawn.ReadyToSetCurrentAvatar(tplayer, max_attempts, attempt)
case SessionActor.SetConnectionState(state) =>
data.connectionState = state
case SessionActor.AvatarLoadingSync(state) =>
data.zoning.spawn.handleAvatarLoadingSync(state)
/* uncommon messages (utility, or once in a while) */
case ZoningOperations.AvatarAwardMessageBundle(pkts, delay) =>
data.zoning.spawn.performAvatarAwardMessageDelivery(pkts, delay)
case CommonMessages.ProgressEvent(delta, finishedAction, stepAction, tick) =>
general.ops.handleProgressChange(delta, finishedAction, stepAction, tick)
case CommonMessages.Progress(rate, finishedAction, stepAction) =>
general.ops.setupProgressChange(rate, finishedAction, stepAction)
case CavernRotationService.CavernRotationServiceKey.Listing(listings) =>
listings.head ! SendCavernRotationUpdates(data.context.self)
case LookupResult("propertyOverrideManager", endpoint) =>
data.zoning.propertyOverrideManagerLoadOverrides(endpoint)
case SessionActor.UpdateIgnoredPlayers(msg) =>
galaxy.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.ops.LocalStopUsingProximityUnit(term)
case SessionActor.Suicide() =>
general.ops.suicide(data.player)
case SessionActor.Recall() =>
data.zoning.handleRecall()
case SessionActor.InstantAction() =>
data.zoning.handleInstantAction()
case SessionActor.Quit() =>
data.zoning.handleQuit()
case ICS.DroppodLaunchDenial(errorCode, _) =>
data.zoning.handleDroppodLaunchDenial(errorCode)
case ICS.DroppodLaunchConfirmation(zone, position) =>
data.zoning.LoadZoneLaunchDroppod(zone, position)
case SessionActor.PlayerFailedToLoad(tplayer) =>
data.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) =>
data.zoning.handleSetZone(zoneId, position)
case SessionActor.SetPosition(position) =>
data.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(data.continent.GUID, obj))
case Zone.Deployable.IsDismissed(obj) => //only if target deployable was never fully introduced
TaskWorkflow.execute(GUIDTask.unregisterObject(data.continent.GUID, obj))
case msg: Containable.ItemPutInSlot =>
data.log.debug(s"ItemPutInSlot: $msg")
case msg: Containable.CanNotPutItemInSlot =>
data.log.debug(s"CanNotPutItemInSlot: $msg")
case _ => ()
}
private def handleGamePkt: PlanetSideGamePacket => Unit = {
case packet: ConnectToWorldRequestMessage =>
general.handleConnectToWorldRequest(packet)
case packet: MountVehicleCargoMsg =>
mountResponse.handleMountVehicleCargo(packet)
case packet: DismountVehicleCargoMsg =>
mountResponse.handleDismountVehicleCargo(packet)
case packet: CharacterCreateRequestMessage =>
general.handleCharacterCreateRequest(packet)
case packet: CharacterRequestMessage =>
general.handleCharacterRequest(packet)
case _: KeepAliveMessage =>
data.keepAliveFunc()
case packet: BeginZoningMessage =>
data.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 =>
data.zoning.spawn.handleReleaseAvatarRequest(packet)
case packet: SpawnRequestMessage =>
data.zoning.spawn.handleSpawnRequest(packet)
case packet: ChatMsg =>
chat.handleChatMsg(packet)
case packet: SetChatFilterMessage =>
chat.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 =>
terminals.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: UplinkRequest =>
shooting.handleUplinkRequest(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 =>
data.zoning.handleWarpgateRequest(packet)
case packet: MountVehicleMsg =>
mountResponse.handleMountVehicle(packet)
case packet: DismountVehicleMsg =>
mountResponse.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 =>
data.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 =>
data.log.warn(s"Unhandled GamePacket $pkt")
}
}
object SpectatorModeLogic {

View file

@ -5,11 +5,10 @@ import akka.actor.{ActorContext, typed}
import net.psforever.actors.session.AvatarActor
import net.psforever.actors.session.support.{SessionData, VehicleFunctions, VehicleOperations}
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle, Vehicles}
import net.psforever.objects.{Vehicle, Vehicles}
import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.vehicles.control.BfrFlight
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{ChildObjectStateMessage, DeployRequestMessage, FrameVehicleStateMessage, VehicleStateMessage, VehicleSubStateMessage}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.{DriveState, Vector3}
@ -41,7 +40,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
is_decelerating,
is_cloaked
) = pkt
GetVehicleAndSeat() match {
ops.GetVehicleAndSeat() match {
case (Some(obj), Some(0)) =>
//we're driving the vehicle
sessionLogic.persist()
@ -100,7 +99,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
log.error(
s"VehicleState: ${player.Name} should not be dispatching this kind of packet from vehicle ${vehicle_guid.guid} when not the driver (actually, seat $index)"
)
case _ => ;
case _ => ()
}
if (player.death_by == -1) {
sessionLogic.kickedByAdministration()
@ -124,7 +123,7 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
unk9,
unkA
) = pkt
GetVehicleAndSeat() match {
ops.GetVehicleAndSeat() match {
case (Some(obj), Some(0)) =>
//we're driving the vehicle
sessionLogic.persist()
@ -296,46 +295,6 @@ class VehicleLogic(val ops: VehicleOperations, implicit val context: ActorContex
/* support functions */
/**
* If the player is mounted in some entity, find that entity and get the mount index number at which the player is sat.
* The priority of object confirmation is `direct` then `occupant.VehicleSeated`.
* Once an object is found, the remainder are ignored.
* @param direct a game object in which the player may be sat
* @param occupant the player who is sat and may have specified the game object in which mounted
* @return a tuple consisting of a vehicle reference and a mount index
* if and only if the vehicle is known to this client and the `WorldSessioNActor`-global `player` occupies it;
* `(None, None)`, otherwise (even if the vehicle can be determined)
*/
private def GetMountableAndSeat(
direct: Option[PlanetSideGameObject with Mountable],
occupant: Player,
zone: Zone
): (Option[PlanetSideGameObject with Mountable], Option[Int]) =
direct.orElse(zone.GUID(occupant.VehicleSeated)) match {
case Some(obj: PlanetSideGameObject with Mountable) =>
obj.PassengerInSeat(occupant) match {
case index @ Some(_) =>
(Some(obj), index)
case None =>
(None, None)
}
case _ =>
(None, None)
}
/**
* If the player is seated in a vehicle, find that vehicle and get the mount index number at which the player is sat.
* @see `GetMountableAndSeat`
* @return a tuple consisting of a vehicle reference and a mount index
* if and only if the vehicle is known to this client and the `WorldSessioNActor`-global `player` occupies it;
* `(None, None)`, otherwise (even if the vehicle can be determined)
*/
private def GetVehicleAndSeat(): (Option[Vehicle], Option[Int]) =
GetMountableAndSeat(None, player, continent) match {
case (Some(v: Vehicle), Some(seat)) => (Some(v), Some(seat))
case _ => (None, None)
}
/**
* Common reporting behavior when a `Deployment` object fails to properly transition between states.
* @param obj the game object that could not

View file

@ -2,6 +2,7 @@
package net.psforever.actors.session.support
import akka.actor.{ActorContext, ActorRef, Cancellable, typed}
import net.psforever.objects.serverobject.containable.Containable
import net.psforever.objects.sourcing.PlayerSource
import scala.collection.mutable
@ -122,6 +123,10 @@ trait GeneralFunctions extends CommonSessionInterfacingFunctionality {
/* messages */
def handleRenewCharSavedTimer(): Unit
def handleRenewCharSavedTimerMsg(): Unit
def handleSetAvatar(avatar: Avatar): Unit
def handleReceiveAccountData(account: Account): Unit
@ -139,6 +144,12 @@ trait GeneralFunctions extends CommonSessionInterfacingFunctionality {
def handleKick(player: Player, time: Option[Long]): Unit
def handleSilenced(isSilenced: Boolean): Unit
def handleItemPutInSlot(msg: Containable.ItemPutInSlot): Unit
def handleCanNotPutItemInSlot(msg: Containable.CanNotPutItemInSlot): Unit
def handleReceiveDefaultMessage(default: Any, sender: ActorRef): Unit
}
class GeneralOperations(
@ -741,6 +752,14 @@ class GeneralOperations(
sendResponse(ChatMsg(ChatMessageType.UNK_227, wideContents=false, "", "@charsaved", None))
}
def noVoicedChat(pkt: PlanetSideGamePacket): Unit = {
log.debug(s"$pkt")
sendResponse(VoiceHostKill())
sendResponse(
ChatMsg(ChatMessageType.CMT_OPEN, wideContents=false, "", "Try our Discord at https://discord.gg/0nRe5TNbTYoUruA4", None)
)
}
override protected[session] def actionsToCancel(): Unit = {
progressBarValue = None
kitToBeUsed = None

View file

@ -1,8 +1,6 @@
// Copyright (c) 2024 PSForever
package net.psforever.actors.session.support
import akka.actor.Actor.Receive
import akka.actor.ActorRef
import net.psforever.objects.Session
trait ModeLogic {
@ -21,8 +19,6 @@ trait ModeLogic {
def switchTo(session: Session): Unit = { /* to override */ }
def switchFrom(session: Session): Unit = { /* to override */ }
def parse(sender: ActorRef): Receive
}
trait PlayerMode {

View file

@ -2,16 +2,35 @@
package net.psforever.actors.session.support
import akka.actor.ActorContext
import net.psforever.objects.{Players, TurretDeployable}
import net.psforever.objects.ce.Deployable
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.services.local.LocalResponse
import net.psforever.types.PlanetSideGUID
trait LocalHandlerFunctions extends CommonSessionInterfacingFunctionality {
def ops: SessionLocalHandlers
def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit
def handleDeployableIsDismissed(obj: Deployable): Unit
def handle(toChannel: String, guid: PlanetSideGUID, reply: LocalResponse.Response): Unit
}
class SessionLocalHandlers(
val sessionLogic: SessionData,
implicit val context: ActorContext
) extends CommonSessionInterfacingFunctionality
) extends CommonSessionInterfacingFunctionality {
def handleTurretDeployableIsDismissed(obj: TurretDeployable): Unit = {
Players.buildCooldownReset(continent, player.Name, obj)
TaskWorkflow.execute(GUIDTask.unregisterDeployableTurret(continent.GUID, obj))
}
def handleDeployableIsDismissed(obj: Deployable): Unit = {
Players.buildCooldownReset(continent, player.Name, obj)
TaskWorkflow.execute(GUIDTask.unregisterObject(continent.GUID, obj))
}
}

View file

@ -74,7 +74,7 @@ class SessionSquadHandlers(
sendResponse(
SquadDefinitionActionMessage(PlanetSideGUID(0), index, SquadAction.ListSquadFavorite(loadout.task))
)
case (None, _) => ;
case (None, _) => ()
}
//non-squad GUID-0 counts as the settings when not joined with a squad
sendResponse(SquadDefinitionActionMessage(PlanetSideGUID(0), 0, SquadAction.IdentifyAsSquadLeader()))

View file

@ -68,6 +68,26 @@ class SessionTerminalHandlers(
)
}
/**
* 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
*/
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))
)
}
/**
* na
* @param terminal na
@ -188,26 +208,6 @@ class SessionTerminalHandlers(
}
}
/**
* 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
*/
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[session] def actionsToCancel(): Unit = {
lastTerminalOrderFulfillment = true
usingMedicalTerminal = None

View file

@ -66,6 +66,19 @@ class VehicleOperations(
(None, None)
}
/**
* If the player is seated in a vehicle, find that vehicle and get the mount index number at which the player is sat.
* @see `GetMountableAndSeat`
* @return a tuple consisting of a vehicle reference and a mount index
* if and only if the vehicle is known to this client and the `WorldSessioNActor`-global `player` occupies it;
* `(None, None)`, otherwise (even if the vehicle can be determined)
*/
def GetVehicleAndSeat(): (Option[Vehicle], Option[Int]) =
GetMountableAndSeat(None, player, continent) match {
case (Some(v: Vehicle), Some(seat)) => (Some(v), Some(seat))
case _ => (None, None)
}
/**
* If the player is seated in a vehicle, find that vehicle and get the mount index number at which the player is sat.<br>
* <br>
@ -86,19 +99,6 @@ class VehicleOperations(
case _ => (None, None)
}
/**
* If the player is seated in a vehicle, find that vehicle and get the mount index number at which the player is sat.
* @see `GetMountableAndSeat`
* @return a tuple consisting of a vehicle reference and a mount index
* if and only if the vehicle is known to this client and the `WorldSessioNActor`-global `player` occupies it;
* `(None, None)`, otherwise (even if the vehicle can be determined)
*/
def GetVehicleAndSeat(): (Option[Vehicle], Option[Int]) =
GetMountableAndSeat(None, player, continent) match {
case (Some(v: Vehicle), Some(seat)) => (Some(v), Some(seat))
case _ => (None, None)
}
/**
* Place the current vehicle under the control of the driver's commands,
* but leave it in a cancellable auto-drive.

View file

@ -288,7 +288,7 @@ class ZoningOperations(
obj.Definition.DeployCategory == DeployableCategory.Sensors &&
!obj.Destroyed &&
(obj match {
case jObj: JammableUnit => !jObj.Jammed;
case jObj: JammableUnit => !jObj.Jammed
case _ => true
})
)
@ -449,7 +449,7 @@ class ZoningOperations(
if (vehicle.Shields > 0) {
sendResponse(PlanetsideAttributeMessage(vguid, vehicle.Definition.shieldUiAttribute, vehicle.Shields))
}
case _ => ; //no vehicle
case _ => () //no vehicle
}
//vehicle wreckages
wreckages.foreach(vehicle => {
@ -487,7 +487,7 @@ class ZoningOperations(
sendResponse(PlanetsideAttributeMessage(silo.GUID, 49, 1)) // silo orb particle effect
case Some(_: WarpGate) =>
sendResponse(PlanetsideAttributeMessage(obj.GUID, 49, 1)) // ant orb particle effect
case _ => ;
case _ => ()
}
}
deployedVehicles.filter(_.Definition == GlobalDefinitions.router).foreach { obj =>
@ -518,7 +518,7 @@ class ZoningOperations(
objDef.Packet.ConstructorData(obj).get
)
)
case _ => ;
case _ => ()
}
//mount terminal occupants
continent.GUID(terminal_guid) match {
@ -534,9 +534,9 @@ class ZoningOperations(
targetDefinition.Packet.ConstructorData(targetPlayer).get
)
)
case _ => ;
case _ => ()
}
case _ => ;
case _ => ()
}
})
//facility turrets
@ -558,7 +558,7 @@ class ZoningOperations(
objDef.Packet.ConstructorData(obj).get
)
)
case _ => ;
case _ => ()
}
}
//reserved ammunition?
@ -575,7 +575,7 @@ class ZoningOperations(
targetDefinition.Packet.ConstructorData(targetPlayer).get
)
)
case _ => ;
case _ => ()
}
turret.Target.collect {
target =>
@ -1071,7 +1071,7 @@ class ZoningOperations(
)
)
}
case _ => ;
case _ => ()
}
}
@ -1092,7 +1092,7 @@ class ZoningOperations(
case Some(obj) if obj.Condition == PlanetSideGeneratorState.Destroyed || building.NtuLevel == 0 =>
sendResponse(PlanetsideAttributeMessage(guid, 48, 1)) //amenities disabled; red warning lights
sendResponse(PlanetsideAttributeMessage(guid, 38, 0)) //disable spawn target on deployment map
case _ => ;
case _ => ()
}
// capitol force dome state
if (building.IsCapitol && building.ForceDomeActive) {
@ -1177,7 +1177,7 @@ class ZoningOperations(
LocalAction.SendPacket(ObjectAttachMessage(llu.Carrier.get.GUID, llu.GUID, 252))
)
}
case _ => ;
case _ => ()
}
}
@ -1495,7 +1495,7 @@ class ZoningOperations(
// remove owner
vehicle.Actor ! Vehicle.Ownership(None)
case _ => ;
case _ => ()
}
avatarActor ! AvatarActor.SetVehicle(None)
}
@ -1736,7 +1736,7 @@ class ZoningOperations(
case Success(overrides: List[Any]) =>
//safe to cast like this
sendResponse(PropertyOverrideMessage(overrides.map { _.asInstanceOf[PropertyOverrideMessage.GamePropertyScope] }))
case _ => ;
case _ => ()
}
}
@ -2119,6 +2119,40 @@ class ZoningOperations(
}
}
def handlePlayerHasLeft(zone: Zone, playerOpt: Option[Player]): Unit = {
playerOpt match {
case None =>
log.debug(s"PlayerHasLeft: ${player.Name} does not have a body on ${zone.id}")
case Some(tplayer) if tplayer.isAlive =>
log.info(s"${tplayer.Name} has left zone ${zone.id}")
case _ => ()
}
}
def handlePlayerCanNotSpawn(zone: Zone, tplayer: Player): Unit = {
log.warn(s"${tplayer.Name} can not spawn in zone ${zone.id}; why?")
}
def handlePlayerAlreadySpawned(zone: Zone, tplayer: Player): Unit = {
log.warn(s"${tplayer.Name} is already spawned on zone ${zone.id}; is this a clerical error?")
}
def handleCanNotSpawn(zone: Zone, vehicle: Vehicle, reason: String): Unit = {
log.warn(
s"${player.Name}'s ${vehicle.Definition.Name} can not spawn in ${zone.id} because $reason"
)
}
def handleCanNotDespawn(zone: Zone, vehicle: Vehicle, reason: String): Unit = {
log.warn(
s"${player.Name}'s ${vehicle.Definition.Name} can not deconstruct in ${zone.id} because $reason"
)
}
def handlePlayerFailedToLoad(tplayer: Player): Unit = {
sessionLogic.failWithError(s"${tplayer.Name} failed to load anywhere")
}
/* support functions */
private def dropMedicalApplicators(p: Player): Unit = {
@ -2289,7 +2323,7 @@ class ZoningOperations(
carrierInfo match {
case (Some(carrier), Some((index, _))) =>
CargoMountBehaviorForUs(carrier, vehicle, index)
case _ => ;
case _ => ()
}
data
}
@ -2476,7 +2510,7 @@ class ZoningOperations(
def FriskDeadBody(obj: Player): Unit = {
if (!obj.isAlive) {
obj.Slot(4).Equipment match {
case None => ;
case None => ()
case Some(knife) =>
RemoveOldEquipmentFromInventory(obj)(knife)
}
@ -2485,7 +2519,7 @@ class ZoningOperations(
if (GlobalDefinitions.isMaxArms(arms.Definition)) {
RemoveOldEquipmentFromInventory(obj)(arms)
}
case _ => ;
case _ => ()
}
//disown boomers and drop triggers
val boomers = avatar.deployables.ClearDeployable(DeployedItem.boomer)
@ -2493,7 +2527,7 @@ class ZoningOperations(
continent.GUID(boomer) match {
case Some(obj: BoomerDeployable) =>
obj.Actor ! Deployable.Ownership(None)
case Some(_) | None => ;
case Some(_) | None => ()
}
})
removeBoomerTriggersFromInventory().foreach(trigger => { sessionLogic.general.normalItemDrop(obj, continent)(trigger) })
@ -3035,7 +3069,7 @@ class ZoningOperations(
case (Some(vehicle), _) =>
//passenger
vehicle.Actor ! Vehicle.UpdateZoneInteractionProgressUI(tplayer)
case _ => ;
case _ => ()
}
interstellarFerryTopLevelGUID = None
if (loadConfZone && sessionLogic.connectionState == 100) {
@ -3329,7 +3363,7 @@ class ZoningOperations(
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
sessionLogic.general.accessContainer(vehicle)
sessionLogic.keepAliveFunc = sessionLogic.keepAlivePersistence
case _ => ;
case _ => ()
//we can't find a vehicle? and we're still here? that's bad
player.VehicleSeated = None
}
@ -3517,7 +3551,7 @@ class ZoningOperations(
delay: Long
): Unit = {
messageBundles match {
case Nil => ;
case Nil => ()
case x :: Nil =>
x.foreach {
sendResponse
@ -3581,10 +3615,11 @@ class ZoningOperations(
}
def randomRespawn(time: FiniteDuration = 300.seconds): Unit = {
val faction = player.Faction
reviveTimer = context.system.scheduler.scheduleOnce(time) {
cluster ! ICS.GetRandomSpawnPoint(
Zones.sanctuaryZoneNumber(player.Faction),
player.Faction,
Zones.sanctuaryZoneNumber(faction),
faction,
Seq(SpawnGroup.Sanctuary),
context.self
)