Revision note (2026-09-30): This article records work from 2026-08-20. Early proxy designs, sample measurements, and evidence about the original algorithm are distinguished below. Pending work retains its historical validation scope. Later progress is covered in heightmap reconstruction and POI, Stamp, vegetation, and rock layouts.
RuntimePCG development retrospective · Runtime and networking
The previous article, From Parameter Panel to Playable World: A UE5 Production Loop for Procedural Terrain and POI Layout, completed the editor-side workflow. A Recipe can be previewed from a UE5 panel, baked into a Landscape, and then used for scene editing, asset persistence, and visual approval.
Runtime has a different set of constraints. During startup, a multiplayer match must generate a 2 km × 2 km terrain, resolve spawn, extraction, and POI locations, prepare grounded platforms for building Cells, create client meshes and server-authoritative collision, and verify that the Dedicated Server and every client joined the same world.
Cutting the heightfield into Tiles is only one step. The startup protocol must also answer five questions:
- which inputs determine the natural terrain;
- which decisions belong exclusively to the server;
- which results clients may reproduce locally;
- which differences may be repaired locally;
- and when terrain, collision, POI Cells, and players each become Ready.
The normal path does not replicate the complete field. The server publishes a versioned Recipe, the resolved Seed, authoritative LayoutData, and layered digests. Clients rebuild from those inputs. Both sides verify the inputs, gameplay layout, complete Field, and individual Tiles in order. The server sends authoritative R16 data only for a small number of content-mismatched Tiles.
Terrain content is still evolving. The early RuntimePCG path froze the R5-S6 Recipe to validate C++, Tiles, collision, and networking. The latest recovery work has moved to a configuration-driven stage graph: Region, SubRegion, HeightGroups, CornerHeights, continuous morphology, local residual, and natural StampGroups. The new Plain candidate is still being validated stage by stage on the Web side and is not counted as a completed runtime feature.
The two progress lines remain separate throughout this article. R5-S6 is the verified Runtime/DS baseline; Plain is a content candidate that has not yet migrated into UE. Terrain algorithms may change without rewriting the authority, lifecycle, or synchronization contracts.
I. Two Independent Contracts: Terrain Content and Multiplayer Sessions
Terrain stages and ownership
The terrain recovery pipeline assigns a separate owner to each stage:

A missing early stage cannot be disguised by a later one. Stamps cannot replace Region/SubRegion-scale structure. Local residual cannot cover the entire map with uniform roughness. POI platforms, roads, craters, and runtime deformation also remain outside natural terrain; they cannot be used to hide gaps in the recovered morphology.
The latest Plain candidate follows this staged structure, but the evidence level is not the same for every stage. Unpacked data confirms region_deciduous_base, GenerationRegionSettings record 25, fourteen valid SubRegion recipes, and the downstream ZoneItem, StampGroup, and StampInfo relationships. The runtime SubRegionCell constructor, exact height consumers, and source Stamp height textures have not been recovered. HeightGroup maps, CornerHeights, continuous morphology, and Stamp height profiles must therefore be described as configuration-constrained reconstructions rather than original game formulas.
With POIs, roads, and runtime deformation disabled, the current Plain candidate exposes Region/SubRegion ownership, broad support, medium morphology, local residual, and natural Stamp population independently. The latest P-ST1 filters fourteen StampGroups and seventeen usable support assets under ZoneItems 54, 56, and 57. A fixed Seed currently produces six parent clusters and roughly 90–96 members. Those numbers describe a reconstruction candidate, not decoded original runtime instance counts, and the candidate has not entered the UE baseline.
A runtime Recipe identifies the versioned stage graph, configuration relationships, and deterministic execution rules in addition to parameter values. Any stage, parameter, asset set, or ordering rule that changes the final R16 belongs in the version or digest.
The multiplayer-session contract is independent of biome style
Runtime code does not need to understand the artistic meaning of a biome. It requires a terrain generator with a precise interface:
- the same version, Recipe, Seed, and asset set produce the same result;
- the complete generation domain and sampling convention are explicit;
- final height can be quantized into one unambiguous session R16 representation;
- the layout layer can query slope, relief, connectivity, and key-point height;
- every content change can be detected through a version or digest.
Content research and runtime engineering can then advance independently. The frozen R5-S6 Recipe remains the Runtime/DS regression fixture. Plain and later candidates first pass staged ablation, multi-Seed comparison, and evidence-boundary review on the Web side. Migration updates the algorithm version, RecipeDigest coverage, and fixed-Seed fixtures without replacing the network protocol.
Scope of Recipe identity
An early Recipe looked mostly like a collection of final terrain controls: world size, mountain amplitude, smoothing radius, Stamp count, and material thresholds. That is no longer sufficient. Two clients can receive identical values and still diverge if they select different Region records, SubRegion rows, StampGroup pools, or stage switches.
Recipe identity covers at least four categories.
The first is domain and sampling: world size, resolution, whether samples lie at pixel centers or grid corners, and the coordinate mapping between the complete field and Tiles. A half-texel offset is already enough to break bitwise comparison.
The second is configuration relationships: the selected RegionInput, GenerationRegionSettings, SubRegionSettings, ZoneItem, StampGroup, and StampInfo sets and their stable identifiers. Raw fields and relationships must be retained. A protocol layer should not rename an undecoded groupRange into a radius or a distance in metres.
The third is stage topology: which stages are enabled, their order, and which stage owns each output. Moving medium morphology behind the Stamp pass creates a different algorithm even if every exposed slider remains unchanged.
The fourth is deterministic adjudication: parent-range sorting, candidate tie-breaking, Stamp Placement order, container output order, and quantization rounding. These rules may have little artistic significance, but they directly affect digests.
RecipeDigest does not need to transmit every large array. It does need to identify all of the above. The algorithm version separates incompatible generations; RecipeDigest proves that both peers are executing the same job within one generation. The two checks operate at different levels and neither replaces the other.
Separate editor and runtime backends
The editor path already creates Landscape assets. Moving the same operation to BeginPlay would still be the wrong runtime architecture.
Editor generation emphasizes persistence, art refinement, and offline builds. Runtime generation requires asynchronous work, chunking, cancellation, frame-budgeted commits, Dedicated Server support, local collision rebuilds, and network repair. Landscape editing APIs, Edit Layers, Nanite data, and derived resources primarily serve editor production and do not fit match-loading-time elevation changes.
RuntimePCG therefore uses two backends. The editor writes Landscape; the runtime owns a Tile mesh. The core algorithm remains in the render-independent TerrainGen module. TerrainGenRT consumes the authoritative heightfield and creates UDynamicMeshComponent objects, collision, and network state.
The final module split is:

