What is the proper way to handle waiting for a reference to be valid?

I have a scenario where I am setting some values on a connecting player pawn. However, sometimes this code is called before the pawn exists in the world. I can easily check if the pawn reference is valid or not but I need to keep checking if it’s valid asynchronously and run the code when it finally is valid.

In blueprints, I would have this crude solution of checking if it’s valid. If it’s not valid, delay for .2 seconds then check again.

In C++, I have found asynchronous tasks which seems like overkill for what I need. I could also run a timer every .2 seconds to check if the reference is valid and run the code (then pause the timer) if it is. But both of these seem like over-engineered systems to handle this.

I’m sure people run into this issue all the time and I’m wondering what you guys have done to get around this

For checking on the server, look into APlayerController::OnPossessed(). That fires on the server when the pawn is possessed by the controller.

There’s various points in AGameMode, APlayerController, and AGameState that I know of where you could perform checks for the pawn when the player connects.

Just spent quite a few hours dealing with this last week. I also do this to specify my own spawn parameters as the Engines RestartPlayer’s settings allow the the pawn to not spawn due to collisions.

Override GameModeBase::RestartPlayer(AController* Player)

Loads stats into PlayerState (my method)

  • Gameplay Ability System resides here
    Calls GameModeBase::GetDefaultPawnClassForController (which is also overriden)
    Spawns the pawn (the location and rotation information was retrieved at the Load Stats call)
    Calls additional setup method on the pawn
    Calls GameModeBase::FinishRestartPlayer (not overriden)

At that point, I’d just recommend walking through the connection process starting from when your client attempts to connect all the way to your player being spawned in. You’d get a real feel for where you should put your initialization code.

Off-topic, but why do you keep your ASC in the PlayerState? I used it that way for some time and found it to be an inconvenience with no benefit compared to just plopping it on the character. Made possessing other characters a bit awkward as well.

Yah, I spent some time tracing through the Engine on the connect and that is what led to my current solution. Felt RestartPlayer was the best place to hook in. I copied most of what they had in their RestartPlayer into mine.

Respawning will avoid trips to the database to reload stats and cost tables is the main reason. Yes, it is inconvenient to remember the PlayerState is the actor GAS sees for PC and the NPC pawn class for NPCs, but I have that sorted out in the key places and it is not such an issue now.

At this point, I don’t see the player possessing other pawns as a gameplay mechanic.