Pawn PlayerState reference on client is sometimes NULL

We were seeing this relatively consistently in a test project, and I was able to track down what I believe is reason for some of calls not working as expected.

short version of the “fix” is to test for GetPawn() == nullptr in ReceivedSpectatorClass() before calling BeginSpectatingState(). That way only on initial connect does it cause a problem. In our case, this fixed problem. We also had a second potential fix that involved rebuilding PlayerState pointer inside of client reset when it acknowledged pawn. This however still caused Pawn value to thrash by switching to a spectator pawn and back.

long version of what was happening, based on my testing, was as follows. Note that our Pawn class was loaded via LoadClass and was not loaded by GameMode’s default values.

  1. Net Player joins
  2. Player pawn class is loaded via GetDefaultPawnClassForController
  3. Player pawn is spawned via SpawnDefaultPawnFor
  4. ClientRestart() is called inside of Server’s Possess
  5. ClientRestart() sends a null for NewPawn since PackageMap has not ack’d pawn class (blueprint class)
  6. ClientRestart() happens on client, sets to NULL pawn, does not enter Playing state since Pawn is null
  7. Controller’s Pawn replicates, calls OnRep_Pawn, sets Pawn
  8. Pawn’s PlayerState replicates, calls OnRep_PlayerState, sets PlayerState
  9. GameState’s SpectatingClass replicates, calls OnRep_SpectatorClass, which calls ReceivedSpectatorClass, which is forwarded to all local player controllers
  10. Since state is Spectating because ClientRestart() failed, and SpectatingPawn is null, it calls BeginSpectatingState()
  11. BeginSpectatingState() sees that Pawn variable is set, calls Unpossess()
  12. Unpossess clears Pawn’s PlayerState variable on client
  13. ClientRestart() is called again on a retry with correct Pawn value.
  14. ClientRestart() uses SetPawn rather than possess, which does NOT set PlayerState locally
  15. ClientRestart() AcknowledgesPawn
  16. ClientRestart() changes state to Playing