This split keeps LandscapeEditor and other editor-only modules out of the Dedicated Server. The server loads only the runtime dependencies required for height data, layout queries, and authoritative collision, allowing the same implementation to run under -server -nullrhi.
II. Authoritative Heightfield: Whole-Domain Generation, Tile Consumption
4097² is the generation domain; Tile is the runtime consumption unit
The runtime map covers 2048 m × 2048 m. Its authoritative heightfield has 4097² vertices at roughly 0.5 m spacing. It is divided into a 16 × 16 Tile grid. Each Tile contains 256 quads, 257² vertices, and covers 128 m × 128 m.
The complete authoritative field is generated before it is cut into Tiles. Individual Tiles do not run the terrain algorithm independently.
R5-S6 depends on global context and cannot be evaluated from one coordinate alone. Its base, HeightGroups, Stamps, and spectral layers operate over the full domain, with global sorting, statistics, and a fixed Placement fold order. Generating 256 Tiles independently would change sampling domains, local normalization, and cross-Tile Stamp ordering, producing boundary differences.
The full-field pipeline avoids those problems:

Every Tile shares one ZMin/ZMax range. Border samples come directly from the same quantized array and can therefore be compared as exact uint16 values. The WP5 regression recorded zero mismatched adjacent-border samples.
Tile is the consumption granularity for commit, LOD, collision, and repair. The authoritative algorithm domain remains the complete field. Partitioning runtime work does not make the generator a local function.
Determinism beyond the Seed
The same Seed only defines the starting point of random selection. It does not describe the complete generation environment.
The result may change if any of the following differs between peers:
- one Recipe parameter changes;
- a new parameter is omitted from replication or the digest;
- the algorithm version differs;
- integer wrapping or Hash implementations differ;
- an intermediate changes from
doubletofloat; - parallel execution changes reduction order;
- Stamp assets or Placement order differ;
- container iteration order participates in tie-breaking;
- one peer is missing a Stamp file required by a Cell.
The R5-S6 port established several baseline rules: use explicit integer Hash functions instead of FMath::Rand; retain double for important intermediates; replay order-sensitive folds in a fixed global order; use scan order as the tie-breaker; and require bit-identical output for repeated runs with identical inputs.
Parallelization must preserve the same contract. Pixel loops without write conflicts are parallelized in row bands, while floating-point reductions still run serially in original index order. The Stamp fold changed from scatter to per-pixel gather, but each pixel still executes the same floating-point operations in the same Placement order. The 4096² core improved from about 17.55 seconds serially to 1.47–1.56 seconds in parallel. Serial and parallel buffers remained identical under Memcmp, and all eight JavaScript fixtures continued to pass.
The result proves bit-identical regeneration for one binary, platform, and input set. The network protocol separately verifies that both peers used the same version and inputs and that their current results were not modified. Both guarantees are required.
R16 as both commit format and repair format
A 4097² float heightfield occupies about 64 MB; R16 occupies about 32 MB. The runtime session quantizes the complete field to uint16 with the shared ZMin/ZMax range:

Runtime R16 differs from the absolute-height encoding used by editor Landscape. It serves two purposes:
- Tile meshes, collision, and digests consume stable integer input.
- The server can send the R16 payload of one mismatched Tile directly to the client.
In the 4096² benchmark, R16 encoding took about 45.1 ms and decoding about 4.4 ms. Maximum round-trip error was 0.156 mm, far below gameplay and collision tolerances at approximately 0.5 m XY spacing.
Integer encoding also provides a stable byte sequence for digests. Tolerance-based float comparison would couple network validation data to an error threshold, and changing that threshold would change compatibility with older clients. R16 turns the result into versioned discrete data.
III. Tile Session Stages and Terminal States
From background generation to game-thread commit
Completing a 4097² height calculation in a worker thread does not permit 256 meshes and collision bodies to be submitted to the game thread at once. Runtime generation needs an observable, cancellable, and throttled state machine.
The session stages are:

