Skip to content

Map Hooks

Zaldaryon edited this page Aug 28, 2026 · 1 revision

Map hooks

GenMapsHost generates one map region through the nine vanilla map stages. Each stage has a region hook, and the factory chain has a separate wrapper hook for consumers that need to wrap or replace a map generator before regions are generated.

The nine stages

Stage Registration Output
1 RegisterMapsGeoprovince Geologic province map
2 RegisterMapsClimate Climate map
3 RegisterMapsForest Forest map
4 RegisterMapsUpheavel Upheaval map
5 RegisterMapsOcean Ocean map
6 RegisterMapsBeach Beach map
7 RegisterMapsShrub Shrub map
8 RegisterMapsBiome Biome map
9 RegisterMapsLandform Landform map

Each stage receives a RegionContext. CurrentMap points at the map produced by that stage. A hook may edit the map in place or replace CurrentMap with another compatible IntDataMap2D. After the hook chain finishes, the host assigns the current map back to the corresponding region property.

private static void SmoothOcean(RegionContext context)
{
    IntDataMap2D map = context.CurrentMap
        ?? throw new InvalidOperationException("Ocean map is unavailable.");

    // Edit map.Data or replace context.CurrentMap with a compatible map.
    SmoothInPlace(map);
}

WorldgenLibAPI.RegisterMapsOcean(
    "my-mod",
    OrderBands.BeforeVanillaMax,
    SmoothOcean);

The stage hooks run after the host invokes the assembled map generator for that stage. Use a generator wrapper when the transformation must happen around the map layer itself.

RegionContext

The context exposes:

  • RegionX, RegionZ, and MapRegion
  • ServerApi
  • ChunkGenParams, when provided by the world-generation request
  • CurrentMap
  • the eight map noise sizes used by the active world configuration
  • GetMap(RegionMapSlot) for a persistent custom map
  • GetMapGenerator(MapGeneratorStep) after initialization
  • ForceLandformAt, ForceClimateAt, and RequireLandAt

Map hooks are region scoped. They must not assume that a different region is being generated at the same time or that a particular order of region requests exists.

Generator wrappers

RegisterMapGenerator wraps one of the nine MapGeneratorStep factory results:

WorldgenLibAPI.RegisterMapGenerator(
    MapGeneratorStep.Ocean,
    "my-mod",
    OrderBands.BeforeVanillaMax,
    (context, current) => new MyOceanLayer(current));

MapGeneratorContext contains the stage, seed, server API, map scale, landcover, ocean scale, landform scale, spawn-offset requirement, required-land coordinates, and climate noise when one is available.

The wrapper must return a non-null MapLayerBase. If it returns null or throws, WorldgenLib disables that registration and leaves the current generator chain intact.

Padding hooks

RegisterMapPadding replaces a local padding value for a map stage without requiring a transpiler:

WorldgenLibAPI.RegisterMapPadding(
    "my-mod",
    OrderBands.BeforeVanillaMax,
    (step, vanillaPadding) =>
        step == MapGeneratorStep.Upheavel ? 5 : vanillaPadding);

The returned padding must be non-negative. A negative value or an exception disables the registration.

Region finalization

RegisterMapsRegionFinalize runs after all nine maps have been generated and their map hooks have completed, before the map region is marked dirty for saving. Use it to derive custom region data from the finalized vanilla maps or to update a RegionMapSlot.

WorldgenLibAPI.RegisterMapsRegionFinalize(
    "my-mod",
    OrderBands.AfterVanillaMin + 20,
    context =>
    {
        RegionMapSlot slot = RegionMapRegistry.GetSlot("my-mod:streammap")
            ?? throw new InvalidOperationException("Slot was not registered.");
        IntDataMap2D streamMap = context.GetMap(slot);
        BuildStreamMap(context, streamMap);
    });

WorldgenLib flushes registered real region maps through their persistent moddata format when the region pass completes.

Force requests

The public force methods mirror the mechanisms used by vanilla map generation:

WorldgenLibAPI.ForceLandformAt(forceLandform);
WorldgenLibAPI.ForceClimateAt(forceClimate);
WorldgenLibAPI.RequireLandAt(mapX, mapZ);
WorldgenLibAPI.ForceRandomLandArea(positionX, positionZ, radius);

Calls made before the map host has initialized its map scales are queued and replayed at the safe point. This includes required-land data needed by the ocean generator constructor. The force objects use Vintage Story's own types and landform codes.

Full region adapter

WorldgenLibAPI.RegisterFullMapRegionGeneration(
    "my-mod",
    OrderBands.FinalOverrideMin,
    context =>
    {
        GenerateCompleteRegion(context);
        return true;
    });

Return true only when the consumer generated the complete region. Return false to allow another terminal adapter and then the normal nine-stage pass. A full-region adapter is appropriate for a genuinely non-decomposable algorithm, such as an incremental migration bridge.

Clone this wiki locally