World Generator

A world generator is a deterministic class that knows which block exists at every coordinate.

World Generator Class Spec

A world generator, loosely defined, is a class that implements the IGenerator class, and with a constructor that takes two arguments (int seed, IBlockLookup blockLookup). The base class GeneratorBase will take care of a lot of the overhead for you, and I highly recommend you use it for backwards-compatibility reasons. In addition, you need to add the attribute WorldGenerator to the class to designate it as a world generator.

Example:

[WorldGenerator("MyWorldGen", Description = "My first world gen", Author = "Chris"]
public class MyWorldGenerator : GeneratorBase
{
  public MyWorldGenerator(int seed, IBlockLookup blockManager)
  {...}
 
  public override IBlock GetBlock(int x, int y, int z)
  {
    ..Deterministic code to get block at (x,y,z)..
  }
}

Your First World Generator

Flat World

The flat world generator is the easiest to understand and interpret. In this case, all blocks under the z-coord (Which is gernally up, but can be changed), will be grass, and any blocks deeper than coordinate -16, will be rock.

MyFirstWorldGenerator.cs
[WorldGenerator("FlatWorld", Author = "Chris"]
public class MyWorldGenerator : GeneratorBase
{
  private readonly int _seed;
  private readonly IBlockLookup _blockManager;
 
  public MyWorldGenerator(int seed, IBlockLookup blockManager)
  {
    _seed = seed;
    _blockManager = blockManager;
  }
 
  public override IBlock GetBlock(int x, int y, int z)
  {
    if (z <= 0)
    {
      return _blockManager.GetBlock<Grass>();
    }
    if (z <= -16)
    {
      return _blockManager.GetBlock<Rock>();
    }
    return _blockManager.EmptyBlock;
  }
}

Using Noise

Plugin Base comes with a few built-in noise operators, including perlin, simplex, and cell. You can read about them here: Noise generators

Advanced Noise Technique

TBD

Optimizations

Clearly, the world generator is at the root of all game engineering, so it's important to be fast. Keep in mind, that this GetBlock method will be called 28,311,552+ times just to render the world within your vision. So here are some tips:

  • Leave the method as soon as you know what you'll return (Don't store the value and return it at the end)
  • Try to eliminate 99% of the use cases first. If you know that all blocks above 100 will be air, check that first and return Air before continuing to other logic.
  • Use a block cache if you can. The BlockManager is optimized to be blazing fast, but a block cache will still out-perform calling into the manager.