diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index 7ea23d760..33e814221 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -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") + } } diff --git a/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala index 0a84b1d3a..6c4460023 100644 --- a/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/AvatarHandlerLogic.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/normal/GalaxyHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/GalaxyHandlerLogic.scala index f50d1e15b..f82492cf2 100644 --- a/src/main/scala/net/psforever/actors/session/normal/GalaxyHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/GalaxyHandlerLogic.scala @@ -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)) => diff --git a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala index 812bf74af..e5a7f8417 100644 --- a/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/GeneralLogic.scala @@ -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 = { diff --git a/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala index b638b0d12..8ddb6896b 100644 --- a/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/LocalHandlerLogic.scala @@ -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 */ /** diff --git a/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala index b4325d743..92f4eebef 100644 --- a/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/MountHandlerLogic.scala @@ -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 => diff --git a/src/main/scala/net/psforever/actors/session/normal/NormalMode.scala b/src/main/scala/net/psforever/actors/session/normal/NormalMode.scala index d6fd141e3..1a88bf9f3 100644 --- a/src/main/scala/net/psforever/actors/session/normal/NormalMode.scala +++ b/src/main/scala/net/psforever/actors/session/normal/NormalMode.scala @@ -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 { diff --git a/src/main/scala/net/psforever/actors/session/normal/TerminalHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/normal/TerminalHandlerLogic.scala index 5b6618562..bf9eb1dc7 100644 --- a/src/main/scala/net/psforever/actors/session/normal/TerminalHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/TerminalHandlerLogic.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/normal/VehicleLogic.scala b/src/main/scala/net/psforever/actors/session/normal/VehicleLogic.scala index f6fe40c83..fdc8c1180 100644 --- a/src/main/scala/net/psforever/actors/session/normal/VehicleLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/VehicleLogic.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/normal/WeaponAndProjectileLogic.scala b/src/main/scala/net/psforever/actors/session/normal/WeaponAndProjectileLogic.scala index 38f398828..05608922b 100644 --- a/src/main/scala/net/psforever/actors/session/normal/WeaponAndProjectileLogic.scala +++ b/src/main/scala/net/psforever/actors/session/normal/WeaponAndProjectileLogic.scala @@ -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 => () } diff --git a/src/main/scala/net/psforever/actors/session/spectator/GalaxyHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/GalaxyHandlerLogic.scala index 7ecff65b9..d3b6abf63 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/GalaxyHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/GalaxyHandlerLogic.scala @@ -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) diff --git a/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala index 2332b5115..806747a5a 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/GeneralLogic.scala @@ -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 = { diff --git a/src/main/scala/net/psforever/actors/session/spectator/LocalHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/LocalHandlerLogic.scala index e0406f564..21d85d7a1 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/LocalHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/LocalHandlerLogic.scala @@ -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 */ /** diff --git a/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala index f5a6caea8..f6c3a4a43 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/MountHandlerLogic.scala @@ -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 => diff --git a/src/main/scala/net/psforever/actors/session/spectator/SpectatorMode.scala b/src/main/scala/net/psforever/actors/session/spectator/SpectatorMode.scala index 2f5647711..b950274db 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/SpectatorMode.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/SpectatorMode.scala @@ -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 { diff --git a/src/main/scala/net/psforever/actors/session/spectator/VehicleLogic.scala b/src/main/scala/net/psforever/actors/session/spectator/VehicleLogic.scala index 355c1fdc5..10fdb8ed6 100644 --- a/src/main/scala/net/psforever/actors/session/spectator/VehicleLogic.scala +++ b/src/main/scala/net/psforever/actors/session/spectator/VehicleLogic.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala index 9ae7677a5..26d1db691 100644 --- a/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/GeneralOperations.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/support/PlayerMode.scala b/src/main/scala/net/psforever/actors/session/support/PlayerMode.scala index 6c5040057..46e7f52ed 100644 --- a/src/main/scala/net/psforever/actors/session/support/PlayerMode.scala +++ b/src/main/scala/net/psforever/actors/session/support/PlayerMode.scala @@ -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 { diff --git a/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala index df53c650e..456e3a237 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionLocalHandlers.scala @@ -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)) + } +} diff --git a/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala index 470db3569..1ccb6bf3f 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionSquadHandlers.scala @@ -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())) diff --git a/src/main/scala/net/psforever/actors/session/support/SessionTerminalHandlers.scala b/src/main/scala/net/psforever/actors/session/support/SessionTerminalHandlers.scala index 21cc9f9d6..347139e6a 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionTerminalHandlers.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionTerminalHandlers.scala @@ -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 diff --git a/src/main/scala/net/psforever/actors/session/support/VehicleOperations.scala b/src/main/scala/net/psforever/actors/session/support/VehicleOperations.scala index d56107506..f23c61d38 100644 --- a/src/main/scala/net/psforever/actors/session/support/VehicleOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/VehicleOperations.scala @@ -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.
*
@@ -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. diff --git a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala index ca3f4a125..47a87c748 100644 --- a/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/ZoningOperations.scala @@ -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 )