mc173/gen/
overworld.rs

1//! Overworld chunk generator.
2//! 
3//! The overworld generator is fully featured and should produces the same chunk terrain
4//! and randomly the same features.
5//! 
6//! The overworld generator is an heavy piece of algorithm, and the runtime duration of
7//! generation and population depends on optimization level:
8//! - Release: populate take around 75% of time to generate
9//! - Debug: populate take around 150% of time to generate
10//! 
11//! However, it's important to note that to fully generate a chunk in middle of nowhere,
12//! it's required to generate terrain for 9 chunks and populate only one, so populating
13//! in this case will always be faster that terrain generation. Even in the worst case
14//! of no optimization, populate only represent around 16% of terrain generation time, 
15//! for each fully populated chunk.
16//! 
17//! If we take a more realistic approach of loading a chunk near already-existing chunks,
18//! we only need to generate 2 to 4 chunks, in the worst case, populate represent 75% of
19//! terrain generation time, for each fully populated chunk.
20//! 
21//! We see that in general, we will have more terrain generation than populating to run.
22
23use glam::{DVec2, IVec3, Vec3Swizzles, DVec3};
24
25use crate::chunk::{Chunk, CHUNK_WIDTH, CHUNK_HEIGHT};
26use crate::block::material::Material;
27use crate::rand::JavaRandom;
28use crate::biome::Biome;
29use crate::world::World;
30use crate::block;
31
32use super::noise::{PerlinOctaveNoise, NoiseCube};
33use super::{ChunkGenerator, FeatureGenerator};
34use super::plant::{PlantGenerator, SugarCanesGenerator, PumpkinGenerator, CactusGenerator};
35use super::liquid::{LakeGenerator, LiquidGenerator};
36use super::dungeon::DungeonGenerator;
37use super::cave::CaveGenerator;
38use super::vein::VeinGenerator;
39use super::tree::TreeGenerator;
40
41
42const NOISE_WIDTH: usize = 5;
43const NOISE_HEIGHT: usize = 17;
44
45const TEMPERATURE_SCALE: DVec2 = DVec2::splat(0.025f32 as f64);
46const TEMPERATURE_FREQ_FACTOR: f64 = 0.25;
47const HUMIDITY_SCALE: DVec2 = DVec2::splat(0.05f32 as f64);
48const HUMIDITY_FREQ_FACTOR: f64 = 1.0 / 3.0;
49const BIOME_SCALE: DVec2 = DVec2::splat(0.25);
50const BIOME_FREQ_FACTOR: f64 = 0.5882352941176471;
51
52
53/// A chunk generator for the overworld dimension. This structure can be shared between
54/// workers.
55pub struct OverworldGenerator {
56    /// The world seed.
57    seed: i64,
58    /// The noise used for generating biome temperature.
59    temperature_noise: PerlinOctaveNoise,
60    /// The noise used for generating biome humidity.
61    humidity_noise: PerlinOctaveNoise,
62    /// The noise used to alter both temperature and humidity for biome.
63    biome_noise: PerlinOctaveNoise,
64    terrain_noise0: PerlinOctaveNoise,
65    terrain_noise1: PerlinOctaveNoise,
66    terrain_noise2: PerlinOctaveNoise,
67    terrain_noise3: PerlinOctaveNoise,
68    terrain_noise4: PerlinOctaveNoise,
69    sand_gravel_noise: PerlinOctaveNoise,
70    thickness_noise: PerlinOctaveNoise,
71    feature_noise: PerlinOctaveNoise,
72    biome_table: Box<[Biome; 4096]>,
73}
74
75/// This structure stores huge structures that should not be shared between workers.
76#[derive(Default, Clone)]
77pub struct OverworldState {
78    temperature: NoiseCube<CHUNK_WIDTH, 1, CHUNK_WIDTH>,
79    humidity: NoiseCube<CHUNK_WIDTH, 1, CHUNK_WIDTH>,
80    biome: NoiseCube<CHUNK_WIDTH, 1, CHUNK_WIDTH>,
81    terrain:  NoiseCube<NOISE_WIDTH, NOISE_HEIGHT, NOISE_WIDTH>,
82    terrain0: NoiseCube<NOISE_WIDTH, NOISE_HEIGHT, NOISE_WIDTH>,
83    terrain1: NoiseCube<NOISE_WIDTH, NOISE_HEIGHT, NOISE_WIDTH>,
84    terrain2: NoiseCube<NOISE_WIDTH, NOISE_HEIGHT, NOISE_WIDTH>,
85    terrain3: NoiseCube<NOISE_WIDTH, 1, NOISE_WIDTH>,
86    terrain4: NoiseCube<NOISE_WIDTH, 1, NOISE_WIDTH>,
87    sand: NoiseCube<CHUNK_WIDTH, CHUNK_WIDTH, 1>,
88    gravel: NoiseCube<CHUNK_WIDTH, 1, CHUNK_WIDTH>,
89    thickness: NoiseCube<CHUNK_WIDTH, CHUNK_WIDTH, 1>,
90}
91
92impl OverworldGenerator {
93
94    /// Create a new overworld generator given a seed.
95    pub fn new(seed: i64) -> Self {
96
97        let biome_lookup = Box::new(std::array::from_fn(|i| {
98            
99            let t = (i % 64) as f32 / 63.0;
100            let h = (i / 64) as f32 / 63.0;
101            let h = h * t;
102
103            if t < 0.1 {
104                Biome::Tundra
105            } else if h < 0.2 {
106                if t < 0.5 {
107                    Biome::Tundra
108                } else if t < 0.95 {
109                    Biome::Savanna
110                } else {
111                    Biome::Desert
112                }
113            } else if h > 0.5 && t < 0.7 {
114                Biome::Swampland
115            } else if t < 0.5 {
116                Biome::Taiga
117            } else if t < 0.97 {
118                if h < 0.35 {
119                    Biome::ShrubLand
120                } else {
121                    Biome::Forest
122                }
123            } else if h < 0.45 {
124                Biome::Plains
125            } else if h < 0.9 {
126                Biome::SeasonalForest
127            } else {
128                Biome::RainForest
129            }
130
131        }));
132
133        let mut rand = JavaRandom::new(seed);
134
135        Self {
136            seed,
137            temperature_noise: PerlinOctaveNoise::new(&mut JavaRandom::new(seed.wrapping_mul(9871)), 4),
138            humidity_noise: PerlinOctaveNoise::new(&mut JavaRandom::new(seed.wrapping_mul(39811)), 4),
139            biome_noise: PerlinOctaveNoise::new(&mut JavaRandom::new(seed.wrapping_mul(543321)), 2),
140            terrain_noise0: PerlinOctaveNoise::new(&mut rand, 16),
141            terrain_noise1: PerlinOctaveNoise::new(&mut rand, 16),
142            terrain_noise2: PerlinOctaveNoise::new(&mut rand, 8),
143            sand_gravel_noise: PerlinOctaveNoise::new(&mut rand, 4),
144            thickness_noise: PerlinOctaveNoise::new(&mut rand, 4),
145            terrain_noise3: PerlinOctaveNoise::new(&mut rand, 10),
146            terrain_noise4: PerlinOctaveNoise::new(&mut rand, 16),
147            feature_noise: PerlinOctaveNoise::new(&mut rand, 8),
148            biome_table: biome_lookup,
149        }
150
151    }
152
153    /// Internal function to calculate the biome from given random variables.
154    #[inline]
155    fn calc_biome(&self, temperature: f64, humidity: f64, biome: f64) -> (f64, f64, Biome) {
156
157        let a = biome * 1.1 + 0.5;
158        let t = (temperature * 0.15 + 0.7) * 0.99 + a * 0.01;
159        let t = 1.0 - (1.0 - t).powi(2);
160        let h = (humidity * 0.15 + 0.5) * 0.998 + a * 0.002;
161
162        let t = t.clamp(0.0, 1.0);
163        let h = h.clamp(0.0, 1.0);
164
165        let pos_biome = self.biome_table[(t * 63.0) as usize + (h * 63.0) as usize * 64];
166        (t, h, pos_biome)
167
168    }
169
170    /// Get a single biome at given position.
171    fn get_biome(&self, x: i32, z: i32) -> Biome {
172
173        let offset = DVec2::new(x as f64, z as f64);
174        let mut temperature = 0.0;
175        let mut humidity = 0.0;
176        let mut biome = 0.0;
177
178        self.temperature_noise.gen_weird_2d(NoiseCube::from_mut(&mut temperature), offset, TEMPERATURE_SCALE, TEMPERATURE_FREQ_FACTOR);
179        self.humidity_noise.gen_weird_2d(NoiseCube::from_mut(&mut humidity), offset, HUMIDITY_SCALE, HUMIDITY_FREQ_FACTOR);
180        self.biome_noise.gen_weird_2d(NoiseCube::from_mut(&mut biome), offset, BIOME_SCALE, BIOME_FREQ_FACTOR);
181
182        self.calc_biome(temperature, humidity, biome).2
183
184    }
185
186    /// Generate a biome map for the chunk and store it in the chunk data.
187    fn gen_biomes(&self, cx: i32, cz: i32, chunk: &mut Chunk, state: &mut OverworldState) {
188
189        let offset = DVec2::new((cx * 16) as f64, (cz * 16) as f64);
190
191        let temperature = &mut state.temperature;
192        let humidity = &mut state.humidity;
193        let biome = &mut state.biome;
194        
195        self.temperature_noise.gen_weird_2d(temperature, offset,TEMPERATURE_SCALE, TEMPERATURE_FREQ_FACTOR);
196        self.humidity_noise.gen_weird_2d(humidity, offset, HUMIDITY_SCALE, HUMIDITY_FREQ_FACTOR);
197        self.biome_noise.gen_weird_2d(biome, offset, BIOME_SCALE, BIOME_FREQ_FACTOR);
198
199        for x in 0usize..16 {
200            for z in 0usize..16 {
201
202                let (t, h, pos_biome) = self.calc_biome(
203                    temperature.get(x, 0, z), 
204                    humidity.get(x, 0, z),
205                    biome.get(x, 0, z));
206                
207                // The value may be used afterward for generation, so we update the value.
208                temperature.set(x, 0, z, t);
209                humidity.set(x, 0, z, h);
210
211                chunk.set_biome(IVec3::new(x as i32, 0, z as i32), pos_biome);
212
213            }
214        }
215
216    }
217
218    /// Generate the primitive terrain of the chunk.
219    fn gen_terrain(&self, cx: i32, cz: i32, chunk: &mut Chunk, state: &mut OverworldState) {
220
221        const NOISE_STRIDE: usize = CHUNK_WIDTH / NOISE_WIDTH;
222        const NOISE_REAL_WIDTH: usize = NOISE_WIDTH - 1;
223        const NOISE_REAL_HEIGHT: usize = NOISE_HEIGHT - 1;
224        const NOISE_REAL_WIDTH_STRIDE: usize = CHUNK_WIDTH / NOISE_REAL_WIDTH;
225        const NOISE_REAL_HEIGHT_STRIDE: usize = CHUNK_HEIGHT / NOISE_REAL_HEIGHT;
226
227        let offset = IVec3::new(cx * NOISE_REAL_WIDTH as i32, 0, cz * NOISE_REAL_WIDTH as i32);
228
229        let terrain = &mut state.terrain;
230        let terrain0 = &mut state.terrain0;
231        let terrain1 = &mut state.terrain1;
232        let terrain2 = &mut state.terrain2;
233        let terrain3 = &mut state.terrain3;
234        let terrain4 = &mut state.terrain4;
235        let temperature = &state.temperature;
236        let humidity = &state.humidity;
237
238        let offset_2d = offset.xz().as_dvec2();
239        let offset_3d = offset.as_dvec3();
240
241        self.terrain_noise3.gen_2d(terrain3, offset_2d, DVec2::splat(1.121));
242        self.terrain_noise4.gen_2d(terrain4, offset_2d, DVec2::splat(200.0));
243        self.terrain_noise2.gen_3d(terrain2, offset_3d, DVec3::new(684.412 / 80.0, 684.412 / 160.0, 684.412 / 80.0));
244        self.terrain_noise0.gen_3d(terrain0, offset_3d, DVec3::splat(684.412));
245        self.terrain_noise1.gen_3d(terrain1, offset_3d, DVec3::splat(684.412));
246
247        // Start by generating a 5x17x5 density map for the terrain.
248        for x_noise in 0..NOISE_WIDTH {
249            let x_block = x_noise * NOISE_STRIDE + (NOISE_STRIDE / 2);
250            for z_noise in 0..NOISE_WIDTH {
251                let z_block = z_noise * NOISE_STRIDE + (NOISE_STRIDE / 2);
252
253                let t = temperature.get(x_block, 0, z_block);
254                let h = humidity.get(x_block, 0, z_block) * t;
255                let h_inv = (1.0 - h).powi(4);
256                let h = 1.0 - h_inv;
257
258                let mut v0 = (terrain3.get(x_noise, 0, z_noise) + 256.0) / 512.0 * h;
259                v0 = v0.min(1.0);
260
261                let mut v1 = terrain4.get(x_noise, 0, z_noise) / 8000.0;
262                if v1 < 0.0 {
263                    v1 = -v1 * 0.3;
264                }
265
266                v1 = v1 * 3.0 - 2.0;
267
268                if v1 < 0.0 {
269                    v1 /= 2.0;
270                    v1 = v1.max(-1.0);
271                    v1 /= 1.4;
272                    v1 /= 2.0;
273                    v0 = 0.0;
274                } else {
275                    v1 = v1.min(1.0);
276                    v1 /= 8.0;
277                }
278
279                v0 = v0.max(0.0);
280                v0 += 0.5;
281
282                v1 = v1 * NOISE_HEIGHT as f64 / 16.0;
283                let v2 = NOISE_HEIGHT as f64 / 2.0 + v1 * 4.0;
284
285                for y_noise in 0..NOISE_HEIGHT {
286
287                    let mut v3 = (y_noise as f64 - v2) * 12.0 / v0;
288                    if v3 < 0.0 {
289                        v3 *= 4.0;
290                    }
291
292                    let v4 = terrain0.get(x_noise, y_noise, z_noise) / 512.0;
293                    let v5 = terrain1.get(x_noise, y_noise, z_noise) / 512.0;
294                    let v6 = (terrain2.get(x_noise, y_noise, z_noise) / 10.0 + 1.0) / 2.0;
295
296                    // NOTE: Basically a clamped linear interpolation.
297                    let mut final_value = if v6 < 0.0 {
298                        v4
299                    } else if v6 > 1.0 {
300                        v5
301                    } else {
302                        v4 + (v5 - v4) * v6
303                    };
304
305                    final_value -= v3;
306                    if y_noise > NOISE_HEIGHT - 4 {
307                        let v7 = ((y_noise - (NOISE_HEIGHT - 4)) as f32 / 3.0) as f64;
308                        final_value = final_value * (1.0 - v7) + (-10.0 * v7);
309                    }
310
311                    terrain.set(x_noise, y_noise, z_noise, final_value);
312
313                }
314
315            }
316        }
317
318        // Then we read the generated density map and place blocks.
319        for x_noise in 0..NOISE_REAL_WIDTH {
320            for z_noise in 0..NOISE_REAL_WIDTH {
321                for y_noise in 0..NOISE_REAL_HEIGHT {
322
323                    let mut a = terrain.get(x_noise + 0, y_noise + 0, z_noise + 0);
324                    let mut b = terrain.get(x_noise + 0, y_noise + 0, z_noise + 1);
325                    let mut c = terrain.get(x_noise + 1, y_noise + 0, z_noise + 0);
326                    let mut d = terrain.get(x_noise + 1, y_noise + 0, z_noise + 1);
327                    let e = (terrain.get(x_noise + 0, y_noise + 1, z_noise + 0) - a) * 0.125; // Should be vectorized.
328                    let f = (terrain.get(x_noise + 0, y_noise + 1, z_noise + 1) - b) * 0.125;
329                    let g = (terrain.get(x_noise + 1, y_noise + 1, z_noise + 0) - c) * 0.125;
330                    let h = (terrain.get(x_noise + 1, y_noise + 1, z_noise + 1) - d) * 0.125;
331
332                    for y_index in 0..NOISE_REAL_HEIGHT_STRIDE {
333
334                        let y = y_noise * NOISE_REAL_HEIGHT_STRIDE + y_index;
335                        
336                        let ca = (c - a) * 0.25;
337                        let db = (d - b) * 0.25;
338
339                        let mut a0 = a;
340                        let mut b0 = b;
341
342                        for x_index in 0..NOISE_REAL_WIDTH_STRIDE {
343
344                            let x = x_noise * NOISE_REAL_WIDTH_STRIDE + x_index;
345
346                            let b0a0 = (b0 - a0) * 0.25;
347                            let mut a00 = a0;
348
349                            for z_index in 0..NOISE_REAL_WIDTH_STRIDE {
350
351                                let z = z_noise * NOISE_REAL_WIDTH_STRIDE + z_index;
352                                let t = temperature.get(x, 0, z);
353
354                                let mut id = block::AIR;
355
356                                if y < 64 {
357                                    id = if t < 0.5 && y == 63 {
358                                        block::ICE
359                                    } else {
360                                        block::WATER_STILL
361                                    };
362                                }
363                                
364                                if a00 > 0.0 {
365                                    id = block::STONE;
366                                }
367
368                                // Chunk should be empty by default, so we ignore if air.
369                                if id != block::AIR {
370                                    chunk.set_block(IVec3::new(x as i32, y as i32, z as i32), id, 0);
371                                }
372
373                                a00 += b0a0;
374
375                            }
376
377                            a0 += ca;
378                            b0 += db;
379
380                        }
381
382                        a += e;
383                        b += f;
384                        c += g;
385                        d += h;
386
387                    }
388
389                }
390            }
391        }
392
393    }
394
395    /// Generate the primitive terrain of the chunk.
396    fn gen_surface(&self, cx: i32, cz: i32, chunk: &mut Chunk, state: &mut OverworldState, rand: &mut JavaRandom) {
397
398        let sand = &mut state.sand;
399        let gravel = &mut state.gravel;
400        let thickness = &mut state.thickness;
401
402        let offset = DVec3::new((cx * 16) as f64, (cz * 16) as f64, 0.0);
403        let scale = 1.0 / 32.0;
404        let sea_level = 64;
405
406        self.sand_gravel_noise.gen_3d(sand, offset, DVec3::new(scale, scale, 1.0));
407        self.sand_gravel_noise.gen_2d(gravel, offset.truncate(), DVec2::new(scale, scale));
408        self.thickness_noise.gen_3d(thickness, offset, DVec3::splat(scale * 2.0));
409
410        // NOTE: Order of iteration is really important for random parity.
411        for z in 0usize..16 {
412            for x in 0usize..16 {
413
414                let mut pos = IVec3::new(x as i32, 0, z as i32);
415
416                let biome = chunk.get_biome(pos);
417                let have_sand = sand.get(x, z, 0) + rand.next_double() * 0.2 > 0.0;
418                let have_gravel = gravel.get(x, 0, z) + rand.next_double() * 0.2 > 3.0;
419                let thickness = (thickness.get(x, z, 0) / 3.0 + 3.0 + rand.next_double() * 0.25) as i32;
420
421                let (
422                    biome_top_id, 
423                    biome_filler_id
424                ) = match biome {
425                    Biome::Desert |
426                    Biome::IceDesert => (block::SAND, block::SAND),
427                    _ => (block::GRASS, block::DIRT),
428                };
429
430                let mut top_id = biome_top_id;
431                let mut filler_id = biome_filler_id;
432                let mut remaining_thickness = -1;
433
434                for y in (0..128).rev() {
435
436                    pos.y = y;
437
438                    if y <= rand.next_int_bounded(5) {
439                        chunk.set_block(pos, block::BEDROCK, 0);
440                        continue;
441                    }
442
443                    let (prev_id, _) = chunk.get_block(pos);
444
445                    if prev_id == block::AIR {
446                        remaining_thickness = -1;
447                    } else if prev_id == block::STONE {
448
449                        if remaining_thickness == -1 {
450                            
451                            // No surface yet, initialize it.
452                            if thickness <= 0 {
453                                top_id = block::AIR;
454                                filler_id = block::STONE;
455                            } else if y >= sea_level - 4 && y <= sea_level + 1 {
456                                
457                                top_id = biome_top_id;
458                                filler_id = biome_filler_id;
459
460                                if have_sand {
461                                    top_id = block::SAND;
462                                    filler_id = block::SAND;
463                                } else if have_gravel {
464                                    top_id = block::AIR;
465                                    filler_id = block::GRAVEL;
466                                }
467
468                            }
469
470                            if y < sea_level && top_id == block::AIR {
471                                top_id = block::WATER_STILL;
472                            }
473
474                            remaining_thickness = thickness;
475
476                            if y >= sea_level - 1 {
477                                chunk.set_block(pos, top_id, 0);
478                            } else {
479                                chunk.set_block(pos, filler_id, 0);
480                            }
481
482                        } else if remaining_thickness > 0 {
483
484                            chunk.set_block(pos, filler_id, 0);
485
486                            remaining_thickness -= 1;
487                            if remaining_thickness == 0 && filler_id == block::SAND {
488                                remaining_thickness = rand.next_int_bounded(4);
489                                filler_id = block::SANDSTONE;
490                            }
491
492                        }
493
494                    }
495
496                }
497
498            }
499        }
500
501    }
502
503    // Generate chunk carving (only caves for beta 1.7.3).
504    fn gen_carving(&self, cx: i32, cz: i32, chunk: &mut Chunk) {
505        CaveGenerator::new(8).generate(cx, cz, chunk, self.seed);
506    }
507
508}
509
510impl ChunkGenerator for OverworldGenerator {
511
512    type State = OverworldState;
513
514    fn gen_biomes(&self, cx: i32, cz: i32, chunk: &mut Chunk, state: &mut Self::State) {
515        self.gen_biomes(cx, cz, chunk, state);
516    }
517
518    fn gen_terrain(&self, cx: i32, cz: i32, chunk: &mut Chunk, state: &mut Self::State) {
519
520        let chunk_seed = i64::wrapping_add(
521            (cx as i64).wrapping_mul(341873128712), 
522            (cz as i64).wrapping_mul(132897987541));
523        
524        let mut rand = JavaRandom::new(chunk_seed);
525
526        self.gen_biomes(cx, cz, chunk, state);
527        self.gen_terrain(cx, cz, chunk, state);
528        self.gen_surface(cx, cz, chunk, state, &mut rand);
529        self.gen_carving(cx, cz, chunk);
530
531        chunk.recompute_all_height();
532
533    }
534
535    fn gen_features(&self, cx: i32, cz: i32, world: &mut World, state: &mut Self::State) {
536
537        let pos = IVec3::new(cx * 16, 0, cz * 16);
538        let biome = self.get_biome(pos.x + 16, pos.z + 16);
539
540        // Start by calculating the chunk seed from chunk coordinates and world seed.
541        let mut rand = JavaRandom::new(self.seed);
542
543        let x_mul = rand.next_long().wrapping_div(2).wrapping_mul(2).wrapping_add(1);
544        let z_mul = rand.next_long().wrapping_div(2).wrapping_mul(2).wrapping_add(1);
545
546        let chunk_seed = i64::wrapping_add(
547            (cx as i64).wrapping_mul(x_mul), 
548            (cz as i64).wrapping_mul(z_mul)
549        ) ^ self.seed;
550
551        rand.set_seed(chunk_seed);
552
553        // if cx == 0 && cz == 2 {
554        //     println!("debugging chunk {cx}/{cz} biome: {biome:?}");
555        // }
556
557        // Function to pick a uniform random position offset.
558        #[inline(always)]
559        fn next_offset(rand: &mut JavaRandom, max_y: i32, offset_xz: i32) -> IVec3 {
560            IVec3 {
561                x: rand.next_int_bounded(16) + offset_xz,
562                y: rand.next_int_bounded(max_y),
563                z: rand.next_int_bounded(16) + offset_xz,
564            }
565        }
566
567        // Water lakes...
568        if rand.next_int_bounded(4) == 0 {
569            let pos = pos + next_offset(&mut rand, 128, 8);
570            LakeGenerator::new(block::WATER_STILL).generate(world, pos, &mut rand);
571        }
572
573        // Lava lakes...
574        if rand.next_int_bounded(8) == 0 {
575
576            let pos = pos + IVec3 {
577                x: rand.next_int_bounded(16) + 8,
578                y: {
579                    let v = rand.next_int_bounded(120);
580                    rand.next_int_bounded(v + 8)
581                },
582                z: rand.next_int_bounded(16) + 8,
583            };
584
585            if pos.y < 64 || rand.next_int_bounded(10) == 0 {
586                LakeGenerator::new(block::LAVA_STILL).generate(world, pos, &mut rand);
587            }
588
589        }
590
591        // Mob dungeons...
592        for _ in 0..8 {
593            let pos = pos + next_offset(&mut rand, 128, 8);
594            DungeonGenerator::new().generate(world, pos, &mut rand);
595        }
596
597        // Clay veins (only in water).
598        for _ in 0..10 {
599            let pos = pos + next_offset(&mut rand, 128, 0);
600            if world.get_block_material(pos) == Material::Water {
601                VeinGenerator::new_clay(32).generate(world, pos, &mut rand);
602            }
603        }
604
605        // Dirt veins.
606        for _ in 0..20 {
607            let pos = pos + next_offset(&mut rand, 128, 0);
608            VeinGenerator::new_ore(block::DIRT, 32).generate(world, pos, &mut rand);
609        }
610
611        // Gravel veins.
612        for _ in 0..10 {
613            let pos = pos + next_offset(&mut rand, 128, 0);
614            VeinGenerator::new_ore(block::GRAVEL, 32).generate(world, pos, &mut rand);
615        }
616
617        // Coal veins.
618        for _ in 0..20 {
619            let pos = pos + next_offset(&mut rand, 128, 0);
620            VeinGenerator::new_ore(block::COAL_ORE, 16).generate(world, pos, &mut rand);
621        }
622
623        // Iron veins.
624        for _ in 0..20 {
625            let pos = pos + next_offset(&mut rand, 64, 0);
626            VeinGenerator::new_ore(block::IRON_ORE, 8).generate(world, pos, &mut rand);
627        }
628
629        // Gold veins.
630        for _ in 0..2 {
631            let pos = pos + next_offset(&mut rand, 32, 0);
632            VeinGenerator::new_ore(block::GOLD_ORE, 8).generate(world, pos, &mut rand);
633        }
634
635        // Redstone veins.
636        for _ in 0..8 {
637            let pos = pos + next_offset(&mut rand, 16, 0);
638            VeinGenerator::new_ore(block::REDSTONE_ORE, 7).generate(world, pos, &mut rand);
639        }
640
641        // Diamond veins.
642        for _ in 0..1 {
643            let pos = pos + next_offset(&mut rand, 16, 0);
644            VeinGenerator::new_ore(block::DIAMOND_ORE, 7).generate(world, pos, &mut rand);
645        }
646
647        // Lapis veins.
648        for _ in 0..1 {
649            
650            let pos = pos + IVec3 {
651                x: rand.next_int_bounded(16),
652                y: rand.next_int_bounded(16) + rand.next_int_bounded(16),
653                z: rand.next_int_bounded(16),
654            };
655
656            VeinGenerator::new_ore(block::LAPIS_ORE, 6).generate(world, pos, &mut rand);
657
658        }
659
660        // Trees, depending on biome and feature noise.
661        let feature_noise = self.feature_noise.gen_2d_point(pos.xz().as_dvec2() * 0.5);
662        let base_tree_count  = ((feature_noise / 8.0 + rand.next_double() * 4.0 + 4.0) / 3.0) as i32;
663        let mut tree_count = 0;
664
665        if rand.next_int_bounded(10) == 0 {
666            tree_count += 1;
667        }
668
669        match biome {
670            Biome::Taiga |
671            Biome::RainForest |
672            Biome::Forest => tree_count += base_tree_count + 5,
673            Biome::SeasonalForest => tree_count += base_tree_count + 2,
674            Biome::Desert |
675            Biome::Tundra |
676            Biome::Plains => tree_count -= 20,
677            _ => {}
678        }
679
680        // if cx == 0 && cz == 2 {
681        //     println!("tree_count: {tree_count}");
682        // }
683
684        if tree_count > 0 {
685            for _ in 0..tree_count {
686
687                let mut pos = pos + IVec3 {
688                    x: rand.next_int_bounded(16) + 8,
689                    y: 0,
690                    z: rand.next_int_bounded(16) + 8,
691                };
692
693                pos.y = world.get_height(pos).unwrap() as i32;
694
695                let mut gen = match biome {
696                    Biome::Taiga => {
697                        if rand.next_int_bounded(3) == 0 {
698                            TreeGenerator::new_spruce1()
699                        } else {
700                            TreeGenerator::new_spruce2()
701                        }
702                    }
703                    Biome::Forest => {
704                        if rand.next_int_bounded(5) == 0 {
705                            TreeGenerator::new_birch()
706                        } else if rand.next_int_bounded(3) == 0 {
707                            TreeGenerator::new_big_natural()
708                        } else {
709                            TreeGenerator::new_oak()
710                        }
711                    }
712                    Biome::RainForest => {
713                        if rand.next_int_bounded(3) == 0 {
714                            TreeGenerator::new_big_natural()
715                        } else {
716                            TreeGenerator::new_oak()
717                        }
718                    }
719                    _ => {
720                        if rand.next_int_bounded(10) == 0 {
721                            TreeGenerator::new_big_natural()
722                        } else {
723                            TreeGenerator::new_oak()
724                        }
725                    }
726                };
727
728                gen.generate(world, pos, &mut rand);
729                
730            }
731        }
732
733        // if cx == 0 && cz == 2 {
734        //     println!("next float: {}", rand.next_float());
735        // }
736
737        // Dandelion patches.
738        let dandelion_count = match biome {
739            Biome::Forest => 2,
740            Biome::Taiga => 2,
741            Biome::SeasonalForest => 4,
742            Biome::Plains => 3,
743            _ => 0,
744        };
745
746        for _ in 0..dandelion_count {
747            let pos = pos + next_offset(&mut rand, 128, 8);
748            PlantGenerator::new_flower(block::DANDELION).generate(world, pos, &mut rand);
749        }
750
751        // Tall grass patches.
752        let tall_grass_count = match biome {
753            Biome::Forest => 2,
754            Biome::RainForest => 10,
755            Biome::SeasonalForest => 2,
756            Biome::Taiga => 1,
757            Biome::Plains => 10,
758            _ => 0,
759        };
760
761        for _ in 0..tall_grass_count {
762
763            let mut metadata = 1;
764            if biome == Biome::RainForest && rand.next_int_bounded(3) != 0 {
765                metadata = 2;
766            }
767
768            let pos = pos + next_offset(&mut rand, 128, 8);
769            PlantGenerator::new_tall_grass(metadata).generate(world, pos, &mut rand);
770
771        }
772
773        // Dead bush in deserts.
774        if biome == Biome::Desert {
775            for _ in 0..2 {
776                let pos = pos + next_offset(&mut rand, 128, 8);
777                PlantGenerator::new_dead_bush().generate(world, pos, &mut rand);
778            }
779        }
780
781        // Poppy.
782        if rand.next_int_bounded(2) == 0 {
783            let pos = pos + next_offset(&mut rand, 128, 8);
784            PlantGenerator::new_flower(block::POPPY).generate(world, pos, &mut rand);
785        }
786
787        // Brown mushroom.
788        if rand.next_int_bounded(4) == 0 {
789            let pos = pos + next_offset(&mut rand, 128, 8);
790            PlantGenerator::new_flower(block::BROWN_MUSHROOM).generate(world, pos, &mut rand);
791        }
792
793        // Red mushroom.
794        if rand.next_int_bounded(8) == 0 {
795            let pos = pos + next_offset(&mut rand, 128, 8);
796            PlantGenerator::new_flower(block::RED_MUSHROOM).generate(world, pos, &mut rand);
797        }
798
799        // Sugar canes.
800        for _ in 0..10 {
801            let pos = pos + next_offset(&mut rand, 128, 8);
802            SugarCanesGenerator::new().generate(world, pos, &mut rand);
803        }
804
805        // Pumpkin.
806        if rand.next_int_bounded(32) == 0 {
807            let pos = pos + next_offset(&mut rand, 128, 8);
808            PumpkinGenerator::new().generate(world, pos, &mut rand);
809        }
810
811        // Cactus.
812        if biome == Biome::Desert {
813            for _ in 0..10 {
814                let pos = pos + next_offset(&mut rand, 128, 8);
815                CactusGenerator::new().generate(world, pos, &mut rand);
816            }
817        }
818
819        // Water sources.
820        for _ in 0..50 {
821
822            let pos = pos + IVec3 {
823                x: rand.next_int_bounded(16) + 8,
824                y: {
825                    let v = rand.next_int_bounded(120);
826                    rand.next_int_bounded(v + 8)
827                },
828                z: rand.next_int_bounded(16) + 8,
829            };
830
831            LiquidGenerator::new(block::WATER_MOVING).generate(world, pos, &mut rand);
832
833        }
834
835        // Lava sources.
836        for _ in 0..20 {
837
838            let pos = pos + IVec3 {
839                x: rand.next_int_bounded(16) + 8,
840                y: {
841                    let v = rand.next_int_bounded(112);
842                    let v = rand.next_int_bounded(v + 8);
843                    rand.next_int_bounded(v + 8)
844                },
845                z: rand.next_int_bounded(16) + 8,
846            };
847
848            LiquidGenerator::new(block::LAVA_MOVING).generate(world, pos, &mut rand);
849
850        }
851
852        // Finally add snow layer if cold enought.
853        let offset = DVec2::new((pos.x + 8) as f64, (pos.y + 8) as f64);
854        let temperature = &mut state.temperature;
855        let biome = &mut state.biome;
856        self.temperature_noise.gen_weird_2d(temperature, offset,TEMPERATURE_SCALE, TEMPERATURE_FREQ_FACTOR);
857        self.biome_noise.gen_weird_2d(biome, offset, BIOME_SCALE, BIOME_FREQ_FACTOR);
858
859        for dx in 0usize..16 {
860            for dz in 0usize..16 {
861
862                let snow_pos = pos + IVec3 {
863                    x: dx as i32,
864                    y: 0,
865                    z: dz as i32,
866                };
867
868                // Find highest block and set pos.y.
869
870                let temp = temperature.get(dx, 0, dz) - (snow_pos.y - 64) as f64 / 64.0 * 0.3;
871                if temp < 0.5 && snow_pos.y > 0 && snow_pos.y < 128 &&  world.is_block_air(snow_pos) {
872                    let material = world.get_block_material(snow_pos - IVec3::Y);
873                    if material.is_solid() && material != Material::Ice {
874                        world.set_block(snow_pos, block::SNOW, 0);
875                    }
876                }
877
878            }
879        }
880
881        // TODO: This is temporary code to avoid light bugs at generation, but this
882        // considerably slows down the feature generation (that is currently 
883        // single-threaded).
884        world.tick_light(usize::MAX);
885
886    }
887
888}