V5 ships seven games in one trench coat — a 1947 noir, a Hong Kong triad
open-world, an 1899 frontier, a Witcher-cell monster hunt, a sci-fi fleet PvP, a
steampunk whodunit, and the Mind-Palace that links them — and three jobs have to
hold that catalogue together without forking the engine per genre. A player
has to get from "pick a thing to play" to "a session is running" through one
registry; the open world that session opens into has to stream a 256-metre
partition lattice on a console frame budget while a quarter-thousand civilians
mill around; and the side-quests, encounters, contracts, loot, decoration, and
galaxy detail that fill the dead space between authored beats have to be born
deterministically from a seed. Those are the three subjects of this page —
mode orchestration, world streaming, and procedural generation — and they live
in four small, separately-compiled C++ modules under V5/ue/Source/: V5Modes
(the registry, build-target gate, HUD router, and esports/cabinet catalogs),
V5Open (the engine-integrated World-Partition streaming source, HLOD ladder,
weather/time/era data layers, and population spawners), V5Crowd (the
density-profile catalog and the Mass-Entity batch descriptor), and V5Procgen
(six seeded content generators). This page is the world-and-modes companion in
the Multiplayer, Modes & World Simulation group; the orientation hub is
../V5_ARCHITECTURE.md.
What ships, honestly#
Six claims up front, so the rest reads at face value.
- Real, compiled, value-tested. All four modules link on this box — the
linker has produced
Binaries/Linux/libUnrealEditor-V5Modes.so,…-V5Open.so,…-V5Crowd.so, and…-V5Procgen.so— and the automation specs assert computed values, not shapes: that a player at the origin pre-warms exactly a 3×3 = 9-cell block, that a76800cm streaming radius comes back from a 768 m request, that a heavy-rain transition at its midpoint reports alpha0.5and thins the crowd-density scalar below0.5, that a 48-minute day advanced by half lands at18:00, and that the same procgen seed reproduces a byte-identical fingerprint while a different one does not. Those fail against placeholders. V5Openis the most engine-integrated of the cluster. It is not a standalone planner that hands back arrays for someone else to apply — its streaming subsystem is a genuineIWorldPartitionStreamingSourceProviderregistered with the liveUWorldPartitionSubsystem, its population spawners callUWorld::SpawnActorandAActor::Destroyfor real, and its weather/era subsystems drive the engine'sUDataLayerManager::SetDataLayerRuntimeState. The tests run against a realUWorld::CreateWorld(EWorldType::Game).V5Modesis a real catalog and a real gate — but it is not aUGameFeatureAction. The 29-mode catalog, the build-target gating, the per-cell HUD routing, and the plugin discovery (a realIPluginManagerwalk) are all genuine C++. What is not here, and what V4's mode module did reach, is an async-asset-streamingUGameFeatureActionsubclass: agrepforGameFeatureAction/RequestAsyncLoad/UGameFeaturesSubsystemacrossV5Modesreturns nothing. V5's modes are described, discovered, and gated; they are not activated through the GameFeatures streaming callback in-tree.V5Procgenis real seeded generation — but it is not PCG. The architecture prose calls this "the PCG (Procedural Content Generation) pipeline"; the shipped code is six hand-writtenFRandomStreamgenerators with no PCG dependency at all.V5Procgen.Build.cslinks onlyCore/CoreUObject/Engine/V5Core, and the onlypcgtoken in the module is an id-prefix string (pcg.<cell>.<x>.<y>). The determinism and the content are real; the "PCG" naming is aspirational.- The crowd density side is Mass-linked, not Mass-driven.
V5Crowd'sBuild.cslistsMassEntity, but agrepforFMassEntityManager,FMassEntityHandle, or anyUMassProcessorreturns nothing.BuildPopulationBatchproduces a descriptor — a lightweight entity count, a spacing, and a namedMassEntityTemplateId— that a Mass spawner would consume; it does not itself run Mass processors. The panicking, fleeing, bark-shouting behavioural half ofV5Crowdis documented separately in ./perception-crowd-and-morality.md; this page covers only the streaming/density seam. - Content is modelled as data, not cooked binaries.
V5/ue/Plugins/holds 29*.upluginGameFeature descriptors, one per mode, and zero have aSource/module — they are content-and-manifest plugins (e.g.Plugins/V5Mode_Urban_Online/Content/Data/urban_online_manifest.json). A scan of the wholeV5/uetree finds zero binary.uassetand a single.umap(Content/V5Core/Maps/BootMap.umap). The crowd vocabulary is the exception that proves the model: a real 1.5 MB, 6,050-barkcrowd_catalog.jsonon disk (more below).
Game modes — the V5Modes registry#
The mode definition and the 29-mode catalog#
Everything begins with FV5ModeDefinition (V5ModeTypes.h:59): a PluginName
key, a DisplayName, an EV5Cell, an EV5ModeNetworkModel, an
EV5ModeHUDSurface, a MaxPlayers, and the boolean policy flags
(bRequiresOnlineServices, bSupportsDedicatedServer, bSupportsListenServer,
bEditorOnly, bPersistentLobby). It is richer than V4's five-field routing
record because the gate downstream reasons over the network model and the policy
flags rather than just opening a map. The catalog is authored in code by
Catalog() (V5ModeSystems.cpp:38), whose 29 MakeMode(...) rows
(:41–:69) span the seven cells: three Urban (HeistCity, StreetTriad,
Online), three Period (MadeMan, ViceSquad, InterrogationKit), two Frontier,
three Hunter, three Sci-Fi, plus the Steampunk, Mind-Palace/Cold-Cases,
Spec-Ops, Horde, Roguelike, four editor tools, Replay, Spectator, Training,
Bureau-HQ lobby, and Photo modes. EnumerateEnabledGameFeaturePlugins
(V5ModeSystems.cpp:306) intersects this catalog with a set of enabled plugin
names and splits the result into EnabledModes and GatedModes for a target —
the registry test pins the partition exactly (four enabled plugins on a
dedicated target yield 2 enabled / 2 gated).
Build-target gating#
The interesting logic is GateKnownMode (V5ModeSystems.cpp:129), a real
fail-closed policy switch over EV5ModeBuildTarget (V5ModeTypes.h:19 — six
targets: ShippingClient, DedicatedServer, ListenServer, Editor,
LANOffline, ArcadeCabinet). An editor-only mode enables only on the Editor
target. A dedicated server keeps only modes whose bSupportsDedicatedServer is
set. A listen target also admits offline/utility rulesets. LANOffline rejects
anything that bRequiresOnlineServices, or is CompetitivePvP, or is a
SocialLobby. And ArcadeCabinet cooks only the five curated cabinet modes
(IsArcadeCabinetMode, :117) and forces bRequiresOnlineServices false so a
cabinet runs offline. Each branch returns a populated Reason string, so a
gated mode explains itself. The spec drives the edges: an editor mode in a
shipping client returns disabled with a reason containing "Editor-only"; Hard
Vacuum is dedicated-eligible; a curated cabinet set yields exactly 5 enabled / 1
gated.
Per-cell HUD routing#
BuildHUDRoute (V5ModeSystems.cpp:333) maps (EV5Cell, ActiveModePlugin) to
an FV5ModeHUDRoute — a HUD surface, a WidgetClassPath soft path, primary/
secondary status labels, feature toggles (bShowsNetworkPanel,
bShowsInvestigationNotebook, bShowsVehicleOrMountStatus,
bShowsSquadOrCrewStatus), and a RequiredLayers list. It is genuinely
per-cell-and-per-mode: the Period cell forks ViceSquad ("Case"/"Evidence",
notebook + evidence tray) from MadeMan ("Family"/"Heat"), the Sci-Fi cell forks
the ship HUD ("Hull"/"Crew") from the squad HUD, and the Urban default surfaces
the network panel only for V5Mode_Urban_Online. The widget paths
(/Game/V5/UI/HUD/WBP_HUD_*) are soft references; no cooked widget binary backs
them in-tree, consistent with the content model above.
Plugin discovery, lobby, and the esports/cabinet catalogs#
Discovery is real engine I/O: DiscoverGameFeaturePlugins
(V5ModeSystems.cpp:102) walks IPluginManager::Get().GetEnabledPlugins() or
GetDiscoveredPlugins(), keeps only plugins whose name starts with V5Mode_
and carry an enabled GameFeatures reference in their descriptor
(IsV5GameFeaturePlugin, :86), and returns a deterministically sorted FName
list. On top of the registry sit three authored catalogs with real validators:
BuildLobbyState (:451) mints the Bureau-HQ social lobby with seven cell
portals and four queue groups, clamping connected players to a 32-cap and
switching its primary action to "Retry online services" when services are
unhealthy; ValidateArcadeCabinetProfile (:503) is a ~30-assertion linter
over the 4K60 kiosk cabinet (five mode slots, coin-op disabled,
watchdog/service-menu gates); and ValidateProStadiumTourCatalog (:577)
checks the six-region, six-stop esports tour and its per-stop broadcast routes
(SRT/NDI/HLS/DASH, ≥14 camera feeds, a 15-second observer delay). These are
evergreen data validators, not gameplay runtimes, and their specs assert the
counts directly.
World streaming — V5Open#
A real World-Partition streaming source#
UV5_Open_StreamingSubsystem (V5OpenStreamingSubsystem.h:10) is a
UWorldSubsystem that implements IWorldPartitionStreamingSourceProvider. On
Initialize it takes a dependency on UWorldPartitionSubsystem and registers
itself (V5OpenStreamingSubsystem.cpp:6, :207), so the engine's streamer
polls it every frame. Game code registers sources by actor or by location
(RegisterStreamingActor / RegisterStreamingLocation) tagged with an
EV5OpenStreamingSourceKind (Player, Companion, MissionMarker), and the
override GetStreamingSources (:109) translates each tracked source into a
real FWorldPartitionStreamingSource: it converts the metre load-radius to
centimetres (× 100), attaches an explicit-radius FStreamingSourceShape, sets
a debug colour by kind, forces 2D, and calls UpdateHash. Priority is policy,
not a constant: ResolvePriority (:192) gives the player Highest, a mission
marker High (Highest in the Sci-Fi cell, where objectives are the streaming
anchor), and a companion Normal. The high-density spec registers a player, a
mission marker, and 128 companions and asserts all 130 sources survive sorted —
player first, mission marker second, companion priority last — and that the
first emitted World-Partition source carries the 76800 cm radius. There is no
megabyte-budget HLOD pruner here the way V4 has one; V5 emits every registered
source and lets the engine's grid loading-range arbitrate.
Mission pre-warm and the HLOD ladder#
GetPrewarmCellsForMissionStart (:167) resolves a mission centre to the 256 m
partition lattice with FloorToInt(center / PartitionCellSizeMeters) and
returns the (2r+1)² block around it — radius 1 ⇒ the 9-cell 3×3 the spec
checks, including the centre cell. The HLOD model is UV5_Open_HLODRules
(V5OpenHLODRules.cpp:3): four layers on a contiguous distance ladder — HLOD0
0–256 m, HLOD1 256–512 m, HLOD2 512–1000 m, HLOD3 1000–2000 m flagged as
the silhouette. ValidateRules (:46) is a real authoring linter: it rejects
any cell size other than 256 m, demands exactly four layers indexed contiguously
with each band starting where the last ended, and requires HLOD3 to be the 2 km
silhouette layer. GetRuleForDistance (:26) resolves a distance to its band,
and the spec confirms 1500 m falls in HLOD3 and HLOD3 is the silhouette.
Data layers: weather, time-of-day, era#
Three UTickableWorldSubsystems drive World-Partition data layers for real.
UV5_Open_Weather (V5OpenWeather.cpp) runs a seven-state machine
(Dry/LightRain/HeavyRain/Snow/Fog/DustStorm/SolarFlare) with timed
transitions; GetCurrentGameplayModifiers (:99) lerps four gameplay scalars —
visibility, traction, crowd-density, clue-legibility — across the transition,
and ApplyWeatherDataLayer (:63) activates the bound UDataLayerAsset and
unloads the rest through UDataLayerManager::SetDataLayerRuntimeState. The spec
proves the blend: heavy rain at its midpoint reports alpha 0.5, reduced
visibility, and on completion a crowd-density scalar below 0.5 — weather
literally thins the streamed crowd. UV5_Open_TimeOfDay
(V5OpenTimeOfDay.h:13) models a 48 × 60-second day (the spec advances it
half a cycle from 06:00 and lands on 18:00, and IsNight is
hour ≥ 20 || hour < 5). UV5_Open_DataLayer_Era (V5OpenDataLayerEra.cpp:16)
swaps the period-cell era bundle (1930s / 1947 / 1968) by activating exactly one
era's data layer — the engine seam for the period-authenticity world dressing.
Population: traffic and pedestrian spawners#
V5Open actually populates the streamed world. UV5_Open_TrafficSpawner and
UV5_Open_PedSpawner (V5OpenPopulation.cpp) hold per-cell densities and spawn
against them. GetPedestrianDensityPerSquareKm (:193) encodes the
architecture spec directly — Urban 250 people within a 100 m radius, Period 120,
Frontier 40 (settlements) / 6 (wilds), Hunter 60 / 10, Sci-Fi 80 / 30 — and
applies the period era scalars (1930s × 0.85, 1968 × 1.15).
GetTrafficDensityPerSquareKm (:137) does the same for vehicles (Urban
260/km², era-scaled Period 85/120/165, Frontier 18, Hunter 6, Sci-Fi 0 — no cars
in space). CalculateCountFromDensity (:19) converts a per-km² density and a
radius into an actor count via the real circle area π·(r/1000)², clamped to a
MaxActors ceiling. SpawnPopulation (:65) then seeds an FRandomStream,
picks a weighted spawn class (PickSpawnClass), and calls
UWorld::SpawnActor<AActor> at a uniformly-sampled radial position;
CullOutsideRadius (:100) Destroys anyone who drifts past the radius. The
density spec confirms Urban > Period > Frontier traffic, that 1968 pedestrians
outnumber 1930s, and — against a real game world — that spawning then culling
round-trips the active-actor count to the spawned count.
Crowd density and the Mass seam — V5Crowd#
The streaming side of crowds is the catalog plus the batch descriptor.
UV5_Crowd_Catalog::ValidateCrowdCatalogJson (V5CrowdCatalog.cpp:248) is a
strict schema-1 linter over Content/V5Crowd/Data/crowd_catalog.json: it
deserialises with FJsonSerializer, parses density profiles / body-language
libraries / bark lines, enforces unique ids, and rejects the set unless it has ≥
8 density profiles, exactly six era-bundle body-language libraries covering
six eras, ≥ 5000 ambient bark lines, and coverage of all five playable crowd
cells. The file on disk satisfies it for real — 1.5 MB, 8 density profiles, 6
libraries, and 6,050 authored barks — so the "thousands of lines" claim is
bytes, not a template generator. BuildPopulationBatch
(V5CrowdSystems.cpp:18) is the bridge to streaming load: it scales a profile's
PopulationWithin100m by a console-throttle percent and a streaming-churn
scalar, then derives an even EntitySpacingMeters from the spawn-circle area
(√(πr²/N)) and stamps the authored MassEntityTemplateId. The catalog spec
reads back Urban's 250-NPC target and asserts the batch preserves 250 on desktop
but throttles below it on a console build. GetPromotionRadius
(V5CrowdSystems.cpp:36) holds the lightweight-to-pawn promotion thresholds the
architecture names — Named 18 m, Generic 30 m, Ambient 60 m — and
EvaluatePromotion (:50) promotes mission-critical or actively-interacting
NPCs unconditionally. The panic, flee, witness-report, and bark-selection logic
that rides on top of these entities lives in
./perception-crowd-and-morality.md.
Procedural generation — V5Procgen#
Six BlueprintPure generators fill the open world deterministically, each
seeding an FRandomStream and emitting a StableFingerprint string so a re-run
with the same seed is byte-identical (every spec asserts
fingerprintA == fingerprintB and != differentSeed). The shared seed mixer
CombineSeed (V5ProcgenSystems.cpp:44) xors the inputs with the classic
spatial-hash constants (73856093, 19349663, 83492791) so distinct
cell/coord/pattern tuples decorrelate. The generators are: side-quests
(GenerateSideQuest, :259) over five authored patterns (talk-to-NPC, escort,
hunt, scavenge, race) with per-step jittered objective locations; frontier
random encounters (BuildFrontierEncounterTemplates, :288) — 320 weighted
templates across eight kinds and five region tags, with
SelectFrontierEncounter (:317) biasing Rescue encounters up for high-honor
players; monster contracts (GenerateContract, :360) drawing from 11
hand-authored archetypes with weakness tags, threat tiers, and crown rewards;
loot tables (RollLoot, :392) — a weighted-random walk
(SelectWeightedLoot, :139) over eight rarity-tiered entries; city
decoration (GeneratePartitionDecoration, :409) placing 36–60 cell-typed
prop instances per 256 m partition; and galaxy detail
(GenerateSystemDetails, :437) seeding mineral hotspots, anomalies, and
derelicts per Sci-Fi system. The spec coverage is concrete — 5 patterns, 320
encounters, 8 loot entries, ≥ 36 decoration instances, all three galaxy kinds —
and would fail instantly against a Math::random stub because it pins the
fingerprint, not just the shape.
How a streamed open-world session fits together#
The intended flow — assembled from the real functions above, even though no single in-tree loop wires all four modules together per tick — looks like this:
Related#
- ./perception-crowd-and-morality.md — the panic propagation, witness reports, barks, and morality that the streamed crowd this page spawns then runs on
- ./netcode-authority-and-determinism.md — the server authority and lockstep determinism behind the online modes the registry gates and the seeds it shares
- ./telemetry-build-and-data.md — the cook,
arcade-cabinet packaging, and content-as-data accounting (0 binary
.uasset, 29.uplugin) these systems assume - ../V5_ARCHITECTURE.md — the orientation hub