cubiomes reproduces Minecraft’s biome generation in two distinct ways depending on the target version. Versions up to 1.17 use a layer stack that progressively transforms a continent map down to block-level resolution. Version 1.18 and newer use a noise-based system where six climate parameters are sampled at each point and mapped onto a biome through a decision tree. The sameDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Cubitect/cubiomes/llms.txt
Use this file to discover all available pages before exploring further.
Generator struct, Range type, and genBiomes() function work across both systems, so you rarely need to know which system is active under the hood.
The Generator struct
Generator (defined in generator.h) holds all state for a single generator instance. You should treat it as opaque — always initialize it through setupGenerator() and applySeed().
union means only one of ls, bn, or bnb is active at a time — determined by the mc field set during setupGenerator(). The nn and en fields are always present because Nether and End generation are independent of the Overworld system.
Two generation systems
Layered generation (MC 1.0 – 1.17)
In layered generation the world is built top-down through a stack of transformation layers. Each layer reads from a coarser parent and refines the output. The stack runs from continental scale down to individual block scale:| Scale | Meaning | Example layer |
|---|---|---|
| 1:256 | One cell = 256×256 blocks | L_BIOME_256 — assigns biome categories |
| 1:64 | One cell = 64×64 blocks | L_HILLS_64 — adds hill and mutation variants |
| 1:16 | One cell = 16×16 blocks | L_SHORE_16 — computes beach and shore edges |
| 1:4 | One cell = 4×4 blocks | L_RIVER_MIX_4 / L_OCEAN_MIX_4 — blends rivers and oceans |
| 1:1 | One cell = one block | L_VORONOI_1 — applies Voronoi zoom to reach block precision |
Noise-based generation (MC 1.18+)
Starting with 1.18, Minecraft replaced the layer stack with a continuous noise map. Six climate parameters are sampled at each point usingDoublePerlinNoise:
| Index | Constant | Role |
|---|---|---|
| 0 | NP_TEMPERATURE | Hot/cold axis |
| 1 | NP_HUMIDITY | Wet/dry axis |
| 2 | NP_CONTINENTALNESS | Ocean–continent gradient |
| 3 | NP_EROSION | Terrain roughness |
| 4 | NP_SHIFT / NP_DEPTH | Vertical depth factor |
| 5 | NP_WEIRDNESS | Rare variant selector |
BiomeTree) maps that point to a BiomeID. The tree is embedded in the library and matches the data Minecraft uses at runtime.
The 1.18 End dimension still uses the pre-1.18
EndNoise system. BiomeNoise only applies to the Overworld.The Range type
ARange describes the region you want to sample. You must fill it before calling genBiomes().
Scale values
scale | Cell size | Typical use |
|---|---|---|
1 | 1×1 blocks | Exact block-level biome lookup with Voronoi sampling |
4 | 4×4 blocks | Default biome scale; best balance of speed and accuracy |
16 | 16×16 blocks | Chunk-level overview |
64 | 64×64 blocks | Region-level fast scan |
256 | 256×256 blocks | Continent-scale structure search |
scale == 1 the vertical position y is in block coordinates (1:1 mapping). For all other scales, y is in 1:4 coordinates (one unit = four blocks in height).
Common Range patterns
3D cache indexing
genBiomes() writes biome IDs into a flat integer array. The output is laid out as a row-major 3D array:
i_x, i_y, i_z are zero-based indices into the range volume. For 2D generation (sy == 0 or sy == 1) the i_y index is always 0, so the formula collapses to cache[ i_z * r.sx + i_x ].
Generating biomes
The full workflow usinggenBiomes():
Allocate the cache
Call
allocCache(&g, r) to get a correctly-sized buffer from malloc. You are responsible for calling free() on it.getBiomeAt() is a more convenient alternative that handles allocation internally:
What is the sha field in Generator?
What is the sha field in Generator?
sha stores the first 8 bytes of the SHA-256 hash of the world seed. It is used to seed the Voronoi noise in MC 1.15+. applySeed() computes it automatically — you do not need to set it yourself.Can I reuse the same cache buffer for multiple calls?
Can I reuse the same cache buffer for multiple calls?
Yes, as long as the buffer is at least as large as required by
getMinCacheSize() for the new range. The buffer is overwritten on each call.Does genBiomes work for the Nether and End?
Does genBiomes work for the Nether and End?
Yes. After calling
applySeed(&g, DIM_NETHER, seed) or applySeed(&g, DIM_END, seed), genBiomes() delegates to genNetherScaled() or genEndScaled() automatically.Versions and dimensions
Reference for MCVersion and Dimension enum constants.
Noise and layer systems
Deep dive into PerlinNoise, OctaveNoise, and the layer stack.