Generation, quantization, slicing, and validation run in the thread pool. Each game-thread Tick dequeues a bounded number of Tiles according to CommitCap. WP5 used a cap of four per frame, and the observed peak was also four. Across three Seeds, Bake took approximately 1.84–2.04 seconds; including frame-budgeted commit of all 256 Tiles, a full session took about 2.8–3.0 seconds.
Cancellation has a defined terminal state. The current core cannot stop at an arbitrary pixel, but it checks the cancellation flag between major stages. On cancellation, already sliced Tiles are cleared and all uncommitted data enters Cancelled; the system never leaves a map with collision on one half and no collision on the other. A test cancelled 50 ms after Bake began and produced zero committed Tiles and 256 cancelled Tiles.
Convergence is more important than simply moving work off the game thread. A complete asynchronous design must define who releases results after cancellation, whether an Actor continues ticking after failure, and whether old components are destroyed before retry. Layout retries in network sessions expose all of these lifecycle gaps at once.
Runtime mesh, LOD, and seams
Each Ready Tile reconstructs an FDynamicMesh3 from R16 and submits it through UDynamicMeshComponent. LOD uses sampling steps of 1, 2, and 4. Normals are always calculated from central differences in the full-resolution authoritative field, so an LOD transition does not change the height or broad slope direction of retained samples.
Runtime distance bands use LOD0 within 600 m, LOD1 from 600 to 1400 m, and LOD2 beyond 1400 m. LOD checks are throttled to once every 0.25 seconds, with a per-frame rebuild cap to prevent a fast camera move from rebuilding many Tiles in one frame.

Tiles at the same LOD share border samples. Different LODs still need to hide cracks caused by tessellation mismatch. The prototype uses skirts, whose depth increased from 6 m to 30 m. The observed failure came from a candidate Recipe whose 64 m edge flattening produced a near-vertical cliff; under grazing views, the LOD chord error exceeded the shallow skirt depth.
Restoring the frozen Recipe produced clean distant, near, and top views. The fault belonged to content configuration rather than Tile slicing. A production solution should align boundaries to the coarsest neighbor rather than keep deepening skirts, but separating an extreme Recipe from a pipeline defect was sufficient for this prototype stage.
In the WP6 fixed-camera capture, the near view contained an LOD distribution of 53/182/21 and approximately 13.08 million triangles. Top-view ProfileGPU frame time was 3.98 ms. These figures describe one workstation, window resolution, and prototype material; they are not a target-machine budget.
Authoritative ground on the Dedicated Server
A Dedicated Server does not render the terrain, but it still creates terrain components for authoritative collision.
The server must decide character grounding, movement, raycasts, and gameplay interactions. Without authoritative collision it would have to trust the height reported by the client, which defeats the purpose of a Dedicated Server.
RuntimePCG creates terrain components on the server with visibility disabled. Rendering LOD bands are disabled, and a fixed sample rate defines the authoritative surface. The current collision path uses DynamicMesh Complex-As-Simple with asynchronous Cooking; Chaos FHeightField has not been integrated.
Chaos::FHeightField in the UE 5.8 source can consume uint16 directly. It remains a reasonable future path for per-cell physical materials, footsteps, or tire friction. Complex-As-Simple is sufficient for the current scope: all 2,304 client-side cell-center raycasts hit, with a maximum height error of 1.2 cm; all 240 samples across 15 internal Tile borders hit with zero height error. The corresponding Dedicated Server test recorded a maximum error of 1.4 cm.
An automated character landed within 3.0 cm, walked 102.5 m across one Tile border, and maintained a maximum foot error of 4.1 cm. Adding a second collision representation without a defined gameplay requirement would increase generation, synchronization, and validation costs.
Dedicated Server validation also exposed a timing issue. bHasCookedCollisionData could already be true while immediate full-map raycasts still missed a small, varying set in the last submitted Tile band. The client never reproduced it because its capture phase naturally waited more frames. Investigation showed that completed Cooking data does not guarantee that the scene-query acceleration structure has consumed the geometry in the same frame. Adding a 150-frame grace stage after DS collision readiness made all raycasts stable.
An asset may report that its work is complete before a consumer subsystem can query the result. Runtime generation crosses threads and subsystems, so this delayed-visibility stage should be modeled separately instead of being folded into one Ready Boolean.
Client and Dedicated Server read the same R16 through different backends. The client builds visible meshes, LOD, materials, and collision. The server builds fixed-precision invisible collision and skips camera-driven LOD. Their component trees may differ; their authoritative surface must still come from identical Tile content.
Cross-peer identity is therefore calculated from R16 rather than the rendered Mesh. Mesh data changes with LOD, normal strategy, skirts, and client graphics configuration. R16 sits between generation output and engine-specific consumers and is the lowest shared representation both sides can interpret consistently. If the server later moves to Chaos FHeightField while clients keep DynamicMesh, network validation data remains unchanged as long as both read the same R16.

