-
-
Notifications
You must be signed in to change notification settings - Fork 0
Contexts and State
WorldgenLib makes state explicit so a consumer can extend world generation without copying private engine fields or sharing mutable buffers across parallel columns.
ChunkContext is a class created for a terrain request. It contains:
| Group | Members |
|---|---|
| Coordinates |
ChunkX, ChunkZ, RegionX, RegionZ, ChunkSize, ChunkPixelSize, BaseX, BaseZ
|
| Map samples | Four corner samples for climate, ocean, and upheaval maps |
| World config |
SeaLevel, MapSizeY, OceanicityFactor, TaperThreshold, GeoUpheavalAmplitude
|
| Resolved blocks |
RockBlockId, FreshWaterBlockId, SaltWaterBlockId, LakeIceBlockId
|
| Terrain data |
TerrainYThresholds, Landforms, LandLerpMap, LandformMap, TaperMap
|
| Runtime objects |
Chunks, MapChunk, MapRegion, and the original Request
|
| Noise |
Distort2dX, Distort2dZ, TerrainNoise, and GeoUpheavalNoise
|
TaperMap is writable at the border-taper step. The other properties are the canonical inputs for the current request.
Use CustomData for communication between hooks in one terrain request. Keys should be namespaced by the owning mod:
var values = chunk.GetOrCreateCustomData(
"my-mod:erosion-values",
() => new float[chunk.ChunkSize * chunk.ChunkSize]);
if (chunk.TryGetCustomData<float[]>("my-mod:erosion-values", out var existing))
{
Consume(existing!);
}GetOrCreateCustomData protects initialization with a lock and rejects reuse of a key with a different type. The collection is safe to initialize from parallel hooks. The object stored in it is not automatically thread-safe. Partition or synchronize it yourself.
ChunkContext.SetChunkModdata writes generic data to the first generated chunk. SetMapChunkModdata writes generic data to the generated map chunk. The carving context provides the same operations after placement, including byte-array overloads.
Use moddata only for bounded, intentional persistence. Do not write one record per block. For region-scale numeric fields, use Registries-and-Sampling and its bounded RegionMapSlot format.
ColumnContext is a ref struct created inside the terrain loop. It exposes:
- coordinates:
WorldX,WorldZ,LocalX,LocalZ - mutable spans:
LandformWeights,OctaveAmplitudes,OctaveThresholds - derived values:
UpheavalStrength,Oceanicity - mutable values:
DistY,WaterBlockId - noise bounds:
NoiseBoundMin,NoiseBoundMax - prepared
ColumnNoise ColumnBlockSolidities
It is valid only during the callback. Do not store the context, its spans, its BitArray, or its column noise for later use. RecalculateOctaves() is the supported way to rebuild octave arrays after changing landform weights.
The Step 10 context is also a ref struct. It provides all vertical chunks and a global-Y accessor:
private static void FillBelowSeaLevel(
ChunkContext chunk,
ref ColumnCarvingContext column)
{
for (int y = 1; y < column.SeaLevel; y++)
{
if (!column.ColumnBlockSolidities[y])
column.SetFluid(column.LocalX, y, column.LocalZ, column.WaterBlockId);
}
}GetBlockDataAtY validates the global Y range and selects the vertical chunk. SetFluid validates local X/Z and converts global Y to the selected chunk's local Y. This avoids the common error of writing every Y level into the bottom chunk.
Map hooks receive RegionContext. It contains the region coordinates, IMapRegion, server API, current map, map noise sizes, custom-map access, generator access, and the force-request methods described in Map-Hooks. CurrentMap can be replaced by a compatible map before the host assigns it back to the region.
The terrain column loop is parallel. A safe consumer follows these rules:
- Keep per-column values in
ColumnContextor local variables. - Keep per-request values in
ChunkContext.CustomDatawith consumer-owned synchronization. - Keep persistent region values in a registered
RegionMapSlot. - Move expensive work to a region or chunk boundary.
- Never rely on callback arrival order across different columns.
These rules preserve deterministic output and keep the hot path close to vanilla allocation behavior.