Skip to main content

steel_worldgen/density/
traits.rs

1//! Traits for dimension-specific noise generation.
2//!
3//! These traits abstract over dimension-specific types (overworld, nether, etc.)
4//! allowing generic chunk generation code to work with any dimension's transpiled
5//! density functions.
6
7use crate::BlockStateId;
8use crate::noise::OreVeinifier;
9use crate::random::RandomSplitter;
10use crate::surface::SurfaceRuleContext;
11use crate::surface_partial::PartialSurfaceRule;
12use rustc_hash::FxHashMap;
13
14use super::NoiseParameters;
15
16/// Noise settings for a dimension, parsed from the datapack.
17///
18/// These are compile-time constants generated from `noise_settings` JSON files.
19pub trait NoiseSettings: Send + Sync {
20    /// Minimum Y coordinate for this dimension.
21    const MIN_Y: i32;
22    /// Total height of the world in blocks.
23    const HEIGHT: i32;
24    /// Sea level Y coordinate.
25    const SEA_LEVEL: i32;
26    /// Cell width in blocks (XZ direction).
27    const CELL_WIDTH: i32;
28    /// Cell height in blocks (Y direction).
29    const CELL_HEIGHT: i32;
30    /// Whether aquifers are enabled for this dimension.
31    const AQUIFERS_ENABLED: bool;
32    /// Whether ore veins are enabled for this dimension.
33    const ORE_VEINS_ENABLED: bool;
34    /// Whether this dimension's material rule contains ore veins.
35    const MATERIAL_ORE_VEINS_ENABLED: bool;
36    /// Whether this dimension uses Java's LCG random (true) or Xoroshiro (false).
37    const LEGACY_RANDOM_SOURCE: bool;
38
39    /// Get the default block state ID for this dimension.
40    fn default_block_id() -> BlockStateId;
41
42    /// Get the default fluid state ID for this dimension.
43    fn default_fluid_id() -> BlockStateId;
44}
45
46/// Column cache for a dimension's flat-cached density function results.
47///
48/// Stores Y-independent values that only need to be computed once per (x, z) column.
49pub trait ColumnCache: Clone + Default + Send + Sync {
50    /// The associated noises type for this cache.
51    type Noises: DimensionNoises<ColumnCache = Self>;
52
53    /// Ensure the cache is populated for the given block coordinates.
54    ///
55    /// If the cache already holds values for this column, this is a no-op.
56    fn ensure(&mut self, x: i32, z: i32, noises: &Self::Noises);
57
58    /// Pre-compute flat-cached values for all quart positions in a chunk.
59    ///
60    /// Matches vanilla's `NoiseChunk.FlatCache`: eagerly fills a 2D grid of
61    /// `(quart_size+1)²` entries (size baked in per dimension at compile time).
62    /// After this call, `ensure()` for in-bounds positions is an O(1) grid
63    /// lookup. Out-of-bounds positions fall back to on-the-fly evaluation at
64    /// raw (non-quantized) coordinates.
65    fn init_grid(&mut self, chunk_block_x: i32, chunk_block_z: i32, noises: &Self::Noises);
66}
67
68/// All noise generators and density functions for a dimension.
69///
70/// This trait abstracts over dimension-specific noise types (`OverworldNoises`,
71/// `NetherNoises`, etc.) allowing generic code to work with any dimension.
72pub trait DimensionNoises: Sized + Send + Sync {
73    /// The column cache type for this dimension.
74    type ColumnCache: ColumnCache<Noises = Self>;
75    /// The noise settings type for this dimension.
76    type Settings: NoiseSettings;
77
78    /// Create all noise generators from a world seed and its positional splitter.
79    fn create(
80        seed: u64,
81        splitter: &RandomSplitter,
82        params: &FxHashMap<String, NoiseParameters>,
83    ) -> Self;
84
85    // ── Router functions ────────────────────────────────────────────────────
86
87    /// Final density for terrain generation (positive = solid, negative = air).
88    fn router_final_density(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
89
90    /// Depth from surface (used for terrain shaping).
91    fn router_depth(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
92
93    // ── Aquifer router functions ────────────────────────────────────────────
94
95    /// Whether aquifer noise lookups require a prepared column cache.
96    ///
97    /// Returning `false` promises that barrier, floodedness, spread and lava
98    /// all use their explicit coordinates without reading prepared cache values.
99    /// Custom implementations retain column-cache preparation by default.
100    #[must_use]
101    fn aquifer_needs_column_cache() -> bool {
102        true
103    }
104
105    /// Barrier noise for aquifer boundaries.
106    fn router_barrier(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
107
108    /// Fluid level floodedness for aquifers.
109    fn router_fluid_level_floodedness(
110        &self,
111        cache: &mut Self::ColumnCache,
112        x: i32,
113        y: i32,
114        z: i32,
115    ) -> f32;
116
117    /// Fluid level spread for aquifers.
118    fn router_fluid_level_spread(
119        &self,
120        cache: &mut Self::ColumnCache,
121        x: i32,
122        y: i32,
123        z: i32,
124    ) -> f32;
125
126    /// Lava placement noise for aquifers.
127    fn router_lava(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
128
129    // ── Ore vein router functions ───────────────────────────────────────────
130
131    /// Vein toggle (sign determines copper vs iron).
132    fn router_vein_toggle(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
133
134    /// Vein ridged noise for ore placement.
135    fn router_vein_ridged(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
136
137    /// Vein gap noise for ore vs filler placement.
138    fn router_vein_gap(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
139
140    // ── Climate/biome router functions (Y-independent, cached) ──────────────
141
142    /// Erosion value (cached in column cache).
143    fn router_erosion(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
144
145    /// Continentalness value (cached in column cache).
146    fn router_continentalness(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
147
148    /// Temperature value (cached in column cache).
149    fn router_temperature(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
150
151    /// Vegetation/humidity value (cached in column cache).
152    fn router_vegetation(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
153
154    /// Ridges/weirdness value (cached in column cache).
155    fn router_ridges(&self, cache: &mut Self::ColumnCache, x: i32, y: i32, z: i32) -> f32;
156
157    /// Preliminary surface level (cached in column cache).
158    fn router_preliminary_surface_level(
159        &self,
160        cache: &mut Self::ColumnCache,
161        x: i32,
162        y: i32,
163        z: i32,
164    ) -> f32;
165
166    // ── Interpolation functions ─────────────────────────────────────────────
167
168    /// Total number of independently interpolated channels across all router
169    /// entries (`final_density` + `vein_toggle` + `vein_ridged`).
170    fn interpolated_count() -> usize;
171
172    /// Whether vein functions have interpolation channels.
173    fn vein_interp_enabled() -> bool;
174
175    /// Interpolated channels that, when `<= 0` at a block, prove its combined
176    /// final density is not positive. Cell corners alone are insufficient for
177    /// Vanilla's repeated-addition interpolation.
178    /// Derived by the transpiler from the final-density tree; `None` when no
179    /// such proof exists.
180    fn final_density_nonpositive_channels() -> Option<&'static [usize]>;
181
182    /// Compute blended noise for an entire column of Y values.
183    ///
184    /// Called by `NoiseChunk::fill_slice` before iterating over Y corners.
185    /// Dimensions that use `BlendedNoise` (e.g. overworld) should override this
186    /// to SIMD-batch the blended noise computation.
187    ///
188    /// Default: no-op (fills `out` with zeros).
189    fn compute_noise_column(&self, _x: i32, _block_ys: &[i32], _z: i32, out: &mut [f32]) {
190        out.fill(0.0);
191    }
192
193    /// Evaluate the inner functions of all `Interpolated` markers at a cell corner.
194    ///
195    /// `out` must have length [`interpolated_count()`]. Each element receives
196    /// the value of one `Interpolated` marker's inner function at `(x, y, z)`.
197    /// `blended_noise_value` is the precomputed blended noise for this Y level.
198    fn fill_cell_corner_densities(
199        &self,
200        cache: &mut Self::ColumnCache,
201        x: i32,
202        y: i32,
203        z: i32,
204        blended_noise_value: f32,
205        out: &mut [f32],
206    );
207
208    /// Evaluate a batch of Y corners at the same X/Z position.
209    ///
210    /// The generated dimension implementations use the best SIMD width for
211    /// the target. The default keeps the same lane-major output layout while
212    /// providing a scalar fallback for dimensions without generated SIMD code.
213    fn fill_cell_corner_densities_y_simd<const N: usize>(
214        &self,
215        cache: &mut Self::ColumnCache,
216        x: i32,
217        ys: [i32; N],
218        z: i32,
219        blended_noise_values: [f32; N],
220        out: &mut [f32],
221    ) {
222        let count = Self::interpolated_count();
223        for lane in 0..N {
224            self.fill_cell_corner_densities(
225                cache,
226                x,
227                ys[lane],
228                z,
229                blended_noise_values[lane],
230                &mut out[lane * count..(lane + 1) * count],
231            );
232        }
233    }
234
235    /// Combine trilinearly interpolated values for `final_density`.
236    fn combine_interpolated(
237        &self,
238        cache: &mut Self::ColumnCache,
239        interpolated: &[f32],
240        x: i32,
241        y: i32,
242        z: i32,
243    ) -> f32;
244
245    /// Combine trilinearly interpolated values for `vein_toggle`.
246    fn combine_vein_toggle(
247        &self,
248        cache: &mut Self::ColumnCache,
249        interpolated: &[f32],
250        x: i32,
251        y: i32,
252        z: i32,
253    ) -> f32;
254
255    /// Combine trilinearly interpolated values for `vein_ridged`.
256    fn combine_vein_ridged(
257        &self,
258        cache: &mut Self::ColumnCache,
259        interpolated: &[f32],
260        x: i32,
261        y: i32,
262        z: i32,
263    ) -> f32;
264
265    // ── Surface rules ───────────────────────────────────────────────────────
266
267    /// Noise IDs referenced by this dimension's surface rule `NoiseThreshold`
268    /// conditions. Used to construct the `SurfaceSystem`'s condition noises.
269    fn surface_noise_ids() -> &'static [&'static str];
270
271    /// Random IDs referenced by this dimension's surface rule `VerticalGradient`
272    /// conditions. Used to construct reusable positional random factories.
273    fn surface_gradient_ids() -> &'static [&'static str];
274
275    /// Block states returned by this dimension's generated surface rules.
276    fn surface_rule_block_states() -> &'static [BlockStateId];
277
278    /// Whether the generated surface rule reads biome-dependent context.
279    fn surface_rule_uses_biome() -> bool;
280
281    /// Distinct `biome_is` sets the generated surface rule tests, as biome
282    /// registry ids. Together with a biome's temperature parameters these are
283    /// everything the rule can observe about a biome.
284    fn surface_rule_biome_sets() -> &'static [Box<[u16]>];
285
286    /// The surface rule reduced to what is decidable from Y and biome below the
287    /// preliminary surface.
288    fn surface_rule_below_preliminary_surface() -> &'static PartialSurfaceRule;
289
290    /// Whether the generated surface rule reads preliminary surface level.
291    fn surface_rule_uses_preliminary_surface() -> bool;
292
293    /// Whether the generated surface rule reads surface secondary noise.
294    fn surface_rule_uses_surface_secondary() -> bool;
295
296    /// Whether the generated surface rule reads steep-column context.
297    fn surface_rule_uses_steep() -> bool;
298
299    /// Apply the transpiled surface rule at the given context position.
300    fn try_apply_surface_rule(ctx: &mut SurfaceRuleContext<'_>) -> Option<BlockStateId>;
301
302    /// Number of prefilled density/richness values for this dimension's material ore rules.
303    fn material_ore_vein_value_count() -> usize;
304
305    /// Height of the prefilled Y prefix, starting at [`NoiseSettings::MIN_Y`].
306    /// Keep it within `HEIGHT`; every omitted ore density must be `<= 0.0`.
307    #[must_use]
308    fn material_ore_vein_value_height() -> usize {
309        Self::Settings::HEIGHT as usize
310    }
311
312    /// Fill one block's material ore density/richness values.
313    ///
314    /// Vanilla samples these functions over the complete chunk volume before
315    /// surface rules start evaluating. `out` has
316    /// [`Self::material_ore_vein_value_count`] entries, two per ore rule.
317    fn fill_material_ore_vein_values(
318        &self,
319        cache: &mut Self::ColumnCache,
320        interpolated: &[f32],
321        x: i32,
322        y: i32,
323        z: i32,
324        out: &mut [f32],
325    );
326
327    /// Evaluates each ore-vein node from this dimension's material rule using
328    /// density/richness values prefilled for this exact block position.
329    ///
330    /// `out` is ordered by the material-rule tree's depth-first traversal, so
331    /// generated rule code can preserve vanilla's sequence ordering.
332    #[expect(
333        clippy::too_many_arguments,
334        reason = "mirrors the generated Vanilla material-rule call"
335    )]
336    fn fill_prefilled_material_ore_vein_results(
337        &self,
338        cache: &mut Self::ColumnCache,
339        ore_veinifier: &OreVeinifier,
340        values: &[f32],
341        x: i32,
342        y: i32,
343        z: i32,
344        out: &mut [Option<BlockStateId>],
345    );
346}