IV. Server Layout Decisions and POI Terrain Writeback
Playable-layout constraints
Seed-to-height is sufficient for a terrain image. A playable map also needs spawn, extraction, POIs, and routes.
The layout solver is a pure function of authoritative R16. Spawn is selected from a southern band and extraction from a northern band. Candidates pass local and macro flatness gates: an 8 m window requires enough samples below 3° and less than 1 m of relief, while a 64 m window rejects locations that are locally flat but sit on a broad mountainside. Candidates must also belong to the flood-filled region connected to spawn.
The final implementation provides three POI placement modes:
- greedy placement that maximizes the minimum distance between candidates;
- stronghold clusters that arrange satellites in a ring around an anchor;
- Voronoi partitioning with farthest-point seeds and six Lloyd relaxation passes, giving each of 14 POIs its own region.
The default Voronoi mode prevents POIs from collapsing toward the map center. Voronoi only assigns spatial ownership; polygon boundaries are never written directly into elevation.
The solver also constructs primary and secondary routes. Traversal cells are 2 m wide; areas steeper than 35° are blocked and then dilated. The primary route uses A*. The secondary route applies a high cost to the 25 m corridor around the primary route, forcing a different path. The result is accepted only when route overlap is below 60%.
If extraction is disconnected, a POI is unreachable, the alternate route overlaps too much, or a trap exists near a critical point, the server rejects the layout. An LCG deterministically derives the next Seed and retries the complete process up to three times. All 100 Seeds passed with retry0 under the frozen Recipe. Under a cliff stress Recipe, 94 of 100 passed within three retries; the remaining failures placed the extraction region behind a macro cliff.
The retry chain must also be reproducible. The same initial Seed, Recipe, and validator must select the same resolved Seed, retry count, and layout signature. Otherwise the server may find a valid map while clients cannot identify which map was selected.
Session and Layout responsibilities in one authoritative package
A client could theoretically rerun layout search from the Seed, but the accepted layout is a gameplay decision. If spawn, extraction, POI types, the resolved retry Seed, or critical routes differ, two peers are not in the same match even if their terrain heights are identical.
The current implementation uses FTerrainLayoutData as one composite authoritative package. Algorithm version, resolved Seed, grid specification, Recipe, expected digests, retry result, and critical points all reach the client through this path. The C++ structure is still composite, but its protocol responsibilities divide into two groups.
The Terrain Session Descriptor defines the job the client must reproduce: algorithm version, Recipe, world and grid specification, Tile contract, session quantization range, and the expected Field and Tile identities.
The Terrain Layout Data defines the gameplay adjudication accepted by the server: initial and resolved Seeds, retry count, spawn, extraction, POIs, Cell assignments, primary and alternate routes, and the identity and application order of Gameplay Stamps.
The diagram separates protocol responsibilities; the current network does not send two separate large objects. Clients do not rerun the server’s layout search. They reconstruct and verify the world from the resolved Seed and accepted layout.
LayoutData carries the server’s decisions; the heightfield is rebuilt from deterministic inputs, avoiding a tens-of-megabytes full-field transfer on the normal path.

Natural StampGroups and POI platforms belong to different layers
The term Stamp refers to two different systems in this article.
Natural StampGroup/StampInfo belongs to the terrain-content chain. It follows Region, SubRegion, continuous morphology, and local residual, adding terrain-conditioned local forms. Plain P-ST1 currently lives at this layer and remains a reconstruction candidate under validation.
A Gameplay POI Stamp belongs to layout. The server first chooses where a building Cell will be placed, then writes a platform, entrance, and transition region back into terrain. It connects procedural terrain to authored level assets and does not participate in natural-terrain recovery.
The early implementation generated terrain and then translated an entire building Cell vertically. That aligned one central height, but platform edges could still float or become buried. The current pipeline uses two bakes:

The first bake produces natural terrain for slope, connectivity, and candidate evaluation. The server then selects POIs and Cells and derives their platform Stamps. The second bake reproduces the same natural terrain and applies Gameplay Stamps in stable order, producing the final authoritative Field. Only the second result enters Tiles, collision, and network digests.
Clients never repeat server-side POI search. They must receive, or derive without ambiguity from the composite package, the complete Gameplay Stamp sequence for the match. Protocol identity must cover the Stamp index, owning POI and Cell, Transform, platform and transition extents, every height-affecting value, application order, and data version. The fields may remain distributed across existing structures, but they cannot depend on a fresh local selection.
The three ownership layers map to three identities:
| Ownership layer | Identity and digest |
|---|---|
| Region/SubRegion, natural StampGroups, and natural execution order | Recipe / RecipeDigest |
| POIs, Cells, routes, Gameplay Stamp list, and application order | LayoutData / LayoutDigest |
| Final R16 after the second bake | FieldDigest / Tile ContentDigest |
The existing code and logs retain the name RecipeDigest. It identifies the complete generation input for the match, including the resolved generation Seed; it is not merely a Hash of one Recipe DataAsset file. Gameplay Stamps remain part of Layout identity, while their final effect is verified by Field and Tile digests.
One match currently uses eighteen Gameplay Stamps across the airport, resource facility, strongholds, extraction, and selected terrain Cells. POI0 is fixed to the airport and POI1 to the resource facility; remaining facilities are assigned from their candidate pool in deterministic order. The Seed also selects a sandy, arctic, or magma ecology. Cells prefer the matching ecology, while unclassified acts as a wildcard.
The scope here is limited to POI placement results, terrain write-back, Cell streaming, and multiplayer consistency. A later POI-layout article will cover how facility type, elevation, passes, sight lines, road entrances, and mission relationships affect placement scores. The current result is not a recovered complete POI-generation algorithm.
Cell assets need semantics that runtime systems can consume
The project filtered thirty-seven Cell candidates down to thirty-three usable assets and converted seventeen metadata columns into a DataAsset. Classification is not folder organization; it determines whether the layout solver can select a legal asset for a role.
Extraction chooses only Cells with extraction semantics. Pure terrain Cells enter an open-landmark pool by grade. Facility Cells use constrained candidate sets. The data already reserves slope, elevation, flatness, and connectivity fields, but type-to-terrain scoring—such as a detection tower preferring high ground, a bunker preferring a pass, or an airport preferring a broad low-slope area—is not complete.
A Cell’s authored platform Mesh must be hidden after the second bake. Otherwise it overlaps the procedural surface, causing Z-fighting or incorrect collision. The final rule combines asset role with relative size so that small platforms are not missed and extraction water is not misclassified as an ordinary flat plane. Diagnostics associate instances with stable Stamp indices rather than Actor display names that Unreal may uniquify.


