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}