1use 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
53pub struct OverworldGenerator {
56 seed: i64,
58 temperature_noise: PerlinOctaveNoise,
60 humidity_noise: PerlinOctaveNoise,
62 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#[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 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 #[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 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 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 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 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 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 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 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; 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 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 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 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 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 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 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 #[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 world.tick_light(usize::MAX);
885
886 }
887
888}