# Networking & Determinism

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](../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`, no `ISocketSubsystem`, no `UFUNCTION(Server/Client/NetMulticast)`
  RPC, and no replicated `UPROPERTY` / `DOREPLIFETIME` anywhere in the module.
  The prediction, reconciliation, hashing, interest-band and budgeting
  _algorithms_ are implemented and tested; binding them to a live `UNetDriver`
  and pushing bytes over a wire is not in this module. (`V4NetcodeModule.cpp` is
  an empty `IModuleInterface` shell — the module is its types and subsystems,
  not a running service.)
- **`Iris` and `NetworkPrediction` are 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 plain
  `UActorComponent`, and `UV4IrisMigrationValidator` is a _bandwidth-planning
  data contract_ (it tallies legacy-vs-Iris bytes per channel), not a live Iris
  migration. The **one** real engine-networking integration is
  `UV4ReplicationBandNode : UReplicationGraphNode_ActorList`
  (`V4ReplicationBandBudgeter.h:39`), which genuinely overrides
  `GatherActorListsForConnection`.
- **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.cs` and `V4TournamentServer.Target.cs` set
  neither `/fp:strict` nor `DETERMINISM`). 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.

```mermaid
flowchart TD
    M[Match starts: which cell?] --> Q{Netcode profile}
    Q -->|RTS Tactics| LS[Deterministic lockstep 25 Hz]
    Q -->|Twitch PvP TDM / S&D / SvM| RB[Rollback-emulated prediction]
    Q -->|Tactical / Battle Royale| CS[Client-server authoritative]
    Q -->|PvE / single-player| LD[Local deterministic + seeded replay]
    LS --> H[Chained integer state hash + SplitMix64 RNG]
    LS --> D{Peer hashes agree?}
    D -->|no| R[Rollback to frame-N, request authoritative snapshot]
    RB --> P[8-frame predicted buffer] --> AC{Server confirms?}
    AC -->|mismatch| RR[Rewind to confirmed frame, replay later inputs]
    CS --> LC[Lag-compensated hit-reg: rewind target history] --> RG[ReplicationGraph band budgeter]
```

## 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
`FV4LagCompensatedSample`s (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:

1. **Anti-cheat plausibility** — `IsTraceDirectionPlausible` (`:95`) rejects a
   trace whose direction diverges from the reported view direction by more than
   `MaxTraceViewAngleDegrees`, setting `bRejectedByAntiCheat`. This is the
   server's "impossible angle" guard.
2. **Rewind** — `FindRewoundSample` (`:158`) clamps the client's fire time into
   the retained window (flagging `bRewindClamped` when 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.
3. **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 by `ExtraTolerance`.
4. **Penetration** — `EvaluatePenetration` (`:111`) walks ordered cover layers,
   subtracting `thickness × resistance` energy per layer and hard-blocking on a
   `bHardBlocks` surface. 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](./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](./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](./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](./online-services-persistence.md). The
section hub is [../V4_ARCHITECTURE.md](../V4_ARCHITECTURE.md).

## Related

- [Game Modes & Live Service](./game-modes-live-service.md) — the mode plugins
  and rule sets that select prediction profiles and replication bands
- [AI, Perception & Stealth](./ai-perception-stealth.md) — server-authoritative
  replication of suspicion, schedules and crowd state, the non-rollback
  authority path
- [Online Services & Persistence](./online-services-persistence.md) — the live
  dedicated-server backbone, matchmaking, anti-cheat service and replay/save
  stores
- The section hub: [../V4_ARCHITECTURE.md](../V4_ARCHITECTURE.md)