Dynamic map paths must also become Cook dependencies. A string stored in a DataAsset does not automatically create a trackable asset reference, so an editor success does not prove that a packaged build contains the map. All thirty-three Cell maps are explicitly included in MapsToCook, allowing clean packaged clients and the Dedicated Server to complete dynamic streaming.
These Cells come from internal reverse-engineering research assets and are used only to validate the prototype. They are not distributable deliverables for a public repository or commercial build. The article documents Cell semantics, terrain interfaces, and streaming mechanics without distributing the restricted source assets.
V. Generation-Protocol Synchronization on the Dedicated Server
Transfer policy for the normal and exceptional paths
The two obvious synchronization strategies each solve only half of the problem.
The server could send the complete 4097² R16 field to every client. That centralizes floating-point determinism risk, but each uncompressed field is roughly 32 MB. Reconnects, multiple clients, and repeated match starts would put that cost on the normal path and leave the compatible local generator unused.
The server could instead send only a Seed. That minimizes traffic, but silently assumes that version, Recipe, assets, layout retries, sampling, and quantization ranges are already identical. When results diverge, a Seed-only protocol cannot even tell whether the error belongs to input, gameplay layout, or generated content.
RuntimePCG combines the two strategies. The normal path sends the description and authoritative digests needed to derive the world. Clients do the local computation. If layered comparison isolates a small number of content-level Tile mismatches, the server sends authoritative R16 for only those Tiles.
The design assumes that compatible binaries and asset sets pass directly in almost every session, while local mismatches remain rare and bounded. If a cross-platform matrix later shows frequent broad divergence, Tile Repair must not become a routine transfer mechanism. Full-field delivery, platform-specific quantized outputs, or a pregenerated content library would then need to be reconsidered.
Authoritative startup order for one world
The server selects the Recipe and initial Seed, generates natural terrain, and validates the layout. Once accepted, it resolves POIs, Cells, and Gameplay Stamps and performs the second authoritative bake. It then publishes LayoutData, the quantization range, and layered digests.
Each client rebuilds the final Field from those authoritative inputs, checks Version, Recipe, Layout, Field, and Tiles, and reports an Ack. Local Repair runs only when required. Player entry waits until repair, collision, and Cell streaming have all reached queryable terminal states.

The normal-path data has two logical groups. The Session Descriptor side contains TerrainGenAlgoVersion, Recipe and RecipeDigest, resolution, Tile size, world size, ZMin/ZMax, FieldDigest, and 256 expected Tile digests. The LayoutData side contains initial and resolved Seeds, retry count, spawn, extraction, POIs, Cell assignments, routes, Gameplay Stamp order, and LayoutDigest.
The current implementation transfers these fields in one composite authoritative package. The responsibility split does not imply two separate large network objects. A client reproduces the world already adjudicated by the server; it does not draw a new random map.
Layered digests and difference ownership
A single whole-field Hash can detect a difference but cannot say whether it came from inputs, gameplay adjudication, or one local content block. RuntimePCG therefore separates the identity chain by ownership.
RecipeDigest: are both peers running the same job?
RecipeDigest covers the resolved generation Seed, world and grid specification, the raw bits of every value that changes natural height, and the stable asset identifiers and execution order of natural StampGroups. Once the configuration-driven algorithm enters runtime, it must also cover Region/SubRegion configuration versions, stage switches, selected ZoneItem and StampGroup sets, and stable ordering. Gameplay POI Stamps do not belong here.
Tile repair is meaningless when RecipeDigest differs. A client may be using an old algorithm or missing a parameter, so repairing one Tile would leave continuing divergence elsewhere. A Recipe gate failure is logged and disconnected explicitly.
LayoutDigest: did both peers receive the same gameplay decision?
LayoutDigest covers the initial and resolved Seeds, retry count, stable critical-point order, Cell assignment, and the Gameplay Stamp list and application order. It remains independent from the height digest because identical terrain with different POIs is still a structural mismatch.
FieldDigest: is the complete field identical?
FieldDigest chains all Tile digests in coordinate order. It provides a whole-field identity for logs, quick comparison, and acceptance reports.
Tile ContentDigest: which Tile differs?
The complete R16 payload of each Tile is hashed with 64-bit FNV-1a. The client compares Tiles individually and builds a coordinate list of mismatches. This is the granularity used by Ack and local Repair.
Together the layers form a diagnostic route:

The digests provide consistency checks and fault localization, not cryptographic security. Repair blocks are not currently signed or encrypted. Anti-cheat and content security remain separate systems.
Handling paths for digest failures
A Version failure means the protocol generations are incompatible. The client may be missing a stage or interpreting quantization differently and must not enter the match.
A RecipeDigest failure means the peers received different generation inputs. Sending the currently mismatched Tile would not fix future regeneration or divergence elsewhere, so this case never enters content-level Repair.
A LayoutDigest failure means gameplay adjudication has diverged. Different spawn, POIs, or retry Seeds define a different match. The client must accept authoritative LayoutData again or terminate if it still cannot reproduce the result.
Only when Version, Recipe, and Layout agree may a Field or Tile content mismatch enter R16 Repair. At that point both sides agree on what should have been generated and the difference is bounded to explicit coordinates. Repair then recomputes Tile and Field identity to prove convergence.
The production threshold between “few” and “many” mismatches is not yet defined. A final implementation needs a limit derived from compression, timeout, and observed failure distributions: repair below it; reject, rejoin, or switch to an authoritative full-field path above it. The current completion claim covers only the demonstrated small-number Tile Repair path.
Client-owned upstream channel for Ack
After local regeneration, reception of LayoutData, and reception of expected digests, the client runs the Version, Recipe, and Layout gates and compares every Tile. It then sends an Ack containing its RecipeDigest, FieldDigest, and flattened mismatch-coordinate list.
The first implementation placed the Server RPC on ATerrainWorldActor, where most terrain state already lived. Network ownership does not allow a client to issue a Server RPC on a map Actor owned by the server. The reliable upstream channel owned by the client is its PlayerController.
The final split is:
ATerrainWorldActorowns generation state, digests, and repair application;ATerrainPlayerControllercarriesServerTerrainAckand client Repair RPCs;ATerrainGameModeonly selects the correct PlayerController class.
Terrain state ownership does not determine RPC placement. Network ownership determines the channel, and PlayerController forwards the message to the terrain system.
Ack comparison must recompute the current Tile instead of reading the digest cached after generation. Tamper occurs after that cache is created, so the old value cannot represent the modified data. DebugComputeTileDigestNow evaluates the current content and makes the modification detectable.
Ack and Repair state is maintained per connection rather than as one global Boolean on the terrain Actor. One client may pass immediately while another is being repaired; either may still be waiting for collision or Cell streaming. The complete connection lifecycle is:

