V4 is one tactical-action universe wearing six bodies, and what makes that a universe rather than six unrelated games is the online backbone every cell shares. A ranked Search & Destroy round, a 1v1 RTS ladder match, a Spies-vs-Mercs hunt, and a boss-rush leaderboard run all sign in through the same account, queue through the same skill-rated matchmaker, land on the same dedicated-server fleet, store the same server-validated replay, and — when an event spins up — feed the same in-client tournament stack. This page is the player-facing tour of three layers that sit next to each other: the online services plumbing (login, friends, parties, matchmaking, leaderboards, replays), the networking that decides how a given match is transported (client-server with lag-compensated hit registration, deterministic lockstep for RTS, rollback-emulated prediction for twitch PvP, plus the server fleet, LAN, and private rooms underneath them), and the esports toolkit that lets an organizer run a bracket, broadcast, and verify results without leaving the game. The store, season pass, and progression vault that ride this same backbone live in Live Service, Progression & Vault; the workshop, contract author, and community surfaces are in Content, Creator & Community; the engine-side treatment is the architecture companion, ../architecture/online-services-persistence.md. For the full feature scope this slots into, start at the hub: ../V4_features.md.
What ships, honestly#
The split is clean and worth stating up front. Two tiers are real code, and a small set of seams are labelled as deployment substrate rather than wired integrations.
The client tier is real Unreal C++. V4/ue/Source/V4OnlineServices ships
fourteen UGameInstanceSubsystems — login, matchmaking, session, presence,
friends, party, leaderboard, replay-upload, crossplay, live-service, moderation,
compliance, online-contract, and contract-schedule — over a typed surface
(V4OnlineTypes.h), and V4OnlineServices.Build.cs really declares the
OnlineSubsystem, OnlineServicesInterface, OnlineServicesCommon, and
EOSShared dependencies that make the EOS abstraction load-bearing rather than
decorative. The networking module V4/ue/Source/V4Netcode is wired just as
seriously: its V4Netcode.Build.cs pulls NetworkPrediction, Iris,
ReplicationGraph, and OnlineSubsystem, and the implementations behind them
are real algorithms, not stubs.
The service tier is real Rust + Axum. apps/v4/online-services is a
v4-online-services crate whose service-manifest.json enumerates twenty-six
services, and whose service_router() (src/lib.rs:24-47) nests twenty of
them — login, matchmaking, sessions, replays, leaderboards, anti-cheat,
moderation, compliance, store, esports, and the rest — each backed by a real
handler in src/http.rs (the esports router alone is at http.rs:1366). The
domain logic is not CRUD: a backtracking exact-fill matchmaker, a
dependency-free SHA-256/PKCE OAuth implementation, and real Challonge/Start.gg
bracket clients, each carrying inline #[cfg(test)] cases that assert computed
answers.
Four honest qualifications travel with the rest of the page:
- Services hold in-memory state. Each Rust service keeps a
BTreeMapbehind anArc<Mutex<…>>. The PostgreSQL / Redis / ClickHouse / S3 stores the architecture names are the specified deployment substrate, not yet wired into these crates. The reference implementations are real and tested; the database backends are the next integration step. - Kernel anti-cheat is a plan; replay validation is real today. The
UV4AntiCheatSubsystemnames EasyAntiCheat as the client driver tier and validates its config, but that kernel driver is a planned surface. The load-bearing integrity layer that ships is server-side replay validation, which rides the deterministic sim the engine already guarantees. - V4 does not ride the
@oshunplane. Unlike V2's event-bus-native backbone, V4's services are a self-contained Rust workspace (v4_shared::ServiceName); a grep for@oshunacrossapps/v4andV4/uesource returns nothing. Where V2 publishes cross-domain events, V4 keeps its own service graph. - Bracket egress is proxied. The Challonge and Start.gg clients in
src/brackets.rsspeak the providers' real wire formats, but egress runs through the platform's configured TLS-terminating proxy (host:port), not a direct outbound socket.
The online backbone, from the player's seat#
Login, accounts, and sessions#
Gameplay code never branches on platform. Every menu and lobby calls a subsystem
whose types speak one enum —
EV4OnlinePlatform { EOS, PSN, XBL, NN, Steam, Apple, Google }
(V4OnlineTypes.h:7) — and the platform stacks sit behind it.
UV4LoginSubsystem is a clean client-side state machine over
EV4LoginState { SignedOut, Pending, SignedIn, Failed }: BeginLogin moves an
account to Pending, CompleteLogin resolves it to SignedIn or Failed, and
the first- party V4 account is the primary identity. The heavy cryptography
deliberately does not live in the client — it lives in the Rust login-service,
where src/oauth.rs carries a dependency-free, FIPS 180-4 SHA-256 used for the
RFC 7636 S256 PKCE code-challenge binding, so the RFC 6749 authorization-code
exchange is genuinely cryptographic and deterministically testable rather than a
synthesised token. Refresh is single-use with replay defense: a presented token
is validated against its expected derivation, inserted into a consumed-token
set, and a replay is rejected before the generation rotates. Account linking
binds any of the seven providers to one first-party account; unlinking never
deletes progression. If the login service is unreachable, the client falls back
to offline play and reconciles to the cloud on the next successful sign-in.
Friends, parties, and voice#
The friends-service serves one cross-platform friend graph over a WebSocket
presence channel, so a friend's current cell, mode, and in-match/in-lobby state
are live. Party caps are per-cell — 4 for tactical PvP, 8 for RTS team modes, 2
for Wukong co-op, 4 for general co-op — and members who cannot meet a mode's
platform or content requirement are flagged before queue rather than after.
Voice runs over a WebRTC SFU (voice-sfu in the manifest) with positional or
channel audio, push-to-talk or open-mic per player, and per-channel mute of any
other player; a server-side whisper-transcription classifier feeds the report
pipeline, and voice defaults off for under-18 accounts pending parental
opt-in.
Matchmaking, skill, and region#
Matchmaking is the backbone's most fairness-sensitive job, and V4 implements it
on both sides of the wire. The authoritative skill model is server-side and
genuine: MatchmakingService (src/matchmaking.rs) runs a Glicko-2
expected-score fairness window. A candidate joins the match only when its
expected score against the seed stays within
FAIR_MATCH_EXPECTED_SCORE_WINDOW = 0.15 of an even 0.5, and find_match is a
real depth-first backtracking exact-fill (fill_exact): it seeds on the
longest-waiting solo (prefer_solo_queue, FIFO within party size), recurses to
assemble exactly team_size players from mixed party sizes, requires one
region every member can play in, then picks the region with the best
worst-case latency. The tests prove behaviour, not shape: a 2400-rated smurf
is excluded from a 1500 lobby and stays queued; a 3+2 backtrack fills a 5-stack
while a lone solo waits; and SA wins over EU because its shared worst-case
QoS is 45 ms versus 80. On the client, UV4MatchmakingSubsystem carries
FV4MatchmakingTicket rows and a FV4MatchmakingDiagnostic that powers an
explanation panel — PlayerMMR, OpponentAverageMMR, MMRDelta,
bWithinTolerance — so a player can see why a match formed. The launch SLO is
concrete: matchmaking p99 ≤ 35 s under 5× expected launch concurrency.
Leaderboards and the replay vault#
UV4LeaderboardSubsystem keeps FV4LeaderboardEntry rows under a BoardId and
serves GetTopEntries/GetEntry; the service slices boards per mode, per cell,
and per region with a global view, resets competitive boards on the 90-day
season boundary, and archives the prior season. Integrity is
server-authoritative: ladder and signature-mode entries (boss rush, contracts,
Contra Survival) are validated by replay analysis before they post — runs that
fail validation are rejected, not silently dropped. Replays default to a
14-day retention; starring moves one into a lifetime per-account vault capped
at 500. Verified speedrun submissions feed a ghost archive where a faster ghost
supersedes the active route ghost while preserving lineage, and a
right-to-be-forgotten scrub anonymises a deleted account's pawns in preserved
replays rather than erasing the match.
Networking: three netcodes on one server fleet#
V4's promise is per-ruleset feel, and that extends to the wire: a slow RTS macro game and a 60 Hz duel cannot share one transport. The product makes dedicated-server client-server the default, with deterministic lockstep for RTS and rollback-emulated prediction for tight twitch PvP — three models that all allocate off one fleet.
The server fleet and allocation#
UV4DedicatedServerRouter (V4ClientServerNetcode.cpp) configures ten
regions — NA-East, NA-West, EU-West, EU-East, LATAM, APAC, AU-NZ, ME, Africa,
India — each with a provider code, endpoint host, capacity, and estimated ping.
AllocateServerForMatchmaking honours a preferred region when it is enabled and
under capacity, otherwise scans for the lowest-ping enabled region with free
slots, increments its active allocations, and mints a QueueId.Region.MatchId
server id; ReleaseAllocation decrements it back. The same router also triages
anti-cheat: RouteAntiCheatSignal kicks-and-escalates a severity ≥ 8 signal to
anti-cheat.eac-review, escalates severity ≥ 4 to anti-cheat.live-review, and
otherwise logs to anti-cheat.telemetry.
Client-server with lag-compensated hit registration (default)#
The default model is server-authoritative with a real rewind. A shot is an
FV4HitRegistrationRequest carrying the client's fire time, trace, a Line or
Cone shape, and a stack of FV4PenetrationLayers; the server rewinds targets
to buffered FV4LagCompensatedSamples (server time, location, box extent),
clamps the rewind, and returns an FV4HitRegistrationResult whose booleans are
honest — bHit, bRewindClamped, bRejectedByAntiCheat,
bBlockedByPenetration, plus the rewound time/location and remaining
penetration energy. Hit acceptance is the server's call, not the client's claim,
and a rejected-by-anti-cheat flag is a first-class output rather than an
afterthought.
Deterministic lockstep (RTS)#
RTS modes (1v1, 2v2, 4v4) run UV4RTSLockstepSubsystem at a 25 Hz tick. Clients
exchange only FV4LockstepInputBundles (frame, match-config hash, RNG seed,
per-player inputs); each peer advances the same ComputeDeterministicHash over
a sorted input bundle so the simulation stays bit-identical. Desync is
detected, not hoped against: CheckRemoteFrameHash compares the local frame's
StateHash to a peer's and, on mismatch, computes a RecoveryFrame;
RecoverFromDesync rolls the sim back to it and adopts the authoritative hash.
The subsystem also draws match randomness through DrawMatchRandomInt and
exposes ValidateRngConsumptionOrder, so a replay can prove the RNG was
consumed in the same order on every machine — the foundation that makes RTS
replays true-rewindable and lockstep matches auditable. Late joiners rebuild
from BuildLateJoinerRebuildFrame, and a pause threshold backs the design's
pause-on-disconnect behaviour.
Rollback-emulated prediction (twitch PvP)#
Tight shooter PvP (TDM, Spies-vs-Mercs) runs UV4RollbackEmulatedComponent. Its
profile predicts movement and firing up to MaxPredictionFrames = 8 at
PredictionFrameRateHz = 60 — roughly a 133 ms prediction budget —
SimulatePredictedInputFrame advancing the local model and
ReconcileAuthoritativeInputFrame correcting it against an
FV4RollbackAuthoritativeFrame: when the predicted location is inside the
server's ErrorTolerance no correction applies, otherwise the component replays
the intervening frames and reports the delta. Fire is server-authoritative
(bRequiresServerFireAuthority), so a rejected shot surfaces as
bServerRejectedFire rather than a phantom kill.
Bandwidth budgets, Iris migration, and host migration#
Each match type gets a tuned replication profile.
UV4ReplicationGraphProfileCatalog ships per-mode band budgets and graph nodes
for Tactical5v5, CoD6v6, BattleRoyale (four distance bands from an
8192-byte critical tier to a 1024-byte far-dormant tier), and SpiesVsMercs,
loaded into the budgeter. UV4IrisMigrationValidator keeps rollback-sensitive
movement channels on legacy replication while migrating inventory, objective,
cosmetic, and social-stealth channels to Iris, and BuildMigrationReport
computes the bandwidth-reduction fraction. For peer-hosted private rooms,
UV4HostMigrationCoordinator::BuildMigrationPlan picks the best-scoring
eligible peer and ValidateSubTwoSecondSwap confirms the estimated swap stays
under two seconds; matchmade dedicated-server play never migrates host.
LAN, server browser, private rooms, and QoS#
For offline events V4 ships a LAN lobby for RTS and tactical modes that runs with no backend — local-network discovery, peer-hosted, no rating recorded. The server browser lists community-hosted RTS, R6-style, and private rooms, filterable by cell, mode, map, ping, player count, and mod-whitelist state, honouring the room's password and content rules on join. Private rooms are friends-only scrim/bracket spaces whose host configures cell, mode, map pool, rules, and team assignment, and can snapshot state so a multi-game series pauses and resumes. The client probes its NAT type at startup and warns on strict/symmetric NAT (which degrades private-room peering; dedicated-server modes are unaffected), and pings all ten regions to cache a sorted latency list that matchmaking and the browser surface as the best three.
Esports: run the whole event from the client#
V4's tournament stack is real service code with a strict completeness
discipline, backed by EsportsService (src/lib.rs) and the bracket clients in
src/brackets.rs.
The tournament server build and integrity#
configure_tournament_build refuses any config that is not fully competitive:
the build flag must be V4Tournament and all of broadcast tools, observer
cameras, pause-on-disconnect, and forced replay-export must be on, or it returns
InvalidTournamentBuild. There is no half-configured tournament build. Sponsor
branding is data, not code: register_branding_hooks requires at least two
crews, enough faction icons, and a broadcast-approved banner card per crew, so
the esports-service populates crew names, team icons, and banner cards per event
rather than hard-coding them. validate_tournament_mods enforces a whitelist —
when reject_unlisted_mods is set, any loaded mod outside allowed_mod_ids is
rejected so every match runs on a known content set.
Bracket sync — real provider wire formats#
The bracket clients speak the providers' real APIs.
ChallongeClient::fetch_matches issues
GET /v1/tournaments/{id}/matches.json?api_key=… and parses Challonge's
{"match": {...}} envelopes; StartggClient::fetch_event_sets POSTs a real
GraphQL EventSets query to /gql/alpha with a bearer token and maps the
sets.nodes back to a common BracketMatch. Both are tested against a spawned
local HTTP server that asserts the exact request line, headers, and GraphQL
variables. Internally, create_first_party_bracket requires
server-authoritative reporting, and the design pulls and cryptographically
verifies external results against the replay hash before they count — results a
client cannot forge.
Anti-collusion and anti-cheat#
Collusion detection is tuned for the modes where it pays.
evaluate_rts_team_collusion scores shared-vision seconds, resource-transfer
spikes, and mirror-pathing events and flags a pairing only past an
evidence-window-and-score threshold; evaluate_search_and_destroy_collusion
scores plant/defuse avoidance and thrown rounds the same way — each emits an
AntiCollusionFinding with a severity, a review queue, and an FNV-style
evidence hash, and flagged matches route to human review rather than
auto-discipline. On the client, UV4AntiCheatSubsystem backs this:
EvaluateBehavior flags impossible recoil (≥ 20 shots at ≥ 0.98 control) and
wallhack patterns, CalculateTrustScore is
100 − strikes·25 − investigations·10, BuildBanTiers enumerates the
mute/match/cell/account ladder, and ValidateLadderReplay insists the replay,
server-state, and input hashes are all present and independently produced
before a run is valid. The EAC config validation requires kernel mode plus
ranked-and-BR protection across PC and current-gen consoles — but, per the
honest label above, that driver is planned; the replay-hash check is the part
that ships real.
Pro circuit, broadcast, and the Hall of Fame#
The first 12-month calendar is authored data, not prose:
V4/esports/pro-circuit/pro-circuit-2026.json defines Major / Minor / Open
tiers with circuit points (1200 / 450 / 120), prize pools, and a twelve-event
calendar from a Launch Open in October 2026 to a World Finals Major in September
2027, plus a broadcast SLA of 8 / 4 / 2 observers by tier, a 365-day replay
archive, and a 90-second integrity delay;
esports/calendar/first-12-months.json mirrors the month-by-month cadence so
Open results feed Minor seeding and Minor feeds Major. The web spectator portal
adds a per-camera picture-in-picture grid, a director-cut observer, true
replay-rewind on lockstep matches, and the same 90-second delay. Finally,
EsportsService enshrines lifetime champions:
enshrine_lifetime_champion_banner validates a one-of-one art commission
anchored to Lobby.BattleHub.Zone.HallOfFame, hall_of_fame_induction_criteria
encodes per-cell evidence requirements (two Major wins for Tactical FPS, a
Grandmaster season plus two Major top-4s for RTS, a world-first boss kill for
ARPG), and a community-veto policy (/hall-of-fame/community-veto, 30-day
window, one-account-one-vote) keeps the honour accountable to the players.
Where this connects#
- Sideways to live service: Live Service, Progression & Vault — the store, battle pass, currency ledger, and replay vault that ride this same backbone and account root.
- Sideways to creators: Content, Creator & Community — the workshop mods the tournament whitelist gates, the Hitman contract author, and the gallery/newsletter community surfaces.
- Down to the engine: ../architecture/online-services-persistence.md — the EOS abstraction, the Glicko-2/PKCE service internals, the persistence and cross-progression model, and the specified PostgreSQL / Redis / ClickHouse / S3 substrate these services deploy onto.
- The feature hub: ../V4_features.md