summaryrefslogtreecommitdiff
path: root/src/proc_gen/mod.rs
blob: fb6a32635b11cd05fee531332ceae7f8582bc593 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use fastnoise_lite::{FastNoiseLite, NoiseType};
use glam::{IVec2, Vec2};

use crate::{
    config::CHUNK_SIZE,
    content::materials::MaterialId,
    sim::{cell::Cell, cell_manager::chunk::Chunk},
};

#[derive(Clone, Copy)]
pub struct WorldGeneratorConfig {
    pub occupied_threshold: f32,
    pub stone_threshold: f32,
    pub proc_gen_seed: i32,

    pub cave_noise_freq: f32,
    pub cave_noise_type: NoiseType,
    pub hardness_noise_freq: f32,
    pub hardness_noise_type: NoiseType,
}

impl Default for WorldGeneratorConfig {
    fn default() -> Self {
        Self {
            occupied_threshold: 0.05,
            stone_threshold: 0.6,
            proc_gen_seed: 10,

            cave_noise_freq: 0.005,
            cave_noise_type: NoiseType::OpenSimplex2S,
            hardness_noise_freq: 0.015,
            hardness_noise_type: NoiseType::OpenSimplex2S,
        }
    }
}

pub struct WorldGenerator {
    config: WorldGeneratorConfig,
    cave_noise: Option<FastNoiseLite>,
    hardness_noise: Option<FastNoiseLite>,
}

impl WorldGenerator {
    pub fn generate_chunk(&mut self, chunk_position: IVec2) -> Chunk {
        if let Some(cave_noise) = &self.cave_noise
            && let Some(hardness_noise) = &self.hardness_noise
        {
            let mut c = Chunk::void();
            let position = chunk_position * CHUNK_SIZE;
            for x in 0..CHUNK_SIZE {
                for y in 0..CHUNK_SIZE {
                    let cell_position = position.as_vec2() + Vec2::new(x as f32, y as f32);
                    let cnv = cave_noise.get_noise_2d(cell_position.x, cell_position.y);
                    let hnv = hardness_noise.get_noise_2d(cell_position.x, cell_position.y);

                    let occupied = cnv < self.config.occupied_threshold;
                    if occupied {
                        let material = if hnv > self.config.stone_threshold {
                            MaterialId::Stone
                        } else {
                            MaterialId::Dirt
                        };
                        c.set_cell_at_local_position(
                            x as u8,
                            y as u8,
                            Cell::from_material(material),
                        );
                    }
                }
            }
            c
        } else {
            panic!("Call update_params first");
        }
    }

    pub fn update_params(&mut self, config: WorldGeneratorConfig) {
        let mut cave_noise = FastNoiseLite::with_seed(config.proc_gen_seed + 50);
        cave_noise.set_frequency(Some(config.cave_noise_freq));
        cave_noise.set_noise_type(Some(config.cave_noise_type));

        let mut hardness_noise = FastNoiseLite::with_seed(config.proc_gen_seed + 100);
        hardness_noise.set_frequency(Some(config.hardness_noise_freq));
        hardness_noise.set_noise_type(Some(config.hardness_noise_type));

        self.cave_noise = Some(cave_noise);
        self.hardness_noise = Some(hardness_noise);

        self.config = config;
    }

    pub fn new(config: WorldGeneratorConfig) -> Self {
        let mut wg = WorldGenerator {
            config,
            cave_noise: None,
            hardness_noise: None,
        };
        wg.update_params(config);
        wg
    }
}