Semantically, an Ack must identify the active session or generation, current stage, Version/Recipe/Layout/Field results, and mismatched Tile coordinates. Collision and Cell readiness may be included in staged Acks or advanced by separate messages, but the server must know where each connection stopped. PlayerController already identifies the sending network connection; the protocol does not need to trust a redundant client-reported identity merely to name the sender.
The two-client test has passed with one client on the normal path and the other in Repair. Explicit Session/Generation identifiers, idempotency keys for repeated Acks, and late-message filtering remain production work and are not claimed as complete fields in the current code.

Scope of local Repair
When the server receives an Ack with a valid RecipeDigest and a non-empty mismatch list, it reads authoritative R16 for each Tile, compresses it with zlib, and splits the payload into 16 KB chunks sent through reliable ordered RPCs.
In one measurement, a 257² Tile contained 132,098 bytes of raw R16, compressed to about 101 KB, and produced seven chunks. The client records coordinates, uncompressed byte count, total chunk count, and server ZMin/ZMax from the Begin message before assembling chunks in order.
The first completed-payload gate checks scale: server ZMin/ZMax must match the local session. If quantization ranges have diverged, identical R16 values represent different metric heights, and applying the payload would conceal the underlying error.
After decompression, the client writes R16 into both the Tile slice and corresponding full-field region, then:
- recomputes the Tile digest;
- requires it to match the server’s expected value;
- rebuilds the Tile mesh and collision;
- rebuilds its four shared-border neighbors so every consumer refreshes its edge;
- marks the local session consistent only after all requested Tiles converge.
If the digest still differs after repair, the protocol fails explicitly and the match cannot continue on an approximate result.
Tamper tests modified (3,5) and (7,9). In each case the client Ack reported exactly one mismatch and the server sent only that Tile. In a Dedicated Server test with two clients, one remained valid and the other was tampered; both completed their own independent protocol path.
Network validation used two kinds of injection. Low-level network simulation introduced 30% packet loss to confirm that the reliable channel eventually completed delivery. Application-level tests submitted duplicate, out-of-order, and late chunks directly to the Repair assembler to test idempotency, completeness, and generation isolation. Reliable ordered RPC does not normally expose out-of-order RPC delivery to application code. These results validate the tested assembly paths, not every public-network failure mode.
Reconnecting to an existing Session
During testing, repeatedly restarting a client produced the same POIs and appeared to indicate a broken random selector.
Random selection occurs when the Dedicated Server creates the match. A client joining an existing Session receives the Seed and LayoutData already chosen by that server and regenerates the same world. Restarting only the client returns to the same match and map.
A client that selects a new random map on every launch would not be joining the server’s world.
Logs and UI now distinguish:
- initial Seed;
- resolved Seed after layout retries;
- connected Session;
- Recipe profile and digest;
- whether the client is creating a world or reproducing an existing world.
Randomness needs an explicit owner and event: which peer selected it, when it was selected, and which selection other peers must reproduce.
Conditions for player creation
Height generation is followed by Tile commit, collision Cooking, layout validation, the second Stamp pass, Cell streaming, and network Ack. Spawning the player earlier can drop the character through unfinished ground, place it on a temporary platform, or produce different server and client landing heights.
RTDemo initially keeps the player in a hovering observation Pawn. After terrain reaches its terminal state, it switches to BP_ThirdPersonCharacter. The character lands at Spawn facing extraction. Multiple players use golden-angle offsets at 2.5 m to prevent capsule overlap.

