Inactive PlayerState code seems faulty

Hello there,

so I’ve been wondering why some of my PlayerState code isn’t working for a Player that quickly reconnects after leaving the game, and while I’m very much aware of InactivePlayerStates and that UE4 keeps track of them for 300 seconds by default, I don’t understand the code behind Add and Finding the PlayerState.

First of all, when the InactivePlayerState is added, it happens before I can do any cleanup. In my case, that means it gets duplicated before the PlayerState is removed from its TeamState in EndPlay. So the duplicated PlayerState now has a Team in it that actually doesn’t list the PlayerState itself inside of it.

And then, I don’t see any call to SetInactive inside of the AddInactivePlayerState function. It’s not marked as Inactive, which makes it pretty hard to actually handle that, nonreplicating, PlayerState while it’s inactive.
I could override the Function in my own GameMode and mark it Inactive, but I would love to know why this is not done in the first place.

After that, I got hit by the FindInactivePlayerState code. The finding is straightforward, but why on earth is the NEWLY SPAWNED PlayerState called “OldPlayerState” and why is that one then marked as Inactive?
And OverrideWith then allows me to do actually what? Override the OLD PlayerState with the NEW PlayerState?
Because we call OverrideWith on the INACTIVE PlayerState, passing in the one that just got freshly spawned for the newly connected Player. What should I override here? Is it just to get the INACTIVE PlayerState up to speed with the new Player?

And finally, where should I make sure that the INACTIVE PlayerState, which still has the Team pointer set, is properly readded to its Team? In OverrideWith? Probably not. Maybe in OnReactivated?

I don’t know why, but I struggle to understand the logic behind this, which makes it look half-broken to me.

Kind regards,
Cedric

TriumphST

Hi, I just stumbled upon the same issue. I struggle to understand the logic here. Especially I can see that if a client disconnects, on the server, AGameMode::Logout function first calls AGameMode::AddInactivePlayer, which I understand that wants to store the player state in the inactive array if the player reconnects, but as you already mentioned, it does not call SetInactive(true), moreover, it duplicates the APlayerState first, APlayerState in its PostInitializeComponents function registers again to AGameStateBase as active player, and right after duplication, it removes the duplicated player state …

void AGameMode::AddInactivePlayer(APlayerState* PlayerState, APlayerController* PC)
{

...
APlayerState* const NewPlayerState = PlayerState->Duplicate();
if (NewPlayerState)
{
// Side effect of Duplicate() adding PlayerState to PlayerArray (see APlayerState::PostInitializeComponents)
GameState->RemovePlayerState(NewPlayerState);

...

}

There even is a check in AGameStateBase::AddPlayerState if the PlayerState is inactive, but it does not do anything since PlayerState->IsInactive() is always false.

void AGameStateBase::AddPlayerState(APlayerState* PlayerState)
{
    // Determine whether it should go in the active or inactive list
    if (!PlayerState->IsInactive())
    {
       // make sure no duplicates
       PlayerArray.AddUnique(PlayerState);
    }
}

I was implementing some logic when a player state was added and removed on AGameState, and this was causing confusing behaviour because of this.

Expected behaviour:

  1. Client disconnects
  2. AGameStateBase::RemovePlayerState(diconnectingPlayerState)

Actual behaviour:

  1. Client disconnects
  2. AGameStateBase::AddPlayerState(diconnectingPlayerState duplicate as active state)
  3. AGameStateBase::RemovePlayerState(diconnectingPlayerState duplicate as active state)
  4. AGameStateBase::RemovePlayerState(diconnectingPlayerState)

UE version - 5.7.4

Seems like this part of the code could use some refactoring.