Gameplay framework
The gameplay framework is the set of base classes Unreal spawns and wires together to run a
game. Choosing the right class for each piece of logic is the single most important design
decision in UE gameplay code.
When to use this skill
- Creating a new game mode, game state, player controller, pawn, player state, or HUD class.
- Implementing player login, spawn, respawn, or possession logic.
- Deciding where a piece of state lives (server-only vs replicated vs per-player vs cross-level).
- Setting up default classes in C++ and exposing them to designers via Blueprint subclasses.
- Wiring the spawn/possession flow or implementing a match-state machine.
The classes and their roles
| Class |
Lives where |
Core responsibility |
Replicated? |
UGameInstance |
one per game, persists across level loads |
app-lifetime state, subsystems, online sessions |
no |
AGameModeBase |
server only |
rules, default classes, login/spawn flow |
no |
AGameMode |
server only |
adds match-state machine on top of Base |
no |
AGameStateBase |
server + all clients |
game-wide visible state (score, timer, match phase) |
yes |
AGameState |
server + all clients |
adds MatchState replication to Base |
yes |
APlayerController |
server + owning client |
input, camera, UI, possession bridge |
to owner only |
APlayerState |
server + all clients |
per-player replicated data (name, score, team) |
yes |
APawn |
server + clients |
physical avatar in the world |
yes |
ACharacter |
server + clients |
bipedal pawn with movement, capsule, skeletal mesh |
yes |
AHUD |
owning client only |
legacy canvas overlay (prefer UMG for real UI) |
local |
Class hierarchy (verified in 5.8 source):
AGameModeBase : public AInfo (GameModeBase.h:47); AGameMode : public AGameModeBase (GameMode.h:35).
AGameStateBase : public AInfo (GameStateBase.h:32); AGameState : public AGameStateBase (GameState.h:16).
APlayerController : public AController (PlayerController.h:262); AController : public AActor (Controller.h:40).
APawn : public AActor (Pawn.h:43); ACharacter : public APawn (Character.h:338).
APlayerState : public AInfo (PlayerState.h:41); AHUD : public AActor (HUD.h:36).
UGameInstance : public UObject, public FExec (Engine/GameInstance.h:151).
Base vs non-base: AGameModeBase and AGameStateBase are the lean modern defaults.
AGameMode/AGameState add the match-state machine (MatchState, WaitingToStart,
InProgress, WaitingPostMatch, …) inherited from UE3-era multiplayer. Start from *Base
unless you need match states.
Ownership and relationship map
UGameInstance (persists across levels)
└── UWorld (current level)
├── AGameModeBase (server only — rules and spawning)
├── AGameStateBase (replicated — global visible state)
│ └── PlayerArray: TArray<APlayerState*> (one per connected player, replicated)
└── per player:
APlayerController ──possesses──> APawn / ACharacter
│ └── movement, mesh, collision components
└── PlayerState (also in GameState.PlayerArray)
Key accessors verified in 5.8 source:
GetWorld()->GetGameState<T>() — replicated on all machines.
GetWorld()->GetAuthGameMode<T>() — server only; returns null on clients.
GetGameInstance<T>() — available via any UObject with a valid outer chain.
AController::GetPawn() (Controller.h:233); APawn::GetController() (Pawn.h:264).
APawn::GetPlayerState<T>() (Pawn.h:193); AController::PlayerState (Controller.h:50).
Server spawn and login flow
On the server, AGameModeBase drives the sequence when a player joins:
InitGame (GameModeBase.h:62) — called before any actor PreInitializeComponents; spawn helper classes here.
PreLogin (GameModeBase.h:293) — reject players by setting ErrorMessage before any state is allocated.
Login (GameModeBase.h:323) — creates and returns the APlayerController; spawns APlayerState.
PostLogin(PC) (GameModeBase.h:326) — first safe place to call replicated functions on the PC.
HandleStartingNewPlayer(PC) (GameModeBase.h:361) — override in Blueprint or C++ to control what happens next.
RestartPlayer(PC) (GameModeBase.h:435) → FindPlayerStart → SpawnDefaultPawnAtTransform → PC->Possess(Pawn).
Full login flow with seamless travel and OnPostLogin details:
references/init-and-login-flow.md.
Possession
AController::Possess(APawn*) is final in 5.8; override OnPossess instead
(Controller.h:299). The symmetric unpossess override is OnUnPossess (Controller.h:306).
// Override OnPossess to react to possession — NOT Possess() which is final
void AMyController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
// Safe to access InPawn here; PlayerState is already assigned
}
// On the pawn side, PossessedBy fires when a controller takes control
void AMyPawn::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
// Bind abilities, movement, etc. that depend on the controller
}
A controller can possess different pawns over its lifetime (death/respawn, vehicle enter/exit).
Do not store gameplay state on the pawn that must survive across possessions — use PlayerState
or PlayerController instead.
Setting default classes in C++
// MyGameMode.h
UCLASS()
class MYGAME_API AMyGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AMyGameMode();
};
// MyGameMode.cpp
#include "MyGameMode.h"
#include "MyCharacter.h"
#include "MyPlayerController.h"
#include "MyPlayerState.h"
#include "MyGameState.h"
AMyGameMode::AMyGameMode()
{
DefaultPawnClass = AMyCharacter::StaticClass();
PlayerControllerClass = AMyPlayerController::StaticClass();
PlayerStateClass = AMyPlayerState::StaticClass();
GameStateClass = AMyGameState::StaticClass();
// HUDClass — set if you use legacy AHUD; omit for pure UMG
}
These five TSubclassOf<> properties are declared on AGameModeBase with
EditAnywhere, NoClear, BlueprintReadOnly (GameModeBase.h:87–108). Assign them in the
constructor so Blueprint subclasses can still override them in Blueprints editor defaults.
Then wire the GameMode per-project (Project Settings → Maps & Modes →
DefaultGameMode/GlobalDefaultGameMode in DefaultEngine.ini
[/Script/EngineSettings.GameMapsSettings]), or per-level (World Settings → GameMode Override).
Where does my logic go? (decision guide)
| Logic |
Belongs in |
| Rules, win/lose, who spawns where, scoring authority |
AGameModeBase — server only |
| State everyone must see (scores, timer, match phase) |
AGameStateBase / AGameState |
| Per-player replicated facts (name, team, kills) |
APlayerState |
| Input handling, camera, opening menus, player intent |
APlayerController |
| Physical movement, abilities of the avatar |
APawn / ACharacter + components |
| Cross-level or app-lifetime (save game, audio settings, online session) |
UGameInstance / a UGameInstanceSubsystem |
If it must survive a level load → UGameInstance or UGameInstanceSubsystem
(see ue-subsystems). If only the server may decide it → AGameModeBase.
GameInstance and subsystems
UGameInstance is created once on engine launch and destroyed when the application exits,
surviving all level transitions. Override Init (GameInstance.h:217) and
Shutdown (GameInstance.h:224) for setup/teardown. Access it from any actor via
GetGameInstance<UMyGameInstance>().
For modular, dependency-isolated systems with the same lifetime:
// Subsystem declared as UCLASS(), auto-created by GameInstance
class UMyOnlineSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
};
// Access from any actor
UMyOnlineSubsystem* Sub = GetGameInstance()->GetSubsystem<UMyOnlineSubsystem>();
GetSubsystem<T>() is declared on UGameInstance (GameInstance.h:440). See ue-subsystems.
PlayerState — per-player replicated data
APlayerState is created by Login and added to AGameStateBase::PlayerArray. It replicates
to all clients, making it the correct place for data every machine needs about each player.
// MyPlayerState.h
UCLASS()
class MYGAME_API AMyPlayerState : public APlayerState
{
GENERATED_BODY()
public:
UPROPERTY(Replicated, BlueprintReadOnly, Category=Player)
int32 TeamIndex = 0;
virtual void GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};
Built-in replicated fields on APlayerState: Score (getter GetScore, setter SetScore,
PlayerState.h:312/318), PlayerNamePrivate (accessed via GetPlayerName/SetPlayerName,
PlayerState.h:235/228), PlayerId, CompressedPing, bIsSpectator, bIsABot.
Network roles
AGameModeBase exists only on the server; never put client logic there.
AGameStateBase/APlayerState are replicated — read on any machine, only write on server.
APlayerController replicates to its owning client only — good for client RPCs and UI.
APawn/ACharacter replicate to all clients; HasAuthority() determines who may change state.
- Use
HasAuthority() or GetLocalRole() == ROLE_Authority to branch server vs client.
See ue-networking-and-replication for property/RPC mechanics.
C++ base + Blueprint subclass pattern
The idiomatic setup:
- Put logic, replicated state, and core API in C++ (
AMyGameMode, AMyCharacter, …).
- Expose designer-facing defaults via Blueprint subclasses (
BP_GameMode, BP_Character, …).
- Set the BP subclasses as defaults in Project Settings or World Settings.
- Use
UPROPERTY(EditDefaultsOnly) for numbers/assets designers should tweak without requiring
recompile. See ue-blueprint-cpp-integration.
Gotchas
GetAuthGameMode() on a client returns null; always guard with HasAuthority().
Possess is final since UE 4.22; override OnPossess/OnUnPossess (Controller.h:299/306).
- Persistent state on the Pawn is lost on death/respawn; use
APlayerState or APlayerController.
- Possession ≠ spawn: a controller can possess different pawns over time; don't assume 1:1 lifetime.
AGameMode vs AGameModeBase mismatch: MatchState machinery only exists in AGameMode;
don't reference it from an AGameModeBase subclass.
DispatchPostLogin deprecated in 5.6: override OnPostLogin(AController*) instead
(GameModeBase.h:334 — note the UE_DEPRECATED annotation at :329).
- HUD for modern UI:
AHUD is legacy canvas drawing; build real UI with UMG (see ue-umg-and-slate).
APlayerState outlives the pawn: the state persists in GameState.PlayerArray even when
the pawn is destroyed; that is by design so scores survive death.
- GameInstance is not replicated: the server and each client each have their own independent
instance. Do not use it as a shared-state store in multiplayer.
Version notes
AGameModeBase introduced in UE 4.14; older projects may subclass AGameMode directly.
Possess/UnPossess marked virtual final in UE 4.22; use OnPossess/OnUnPossess.
DispatchPostLogin deprecated in UE 5.6; the replacement is OnPostLogin (protected virtual).
- The framework is stable across UE 5.x; line numbers in citations drift between patch releases
but header paths and class names are stable.
References & source material
Engine source (UE 5.8, under Engine/Source/Runtime/Engine/Classes/):
GameFramework/GameModeBase.h — AGameModeBase:47, InitGame:62, InitGameState:69,
DefaultPawnClass:108, PlayerControllerClass:96, PlayerStateClass:100, GameStateClass:92,
HUDClass:104, PreLogin:293, Login:323, PostLogin:326, OnPostLogin:334,
HandleStartingNewPlayer:361, RestartPlayer:435, SpawnDefaultPawnAtTransform:461,
ChoosePlayerStart:405, GetDefaultPawnClassForController:84.
GameFramework/GameMode.h — AGameMode:35, MatchState namespace:16, GetMatchState:43,
StartMatch:51, EndMatch:55, SetMatchState:72.
GameFramework/GameStateBase.h — AGameStateBase:32, PlayerArray:55, GetServerWorldTimeSeconds:72,
HasBegunPlay:76, AddPlayerState:112, RemovePlayerState:115.
GameFramework/GameState.h — AGameState:16, MatchState:35, ElapsedTime:57.
GameFramework/Controller.h — AController:40, PlayerState:50, GetPawn():233,
Possess (final):284, UnPossess (final):288, OnPossess:299, OnUnPossess:306.
GameFramework/PlayerController.h — APlayerController:262, PlayerCameraManager:287,
MyHUD:280, SetInputMode:1649, SetShowMouseCursor:2168.
GameFramework/Pawn.h — APawn:43, GetController():264, GetPlayerState<T>():193,
PossessedBy:374, UnPossessed:381.
GameFramework/Character.h — ACharacter:338.
GameFramework/PlayerState.h — APlayerState:41, Score:49, GetScore:312, SetScore:318,
PlayerNamePrivate:162, GetPlayerName:235, SetPlayerName:228.
GameFramework/HUD.h — AHUD:36, PlayerOwner:42, bShowHUD:50.
Engine/GameInstance.h — UGameInstance:151, Init:217, Shutdown:224,
GetSubsystem<T>():440.
Official docs (UE 5.8, all fetched and confirmed live):
Deep-dive references in this skill:
- references/gamemode-and-state.md — GameMode class
hierarchy, match-state machine, GameState replication, setting default classes per-map.
- references/controllers-and-pawns.md — controller
lifecycle, possession API, PlayerController responsibilities, Pawn vs Character choice,
PlayerState data design.
- references/init-and-login-flow.md — step-by-step server
login/spawn sequence, seamless travel, respawn patterns,
HandleStartingNewPlayer override
points.
Cross-references: ue-actors-and-components (AActor lifecycle), ue-character-and-movement
(ACharacter / UCharacterMovementComponent detail), ue-subsystems (UGameInstanceSubsystem),
ue-networking-and-replication (replication mechanics), ue-blueprint-cpp-integration
(exposing C++ to designers).
1---2name: ue-gameplay-framework3description: Implement Unreal's gameplay framework in C++ — GameInstance, AGameModeBase/AGameMode, AGameStateBase/AGameState, APlayerController, APawn/ACharacter, APlayerState, and AHUD — including the server-only spawn/login flow, possession, controller-pawn lifecycle, and which class each piece of logic belongs in. Use when setting up game rules, default pawn/controller classes, player login/spawn/possession, replicated game or player state, match-state machines, respawn logic, or deciding "where does this code live?"4---56# Gameplay framework78The gameplay framework is the set of base classes Unreal spawns and wires together to run a9game. Choosing the *right* class for each piece of logic is the single most important design10decision in UE gameplay code.1112## When to use this skill1314- Creating a new game mode, game state, player controller, pawn, player state, or HUD class.15- Implementing player login, spawn, respawn, or possession logic.16- Deciding where a piece of state lives (server-only vs replicated vs per-player vs cross-level).17- Setting up default classes in C++ and exposing them to designers via Blueprint subclasses.18- Wiring the spawn/possession flow or implementing a match-state machine.1920## The classes and their roles2122| Class | Lives where | Core responsibility | Replicated? |23|---|---|---|---|24| `UGameInstance` | one per game, persists across level loads | app-lifetime state, subsystems, online sessions | no |25| `AGameModeBase` | **server only** | rules, default classes, login/spawn flow | no |26| `AGameMode` | **server only** | adds match-state machine on top of Base | no |27| `AGameStateBase` | server + all clients | game-wide visible state (score, timer, match phase) | yes |28| `AGameState` | server + all clients | adds `MatchState` replication to Base | yes |29| `APlayerController` | server + owning client | input, camera, UI, possession bridge | to owner only |30| `APlayerState` | server + all clients | per-player replicated data (name, score, team) | yes |31| `APawn` | server + clients | physical avatar in the world | yes |32| `ACharacter` | server + clients | bipedal pawn with movement, capsule, skeletal mesh | yes |33| `AHUD` | owning client only | legacy canvas overlay (prefer UMG for real UI) | local |3435Class hierarchy (verified in 5.8 source):36- `AGameModeBase : public AInfo` (`GameModeBase.h`:47); `AGameMode : public AGameModeBase` (`GameMode.h`:35).37- `AGameStateBase : public AInfo` (`GameStateBase.h`:32); `AGameState : public AGameStateBase` (`GameState.h`:16).38- `APlayerController : public AController` (`PlayerController.h`:262); `AController : public AActor` (`Controller.h`:40).39- `APawn : public AActor` (`Pawn.h`:43); `ACharacter : public APawn` (`Character.h`:338).40- `APlayerState : public AInfo` (`PlayerState.h`:41); `AHUD : public AActor` (`HUD.h`:36).41- `UGameInstance : public UObject, public FExec` (`Engine/GameInstance.h`:151).4243**Base vs non-base:** `AGameModeBase` and `AGameStateBase` are the lean modern defaults.44`AGameMode`/`AGameState` add the match-state machine (`MatchState`, `WaitingToStart`,45`InProgress`, `WaitingPostMatch`, …) inherited from UE3-era multiplayer. Start from `*Base`46unless you need match states.4748## Ownership and relationship map4950```51UGameInstance (persists across levels)52└── UWorld (current level)53 ├── AGameModeBase (server only — rules and spawning)54 ├── AGameStateBase (replicated — global visible state)55 │ └── PlayerArray: TArray<APlayerState*> (one per connected player, replicated)56 └── per player:57 APlayerController ──possesses──> APawn / ACharacter58 │ └── movement, mesh, collision components59 └── PlayerState (also in GameState.PlayerArray)60```6162Key accessors verified in 5.8 source:63- `GetWorld()->GetGameState<T>()` — replicated on all machines.64- `GetWorld()->GetAuthGameMode<T>()` — **server only**; returns null on clients.65- `GetGameInstance<T>()` — available via any `UObject` with a valid outer chain.66- `AController::GetPawn()` (`Controller.h`:233); `APawn::GetController()` (`Pawn.h`:264).67- `APawn::GetPlayerState<T>()` (`Pawn.h`:193); `AController::PlayerState` (`Controller.h`:50).6869## Server spawn and login flow7071On the server, `AGameModeBase` drives the sequence when a player joins:72731. `InitGame` (`GameModeBase.h`:62) — called before any actor `PreInitializeComponents`; spawn helper classes here.742. `PreLogin` (`GameModeBase.h`:293) — reject players by setting `ErrorMessage` before any state is allocated.753. `Login` (`GameModeBase.h`:323) — creates and returns the `APlayerController`; spawns `APlayerState`.764. `PostLogin(PC)` (`GameModeBase.h`:326) — first safe place to call replicated functions on the PC.775. `HandleStartingNewPlayer(PC)` (`GameModeBase.h`:361) — override in Blueprint or C++ to control what happens next.786. `RestartPlayer(PC)` (`GameModeBase.h`:435) → `FindPlayerStart` → `SpawnDefaultPawnAtTransform` → `PC->Possess(Pawn)`.7980Full login flow with seamless travel and `OnPostLogin` details:81[references/init-and-login-flow.md](references/init-and-login-flow.md).8283## Possession8485`AController::Possess(APawn*)` is `final` in 5.8; override `OnPossess` instead86(`Controller.h`:299). The symmetric unpossess override is `OnUnPossess` (`Controller.h`:306).8788```cpp89// Override OnPossess to react to possession — NOT Possess() which is final90void AMyController::OnPossess(APawn* InPawn)91{92 Super::OnPossess(InPawn);93 // Safe to access InPawn here; PlayerState is already assigned94}9596// On the pawn side, PossessedBy fires when a controller takes control97void AMyPawn::PossessedBy(AController* NewController)98{99 Super::PossessedBy(NewController);100 // Bind abilities, movement, etc. that depend on the controller101}102```103104A controller can possess different pawns over its lifetime (death/respawn, vehicle enter/exit).105Do not store gameplay state on the pawn that must survive across possessions — use `PlayerState`106or `PlayerController` instead.107108## Setting default classes in C++109110```cpp111// MyGameMode.h112UCLASS()113class MYGAME_API AMyGameMode : public AGameModeBase114{115 GENERATED_BODY()116public:117 AMyGameMode();118};119120// MyGameMode.cpp121#include "MyGameMode.h"122#include "MyCharacter.h"123#include "MyPlayerController.h"124#include "MyPlayerState.h"125#include "MyGameState.h"126127AMyGameMode::AMyGameMode()128{129 DefaultPawnClass = AMyCharacter::StaticClass();130 PlayerControllerClass = AMyPlayerController::StaticClass();131 PlayerStateClass = AMyPlayerState::StaticClass();132 GameStateClass = AMyGameState::StaticClass();133 // HUDClass — set if you use legacy AHUD; omit for pure UMG134}135```136137These five `TSubclassOf<>` properties are declared on `AGameModeBase` with138`EditAnywhere, NoClear, BlueprintReadOnly` (`GameModeBase.h`:87–108). Assign them in the139constructor so Blueprint subclasses can still override them in Blueprints editor defaults.140141Then wire the GameMode per-project (Project Settings → Maps & Modes →142`DefaultGameMode`/`GlobalDefaultGameMode` in `DefaultEngine.ini`143`[/Script/EngineSettings.GameMapsSettings]`), or per-level (World Settings → GameMode Override).144145## Where does my logic go? (decision guide)146147| Logic | Belongs in |148|---|---|149| Rules, win/lose, who spawns where, scoring authority | `AGameModeBase` — server only |150| State everyone must see (scores, timer, match phase) | `AGameStateBase` / `AGameState` |151| Per-player replicated facts (name, team, kills) | `APlayerState` |152| Input handling, camera, opening menus, player intent | `APlayerController` |153| Physical movement, abilities of the avatar | `APawn` / `ACharacter` + components |154| Cross-level or app-lifetime (save game, audio settings, online session) | `UGameInstance` / a `UGameInstanceSubsystem` |155156If it must survive a level load → `UGameInstance` or `UGameInstanceSubsystem`157(see `ue-subsystems`). If only the server may decide it → `AGameModeBase`.158159## GameInstance and subsystems160161`UGameInstance` is created once on engine launch and destroyed when the application exits,162surviving all level transitions. Override `Init` (`GameInstance.h`:217) and163`Shutdown` (`GameInstance.h`:224) for setup/teardown. Access it from any actor via164`GetGameInstance<UMyGameInstance>()`.165166For modular, dependency-isolated systems with the same lifetime:167168```cpp169// Subsystem declared as UCLASS(), auto-created by GameInstance170class UMyOnlineSubsystem : public UGameInstanceSubsystem171{172 GENERATED_BODY()173public:174 virtual void Initialize(FSubsystemCollectionBase& Collection) override;175 virtual void Deinitialize() override;176};177178// Access from any actor179UMyOnlineSubsystem* Sub = GetGameInstance()->GetSubsystem<UMyOnlineSubsystem>();180```181182`GetSubsystem<T>()` is declared on `UGameInstance` (`GameInstance.h`:440). See `ue-subsystems`.183184## PlayerState — per-player replicated data185186`APlayerState` is created by `Login` and added to `AGameStateBase::PlayerArray`. It replicates187to all clients, making it the correct place for data every machine needs about each player.188189```cpp190// MyPlayerState.h191UCLASS()192class MYGAME_API AMyPlayerState : public APlayerState193{194 GENERATED_BODY()195public:196 UPROPERTY(Replicated, BlueprintReadOnly, Category=Player)197 int32 TeamIndex = 0;198199 virtual void GetLifetimeReplicatedProps(200 TArray<FLifetimeProperty>& OutLifetimeProps) const override;201};202```203204Built-in replicated fields on `APlayerState`: `Score` (getter `GetScore`, setter `SetScore`,205`PlayerState.h`:312/318), `PlayerNamePrivate` (accessed via `GetPlayerName`/`SetPlayerName`,206`PlayerState.h`:235/228), `PlayerId`, `CompressedPing`, `bIsSpectator`, `bIsABot`.207208## Network roles209210- `AGameModeBase` exists **only on the server**; never put client logic there.211- `AGameStateBase`/`APlayerState` are replicated — read on any machine, only write on server.212- `APlayerController` replicates to its owning client only — good for client RPCs and UI.213- `APawn`/`ACharacter` replicate to all clients; `HasAuthority()` determines who may change state.214- Use `HasAuthority()` or `GetLocalRole() == ROLE_Authority` to branch server vs client.215216See `ue-networking-and-replication` for property/RPC mechanics.217218## C++ base + Blueprint subclass pattern219220The idiomatic setup:221- Put logic, replicated state, and core API in C++ (`AMyGameMode`, `AMyCharacter`, …).222- Expose designer-facing defaults via Blueprint subclasses (`BP_GameMode`, `BP_Character`, …).223- Set the BP subclasses as defaults in Project Settings or World Settings.224- Use `UPROPERTY(EditDefaultsOnly)` for numbers/assets designers should tweak without requiring225 recompile. See `ue-blueprint-cpp-integration`.226227## Gotchas228229- **`GetAuthGameMode()` on a client** returns null; always guard with `HasAuthority()`.230- **`Possess` is `final`** since UE 4.22; override `OnPossess`/`OnUnPossess` (`Controller.h`:299/306).231- **Persistent state on the Pawn** is lost on death/respawn; use `APlayerState` or `APlayerController`.232- **Possession ≠ spawn**: a controller can possess different pawns over time; don't assume 1:1 lifetime.233- **`AGameMode` vs `AGameModeBase` mismatch**: `MatchState` machinery only exists in `AGameMode`;234 don't reference it from an `AGameModeBase` subclass.235- **`DispatchPostLogin` deprecated in 5.6**: override `OnPostLogin(AController*)` instead236 (`GameModeBase.h`:334 — note the UE_DEPRECATED annotation at :329).237- **HUD for modern UI**: `AHUD` is legacy canvas drawing; build real UI with UMG (see `ue-umg-and-slate`).238- **`APlayerState` outlives the pawn**: the state persists in `GameState.PlayerArray` even when239 the pawn is destroyed; that is by design so scores survive death.240- **GameInstance is not replicated**: the server and each client each have their own independent241 instance. Do not use it as a shared-state store in multiplayer.242243## Version notes244245- `AGameModeBase` introduced in UE 4.14; older projects may subclass `AGameMode` directly.246- `Possess`/`UnPossess` marked `virtual final` in UE 4.22; use `OnPossess`/`OnUnPossess`.247- `DispatchPostLogin` deprecated in UE 5.6; the replacement is `OnPostLogin` (protected virtual).248- The framework is stable across UE 5.x; line numbers in citations drift between patch releases249 but header paths and class names are stable.250251## References & source material252253Engine source (UE 5.8, under `Engine/Source/Runtime/Engine/Classes/`):254- `GameFramework/GameModeBase.h` — `AGameModeBase`:47, `InitGame`:62, `InitGameState`:69,255 `DefaultPawnClass`:108, `PlayerControllerClass`:96, `PlayerStateClass`:100, `GameStateClass`:92,256 `HUDClass`:104, `PreLogin`:293, `Login`:323, `PostLogin`:326, `OnPostLogin`:334,257 `HandleStartingNewPlayer`:361, `RestartPlayer`:435, `SpawnDefaultPawnAtTransform`:461,258 `ChoosePlayerStart`:405, `GetDefaultPawnClassForController`:84.259- `GameFramework/GameMode.h` — `AGameMode`:35, `MatchState` namespace:16, `GetMatchState`:43,260 `StartMatch`:51, `EndMatch`:55, `SetMatchState`:72.261- `GameFramework/GameStateBase.h` — `AGameStateBase`:32, `PlayerArray`:55, `GetServerWorldTimeSeconds`:72,262 `HasBegunPlay`:76, `AddPlayerState`:112, `RemovePlayerState`:115.263- `GameFramework/GameState.h` — `AGameState`:16, `MatchState`:35, `ElapsedTime`:57.264- `GameFramework/Controller.h` — `AController`:40, `PlayerState`:50, `GetPawn()`:233,265 `Possess` (final):284, `UnPossess` (final):288, `OnPossess`:299, `OnUnPossess`:306.266- `GameFramework/PlayerController.h` — `APlayerController`:262, `PlayerCameraManager`:287,267 `MyHUD`:280, `SetInputMode`:1649, `SetShowMouseCursor`:2168.268- `GameFramework/Pawn.h` — `APawn`:43, `GetController()`:264, `GetPlayerState<T>()`:193,269 `PossessedBy`:374, `UnPossessed`:381.270- `GameFramework/Character.h` — `ACharacter`:338.271- `GameFramework/PlayerState.h` — `APlayerState`:41, `Score`:49, `GetScore`:312, `SetScore`:318,272 `PlayerNamePrivate`:162, `GetPlayerName`:235, `SetPlayerName`:228.273- `GameFramework/HUD.h` — `AHUD`:36, `PlayerOwner`:42, `bShowHUD`:50.274- `Engine/GameInstance.h` — `UGameInstance`:151, `Init`:217, `Shutdown`:224,275 `GetSubsystem<T>()`:440.276277Official docs (UE 5.8, all fetched and confirmed live):278- Gameplay Framework overview —279 <https://dev.epicgames.com/documentation/unreal-engine/gameplay-framework-in-unreal-engine>280- Game Mode and Game State —281 <https://dev.epicgames.com/documentation/unreal-engine/game-mode-and-game-state-in-unreal-engine>282- Player Controllers —283 <https://dev.epicgames.com/documentation/unreal-engine/player-controllers-in-unreal-engine>284- Pawn — <https://dev.epicgames.com/documentation/unreal-engine/pawn-in-unreal-engine>285- Controllers — <https://dev.epicgames.com/documentation/unreal-engine/controllers-in-unreal-engine>286- Gameplay Framework Quick Reference —287 <https://dev.epicgames.com/documentation/unreal-engine/gameplay-framework-quick-reference-in-unreal-engine>288289Deep-dive references in this skill:290- [references/gamemode-and-state.md](references/gamemode-and-state.md) — GameMode class291 hierarchy, match-state machine, GameState replication, setting default classes per-map.292- [references/controllers-and-pawns.md](references/controllers-and-pawns.md) — controller293 lifecycle, possession API, PlayerController responsibilities, Pawn vs Character choice,294 PlayerState data design.295- [references/init-and-login-flow.md](references/init-and-login-flow.md) — step-by-step server296 login/spawn sequence, seamless travel, respawn patterns, `HandleStartingNewPlayer` override297 points.298299Cross-references: `ue-actors-and-components` (AActor lifecycle), `ue-character-and-movement`300(ACharacter / UCharacterMovementComponent detail), `ue-subsystems` (UGameInstanceSubsystem),301`ue-networking-and-replication` (replication mechanics), `ue-blueprint-cpp-integration`302(exposing C++ to designers).