V4 is not one game with one netcode — it is a tactical-action universe of
cells (an RTS, tactical FPS PvP, Battle Royale, twitch shooters, stealth
sandboxes, ARPG and co-op campaigns) running on one engine, and the single most
consequential networking decision in the project is that each cell picks the
netcode model that fits its loop. A 200-pop RTS match cannot afford to
replicate every unit's state, so it ships only inputs and trusts every client
to reach the same world deterministically. A 5v5 tactical round cannot trust the
client with a kill, so it is server-authoritative with lag-compensated hit-reg.
A twitch TDM round cannot wait a round-trip to move your own pawn, so it
predicts locally and reconciles. A single-player Hitman level needs none of
that, but it does need a seedable replay. All four postures, plus the
replication graph, dedicated-server allocation, host migration and anti-cheat
that sit underneath them, live in one Unreal C++ module: V4Netcode
(V4/ue/Source/V4Netcode/, nine .cpp / ten .h plus V4Netcode.Build.cs,
which declares Core/CoreUObject/Engine/V4Core/Json and the four
networking modules NetworkPrediction, Iris, OnlineSubsystem,
ReplicationGraph). The module is real and compiles on the on-box engine — the
build tree carries 21 V4Netcode/*.o objects under
V4/ue/Intermediate/Build/Linux/x64/UnrealEditor/Development/V4Netcode/. This
page is the architecture-side companion for V4's netcode and determinism, part
of the Netcode, Modes & World group; the section hub is
../V4_ARCHITECTURE.md.
What ships, honestly#
The netcode logic is real, deterministic-by-construction where it must be, and
test-driven. Five automation specs under
V4/ue/Source/V4Tests/Private/V4NetcodeTests/ exercise it and assert computed
values, not shapes: V4.Netcode.Lockstep.DeterminismAndRecovery,
V4.Netcode.RollbackPrediction.{WindowAndFiring,ServerReconcileReplay,TwitchModeWiring},
V4.Netcode.ClientServer.ProvisionReplicationIrisHostMigration,
V4.Netcode.HitRegistration.LagCompensation, and
V4.Netcode.LocalDeterminism.RngAndPveReplay. They drive a live
UV4RTSLockstepSubsystem through resimulation and desync recovery, replay a
rollback rewind and check the exact corrected coordinate, rewind a
lag-compensated target between interpolated samples, and round-trip the replay
codecs.
Three honest qualifications keep the rest of the page at face value.
- This is a deterministic library, not a wired net driver. There is no
FSocket, noISocketSubsystem, noUFUNCTION(Server/Client/NetMulticast)RPC, and no replicatedUPROPERTY/DOREPLIFETIMEanywhere in the module. The prediction, reconciliation, hashing, interest-band and budgeting algorithms are implemented and tested; binding them to a liveUNetDriverand pushing bytes over a wire is not in this module. (V4NetcodeModule.cppis an emptyIModuleInterfaceshell — the module is its types and subsystems, not a running service.) IrisandNetworkPredictionare declared dependencies but not actually called. A search of the module finds no Iris API symbols (UReplicationSystem,UE::Net::,FReplicationFragment) and no NetworkPrediction simulation types (TNetworkedSimulation,FNetworkPredictionData). The rollback component is hand-rolled on a plainUActorComponent, andUV4IrisMigrationValidatoris a bandwidth-planning data contract (it tallies legacy-vs-Iris bytes per channel), not a live Iris migration. The one real engine-networking integration isUV4ReplicationBandNode : UReplicationGraphNode_ActorList(V4ReplicationBandBudgeter.h:39), which genuinely overridesGatherActorListsForConnection.- Determinism is enforced by integer-state hashing and a seeded, order-audited
RNG — not by a strict-FP build. Unlike V2 (
V2_STRICT_FP=1) or V7's dedicated-realm target (/fp:strict), no V4 target sets any compiler determinism flag (V4.Target.csandV4TournamentServer.Target.csset neither/fp:strictnorDETERMINISM). V4's determinism therefore lives in what gets hashed (integers only) and how RNG is consumed (canonical order), described honestly below. The float-math rollback path is safe precisely because it is server-reconciled, never cross-machine lockstep.
The per-cell netcode model#
The architecture monolith's promise — "choose a netcode strategy per cell" — is realized as four concrete code paths, each with its own authority and determinism posture:
| Cell / mode | Strategy | Authority | Determinism posture |
|---|---|---|---|
| RTS (Tactics) | Deterministic lockstep, 25 Hz | Shared (every client re-sims) | Integer input-digest + seeded RNG |
| Tactical FPS PvP (R6/5v5) | Client-server + reconcile | Server (lag-comp hit-reg) | Server-authoritative, float OK |
| Twitch PvP (TDM, S&D, Spies-vs-Mercs) | Rollback-emulated prediction | Server (fire authority) | Predict-and-confirm, float OK |
| Battle Royale (Warzone 100p) | Client-server + relevancy bands | Server | Server-authoritative, float OK |
| PvE / single-player / co-op | Local deterministic | Local | Seeded, serializable replay |
The wiring between a mode and its netcode profile is data, not code
branches. UV4RollbackPredictionProfileCatalog::LoadDefaultProfiles
(V4RollbackEmulatedComponent.cpp:309) registers four twitch profiles keyed by
(ModePluginName, RuleSetId) — V4Mode_Tactical_CoDMultiplayer.TDM,
…SearchAndDestroy (a one-life round),
V4Mode_Tactical_CoDWarzone.BattleRoyale (100 players), and
V4Mode_Stealth_SpiesVsMercs.Default — each carrying an 8-frame prediction
window, a 60 Hz prediction rate, and a ReplicationProfileId that points at the
matching replication band set. The test …TwitchModeWiring confirms the catalog
resolves S&D as bOneLifeRound and configures a live
UV4RollbackEmulatedComponent from the profile.
RTS deterministic lockstep#
The RTS cell is the one place V4 must be bit-deterministic across machines,
because no game state is replicated — only inputs are. UV4RTSLockstepSubsystem
(a UGameInstanceSubsystem) owns that control plane. It advances on a fixed
integer step: TickLockstep(DeltaSeconds, …) (V4RTSLockstepSubsystem.cpp:90)
accumulates wall-clock time and emits exactly one frame per 1/TickRateHz
(default 25 Hz, 40 ms), so the same input stream produces the same frame
count regardless of render rate — the spec pins it: "25 Hz lockstep does not
advance before 40 ms" then "advances exactly at 40 ms." Each tick, pending
inputs for that frame are gathered (ConsumeInputBroadcastBundle) and run
through a single canonical sort (SortInputs, :287) ordering by player
id, then command string, then primary/secondary values, then target cell — so
two clients that received the same inputs in different network order sort them
identically before hashing.
The determinism digest is
ComputeDeterministicHash(PreviousHash, Frame, Inputs) (:227). It chains the
previous hash with MatchConfigHash, both halves of the 64-bit RngSeed, the
frame number, and every sorted input field, folding each with HashCombineFast.
The subtle, load-bearing detail is FName hashing: a raw GetTypeHash(FName)
hashes the process-local name-table index, which differs between machines, so
the subsystem uses StableNameHash (:316) = FCrc::StrCrc32 over the name
string, making the digest content-based and stable across peers. The spec
asserts the property directly: "Same inputs produce same deterministic hash
regardless of arrival order."
Determinism, honestly labeled#
Two precise statements keep this from over-claiming.
First, what the digest actually hashes is the input history, config, and seed
— not unit positions. AdvanceSimulationTick chains CurrentStateHash
forward over every frame's sorted inputs (:74). That is a genuine desync
detector for a lockstep whose only divergence sources are input ordering, config
drift, or RNG misuse — but folding the RTS gameplay sim's own unit state into
the digest is the RTS simulation's responsibility (the V4RTS module), and is
not exercised by this module's tests. The subsystem provides the mechanism
(per-frame chained hash, HashIntervalFrames-sampled checkpoints every 100
frames via StoreFrame, GetStateHashSample); the gameplay state it would hash
is wired in elsewhere.
Second, the real cross-machine guard is the RNG-consumption audit. Match RNG
is a named algorithm — V4SplitMix64 (V4LocalDeterminism.cpp:10), the
standard SplitMix64 with the 0x9E3779B97F4A7C15 increment and the two mix
constants — seeded per match. Every draw goes through
DrawMatchRandomInt(UnitId, Reason, …) (:189), which logs an
FV4RngConsumptionRecord with a monotonic draw index, and
ValidateRngConsumptionOrder (:208) asserts the log is in canonical
(frame, unitId, reason, drawIndex) order. That catches the classic lockstep
desync — non-deterministic iteration order consuming the RNG stream differently
on two machines — before it diverges the sim. The spec proves both halves:
"Per-match Splitmix64 RNG is deterministic" and "RNG consumption audit
accepts canonical unit order."
When a peer hash does disagree, CheckRemoteFrameHash flags bDesynced, and
RecoverFromDesync (:138) rolls the current frame back to
Frame − RecoveryRollbackFrames (default 4), discards confirmed frames and
recovery snapshots at or after that point, and applies the authoritative hash —
the "desynced client pauses, requests snapshot, replays" recovery the monolith
describes. A late joiner is rebuilt with BuildLateJoinerRebuildFrame (:163),
which returns the exact recovery snapshot or the nearest earlier one.
IsPauseThresholdExceeded enforces the ≤ MaxInputWaitSeconds (3 s) stall
before a match is flagged for replay-loss recovery. The whole input stream
serializes through UV4RTSLockstepReplaySerializer (header + seed + bundle
stream) and re-plays through UV4RTSLockstepReplayPlayer — the monolith's "~1
MB per 30-minute match, input-only" replay format.
Rollback-emulated prediction (twitch PvP)#
For TDM, Search & Destroy and Spies-vs-Mercs, V4 layers
prediction-with-confirm on top of the client-server stack — explicitly not
full peer-to-peer rollback like a fighting game; the server stays authoritative.
UV4RollbackEmulatedComponent predicts the local pawn each frame in
SimulatePredictedInputFrame(Frame, MoveInput, FireInput, DeltaSeconds)
(V4RollbackEmulatedComponent.cpp:68): it integrates movement (speed-clamped so
a diagonal can't out-run a cardinal), records an FV4RollbackInputFrame (move,
delta, predicted location and velocity, fire intent) into a ring, and trims the
ring to MaxRollbackFrames (default 8 — 133 ms at 60 Hz; the spec asserts
"defaults to the documented 8-frame window" and "8 frames at 60 Hz is about
133 ms").
Reconciliation is
ReconcileAuthoritativeInputFrame(AuthoritativeFrame, OutCorrection) (:92).
It finds the confirmed frame in the buffer; if the predicted location is within
ErrorTolerance of the authoritative one, nothing rewinds (cheap path). On a
mismatch it snaps that frame to the authoritative position and replays every
later buffered input forward from there, recomputing each predicted location
and velocity and marking them bReplayedFromCorrection — the rewind-and-replay
step, resolved in one call. The spec nails the arithmetic: after predicting to
X=30 over three frames, an authoritative frame-1 at X=15 reconciles to a final
predicted X=25 with one replayed frame and a CorrectionDelta.X of −5. Firing
has its own authority: predicted fires hold a sequence in
PendingFireSequences; a server frame that confirms or rejects the fire moves
it to confirmed or RejectedFireSequences ("Rejected fire sequence is retained
for cosmetic rollback"), so a denied shot can un-play its tracer. This is the
layer the prediction-profile catalog configures per twitch mode.
Client-server authority & lag-compensated hit-reg#
Every networked shooter, rollback or not, validates the kill on the server.
UV4ServerAuthorityComponent keeps a per-target history ring of
FV4LagCompensatedSamples (server time, location, box extent), sorted and
trimmed to MaxRewindSeconds (the monolith's ~300 ms clamp) in
RecordTargetSample. When a client reports a shot,
ValidateServerAuthoritativeHit (V4ServerAuthorityComponent.cpp:51) does four
things in order:
- Anti-cheat plausibility —
IsTraceDirectionPlausible(:95) rejects a trace whose direction diverges from the reported view direction by more thanMaxTraceViewAngleDegrees, settingbRejectedByAntiCheat. This is the server's "impossible angle" guard. - Rewind —
FindRewoundSample(:158) clamps the client's fire time into the retained window (flaggingbRewindClampedwhen the shot is older than the window) and interpolates the target's location, rotation and extent between the two bracketing samples. The spec checks the interpolated center lands at X=150 between X=100 and X=200 samples, and that an out-of-window shot clamps to the oldest retained position rather than teleporting the target forward. - Geometry — a line shot uses a slab-method segment-vs-AABB test
(
SegmentIntersectsExpandedBox,:204); a shotgun-style cone uses an angular test with per-distance slack (ConeIntersectsExpandedBox), both against the box expanded byExtraTolerance. - Penetration —
EvaluatePenetration(:111) walks ordered cover layers, subtractingthickness × resistanceenergy per layer and hard-blocking on abHardBlockssurface. The spec drives a 25-energy round through two 5 cm layers (both penetrate, energy 25 → 5) and a steel plate (blocked, surface reported).
Replication graph & bandwidth budgeting#
The Battle Royale and tactical cells partition relevancy through Unreal's
ReplicationGraph, and this is where V4 actually touches the engine net path.
UV4ReplicationBandNode (V4ReplicationBandBudgeter.cpp:80) subclasses
UReplicationGraphNode_ActorList and overrides GatherActorListsForConnection
to estimate the band's per-frame cost and gate the real Super:: gather on a
budget: if UV4ReplicationBandBudgeter::TrySpend (:25) would exceed the
band's MaxBytesPerFrame, the node simply doesn't gather, throttling the
lowest-priority actors first.
UV4ReplicationGraphProfileCatalog::LoadDefaultProfiles
(V4ClientServerNetcode.cpp:216) defines the band sets per match type — the BR
profile is the monolith's four-ring A→D model (200 m full → >1500 m dormant),
with budgets shrinking 8192 → 1024 bytes/frame and cull distances growing 0 →
120000 cm. The spec confirms "BR band A admits one critical actor" while "BR
band D throttles excessive far actors."
The Iris story is the honest one from the top: UV4IrisMigrationValidator
(:322) records a per-channel legacy-vs-Iris byte rate, keeps
rollback-sensitive channels (movement) on the legacy path, and computes a
BandwidthReductionFraction over the rest — the monolith's "~30 % saving." The
spec asserts the rollback channel stays legacy and the migration saves ≥ 35 % of
non-rollback bandwidth. It is a planning and conformance artifact that proves
the policy arithmetic; it is not a call into the real Iris runtime.
Dedicated servers, host migration & anti-cheat#
UV4DedicatedServerRouter::ConfigureDefaultRegions (:70) provisions the
monolith's ten regions (NA-East/West, EU-West/East, LATAM, APAC, AU-NZ, ME,
Africa, India) with capacities and estimated pings, and
AllocateServerForMatchmaking (:100) honors a preferred region when it has
headroom, else greedily picks the lowest-ping enabled region with capacity,
mints a ServerId and :7777 endpoint, and increments the region's active
count (released cleanly by ReleaseAllocation). Host migration is
UV4HostMigrationCoordinator::BuildMigrationPlan (:365): it is disabled for
dedicated/public rooms and only runs for private rooms, picking the highest
HostScore eligible peer (ties broken by freshest ack) and estimating a swap
time the ValidateSubTwoSecondSwap gate holds under 2 s — the spec confirms a
public room cannot migrate while a private room picks Player.Two (score 65
over 40).
Anti-cheat spans both the router and UV4AntiCheatSubsystem. The router's
RouteAntiCheatSignal escalates by severity (≥ 8 → kick +
anti-cheat.eac-review, ≥ 4 → anti-cheat.live-review, else telemetry). The
subsystem validates an EAC config (kernel-mode required, ranked + BR protected
across five platforms), classifies behavior in EvaluateBehavior
(V4AntiCheatSubsystem.cpp:88 — impossible-recoil over 20+ shots at ≥ 0.98
control, wallhack pre-aim patterns), computes a clamped TrustScore, defines a
ten-tier ban ladder, and — the competitive-integrity piece —
ValidateLadderReplay (:59) requires three independently produced integrity
hashes (replay, server-state, input); identical hashes are rejected as forged.
The live anti-cheat service, matchmaker and replay store these route into are
the subject of
./online-services-persistence.md.
World state & the determinism boundary#
Above the per-cell netcode sits a cross-cell world state contract, expressed
as data in V4/world-state/. persistent-world-economy-deep.json and
world-boss-community-raid.json describe ripple events where one cell's outcome
seeds another's — and crucially, each carries an explicit determinismPolicy
that respects the netcode boundary: a Hitman kill that unlocks a CoD objective
is "Resolved before mission load from signed season state," and an RTS season
win that lifts Wukong lore is "read-only area context and does not mutate
combat frames." In other words, cross-cell world state is resolved at load
boundaries and never injected mid-simulation, so it can never perturb a
deterministic lockstep frame or a server-authoritative tick. The manifest is
also honest about its own data: a dataStatusNote records that community
counters start at zero and that previously published non-zero values "have been
removed as fabricated-progress data" — the same fail-loud discipline the
netcode module follows.
How it connects#
The netcode module is consumed, not standalone. The mode plugins that pick a
prediction profile and a replication band set — and the live-service playlists
that route players into them — are detailed in
./game-modes-live-service.md; the
(ModePluginName, RuleSetId) keys in the rollback catalog are exactly those
modes. The server-authoritative replication of non-combat state — guard
suspicion, schedule clocks, crowd panic — is the AI side of the same
client-server backbone, distinct from the rollback path, and is covered in
./ai-perception-stealth.md. The dedicated-server
allocation, matchmaking, anti-cheat service, ladder-replay validation and
persistent-world / save-sync stores that the router and anti-cheat subsystem
feed live in
./online-services-persistence.md. The
section hub is ../V4_ARCHITECTURE.md.
Related#
- Game Modes & Live Service — the mode plugins and rule sets that select prediction profiles and replication bands
- AI, Perception & Stealth — server-authoritative replication of suspicion, schedules and crowd state, the non-rollback authority path
- Online Services & Persistence — the live dedicated-server backbone, matchmaking, anti-cheat service and replay/save stores
- The section hub: ../V4_ARCHITECTURE.md