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.
39pub struct WorldGenContext {
40    /// The chunk generator to use.
41    pub generator: Arc<ChunkGeneratorType>,
42    /// Weak reference to the world (to avoid circular Arc reference).
43    /// Use `world()` to get a strong reference when needed.
44    world: Weak<World>,
45    /// Cached dimension minimum build Y. Immutable for the world's lifetime;
46    /// cached here so per-block queries avoid a `Weak<World>::upgrade` (a
47    /// cross-thread atomic refcount round-trip) on every call.
48    min_y: i32,
49    /// Cached dimension build height. See [`Self::min_y`].
50    height: i32,
51    /// Cached dimension sea level. Immutable for the world's lifetime. Read
52    /// per-column by the `freeze_top_layer` feature (snow/ice placement);
53    /// cached here so it avoids a `Weak<World>::upgrade` (cross-thread atomic
54    /// on the shared `Arc<World>`) on every column. See [`Self::min_y`].
55    sea_level: i32,
56}
57
58impl WorldGenContext {
59    /// Creates a new `WorldGenContext`.
60    ///
61    /// `min_y`/`height` are the dimension's build bounds (`DimensionType::min_y`
62    /// / `::height`); they are cached rather than read from the world per call.
63    #[must_use]
64    pub const fn new(
65        generator: Arc<ChunkGeneratorType>,
66        world: Weak<World>,
67        min_y: i32,
68        height: i32,
69        sea_level: i32,
70    ) -> Self {
71        Self {
72            generator,
73            world,
74            min_y,
75            height,
76            sea_level,
77        }
78    }
79
80    /// Returns the dimension's sea level (cached; see [`Self::min_y`]).
81    #[must_use]
82    pub const fn sea_level(&self) -> i32 {
83        self.sea_level
84    }
85
86    /// Gets a strong reference to the world.
87    ///
88    /// # Panics
89    /// Panics if the world has been dropped.
90    #[must_use]
91    pub fn world(&self) -> Arc<World> {
92        self.world.upgrade().expect("World has been dropped")
93    }
94
95    /// Gets a weak reference to the world.
96    ///
97    /// This is useful for passing to chunks without creating a strong reference cycle.
98    #[must_use]
99    pub fn weak_world(&self) -> Weak<World> {
100        Weak::clone(&self.world)
101    }
102
103    /// Returns the minimum Y coordinate of the world.
104    #[must_use]
105    pub const fn min_y(&self) -> i32 {
106        self.min_y
107    }
108
109    /// Returns the total height of the world in blocks.
110    #[must_use]
111    pub const fn height(&self) -> i32 {
112        self.height
113    }
114
115    /// Returns the minimum Y coordinate used by `WorldGenerationContext`.
116    #[must_use]
117    pub fn generation_min_y(&self) -> i32 {
118        self.min_y.max(self.generator.min_y())
119    }
120
121    /// Returns the height used by `WorldGenerationContext`.
122    #[must_use]
123    pub fn generation_height(&self) -> i32 {
124        self.height.min(self.generator.gen_depth())
125    }
126
127    #[must_use]
128    /// How many sections this dimension has
129    pub const fn section_count(&self) -> usize {
130        (self.height / 16) as usize
131    }
132}