From 92ada951e5db9f6678b2e25745acbcfb261e1c32 Mon Sep 17 00:00:00 2001 From: "Jason_DiDonato@yahoo.com" Date: Sun, 31 Oct 2021 19:24:21 -0400 Subject: [PATCH 1/2] re-use old locker entity during cases of player relog to fix registration issues --- .../scala/net/psforever/actors/session/AvatarActor.scala | 8 +++++++- .../scala/net/psforever/actors/session/SessionActor.scala | 6 +++--- .../net/psforever/objects/locker/LockerEquipment.scala | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala index b4c9cd46a..aee288838 100644 --- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala +++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala @@ -366,13 +366,19 @@ class AvatarActor( result.onComplete { case Success((loadouts, implants, certs, locker)) => + val validatedLocker = if (avatar.locker.HasGUID || avatar.locker.Inventory.Size > 0) { + //if locker shows indication of being previously used, this player is rejoining an active session + avatar.locker + } else { + locker + } avatar = avatar.copy( loadouts = loadouts, // make sure we always have the base certifications certifications = certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications, implants = implants.map(implant => Some(Implant(implant.toImplantDefinition))).padTo(3, None), - locker = locker + locker = validatedLocker ) staminaRegenTimer.cancel() diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index 73d67cd58..55739fb67 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -1418,7 +1418,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //rejoin current avatar/player log.info(s"LoginInfo: player $playerName is alive") deadState = DeadState.Alive - session = session.copy(player = p) + session = session.copy(player = p, avatar = a) persist() setupAvatarFunc = AvatarRejoin avatarActor ! AvatarActor.ReplaceAvatar(a) @@ -1428,7 +1428,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con //convert player to a corpse (unless in vehicle); automatic recall to closest spawn point log.info(s"LoginInfo: player $playerName is dead") deadState = DeadState.Dead - session = session.copy(player = p) + session = session.copy(player = p, avatar = a) persist() player.Zone = inZone HandleReleaseAvatar(p, inZone) @@ -1449,7 +1449,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con tplayer.Release //for proper respawn tplayer.Zone = inZone tplayer - } + }, avatar = a ) avatarActor ! AvatarActor.ReplaceAvatar(a) avatarActor ! AvatarActor.LoginAvatar(context.self) diff --git a/src/main/scala/net/psforever/objects/locker/LockerEquipment.scala b/src/main/scala/net/psforever/objects/locker/LockerEquipment.scala index cded00c94..b69fc1e58 100644 --- a/src/main/scala/net/psforever/objects/locker/LockerEquipment.scala +++ b/src/main/scala/net/psforever/objects/locker/LockerEquipment.scala @@ -8,7 +8,7 @@ import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID} /** * A wrapper class that allows a player-facing locker component - * to be treated standard `Equipment` object in the player's fifth (sixth) slot. + * to be treated like a standard `Equipment` object in the player's fifth (sixth) slot. * (The opposite is not true - the equipment does not get treated as a locker component.) * During packet conversion and registration and general access in terms of holsters or "equipment slots", * the component may be be treated the same as other existing objects at the same level. From 6d61ff034af54f821b716947a843a90268bf1d9d Mon Sep 17 00:00:00 2001 From: "Jason_DiDonato@yahoo.com" Date: Mon, 1 Nov 2021 10:44:18 -0400 Subject: [PATCH 2/2] streamlined messaging; no longer query database if no need to query database exists --- .../actors/session/AvatarActor.scala | 14 ++++------- .../actors/session/SessionActor.scala | 24 +++++++++++++------ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/AvatarActor.scala b/src/main/scala/net/psforever/actors/session/AvatarActor.scala index aee288838..78bc24582 100644 --- a/src/main/scala/net/psforever/actors/session/AvatarActor.scala +++ b/src/main/scala/net/psforever/actors/session/AvatarActor.scala @@ -366,30 +366,26 @@ class AvatarActor( result.onComplete { case Success((loadouts, implants, certs, locker)) => - val validatedLocker = if (avatar.locker.HasGUID || avatar.locker.Inventory.Size > 0) { - //if locker shows indication of being previously used, this player is rejoining an active session - avatar.locker - } else { - locker - } avatar = avatar.copy( loadouts = loadouts, // make sure we always have the base certifications certifications = certs.map(cert => Certification.withValue(cert.id)).toSet ++ Config.app.game.baseCertifications, implants = implants.map(implant => Some(Implant(implant.toImplantDefinition))).padTo(3, None), - locker = validatedLocker + locker = locker ) - staminaRegenTimer.cancel() staminaRegenTimer = defaultStaminaRegen() replyTo ! AvatarLoginResponse(avatar) - case Failure(e) => log.error(e)("db failure") + case Failure(e) => + log.error(e)("db failure") } Behaviors.same case ReplaceAvatar(newAvatar) => replaceAvatar(newAvatar) + staminaRegenTimer.cancel() + staminaRegenTimer = defaultStaminaRegen() Behaviors.same case AddFirstTimeEvent(event) => diff --git a/src/main/scala/net/psforever/actors/session/SessionActor.scala b/src/main/scala/net/psforever/actors/session/SessionActor.scala index 55739fb67..7dd530d4e 100644 --- a/src/main/scala/net/psforever/actors/session/SessionActor.scala +++ b/src/main/scala/net/psforever/actors/session/SessionActor.scala @@ -431,9 +431,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con accountPersistence ! AccountPersistenceService.Login(avatar.name) case AvatarActor.AvatarLoginResponse(avatar) => - session = session.copy(avatar = avatar) - Deployables.InitializeDeployableQuantities(avatar) - cluster ! ICS.FilterZones(_ => true, context.self) + avatarLoginResponse(avatar) case packet: PlanetSideGamePacket => handleGamePkt(packet) @@ -1390,7 +1388,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con deadState = DeadState.RespawnTime session = session.copy(player = new Player(avatar)) - //ay-coordinates indicate sanctuary spawn bias: + //xy-coordinates indicate sanctuary spawn bias: player.Position = math.abs(scala.util.Random.nextInt() % avatar.name.hashCode % 4) match { case 0 => Vector3(8192, 8192, 0) //NE case 1 => Vector3(8192, 0, 0) //SE @@ -1422,7 +1420,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con persist() setupAvatarFunc = AvatarRejoin avatarActor ! AvatarActor.ReplaceAvatar(a) - avatarActor ! AvatarActor.LoginAvatar(context.self) + avatarLoginResponse(a) case (Some(a), Some(p)) => //convert player to a corpse (unless in vehicle); automatic recall to closest spawn point @@ -1433,7 +1431,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con player.Zone = inZone HandleReleaseAvatar(p, inZone) avatarActor ! AvatarActor.ReplaceAvatar(a) - avatarActor ! AvatarActor.LoginAvatar(context.self) + avatarLoginResponse(a) case (Some(a), None) => //respawn avatar as a new player; automatic recall to closest spawn point @@ -1452,7 +1450,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con }, avatar = a ) avatarActor ! AvatarActor.ReplaceAvatar(a) - avatarActor ! AvatarActor.LoginAvatar(context.self) + avatarLoginResponse(a) case _ => //fall back to sanctuary/prior? @@ -9378,6 +9376,18 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con heightLast = zHeight } + /** + * During login, when the avatar is set, the response code sets up session and deployable toolbox stats. + * Immediately contact the interstellar cluster to deal with zoning conditions. + * Only call this once during login and never any time after that. + * @param avatar the avatar being set as the current one belonging to this session + */ + def avatarLoginResponse(avatar: Avatar): Unit = { + session = session.copy(avatar = avatar) + Deployables.InitializeDeployableQuantities(avatar) + cluster ! ICS.FilterZones(_ => true, context.self) + } + def failWithError(error: String) = { log.error(error) middlewareActor ! MiddlewareActor.Teardown()