reznok/gmcabilitysystem/gmc-prediction
Claude Code and agent skill by reznok/gmcabilitysystem
- community
Checking that the SKILL.md file is still in the repository.
Use when writing or reviewing code that runs inside GMC's movement cycle (GenPredictionTick, bound values, replays, combined moves, simulated proxies, move timestamps) or when a GMC pawn behaves differently on client and server.
Install
npx vskill@latest install reznok/gmcabilitysystem/gmc-predictionSKILL.md
Behavior below was verified against GMC 2.3.x and GMAS 1.4. Confirm signatures in this project's own headers (paths are relative to each plugin's root, e.g.Source/GMCCore/Public/Components/GMCReplicationComponent.h); GMC's source is not part of this plugin.
GMC (General Movement Component) replaces the engine's character movement with a generic, client-predicted, server-authoritative move pipeline. Your pawn is an AGMC_Pawn, your movement component derives from UGMC_MovementUtilityCmp (or UGMC_OrganicMovementCmp), player controllers from AGMC_PlayerController, AI controllers from AGMC_AIController. GMAS's ability component plugs into the same hooks (gmas:gmas-rules); everything here applies to GMAS abilities too. Diagnostics: references/gmc-diagnostics.md.
The move cycle
A move is one input state (the bound values flagged as input), one output state (every bound value after execution) and metadata (timestamp, delta time). Only machines that control a pawn create moves; everyone else receives states.
- Owning client (autonomous proxy). Each frame GMC calls
PreLocalMoveExecution, saves the input, runsGenPredictionTick(DeltaTime)(sub-stepped into iterations of at mostMaxTimeStep, 0.04 s, when the move's delta is larger), thenGenAncillaryTick, then saves the output. The move goes into a history (MoveHistoryMaxSize, 256) and completed moves are sent to the server at mostClientSendRate(30) times a second. - Server. For a remote pawn it re-executes each received move with the client's input, delta time and timestamp (
SV_IsExecutingRemoteMoves()is true), compares server-authoritative bound values with what the client reported, and sends back the authoritative state. For pawns it controls itself (listen-server host, AI) it executes one local move per frame, exactly like the client but with nobody to correct. - Correction and replay. When the reply differs from the client's recorded output, the client adopts the server state and re-executes every move still pending after it, in order, with their recorded inputs and delta times (
bUseClientReplay, default true).CL_IsReplaying()is true throughout. - Simulated proxies. Never run
GenPredictionTick. They buffer the states the server sends and display an interpolated state slightly in the past (SmoothingMode, defaultAdaptiveBufferedInterpolation).GenSimulationTick(DeltaTime)runs once per frame for cosmetics. The same path serves an autonomous proxy whosebUseClientPredictionis false: it is smoothed like a proxy and getsGenSimulationTickinstead of predicted moves.
Hook (Public/Components/...) | Runs for | During a replay | Notes | |
|---|---|---|---|---|
BindReplicationData_Implementation() (GMCReplicationComponent.h) | every machine, once, before any net serialization | – | the only place to bind | |
PreLocalMoveExecution_Implementation(const FGMC_Move&) (GMCReplicationComponent.h) | owning client and server-controlled pawns, before the move's input is saved | no | last chance to write input values for this move | |
GenPredictionTick_Implementation(float DeltaTime) (GMCMovementUtilityComponent.h) | owning client (live, combined and replayed moves), server (local and remote moves), simulated executions | yes | the predicted logic | |
GenAncillaryTick_Implementation(float DeltaTime, bool bLocalMove, bool bCombinedClientMove) (GMCMovementUtilityComponent.h) | owning client and server, after the move, never sub-stepped | no | bCombinedClientMove is true on the client when the move was re-executed rather than newly enqueued; always false on the server | |
GenSimulationTick_Implementation(float DeltaTime) (GMCMovementUtilityComponent.h) | simulated proxies, smoothed remote pawns on a listen server, and autonomous proxies with bUseClientPrediction off, every frame | – | cosmetics only; never on a dedicated server | |
OnSyncDataApplied_Implementation(const FGMC_PawnState&, EGMC_NetContext) (GMCReplicationComponent.h) | every machine, every time GMC loads a state into the pawn | yes, with historical states | see Detecting state changes | |
WorldTickEnd_Implementation(float DeltaTime) (GMCReplicationComponent.h) | every machine, once per frame after all moves, replays and smoothing | no | the place for once-per-frame transitions |
DeltaTime passed to the prediction tick is the move's delta (derived from timestamps, clamped to MaxMoveDeltaTime, 0.05 s), not the frame delta; inside a sub-stepped iteration it is that iteration's slice (IsSubSteppedIteration(), GetIterationNumber(), at most MaxIterations, 15, per move). The predicted logic must be a pure function of the bound input state, the bound previous state and that delta: anything else (wall-clock time, frame delta, unbound members, random numbers without a bound seed, other actors' transforms) diverges between client and server and shows up as corrections.
Roles
All queries live on UGMC_ReplicationCmp (Public/Components/GMCReplicationComponent.h).
| Query | True when | |
|---|---|---|
IsAutonomousProxy() | on a client, for the pawn this client controls (ROLE_AutonomousProxy) | |
IsSimulatedProxy() | on a client, for every pawn it does not control (ROLE_SimulatedProxy), including AI pawns | |
IsLocallyControlledServerPawn() | on the server, for a pawn controlled there: the listen-server host's own pawn, AI pawns, and every pawn in a standalone game | |
IsRemotelyControlledServerPawn() | on the server, for a pawn controlled by a connected client |
Useful refinements: IsServerPawn(), IsClientPawn(), IsPredictedAutonomousProxy(), IsSmoothedListenServerPawn(), SV_IsExecutingRemoteMoves(), CL_IsReplaying(), IsSimulatedMove(), IsLocalMove(), IsCombinedMove() (the last three on UGMC_MovementUtilityCmp).
- Dedicated server: every player pawn is remotely controlled; AI pawns are locally controlled; nothing is smoothed and
GenSimulationTicknever runs. - Listen server: the host's pawn is a locally controlled server pawn: no prediction, no replays, no corrections, one move per frame. Remote pawns are authoritative and smoothed for display on the host (
IsSmoothedListenServerPawn()), soGenSimulationTickruns for them there while gameplay still reads the bound (authoritative) members. - Standalone / PIE without a net mode: the pawn is a locally controlled server pawn. Code that only ever ran standalone has never been replayed, combined or smoothed; test it under a networked PIE (
gmas:gmas-testing).
Bound values
GMC replicates nothing you do not bind. State that must carry over between moves, reach the server, be validated, be restored by a replay or be visible on simulated proxies is bound in BindReplicationData_Implementation with Bind<Type>(Variable, PredictionMode, CombineMode, SimulationMode, Interpolation). Each call returns a binding index that reads the value back from any saved FGMC_PawnState.
Rules: bind only in that function, bind members of the movement component (the GMC documentation recommends it), call Super first so the chain is base → derived → ability component last (gmas:gmas-rules), and keep the order identical on every machine: the order is the wire layout and the comparison layout. Bindings cannot be removed once made, and bindings that differ between client and server corrupt every state the two exchange.
| Function | Variable type | On the wire | |
|---|---|---|---|
BindBool | bool | 1 bit | |
BindHalfByte | uint8 | lower 4 bits | |
BindByte | uint8 | 8 bits | |
BindInt | int32 | full | |
BindSinglePrecisionFloat / BindCompressedSinglePrecisionFloat | float | full / 2 decimals | |
BindDoublePrecisionFloat / BindCompressedDoublePrecisionFloat / BindTruncatedDoublePrecisionFloat | double | full / 2 decimals / as float | |
BindCompressedVector2D, BindCompressedVector, BindCompressedRotator | FVector2D, FVector, FRotator | 2 decimals per component | |
BindActorReference, BindActorComponentReference, BindAnimMontageReference | AActor*, UActorComponent*, UAnimMontage* | object reference | |
BindName, BindGameplayTag, BindGameplayTagContainer, BindInstancedStruct | FName, FGameplayTag, FGameplayTagContainer, FInstancedStruct | serialized |
The four modes (Public/Replication/SyncSettings.h, interpolation in Public/Replication/Smoothing.h):
- `EGMC_PredictionMode`:
ClientAuth_Inputfor player input (the server accepts it unquestioned);ServerAuth_Output_ClientValidatedfor state the server owns and the client checks (a deviation triggers a correction);_Input/_Output/_InputOutputsay which side of the move the value belongs to;_ServerValidatedmoves the check to the server;Localis not synchronized at all. - `EGMC_CombineMode`:
CombineIfUnchanged(a changed value forces a new move: the right choice for inputs),AlwaysCombine(keeps the first value of the window),AlwaysCombineOverwrite(keeps the latest),Default(GMC's built-in rules for the type). For a one-shot input such asInput.Dashheld for one frame,CombineIfUnchangedguarantees the frame it rises and the frame it falls each start a new move, so the server sees the pulse. - `EGMC_SimulationMode`:
Periodic_*sends the value with every state update (simulated proxies may miss intermediate values),PeriodicAndOnChange_*additionally sends it whenever it changes (for rare flags such asState.Stunned),Nonenever reaches simulated proxies. - `EGMC_InterpolationFunction`:
Linear,Cubic,NearestNeighbour,StartValue,TargetValue,Custom1–Custom8; non-numeric values useNearestNeighbourorTargetValue.
Bound values are the only state a replay restores. An unbound member that GenPredictionTick writes keeps its newest value while older moves are replayed on top of it: the replay produces a different result than the live run did, and the next correction is guaranteed. Either bind it, recompute it from bound values at the start of every tick, or make it a local variable.
Replays and combined moves
Replay. The client sets the pawn to the server's state, then re-executes every pending move. CL_IsReplaying() is true for the whole pass (always false on the server and on simulated proxies); IsLocalMove() is false; GenAncillaryTick is not called for replayed moves. A correct replay is invisible. A visible one (snapping, repeated effects, a cooldown that jumps) means a side effect or an unbound dependency leaked into the predicted logic.
Combined moves. The client does not enqueue a new move every frame. While the bound inputs allow combining and the accumulated delta stays within MaxCombinedDeltaTime (0.03334 s), the newest frame is merged into the pending move: the pending move's timestamp advances, its inputs are combined per their combine modes, the pawn is reset to that move's start state and GenPredictionTick runs again with the accumulated delta time. At 120 fps a move's tick therefore runs up to four times with a growing DeltaTime, and only the last run counts. The server executes each enqueued move exactly once and never sees the intermediate runs (bCombinedClientMove is always false there).
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingClaude/gmas/skills/gmc-prediction/SKILL.md
Popularity
- Repository stars
- 56
- Repository forks
- 27
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/reznok/gmcabilitysystem/gmc-prediction)