A procedural Tile under construction or replacement must not become a stable movement base. The project intercepts these unstable terrain components in the character SetBase path; otherwise remote movement can inherit a changing reference frame and appear to jitter or slide. This is the only separately recorded engine-side seam. Terrain generation, layout, and synchronization remain in project modules.
VI. Complete-Startup Evidence and the Proper Scope of Generate Benchmarks
Implemented optimization comparison
| Area | Baseline or direct approach | Current implementation | Measured gain and boundary |
|---|---|---|---|
| 4096² height core | Approximately 17.55 seconds on one thread | Parallel row bands for pixel stages without write conflicts; reductions and Stamp order remain fixed | 1.47–1.56 seconds, approximately 11.3×–11.9× faster; serial and parallel buffers are identical under Memcmp |
| Complete heightfield representation | A 4097² float field occupies approximately 64 MB |
One session-wide R16 field is shared by Tiles, collision, digests, and Repair | Approximately 32 MB, halving field memory and a full-field payload; encoding takes about 45.1 ms, decoding 4.4 ms, with 0.156 mm maximum round-trip error |
| Game-thread commit | Submitting 256 meshes and collision bodies together would create a long frame | Generation, quantization, slicing, and validation run in the thread pool; the game thread commits through CommitCap |
WP5 commits at most four Tiles per frame; Bake takes 1.84–2.04 seconds and the session including all commits takes 2.8–3.0 seconds. No comparable one-shot frame-time capture was retained |
| Runtime mesh updates | Keep one full-detail mesh at every distance, or rebuild many Tiles after one camera move | LOD bands at 600 m and 1400 m, checks throttled to 0.25 seconds, with a per-frame rebuild cap | One WP6 fixed view used 53/182/21 LOD0/1/2 Tiles and about 13.08 million triangles; top-view ProfileGPU was 3.98 ms. This is a prototype-workstation observation, not a target-platform budget |
| Dedicated Server terrain backend | Reusing the visible client path would retain rendering work the server does not need | The server skips materials, camera LOD, and rendering, and creates only fixed-precision invisible authoritative collision | Terrain rendering work is removed from the server path; a same-machine CPU and memory A/B delta has not yet been recorded |
| Normal network path | Send each client the complete uncompressed R16 field, approximately 32 MB | Send Recipe, LayoutData, and layered digests; clients rebuild deterministically | Avoids the complete heightfield transfer on the normal path; this article does not yet use the actual descriptor and digest byte count as a bandwidth benchmark |
| Content repair | Resend the complete R16 field or restart the match | Compress and send only Tiles whose content digest differs | One 257² Tile compressed from 132,098 B to about 101 KB and used seven 16 KB Chunks; the advantage applies only when the mismatch set is small |
| Complete startup | Looking only at Generate can make a local speedup appear to solve startup |
Treat both bakes, layout, collision, Cell streaming, handshakes, and player landing as one critical path | Process launch to playable state still takes approximately one minute and does not meet a product loading budget |
The first three rows have explicit timing, capacity, or error measurements. LOD, the Dedicated Server backend, and the normal network path also remove work by design, but they should not be presented as percentage gains without same-machine A/B captures. The approximately one-minute complete startup further shows that optimization cannot stop at the height core.
Timing scope: Generate versus complete startup
The previous C++ performance article measured the parallel 4096² core at about 1.5 seconds and the Tile Session, including quantization and frame-budgeted commit, at about three seconds. A complete match currently takes approximately one minute from process launch to playable state. These measurements cover different scopes.
The core benchmark includes only the height algorithm. Complete startup also includes:
- engine and map startup;
- the first 4097² natural-terrain generation;
- layout candidate, connectivity, and route validation;
- deterministic Seed retry when required;
- Cell selection and Stamp Placement;
- the second 4097² bake with all Stamps;
- 256 Tile mesh builds, LOD setup, and GPU upload;
- asynchronous collision Cooking and scene integration for 256 Tiles;
- dynamic streaming, Actor initialization, and platform hiding for 18 Cells;
- Layout, Digest, and Ack handshakes between Dedicated Server and clients;
- character possession and landing.
Further reduction of the isolated Generate time cannot explain complete startup latency. Performance analysis must cover the full critical path and record generation, validation, rebake, commit, collision, streaming, and network-handshake stages separately.
Approximately one minute is still a prototype result and does not meet a product loading budget. It demonstrates pipeline closure; subsequent optimization must be prioritized from stage timing.
Regression coverage for normal and fault paths
Every generation change runs three test groups in a fixed order.
The layout batch requires all 20 Seeds to pass with zero deterministic replay failures, checking algorithms and layout without rendering.
The screenshot smoke test captures layout, distant, near, top, and per-POI views from fixed cameras while running collision and streaming diagnostics. A headless editor viewport does not render valid captures, so screenshots use -game -windowed -TerrainRTCapture; the same flag exits the process after completion.
Third, a two-process network test launches a Dedicated or Listen Server followed by a client and checks NETTEST and LAYOUTTEST. Passing requires an identical LayoutDigest, all 256 Tiles identical, and no FAIL line.
After the normal path passes, tests inject:
TerrainRTTamperX/Yto modify one Tile and confirm detection and local repair;TerrainRTFakeVersionto simulate a protocol mismatch and confirm disconnection;- packet loss, duplication, and reordering;
- a Dedicated Server with two clients, one valid and one tampered;
- a new client reconnecting after disconnection.
A useful test must fail accurately under injected errors and reconverge for errors defined as repairable. A green log line alone is not evidence.
Regression exposed four failures worth retaining because each changes multiplayer correctness. Several reflected Recipe values were declared on one UPROPERTY line and therefore did not all replicate; RecipeDigest exposed the difference. Ack originally read a cached digest and could not observe a later Tamper, so it now hashes current R16. Layout retry did not fully clear previous Tiles and one-shot state, allowing the next session to inherit stale objects. Finally, collision Cooking completed before scene-query structures could see the new geometry, which required distinct Generated and Queryable states.
All four failures live outside the height formula, yet each can make two peers disagree about the world.
Runtime scope of World Partition
A 2 km map naturally suggests World Partition. World Partition manages Actor Cells that were placed and described during an offline build. It does not convert a newly generated runtime heightfield into new Partition data, and dynamically spawned buildings do not automatically receive offline Actor descriptors.
The terrain system therefore schedules its own Tiles and uses ULevelStreamingDynamic for POI Cells. If buildings must be managed by World Partition later, candidate layouts can be baked into the editor database. Runtime-generated Actors will not be adopted automatically by the offline partition description.
World Partition and runtime height generation solve different ownership problems. The current implementation retains independent Tile scheduling and Cell streaming.
VII. Completion Boundary and Admission Criteria for New Algorithms
Verified Runtime/DS baseline
The current runtime prototype has completed:
- a 4097² authoritative heightfield and 16 × 16 Tiles;
- bit-identical generation for the same Seed and configuration;
- DynamicMesh rendering, distance-band LOD, and Complex-As-Simple collision;
- hidden rendering with authoritative collision on the Dedicated Server;
- Spawn, extraction, 14 POIs, routes, and deterministic retry;
- two-pass POI Stamps and 18 Stamps per match;
- dynamic Cell streaming and platform hiding;
- layered Version, Recipe, Layout, Field, and Tile validation;
- Ack, Tamper, and zlib Tile Repair;
- all 256 Tiles identical between Dedicated Server and client, with
mismatch=0; - Cell streaming with
ok=1on both sides; - TPS character entry after the terrain terminal state.
These results cover runtime and multiplayer infrastructure under the frozen Recipe. They do not mean that the latest terrain candidate has already migrated into UE.
The latest Plain work remains content research
Plain now has separately inspectable Region/SubRegion, HeightGroup, CornerHeights, broad support, medium morphology, local residual, and natural StampGroup stages. Several important pieces remain unresolved:
- the exact SubRegionCell construction and height consumer have not been recovered;
- HeightGroup, CornerHeights, and Stamp height profiles still contain reconstruction hypotheses;
- the P-SR2 distribution-based boundary remains too smooth and too C-shaped to freeze;
- the cluster and member rhythm of P-ST1 still needs validation against more references;
- POIs, roads, and runtime deformation remain disabled and cannot compensate for missing natural morphology.
The next C++/Runtime migration therefore starts at a freeze gate. When a candidate passes, the new stage topology, configuration version, asset list, and stable execution order enter RecipeDigest; TerrainGenAlgoVersion increments; fixed-Seed fixtures are regenerated; and the complete Tile, DS, Layout, Ack, and Repair matrix runs again.
Migration starts by freezing the Web-stage outputs and building intermediate fixtures. Region/SubRegion ownership, HeightGroup identity, CornerHeights, broad support, medium morphology, local residual, and natural Stamp deltas are compared separately before work moves to the 4097² C++ implementation.
Three interfaces form the gate:
- Complete-field interface: C++ and the Web reference use the same 4097² domain, sampling rules, configuration records, and execution order, and serial and parallel paths agree.
- Layout interface: after the new morphology changes slope, connectivity, and candidate distribution, the existing 8 m/64 m flatness windows, 35° blocking threshold, and retry limit remain valid—or are deliberately revised. Passing visual review does not automatically pass gameplay layout.
- Network interface: every new-stage input enters replication and RecipeDigest; the second POI bake preserves stable Placement order; and a repaired Tile reconverges to the server digest.
A failed check returns to the owning stage; no compensation is added to the final heightmap.

