From 0fac4531e049bf6c93ae74d489fc46acd691b50d Mon Sep 17 00:00:00 2001 From: griffi-gh Date: Fri, 3 May 2024 00:27:43 +0200 Subject: [PATCH] decoration and layers --- kubi-shared/src/worldgen.rs | 21 +++++++++++++ kubi-shared/src/worldgen/_01_terrain.rs | 3 ++ kubi-shared/src/worldgen/_02_water.rs | 4 ++- kubi-shared/src/worldgen/_03_caves.rs | 39 +++++++++++++----------- kubi-shared/src/worldgen/_04_layers.rs | 32 +++++++++++++++++++ kubi-shared/src/worldgen/_05_decorate.rs | 28 +++++++++++++++++ 6 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 kubi-shared/src/worldgen/_04_layers.rs create mode 100644 kubi-shared/src/worldgen/_05_decorate.rs diff --git a/kubi-shared/src/worldgen.rs b/kubi-shared/src/worldgen.rs index d15d8bd..d8602b8 100644 --- a/kubi-shared/src/worldgen.rs +++ b/kubi-shared/src/worldgen.rs @@ -12,6 +12,8 @@ use crate::{ mod _01_terrain; mod _02_water; mod _03_caves; +mod _04_layers; +mod _05_decorate; #[repr(u8)] #[derive(Clone, Copy, Debug, Default, NoUninit, CheckedBitPattern)] @@ -83,11 +85,17 @@ macro_rules! run_steps { }; } +#[derive(Default)] +pub struct WorldGeneratorData { + pub master_height_map: Option>>, +} + pub struct WorldGenerator { seed: u64, chunk_position: IVec3, blocks: BlockData, queue: Vec, + pub data: WorldGeneratorData, } impl WorldGenerator { @@ -153,12 +161,23 @@ impl WorldGenerator { (0..CHUNK_SIZE as i32).contains(&position).then_some(position) } + /// crude hash of self.seed and x + fn seeded_hash(&self, x: impl std::hash::Hash) -> u64 { + //use std::hash to hash the seed and x + use std::hash::{Hash, Hasher}; + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + x.hash(&mut hasher); + self.seed.hash(&mut hasher); + hasher.finish() + } + pub fn new(chunk_position: IVec3, seed: u64) -> Self { Self { seed, chunk_position, blocks: Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]), queue: Vec::with_capacity(0), + data: Default::default(), } } @@ -170,6 +189,8 @@ impl WorldGenerator { _01_terrain::TerrainStep, _02_water::WaterStep, _03_caves::CaveStep, + _04_layers::LayersStep, + _05_decorate::DecorateStep, ]).then_some((self.blocks, self.queue)) } } diff --git a/kubi-shared/src/worldgen/_01_terrain.rs b/kubi-shared/src/worldgen/_01_terrain.rs index f5342a7..dc1da1d 100644 --- a/kubi-shared/src/worldgen/_01_terrain.rs +++ b/kubi-shared/src/worldgen/_01_terrain.rs @@ -18,14 +18,17 @@ impl WorldGenStep for TerrainStep { } fn generate(&mut self, gen: &mut WorldGenerator) { + let mut height_map = vec![vec![0; CHUNK_SIZE]; CHUNK_SIZE]; for x in 0..CHUNK_SIZE as i32 { for z in 0..CHUNK_SIZE as i32 { let global_xz = gen.global_position(ivec3(x, 0, z)); let height = (self.noise.get_noise_2d(global_xz.x as f64, global_xz.z as f64) * 32.0) as i32; + height_map[x as usize][z as usize] = height; for y in 0..gen.local_height(height) { gen.place(ivec3(x, y, z), Block::Stone); } } } + gen.data.master_height_map = Some(height_map); } } diff --git a/kubi-shared/src/worldgen/_02_water.rs b/kubi-shared/src/worldgen/_02_water.rs index 63c0b11..f761f5e 100644 --- a/kubi-shared/src/worldgen/_02_water.rs +++ b/kubi-shared/src/worldgen/_02_water.rs @@ -2,6 +2,8 @@ use glam::ivec3; use crate::{block::Block, chunk::CHUNK_SIZE}; use super::{WorldGenerator, WorldGenStep}; +pub const WATER_LEVEL: i32 = 0; + pub struct WaterStep; impl WorldGenStep for WaterStep { @@ -9,7 +11,7 @@ impl WorldGenStep for WaterStep { fn generate(&mut self, gen: &mut WorldGenerator) { for x in 0..CHUNK_SIZE as i32 { for z in 0..CHUNK_SIZE as i32 { - for y in 0..gen.local_height(0) { + for y in 0..gen.local_height(WATER_LEVEL) { gen.place_if_empty(ivec3(x, y, z), Block::Water); } } diff --git a/kubi-shared/src/worldgen/_03_caves.rs b/kubi-shared/src/worldgen/_03_caves.rs index a0ddd5a..bfb0a75 100644 --- a/kubi-shared/src/worldgen/_03_caves.rs +++ b/kubi-shared/src/worldgen/_03_caves.rs @@ -1,6 +1,5 @@ - use fastnoise_lite::{FastNoiseLite, FractalType}; -use glam::{ivec3, IVec3}; +use glam::{ivec3, FloatExt, IVec3}; use crate::{block::Block, chunk::CHUNK_SIZE}; use super::{SeedThingy, WorldGenStep, WorldGenerator}; @@ -25,22 +24,26 @@ impl WorldGenStep for CaveStep { } fn generate(&mut self, gen: &mut WorldGenerator) { - //TODO + for x in 0..CHUNK_SIZE as i32 { + for y in 0..CHUNK_SIZE as i32 { + for z in 0..CHUNK_SIZE as i32 { + let cave_size = ((gen.offset().y + y - 50) as f64 / -200.).clamp(0., 1.) as f32; + let inv_cave_size = 1. - cave_size; + if cave_size < 0.1 { continue } - // for x in 0..CHUNK_SIZE as i32 { - // for y in 0..CHUNK_SIZE as i32 { - // for z in 0..CHUNK_SIZE as i32 { - // let pos = ivec3(x, y, z); - // if gen.query(pos) != Block::Stone { continue } - // let pos_global = gen.global_position(pos); - // let noise_a = self.a.get_noise_3d(pos_global.x as f64, pos_global.y as f64, pos_global.z as f64) * 0.5 + 0.5; - // let noise_b = self.b.get_noise_3d(pos_global.x as f64, pos_global.y as f64, pos_global.z as f64) * 0.5 + 0.5; - // if noise_a.min(noise_b) > (1. - (-y as f32 / 400.).clamp(0., 1.)) { - // gen.place(pos, Block::Air); - // } - // //TODO - // } - // } - // } + let pos = ivec3(x, y, z); + if gen.query(pos) != Block::Stone { continue } + + let pos_global = gen.global_position(pos); + let noise_a = self.a.get_noise_3d(pos_global.x as f64, pos_global.y as f64, pos_global.z as f64) * 0.5 + 0.5; + let noise_b = self.b.get_noise_3d(pos_global.x as f64, pos_global.y as f64, pos_global.z as f64) * 0.5 + 0.5; + + if noise_a.min(noise_b) > (0.6 + 0.4 * inv_cave_size) { + gen.place(pos, Block::Air); + } + //TODO + } + } + } } } diff --git a/kubi-shared/src/worldgen/_04_layers.rs b/kubi-shared/src/worldgen/_04_layers.rs new file mode 100644 index 0000000..d9a2dc8 --- /dev/null +++ b/kubi-shared/src/worldgen/_04_layers.rs @@ -0,0 +1,32 @@ +use glam::ivec3; +use crate::{block::Block, chunk::CHUNK_SIZE}; +use super::{WorldGenStep, WorldGenerator, _02_water::WATER_LEVEL}; +pub struct LayersStep; + +impl WorldGenStep for LayersStep { + fn initialize(_: &WorldGenerator) -> Self { Self } + + fn generate(&mut self, gen: &mut WorldGenerator) { + for x in 0..CHUNK_SIZE as i32 { + for z in 0..CHUNK_SIZE as i32 { + let terrain_height = gen.data.master_height_map.as_ref().unwrap()[x as usize][z as usize]; + + // Dirt layer height, naturally gets thinner as height gets deeper + let mut dirt_layer_height = (((terrain_height as f32 + 15.) / 20.).clamp(0., 1.) * 8.).round() as i32; + dirt_layer_height -= (gen.seeded_hash((x, z, 1)) & 1) as i32; //+ (gen.seeded_hash((x, z, 0xbau8)) & 1) as i32; + + // Place dirt layer + for y in gen.local_height(terrain_height - dirt_layer_height)..gen.local_height(terrain_height) { + gen.place(ivec3(x, y, z), Block::Dirt); + } + + // If above water level, place grass + if terrain_height >= WATER_LEVEL { + if let Some(local_y) = gen.local_y_position(terrain_height - 1) { + gen.place(ivec3(x, local_y, z), Block::Grass); + } + } + } + } + } +} diff --git a/kubi-shared/src/worldgen/_05_decorate.rs b/kubi-shared/src/worldgen/_05_decorate.rs new file mode 100644 index 0000000..a4850de --- /dev/null +++ b/kubi-shared/src/worldgen/_05_decorate.rs @@ -0,0 +1,28 @@ +use glam::ivec3; +use crate::{block::Block, chunk::CHUNK_SIZE}; +use super::{WorldGenStep, WorldGenerator, _02_water::WATER_LEVEL}; + +pub struct DecorateStep; + +impl WorldGenStep for DecorateStep { + fn initialize(_: &WorldGenerator) -> Self { Self } + + fn generate(&mut self, gen: &mut WorldGenerator) { + for x in 0..CHUNK_SIZE as i32 { + for z in 0..CHUNK_SIZE as i32 { + let global_xz = gen.global_position(ivec3(x, 0, z)); + + let terrain_height = gen.data.master_height_map.as_ref().unwrap()[x as usize][z as usize]; + + //Place tall grass + if terrain_height >= WATER_LEVEL { + if let Some(local_y) = gen.local_y_position(terrain_height) { + if (gen.seeded_hash((global_xz.x, global_xz.z)) & 0xf) == 0xf { + gen.place_if_empty(ivec3(x, local_y, z), Block::TallGrass); + } + } + } + } + } + } +}