CAbstractWorldmaker

Overview

UCAbstractWorldmaker is the abstract base class for terrain generation. It manages the tile grid, LOD computation, async build pipeline, noise blending and mesh lifecycle. Concrete implementations (UCWorldmaker_ProceduralMesh, UCWorldmaker_DynamicMesh) provide the actual mesh creation.

Pure Virtual Functions

Name Description
isFirstStart Returns true if no mesh has been created yet
cleanPmc Destroys the mesh component at a given UV index
calculatePoint Computes tile mesh data (LOD, vertex count, transform) for a world/relative UV pair
createPMC_sync Creates mesh components on the game thread from pre-calculated data
debug Toggles debug material on/off for all mesh components
// These must be implemented by subclasses:
virtual bool isFirstStart() = 0;
virtual void cleanPmc(FCUVIndex index, bool clearContent, bool remove = true) = 0;
virtual void calculatePoint(const FCUVIndex& world, const FCUVIndex& rel) = 0;
virtual void createPMC_sync(const TArray<TPair<FCUVIndex, FCUVIndex>>& pairUVArray, bool poolStart, int poolSize) = 0;
virtual void debug(bool onOff, UMaterialInterface* debugMaterial) = 0;

Build Pipeline

Name Description
buildASync Entry point called by the spawner. Runs drawFloor async then updatePMC_sync on game thread
wantDraw Guards against redundant draws: checks room state, pawn movement and queue status
drawFloor Computes the tile grid around the pawn, runs calculatePoint in parallel, enqueues pooled batches
updatePMC_sync Dequeues one batch, removes old tiles, calls createPMC_sync, broadcasts delegates
adaptPoolSize Dynamically adjusts pool batch size based on frame time
// buildASync is the main entry point, called each tick by ACWorldSpawner:
worldmaker->buildASync(singleDoRun, pawnX, pawnY);

// Internally:
// 1. wantDraw() checks if a new draw pass is needed
// 2. drawFloor() computes UV grid, runs calculatePoint() in ParallelFor
// 3. Results are enqueued as FCWorldDataQueue batches
// 4. updatePMC_sync() dequeues and creates meshes on game thread

Z Calculation & Noise Blending

Name Description
innerZCalculate Computes the Z height at (x,y) by blending world, cluster, room and edge noises
calcMax4PointSlope Samples 4 surrounding points to estimate terrain slope
calcNormal Computes a surface normal from 3 sample points
bendRotatorOnSlope Adapts a rotator to align with the computed slope
// innerZCalculate blends multiple noise layers:
// - worldNoise: base terrain noise
// - clusterNoise: per-cluster noise variation (with optional specific noise per cluster)
// - clusterShiftNoise: shift noise for cluster boundaries
// - roomNoise: noise variation inside rooms
// Blending uses easeIt() with the configured easeMethod (default QuinticInOut).

FLinearColor vertexColor;
float z = worldmaker->innerZCalculate(x, y, vertexColor);

// Vertex color encodes spatial context for material use:
// R = cluster proximity (0 = outside, 1 = center)
// G = room proximity (0 = outside, 1 = center)
// B = corridor/edge proximity (0 = outside, 1 = center)
// A = biome noise value (normalized)

Noise Sources

Name Description
worldNoise Base terrain noise, singleton CNAME_Singleton_WorldNoise
biomeNoise Biome boundary noise, singleton CNAME_Singleton_BiomeNoise. Stored in vertex color alpha
clusterNoise Cluster-level noise, singleton CNAME_Singleton_ClusterNoise. Can be overridden per cluster
clusterShiftNoise Cluster boundary shift noise, singleton CNAME_Singleton_ClusterShiftNoise. Can be overridden per cluster
roomNoise Room-level noise, singleton CNAME_Singleton_RoomNoise

State & Delegates

Name Description
isReady Returns true once noise initialization is complete
isBuilt Returns true once all tile batches have been processed
isRendered Checks if a tile at (x,y) is rendered, outputs UV index and full LOD status
onTileReady Delegate broadcast when a tile mesh is created (with UV index and fullLOD flag)
onTileRemoved Delegate broadcast when a tile mesh is removed (with UV index and area rectangle)
// Bind to tile lifecycle events:
worldmaker->onTileReady.AddDynamic(myObject, &ICWorldBoundable::onTileReady);
worldmaker->onTileRemoved.AddDynamic(myObject, &ICWorldBoundable::onTileRemoved);

// Check world state:
if (worldmaker->isReady()) { /* Z queries are safe */ }
if (worldmaker->isBuilt()) { /* all tiles generated */ }

FCUVIndex uvIndex;
bool fullLOD;
if (worldmaker->isRendered(x, y, uvIndex, fullLOD)) {
    // tile exists and is rendered
}