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}