24 Jul 2023

What happens when Player exits a multiplayer game

Gaida San
By Gaida San Unreal Engine Development Lead

Remember to unpossess the Pawn if you want to keep it after the Player leaves the game.

Pic 1. When Player leaves the game, Unreal destroys his possessed Pawn by default

Disappearing cars

Have you ever wondered what happens to the Player’s Pawn when Player logs out of the multiplayer game? You are right – it disappears. That’s ok if the Pawn is Player’s character. If the physical player is no longer there, we don’t want to keep his character. 

But what if the Player possessed some other Pawn during the gameplay, i.e. a car that is a team resource? When such a Player rage-quits or his game crashes, Unreal will remove his Player Controller together with the possessed Pawn. The team is now robbed of a car.

Fortunately, the fix is very easy: just unpossess the Pawn. You need to do it in a very specific place though – in Player Controller’s overridden Destroyed() function. Here, the Engine notifies your code that Player Controller is about to be destroyed. You need to unpossess before the call to the parent, otherwise Unreal will mark the Pawn as PendingKill and the game is over. Even if you unpossess later on, the Garbage Collector will remove the Pawn.

Pic 2. Vehicle Pawn is marked as PendingKill

Investigating call stack

Now, let’s see what exactly Unreal does when Player logs out of the game unexpectedly. We will start at the bottom of the Server call stack and go up all the way to the PlayerController::Destroyed() function:

  1. At the beginning, Unreal runs the game loop through UWorld::Tick() and notifies all his components that they should tick as well.
  2. Among others, the UNetDriver and UIpNetDriver receive the tick and update their state. The UIpNetDriver detects that the connection to Client is unresponsive and begins the cleanup process.
  3. The call goes through UIpConnection to UNetConnection::CleanUp() which begins destroying the connection which also includes destroying the owning Actor.
  4. Then Unreal calls the APlayerController::OnNetCleanup() that begins the destroying process. If you want to do something before that, Unreal allows you to override this function.
  5. AActor::Destroy() and UWorld::DestroyActor() (located in LevelActor.cpp) are called. The latter does the main removal processing, marking the Player Controller as PendingKill for the Garbage Collector. 
  6. Fortunately, in the middle of this process, we have a call to PlayerController::Destroyed() which we can override in our custom Player Controller. It’s here where we have last chance to unpossess the Pawn before the Player Controller will vanish. Why?
  7. When Server goes further to the PlayerController::Destroyed() it executes the APlayerController::PawnLeavingGame(), and this function marks the possessed Pawn as PendingKill. It’s too late to disconnect Pawn from the Controller after that – it will be destroyed by the Garbage Collector anyway.
Vid 1. PlayerController::Destroyed() call stack after Player left the game

Please note that unpossessing the Pawn using the Destroyed() function or OnDistroyed() dispatcher in BP is too late as well since there is a call at the very end in the Actor base class in AActor::Destroyed(). The PendingKill mark has already been attached to the PlayerController and Pawn at this point.

If you unpossess the Pawn at the right moment, the car stays in the game:

Pic 3. The car is not removed from the game when Player logs out

Final thoughts

In this article I used Epic’s City Sample project. It’s not prepared for multiplayer so I had to hack it a little.

I had to make ACitySamplePlayerController::TryToInteract() an RPC, because I need to pass the CurrentVisibleInteractionComponent to Server for the interaction to work.

Pic 4. I changed the ACitySamplePlayerController::TryToInteract() to a Server RPC

I had to remove MassAgent Component in the Player Character and the car because it crashes the game on end play:

Pic 5. Removed unused MassAgent Component

Lastly, I had to go to the BP_CitySamplePlayerCharacter -> CapsuleComponent and disable all collisions related to Vehicle:

Pic 6. Ignored Vehicle collision in the BP_CitySamplePlayerCharacter

Otherwise, I got something like this:

Pic 7. Issues with collision when entering the car

I ran my tests in the Listen Server mode, but this solution will work on Dedicated Servers without any issues.

I hope this little article helped you understand what happens when the Player leaves during the game.

Gaida San
By Gaida San Unreal Engine Development Lead
SIRBart

Call The Knights!

    Table of contents