Skip to main content

steel_core/worldgen/generator/
mod.rs

1//! This module contains the `ChunkGenerator` trait, which is used to generate chunks.
2
3pub mod context;
4mod empty;
5mod flat;
6mod generation_chunk;
7pub mod registry;
8pub(crate) mod vanilla;
9
10pub use empty::EmptyChunkGenerator;
11pub use flat::FlatChunkGenerator;
12#[cfg(feature = "benchmark-support")]
13pub use generation_chunk::benchmark_support as generation_benchmark_support;
14pub use generation_chunk::{CarversPhase, GenerationChunk, NoisePhase, SurfacePhase};
15pub use vanilla::{SteelPostNoiseState, VanillaGenerator, VanillaPostNoiseStateType};
16
17use enum_dispatch::enum_dispatch;
18use glam::IVec3;
19use steel_registry::biome::BiomeRef;
20use steel_utils::random::{
21    PositionalRandom as _, Random as _, RandomSource, RandomSplitter, name_hash::NameHash,
22    xoroshiro::Xoroshiro,
23};
24use steel_utils::{BlockPos, ChunkPos};
25
26use self::context::{ChunkGeneratorType, EndGenerator, NetherGenerator, OverworldGenerator};
27use crate::chunk::Chunk;
28use crate::worldgen::region::WorldGenRegion;
29use crate::worldgen::structure::StructureGenerator;
30use steel_worldgen::noise::Beardifier;
31
32/// A trait for generating chunks.
33#[enum_dispatch]
34pub trait ChunkGenerator: Send + Sync {
35    /// Returns the generator's minimum Y coordinate.
36    fn min_y(&self) -> i32;
37
38    /// Returns the generator's vertical generation depth in blocks.
39    fn gen_depth(&self) -> i32;
40
41    /// Returns the generator biome at one quart position without requiring a loaded chunk.
42    fn noise_biome(&self, quart_x: i32, quart_y: i32, quart_z: i32) -> BiomeRef;
43
44    /// Returns the climate-selected origin used by vanilla before searching for a safe spawn chunk.
45    fn initial_spawn_search_origin(&self) -> BlockPos {
46        BlockPos::new(0, 0, 0)
47    }
48
49    /// Returns the generator-provided spawn height used before falling back to the surface heightmap.
50    fn spawn_height(&self, min_y: i32, _height: i32) -> i32 {
51        let _ = min_y;
52        64
53    }
54
55    /// Returns the structure generator used for placement and locate queries.
56    fn structure_generator(&self) -> Option<&StructureGenerator> {
57        None
58    }
59
60    /// Creates the structures in a chunk.
61    fn create_structures(&self, chunk: &Chunk);
62
63    /// Creates the biomes in a chunk.
64    fn create_biomes(&self, chunk: &Chunk);
65
66    /// Fills the chunk with noise.
67    ///
68    /// `beardifier` carries pre-collected structure-piece terrain adaptation. The caller
69    /// (production: noise stage; tests: harness) is responsible for walking the chunk's
70    /// structure references and building the beardifier — this trait stays free of any
71    /// cross-chunk lookup. `None` skips the integration entirely (cheaper than passing
72    /// an empty beardifier).
73    fn fill_from_noise(
74        &self,
75        chunk: GenerationChunk<'_, NoisePhase>,
76        beardifier: Option<&Beardifier>,
77    );
78
79    /// Builds the surface of the chunk.
80    ///
81    /// `neighbor_biomes` maps `(quart_x, quart_y, quart_z)` to a biome palette ID,
82    /// reading from neighbor chunk palettes for out-of-chunk biome lookups (matching
83    /// vanilla's `WorldGenRegion.getNoiseBiome`).
84    fn build_surface(
85        &self,
86        chunk: GenerationChunk<'_, SurfacePhase>,
87        neighbor_biomes: &dyn Fn(IVec3) -> u16,
88    );
89
90    /// Applies carvers to the chunk.
91    fn apply_carvers(&self, chunk: GenerationChunk<'_, CarversPhase>);
92
93    /// Creates the per-region random source exposed by vanilla `WorldGenRegion.getRandom()`.
94    fn create_worldgen_region_random(&self, world_seed: i64, center: ChunkPos) -> RandomSource;
95
96    /// Applies structure piece placement and biome feature decorations.
97    fn apply_biome_decorations(&self, region: &mut WorldGenRegion<'_>);
98}
99
100pub(crate) fn worldgen_region_random_from_splitter(
101    splitter: &RandomSplitter,
102    center: ChunkPos,
103) -> RandomSource {
104    const WORLDGEN_REGION_RANDOM: NameHash = NameHash::new("minecraft:worldgen_region_random");
105
106    let mut named_random = splitter.with_hash_of(&WORLDGEN_REGION_RANDOM);
107    let region_factory = named_random.next_positional();
108    region_factory.at(center.0.x * 16, 0, center.0.y * 16)
109}
110
111pub(crate) fn xoroshiro_worldgen_region_random(world_seed: i64, center: ChunkPos) -> RandomSource {
112    let splitter = Xoroshiro::from_seed(world_seed as u64).next_positional();
113    worldgen_region_random_from_splitter(&splitter, center)
114}