ue-gameplay-framework
Use this skill when working with Unreal Engine's gameplay framework classes: GameMode, GameState, PlayerController, PlayerState, Pawn, Character, or GameInstance. Also use when the user mentions 'gameplay framework', 'game rules', 'player management', 'match flow', or 'player spawning'. See referenc
By quodsoler · 854 installs
npx skills add quodsoler/unreal-engine-skills --skill ue-gameplay-framework
Source repository · Upstream listing
UE Gameplay Framework
Target engine: UE 5.8 . APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".
The gameplay framework is the set of classes the engine spawns for you — AGameModeBase , AGameStateBase , APlayerController , APlayerState , APawn , ACharacter , AHUD , UGameInstance — plus the join, spawn, match state, travel and damage flows that wire them together. All of it ships in the Engine module ( Classes/GameFramework , Classes/Engine , Classes/Kismet ), so Build.cs needs "Core" , "CoreUObject" , "Engine" . Add "EnhancedInput" when binding input, and "OnlineSubsystem" + "OnlineSubsystemUtils" (or "OnlineServicesInterface" ) only when touching sessions.
Context
Read .agents/ue project context.md if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.
Identify the area from the request and the codebase. Ask only when two plausible readings would produce different code.
Request is about… Go to
Which class holds which data; server vs client presence [Class Responsibility Map]( class responsibility map)
Join flow, player starts, pawn spawning, match state [GameMode]( gamemode server only)
Replicated scores, timers, connected player list [GameState]( gamestate everywhere)
Per player input, RPC bridge, possession, input mode [PlayerController]( playercontroller)
Per player replicated stats, team, name [PlayerState]( playerstate)
Possessable bodies, PossessedBy , character setup [Pawn and Character]( pawn and character)
Canvas overlay, hit boxes, showdebug [HUD]( hud)
Health and damage without Gameplay Abilities [Damage without GAS]( damage without gas)
Data that survives level load, subsystems, accessors [GameInstance]( gameinstance)
Hosting, finding and joining online sessions [Sessions]( sessions)
ServerTravel , ClientTravel , seamless travel [Travel]( travel)
Presence/authority matrix, the full class declarations these snippets come from, lifecycle order and inherited property tables: [references/framework class map.md](references/framework class map.md).
Class Responsibility Map
Class Lives on Owns Never put here
AGameModeBase / AGameMode Server and standalone only; nullptr on clients Rules, join approval, spawn selection, match state Anything a client must read
AGameStateBase / AGameState Everywhere, replicated Global replicated state, PlayerArray , server clock Server only decisions
APlayerController Server holds all; each client holds only its own Input, RPC bridge, possession, input mode, view target Data other clients need
APlayerState Everywhere ( bAlwaysRelevant = true ) Per player replicated stats, team, name, ping Input handling, UI state
APawn / ACharacter Server plus all clients The body: collision, mesh, movement Rules, scoring
AHUD Local players only; never on a dedicated server Canvas overlay, hit boxes, debug display Replicated data
UGameInstance One per process, survives every level load Session handles, cross level state, subsystems Per match state
APlayerState sets bReplicates = true and bAlwaysRelevant = true in its constructor, which is why scoreboards work at any distance.
GameMode (Server Only)
AGameModeBase is the minimal base. AGameMode adds the match state machine — use it when you need MatchState::EnteringMap → WaitingToStart → InProgress → WaitingPostMatch → LeavingMap (plus Aborted on failure).
Join sequence (server only)
Order Signature to override Notes
1 virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) Before any player joins; also virtual void InitGameState()
2 virtual void PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) Set ErrorMessage non empty to reject. For a non blocking credential check override PreLoginAsync(..., const FOnPreLoginCompleteDelegate& OnComplete) ( GameModeBase.h:303 ) instead; it must always call OnComplete (empty string = accept) or the connection hangs, and it must still run the PreLogin checks
3 virtual APlayerController Login(UPlayer NewPlayer, ENetRole InRemoteRole, const FString& Portal, const FString& Options, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage) Spawns the APlayerController and its APlayerState
4 virtual void PostLogin(APlayerController NewPlayer) First point where server→client RPCs are safe
5 virtual void OnPostLogin(AController NewPlayer) Protected; runs at the end of PostLogin , last hook before the pawn spawns
6 virtual void HandleStartingNewPlayer Implementation(APlayerController NewPlayer) BlueprintNativeEvent ; calls RestartPlayer unless the player must spectate
7 virtual void RestartPlayer(AController NewPlayer) FindPlayerStart → SpawnDefaultPawnFor → Possess
— virtual void Logout(AController Exiting) Fires when a controller with a PlayerState leaves
ChoosePlayerStart , FindPlayerStart , SpawnDefaultPawnFor , PlayerCanRestart , MustSpectate , ReadyToStartMatch and ReadyToEndMatch are BlueprintNativeEvent — override the generated Implementation , never the bare name. Verbatim forms: virtual AActor ChoosePlayerStart Implementation(AController Player) , virtual AActor FindPlayerStart Implementation(AController Player, const FString& IncomingName) , virtual APawn SpawnDefaultPawnFor Implementation(AController NewPlayer, AActor StartSpot) . Plain virtuals in the same pipeline: virtual void RestartPlayerAtPlayerStart(AController NewPlayer, AActor StartSpot) , virtual void RestartPlayerAtTransform(AController NewPlayer, const FTransform& SpawnTransform) , virtual bool ShouldSpawnAtStartSpot(AController Player) . Spawn points are APlayerStart actors, selected by their FName PlayerStartTag .
Match state (AGameMode only)
Public: FName GetMatchState() const , virtual bool IsMatchInProgress() const , virtual void StartMatch() , virtual void EndMatch() , virtual void AbortMatch() , virtual void RestartGame() .
Protected hooks: virtual void SetMatchState(FName NewState) , virtual void OnMatchStateSet() , virtual void HandleMatchIsWaitingToStart() , virtual void HandleMatchHasStarted() , virtual void HandleMatchHasEnded() , virtual void HandleLeavingMap() , virtual void HandleMatchAborted() .
SetMatchState is the only sanctioned way to move states; it pushes the new state onto AGameState::MatchState , which replicates to clients. Do not write MatchState directly.
GameState (Everywhere)
Clients cannot see the GameMode, so everything they need goes here.
Every ReplicatedUsing = X needs a matching UFUNCTION() void X(); declaration, and every Replicated / ReplicatedUsing property needs a DOREPLIFETIME line inside GetLifetimeReplicatedProps . Conditions, COND , push model and RPC rules belong to ue networking replication .
Inherited: TArray<TObjectPtr<APlayerState PlayerArray (not itself replicated; each APlayerState adds itself on every machine via AddPlayerState , which works because PlayerStates are always relevant). Inherited and replicated: TSubclassOf<AGameModeBase GameModeClass ( ReplicatedUsing = OnRep GameModeClass ), TSubclassOf<ASpectatorPawn SpectatorClass , bReplicatedHasBegunPlay , ReplicatedWorldTimeSecondsDouble . Accessors: virtual double GetServerWorldTimeSeconds() const , virtual bool HasBegunPlay() const , virtual bool HasMatchStarted() const , virtual bool HasMatchEnded() const , virtual void AddPlayerState(APlayerState PlayerState) , virtual void RemovePlayerState(APlayerState PlayerState) . AGameState adds FName MatchState ( ReplicatedUsing = OnRep MatchState ) and int32 ElapsedTime ( replicatedUsing = OnRep ElapsedTime ).
PlayerController
Declarations for the above (full class body in the reference): virtual void BeginPlay() override; , virtual void SetupInputComponent() override; , virtual void OnPossess(APawn aPawn) override; , virtual void OnUnPossess() override; , and UFUNCTION(Server, Reliable, WithValidation) void ServerRequestRespawn(); .
AController::Possess and AController::UnPossess are virtual final ; override OnPossess / OnUnPossess instead. APlayerController::SetupInputComponent() is a protected virtual declared on APlayerController itself — use it for input that outlives possession (menus, spectator keys, global shortcuts). Pawn specific bindings go in APawn::SetupPlayerInputComponent ; mapping contexts, actions, modifiers and triggers belong to ue input system .
Notable members: TObjectPtr<APawn AcknowledgedPawn (server confirmed possession), TObjectPtr<AHUD MyHUD , TObjectPtr<APlayerCameraManager PlayerCameraManager , TObjectPtr<UPlayerInput PlayerInput (local only), TSubclassOf<UCheatManager CheatClass , uint32 bShowMouseCursor:1 , uint32 bEnableClickEvents:1 , uint32 bEnableStreamingSource:1 (drives World Partition loading for this viewport), uint16 SeamlessTravelCount . Input modes FInputModeGameOnly , FInputModeUIOnly and FInputModeGameAndUI are applied with virtual void SetInputMode(const FInputModeDataBase& InData) .
Camera work Owner
PlayerCameraManager , SetViewTarget , SetViewTargetWithBlend , camera modifiers, camera shakes, Gameplay Cameras (Experimental in 5.8) ue gameplay cameras
Listen server dual role: the host's PlayerController has both ROLE Authority and a local player. Guard with IsLocalController() as well as HasAuthority() ; code written for a dedicated server often runs twice on a listen server host.
PlayerState
Without both the UFUNCTION() OnRep declaration and the DOREPLIFETIME entries the properties compile, run, and silently never replicate. Replication conditions and push model: ue networking replication .
Seamless travel hooks: virtual void CopyProperties(APlayerState PlayerState) (protected; called on the old PlayerState with the surviving one as the argument, and when an inactive PlayerState is saved on disconnect), virtual void OverrideWith(APlayerState PlayerState) , virtual void SeamlessTravelTo(class APlayerState NewPlayerState) . Built ins: FString GetPlayerName() const , float GetScore() const / void SetScore(const float NewScore) , int32 GetPlayerId() const , APawn GetPawn() const , class APlayerController GetPlayerController() const , virtual void ClientInitialize(class AController C) .
Reach one with MyPawn GetPlayerState() or MyController PlayerState ; reach all of them through PlayerArray on the GameState:
Pawn and Character
APawn is the minimal possessable actor: no mesh, no collision component, no movement component. ACharacter adds a capsule root, a skeletal mesh and UCharacterMovementComponent with networked prediction. ADefaultPawn is the engine's flying placeholder ( GetCollisionComponent() , GetMeshComponent() , bAddDefaultMovementBindings ); ASpectatorPawn derives from it.
PossessedBy runs on the server only. OnRep Controller is the client side counterpart for the replicated Controller pointer; NotifyControllerChanged fires on the server and the owning client (not simulated proxies, Pawn.h:396 ), which makes it the right place for owner side logic such as refreshing the input mapping context.
In the Character constructor, size the capsule with GetCapsuleComponent() SetCapsuleSize(42.f, 96.f) and place the mesh with GetMesh() SetRelativeLocation(...) / SetRelativeRotation(...) ; that needs include "Components/CapsuleComponent.h" and include "Components/Skeleta