Skip to main content

steel_core/worldgen/generator/
context.rs

1//! This module contains the `WorldGenContext` struct, which is used to provide context for chunk generation.
2
3use std::sync::{Arc, Weak};
4
5use enum_dispatch::enum_dispatch;
6use steel_worldgen::density_functions::{
7    end::EndNoises, nether::NetherNoises, overworld::OverworldNoises,
8};
9
10use crate::world::World;
11use crate::worldgen::generator::{
12    ChunkGenerator, EmptyChunkGenerator, FlatChunkGenerator, VanillaGenerator,
13};
14
15/// Type alias for overworld generator.
16pub type OverworldGenerator = VanillaGenerator<OverworldNoises>;
17
18/// Type alias for nether generator.
19pub type NetherGenerator = VanillaGenerator<NetherNoises>;
20
21/// Type alias for end generator.
22pub type EndGenerator = VanillaGenerator<EndNoises>;
23
24#[expect(
25    missing_docs,
26    reason = "variants are named after their dimension; self-explanatory"
27)]
28#[enum_dispatch(ChunkGenerator)]
29pub enum ChunkGeneratorType {
30    Flat(FlatChunkGenerator),
31    Empty(EmptyChunkGenerator),
32    Overworld(OverworldGenerator),
33    Nether(NetherGenerator),
34    End(EndGenerator),
35    //Custom(Box<dyn ChunkGenerator>),
36}
37
38/// Context for world generation.
39///
40/// Similar to vanilla's `WorldGenContext`, this provides access to the level/dimension
41/// and generation infrastructure.
42pub struct WorldGenContext {
43    /// The chunk generator to use.
44    pub generator: Arc<ChunkGeneratorType>,
45    /// Weak reference to the world (to avoid circular Arc reference).
46    /// Use `world()` to get a strong reference when needed.
47    world: Weak<World>,
48    /// Cached dimension minimum build Y. Immutable for the world's lifetime;
49    /// cached here so per-block queries avoid a `Weak<World>::upgrade` (a
50    /// cross-thread atomic refcount round-trip) on every call.
51    min_y: i32,
52    /// Cached dimension build height. See [`Self::min_y`].
53    height: i32,
54    /// Cached dimension sea level. Immutable for the world's lifetime. Read
55    /// per-column by the `freeze_top_layer` feature (snow/ice placement);
56    /// cached here so it avoids a `Weak<World>::upgrade` (cross-thread atomic
57    /// on the shared `Arc<World>`) on every column. See [`Self::min_y`].
58    sea_level: i32,
59}
60
61impl WorldGenContext {
62    /// Creates a new `WorldGenContext`.
63    ///
64    /// `min_y`/`height` are the dimension's build bounds (`DimensionType::min_y`
65    /// / `::height`); they are cached rather than read from the world per call.
66    #[must_use]
67    pub const fn new(
68        generator: Arc<ChunkGeneratorType>,
69        world: Weak<World>,
70        min_y: i32,
71        height: i32,
72        sea_level: i32,
73    ) -> Self {
74        Self {
75            generator,
76            world,
77            min_y,
78            height,
79            sea_level,
80        }
81    }
82
83    /// Returns the dimension's sea level (cached; see [`Self::min_y`]).
84    #[must_use]
85    pub const fn sea_level(&self) -> i32 {
86        self.sea_level
87    }
88
89    /// Gets a strong reference to the world.
90    ///
91    /// # Panics
92    /// Panics if the world has been dropped.
93    #[must_use]
94    pub fn world(&self) -> Arc<World> {
95        self.world.upgrade().expect("World has been dropped")
96    }
97
98    /// Gets a weak reference to the world.
99    ///
100    /// This is useful for passing to chunks without creating a strong reference cycle.
101    #[must_use]
102    pub fn weak_world(&self) -> Weak<World> {
103        self.world.clone()
104    }
105
106    /// Returns the minimum Y coordinate of the world.
107    #[must_use]
108    pub const fn min_y(&self) -> i32 {
109        self.min_y
110    }
111
112    /// Returns the total height of the world in blocks.
113    #[must_use]
114    pub const fn height(&self) -> i32 {
115        self.height
116    }
117
118    /// Returns the minimum Y coordinate used by `WorldGenerationContext`.
119    #[must_use]
120    pub fn generation_min_y(&self) -> i32 {
121        self.min_y.max(self.generator.min_y())
122    }
123
124    /// Returns the height used by `WorldGenerationContext`.
125    #[must_use]
126    pub fn generation_height(&self) -> i32 {
127        self.height.min(self.generator.gen_depth())
128    }
129
130    #[must_use]
131    /// How many sections this dimension has
132    pub const fn section_count(&self) -> usize {
133        (self.height / 16) as usize
134    }
135}