Post-processing - Noise Generator
Post-processing is a powerful system that allows you to extend and customize the noise generator's level generation process. By creating custom post-processing scripts, you can alter how a level is generated. You can add extra steps to the generator or modify how built-in steps work.
Post-processing is only available for use with the Noise generator for now. If you would like to use it with a different generator as well, please let me know!
Overview
The post-processing system works by allowing you to register callbacks that execute at specific points during the generation pipeline. Each callback runs at a defined execution order, ensuring that operations happen in the correct sequence.
Post-processing scripts inherit from the NoiseGeneratorPostProcessor
class and are automatically discovered and executed by the NoiseGenerator
when attached to the generator object or as a child of the generator.
The NoiseGeneratorPostProcessor
base class inherits from MonoBehaviour
, so it is expected that each post-processor is attached to a game object in a scene.
Execution Order
Post-processing operations follow a specific execution order. Lower order values execute earlier in the pipeline:
Order | Operation | Description |
---|---|---|
100 | Noise Mapping | Converting noise values to tiles and biomes |
200 | Border | Adding borders around the level |
300 | Connectivity | Handling unreachable areas |
400 | Structures | Placing structures in the level |
500 | Chunk Sizes | Enforcing minimum tile chunk sizes |
1000 | Layout Generated | When the layout has been generated (int grid should not be modified after this point) |
1100 | Theme Engine | When the theme engine is applied |
2000 | Level Generated | When the level has been fully generated |
You should almost never use hardcoded order values when registering custom callbacks. From inside a post-processor, you can use constants from the ExecutionOrder
class like this: callbacks.RegisterAfter(ExecutionOrder.NoiseMapping, PlaceIslands);
.
Creating Custom Post-Processors
To create a custom post-processor:
- Create a new script that inherits from
NoiseGeneratorPostProcessor
- Implement the required
SetupCallbacks
method - Optionally override
SetupNoiseEvaluators
for custom noise calculations - Attach the script to your
NoiseGenerator
or to a child object
Basic Structure
public class MyCustomPostProcessor : NoiseGeneratorPostProcessor
{
public override void SetupCallbacks(GeneratorCallbacks callbacks)
{
// Register your callbacks here
callbacks.RegisterCallbackAfter(Priorities.Structures, ProcessLevel);
}
private object ProcessLevel(GeneratorResult result)
{
// Your custom processing logic here
// The result object should contain everything you need
return null;
}
}
Callback Registration
Use the Priorities
constants to register callbacks at the appropriate execution point:
// Execute after noise mapping
callbacks.RegisterCallback(Priorities.NoiseMapping, MyCallback);
// Execute after a specific priority
callbacks.RegisterAfter(Priorities.NoiseMapping, MyCallback);
// Execute before a specific priority
callbacks.RegisterBefore(Priorities.Structures, MyCallback);
Performance Considerations
For performance-heavy operations, return an IEnumerator
and use yield return null
to keep the game responsive:
private IEnumerator HeavyProcessing(GeneratorResult result)
{
for (int i = 0; i < largeArray.Length; i++)
{
// Process item
ProcessItem(largeArray[i]);
// Yield every few iterations to maintain responsiveness
if (i % 100 == 0)
yield return null;
}
}
Examples
Checkerboard Post-processor
Below is an example of a Checkerboard post-processor that replaces every other tile with a specific tile.

using Frigga;
namespace PostProcessing
{
// Inherit from the NoiseGeneratorPostProcessor base class
// Then create a child object under the generator object and attach this script to it
public class CheckerboardPostProcessor : NoiseGeneratorPostProcessor
{
// Tile that we will set on the checkerboard pattern
// Use the [IntGridTilePicker] attribute to get a tile picker in the inspector
[IntGridTilePicker] public int Tile;
// Biome that we will set on the checkerboard pattern
// Use the [BiomePicker] attribute to get a biome picker in the inspector
[BiomePicker] public int Biome;
// The SetupCallbacks needs to be overridden in each post-processor
public override void SetupCallbacks(GeneratorCallbacks callbacks)
{
// Register a callback here to alter the logic of the noise generator
// Here we let the generator run the NoiseMapping step first, then we run our checkerboard logic
callbacks.RegisterAfter(ExecutionOrder.NoiseMapping, HandleCheckerboard);
}
// Each callback receives a reference to the level being generated
private void HandleCheckerboard(GeneratorResult result)
{
foreach (var position in result.Bounds.allPositionsWithin)
{
if (position.y % 2 == 0 && position.x % 2 == 0 ||
position.y % 2 != 0 && position.x % 2 != 0)
{
// Get current tile data from the int grid
var tileData = result.IntGrid.GetTileData(position);
// Set the tile and biome if they are not zero
if (Tile != 0)
{
tileData.Tile = Tile;
}
if (Biome != 0)
{
tileData.Biomes.SetBiomeSelected(Biome, true);
}
// Save the modified tile data back to the int grid
result.IntGrid.SetTileData(position, tileData);
}
}
// Not needed here but if we change the bounds of the level, we should update them in the result
// result.Bounds = result.IntGrid.ComputeBounds();
}
}
}
Island Region Post-Processing
Look for the IslandRegionPostProcessor.cs file to see an example post-processor that generates a specified sub-region of an island level. You can find more information on the dedicated Island regions page.
Multi-Island Post-Processing
Look for the FriggaMultiIslandPostProcessor.cs file to see an example post-processor that generates a level made of multiple islands. You can find more information on the dedicated Nested generators page.
Advanced Usage
Custom Noise Evaluators
You can override the SetupNoiseEvaluators
method to alter how a specific noise is computed. This feature makes it possible to create your own noise algorithms or modify the existing behavior. The main idea is that inside the method you call evaluator.AddNoiseEvaluator
to replace one of the existing noises. An example of this behavior can be found in IslandRegionPostProcessor.cs.
public override void SetupNoiseEvaluators(CompositeNoiseEvaluator evaluator)
{
evaluator.AddNoiseEvaluator(noiseId, (position) => {
// Custom noise calculation logic
return Mathf.PerlinNoise(position.x * 0.1f, position.y * 0.1f);
});
}