Unreal's gameplay framework took me an embarrassingly long time to internalise. Not because any one class is hard, but because the documentation describes them in isolation and the whole thing only makes sense once you see who is allowed to talk to whom, and who survives what. I spent a fortnight putting state in the wrong place before the shape clicked, so this is the explanation I wish someone had handed me.
The core question the framework answers is: where does a given piece of state belong? Get that right and the rest follows. Get it wrong and you end up replicating a variable that should have been server-authoritative, or storing per-player data on something every player shares.
The cast, in order of lifetime
GameMode lives only on the server, and only for the duration of a level. It is the rules referee: who can join, what the win condition is, where players spawn. Clients never see it. If you put scoreboard state here, the clients have no way to read it, which is a mistake I made early and could not understand until I learned the visibility rules.
GameState is the replicated counterpart. It exists on the server and every client, and it is where shared, world-level state belongs: the match timer, the team scores, the current round. If everyone in the game needs to agree on a number, it goes here.
PlayerController is the bridge between a human and the game. There is one per player, it persists across Pawn deaths, and it is where input lives. The Pawn is the body; the controller is the will driving it.
// Possessing a pawn from the controller
void AMyPlayerController::OnRestart()
{
APawn* NewBody = GetWorld()->SpawnActor<AMyCharacter>(SpawnPoint);
Possess(NewBody);
}
Pawn (and Character, its movement-enabled subclass) is the thing in the world that gets possessed. It is disposable. When the player dies, the Pawn is destroyed and a new one is spawned and possessed, but the controller carries on. This is the distinction that fixes most beginner confusion: anything that should outlive death, ammo reserves, score, loadout choices, does not belong on the Pawn.
PlayerState rounds it out. One per player, replicated to everyone, surviving Pawn destruction. Names, scores, ping, the data other players legitimately need to see about you. It is the public record card for a player, and it is the right home for the stuff people instinctively try to cram onto the controller or the character.
The rule that makes it stick
Ask two questions of every variable. Does it need to survive the Pawn dying? Does it need to be visible to other clients? Those two answers route you to exactly one class. Per-player and private to the server goes near the controller. Per-player and public goes on PlayerState. World-wide and public goes on GameState. Server-only rules go on GameMode.
It is not glamorous, and it does not feel like a revelation when you read it. But once the routing is automatic, you stop fighting the framework and start using it, and a surprising amount of multiplayer plumbing just works because you finally put the data where Epic always intended it to live.