reznok/gmcabilitysystem/gmc-prediction

Claude Code and agent skill by reznok/gmcabilitysystem

Trust tier 2
  • community
LLM review pending
Source check pending

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-prediction

SKILL.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, runs GenPredictionTick(DeltaTime) (sub-stepped into iterations of at most MaxTimeStep, 0.04 s, when the move's delta is larger), then GenAncillaryTick, then saves the output. The move goes into a history (MoveHistoryMaxSize, 256) and completed moves are sent to the server at most ClientSendRate (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, default AdaptiveBufferedInterpolation). GenSimulationTick(DeltaTime) runs once per frame for cosmetics. The same path serves an autonomous proxy whose bUseClientPrediction is false: it is smoothed like a proxy and gets GenSimulationTick instead of predicted moves.
Hook (Public/Components/...)Runs forDuring a replayNotes
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 savednolast 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 executionsyesthe predicted logic
GenAncillaryTick_Implementation(float DeltaTime, bool bLocalMove, bool bCombinedClientMove) (GMCMovementUtilityComponent.h)owning client and server, after the move, never sub-steppednobCombinedClientMove 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 pawnyes, with historical statessee Detecting state changes
WorldTickEnd_Implementation(float DeltaTime) (GMCReplicationComponent.h)every machine, once per frame after all moves, replays and smoothingnothe 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).

QueryTrue 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 GenSimulationTick never 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()), so GenSimulationTick runs 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.

FunctionVariable typeOn the wire
BindBoolbool1 bit
BindHalfByteuint8lower 4 bits
BindByteuint88 bits
BindIntint32full
BindSinglePrecisionFloat / BindCompressedSinglePrecisionFloatfloatfull / 2 decimals
BindDoublePrecisionFloat / BindCompressedDoublePrecisionFloat / BindTruncatedDoublePrecisionFloatdoublefull / 2 decimals / as float
BindCompressedVector2D, BindCompressedVector, BindCompressedRotatorFVector2D, FVector, FRotator2 decimals per component
BindActorReference, BindActorComponentReference, BindAnimMontageReferenceAActor*, UActorComponent*, UAnimMontage*object reference
BindName, BindGameplayTag, BindGameplayTagContainer, BindInstancedStructFName, FGameplayTag, FGameplayTagContainer, FInstancedStructserialized

The four modes (Public/Replication/SyncSettings.h, interpolation in Public/Replication/Smoothing.h):

  • `EGMC_PredictionMode`: ClientAuth_Input for player input (the server accepts it unquestioned); ServerAuth_Output_ClientValidated for state the server owns and the client checks (a deviation triggers a correction); _Input / _Output / _InputOutput say which side of the move the value belongs to; _ServerValidated moves the check to the server; Local is 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 as Input.Dash held for one frame, CombineIfUnchanged guarantees 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 as State.Stunned), None never reaches simulated proxies.
  • `EGMC_InterpolationFunction`: Linear, Cubic, NearestNeighbour, StartValue, TargetValue, Custom1–Custom8; non-numeric values use NearestNeighbour or TargetValue.
cpp
void UMyMovementCmp::BindReplicationData_Implementation()
{
Super::BindReplicationData_Implementation();
BindBool(bInput_Dash, EGMC_PredictionMode::ClientAuth_Input, EGMC_CombineMode::CombineIfUnchanged,
EGMC_SimulationMode::None, EGMC_InterpolationFunction::NearestNeighbour);
BindSinglePrecisionFloat(DashCooldown, EGMC_PredictionMode::ServerAuth_Output_ClientValidated,
EGMC_CombineMode::Default, EGMC_SimulationMode::Periodic_Output, EGMC_InterpolationFunction::Linear);
// The ability system component binds after everything else (gmas:gmas-rules).
}

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

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
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/reznok/gmcabilitysystem/gmc-prediction/badge)](https://verified-skill.com/skills/reznok/gmcabilitysystem/gmc-prediction)

Something wrong with this skill or its page? Tell us.