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 You are an expert in Unreal Engine's gameplay framework architecture. Context Check Read .agents/ue project context.md before proceeding. The game type (single player, co op, competitive multiplayer, dedicated vs listen server) determines which classes to subclass and which replication patterns apply. Resolve: single player or multiplayer? Dedicated or listen server? What are you implementing? Class Responsibility Map Each class exists on specific machines for specific reasons. Getting this wrong is the primary source of multiplayer bugs. AGameModeBase / AGameMode — Server Only Exists on: Server and standalone only. Never instantiated on clients. Why server only: GameMode is the authoritative referee. It decides who joins, when the match starts, where players spawn, and what the win conditions are. Client execution would allow cheating via local state manipulation. AGameMode adds the full match state machine ( EnteringMap → WaitingToStart → InProgress → WaitingPostMatch → LeavingMap ; Aborted on failure) with ReadyToStartMatch and ReadyToEndMatch hooks. Use AGameModeBase for lobby/simple games, AGameMode for match flow. Key API from source (GameModeBase.h): AGameStateBase / AGameState — Server + All Clients Exists on: Everywhere. Fully replicated. Why everywhere: Clients cannot read GameMode (it does not exist on them). Any global data clients need — scores, match timer, phase — belongs in GameState. PlayerArray exposes all connected APlayerState instances to every machine. Key API from source (GameStateBase.h): Custom replicated match data: APlayerController — Server (all) + Owning Client (own only) Exists on: Server holds one per connected player. Each client holds only its own. Remote clients do not see other players' PlayerControllers. Why this split: The PlayerController bridges one human to the server. Both ends run it for client side prediction and server validation. A client has no reason to know another player's input state. Key API from source (PlayerController.h): SetupInputComponent on PlayerController is for non pawn input: spectator actions, UI shortcuts, or global keybinds that persist across possession changes. For pawn specific input, override APawn::SetupPlayerInputComponent() instead — see ue input system . Enhanced Input setup: RPC patterns: Possess/UnPossess (server authority required): Listen server dual role: On a listen server, the host's PlayerController is both ROLE Authority and locally controlled. Guard dual role logic with IsLocalController() checks. This is a common source of bugs where code assumes authority implies non local (i.e., code written for dedicated servers runs incorrectly on a listen server host). ClientTravel — connect this client to a different server: ServerTravel — move all players to a new map (called from GameMode, server only): AController — Shared Base AController is the base class for both APlayerController and AAIController . It owns the pawn possession interface ( Possess , UnPossess , GetPawn ) and the rotation used to drive pawn orientation ( ControlRotation ). Subclass APlayerController for human players and AAIController for AI. APlayerState — Server + All Clients (Always Relevant) Exists on: Server and all clients. Marked always relevant so it replicates to everyone regardless of distance. Why always relevant: Scoreboards, team displays, and player lists need to show data for every player, not just nearby ones. PlayerState survives pawn death — when a pawn is destroyed and respawned, the PlayerController keeps its PlayerState, preserving accumulated stats. APawn — Server + All Clients (Replicated) Exists on: Server (authority) and all clients (simulated or autonomous proxy). Minimal base — no mesh, no collision component, no movement component. Use APawn when: entity is not a humanoid (vehicle, turret, drone), you need a completely custom movement component, or you need zero overhead baseline. ADefaultPawn is the engine's built in pawn with floating movement (no gravity) and a sphere collision root. It is used as the DefaultPawnClass placeholder when no custom pawn is assigned. ACharacter — Server + All Clients (Replicated with Prediction) Exists on: Server (authority) and all clients. The locally controlled instance runs client side prediction; simulated proxies interpolate from server updates. Why ACharacter: Walking humanoids need capsule collision, gravity, jump, crouch, and movement prediction. ACharacter bundles all of this with built in networked prediction via UCharacterMovementComponent . Component layout from source (Character.h): Constructor configuration: Key ACharacter API from source: Custom movement modes: Set MOVE Custom then override PhysCustom(float deltaTime, int32 Iterations) in your UCharacterMovementComponent subclass. The CustomMovementMode byte lets you distinguish multiple custom modes within the same PhysCustom dispatch. Movement replication: Client sends ServerMovePacked , server validates and replies via ClientMoveResponsePacked . This is automatic — do not call these RPCs manually. UGameInstance — Process Lifetime Singleton Exists on: One per process. Survives ALL level loads. Why: On level travel, every actor (including GameMode, GameState, PlayerController, PlayerState) is destroyed. GameInstance is never destroyed. It holds session handles, save game references, analytics state, and any data that must span the entire application lifetime. Session Management (Online Subsystem) The Online Subsystem abstracts platform specific backends (Steam, EOS, Null for testing). Add "OnlineSubsystem" and "OnlineSubsystemUtils" to your Build.cs dependencies. After joining, retrieve the connect string with GetResolvedConnectString and call ClientTravel . GameMode: Registration and Spawn Pipeline Join sequence (server only): Match state (AGameMode only): Travel Patterns Pattern Clients disconnect? GameMode/GameState survive? Use when Non seamless ( ServerTravel ) Yes, reconnect No, recreated Map change with clean slate Seamless ( bUseSeamlessTravel=true ) No No, recreated Lobby→game, round change Seamless travel survival: Always: UGameInstance , APlayerController , APlayerState Never: AGameMode , AGameState , level actors Optional: actors you add in GetSeamlessTravelActorList() Common Mistakes GameMode on client (null crash): Wrong class for data: AcknowledgedPawn vs GetPawn: GetPawn() on a PlayerController may return a pawn before the server confirms possession. Use AcknowledgedPawn when you need the server confirmed pawn. Dedicated server guard: PIE multi player: In PIE with multiple players, each has its own PlayerController but all share the same GameMode instance. Test multiplayer logic with PIE Number of Players set to 2 or more. Related Skills ue actor component architecture — actor lifecycle, component tick, attachment ue networking replication — DOREPLIFETIME conditions, RPC patterns, push model ue input system — Enhanced Input mapping contexts and input actions