Next work
This article completes the Runtime/DS infrastructure, but it does not yet cover three areas that directly shape the final player experience and production quality: detailed POI placement, visual terrain refinement, and runtime performance optimization. All three will use the authority, second-bake, and multiplayer-validation paths established here, but none is counted as complete in this article.
The next phase has five workstreams:
- Natural-terrain content: correct Plain P-SR2 topology and validate Stamp population before deciding when to migrate. This stage still excludes POIs, roads, and runtime deformation.
- Gameplay and POI placement: refine terrain-semantic scoring for each POI type and incorporate road entrances, passes, elevation, sight lines, mission relationships, site spacing, and route structure. The current work covers deterministic placement, platform writeback, and synchronization; a later POI article will cover the placement algorithm itself.
- Visual terrain and landform refinement: after the natural-stage evidence boundary stabilizes, refine the overall silhouette, landform hierarchy, slope rhythm, Quiet Ground, and biome-specific presentation. This work has not passed final visual review and will be documented separately.
- Server and scene performance: establish CPU, memory, collision-Cooking, scene-query, and multi-connection startup budgets for the Dedicated Server. Client work will cover Tile commits, LOD rebuilds, Cell streaming, collision-query readiness, and complete-startup time. Current evidence includes only the height core, Tile Session, and partial GPU and collision measurements; it is not yet a production performance result.
- Production: add full-startup stage timing, a cross-platform determinism matrix, a Tile Repair count threshold, and security for authoritative repair content.
Conclusion
The runtime terrain system delivers world data that the server can adjudicate and every client can reproduce and verify, rather than a heightmap in isolation.
Natural-terrain stages produce the base field. Server layout selects spawn, extraction, and POIs. Gameplay Stamps connect authored buildings to the surface. Tile Session turns the complete field into throttled, cancellable, and repairable runtime objects. The Dedicated Server uses authoritative collision to adjudicate player behavior. Layered digests prove that clients reproduced the same match.
Configuration-driven terrain recovery will continue to change the internal structure of Recipe. The runtime boundaries remain fixed: authoritative inputs are versioned, client recomputation is verified, bounded content differences may be repaired, and structural divergence is rejected. POIs may write back into terrain, but they may not compensate for missing natural morphology.
Detailed gameplay rules for POI placement, final visual refinement of the terrain, and production performance optimization are outside the completed scope of this article. Later articles will cover POI placement against terrain semantics, roads, and mission relationships; the process of bringing the current natural-terrain candidate to an accepted silhouette, hierarchy, and visual rhythm; and budget-driven optimization of the Dedicated Server and client scene startup path.
New biomes, POI logic, roads, and cross-platform Dedicated Servers retain the same requirements for traceable inputs, verifiable results, and ownership-based fault diagnosis.
2 thoughts on “From Playable World to Multiplayer Session: UE5 Runtime Terrain, POI Placement, and Dedicated Server Synchronization”