diff --git a/kubi-shared/src/worldgen.rs b/kubi-shared/src/worldgen.rs index d8602b8..f5ebba6 100644 --- a/kubi-shared/src/worldgen.rs +++ b/kubi-shared/src/worldgen.rs @@ -9,11 +9,8 @@ use crate::{ queue::QueuedBlock, }; -mod _01_terrain; -mod _02_water; -mod _03_caves; -mod _04_layers; -mod _05_decorate; +pub mod steps; +pub mod structures; #[repr(u8)] #[derive(Clone, Copy, Debug, Default, NoUninit, CheckedBitPattern)] @@ -186,11 +183,12 @@ impl WorldGenerator { /// Will return `None` only if the generation was aborted. pub fn generate(mut self, abort: Option>>) -> Option<(BlockData, Vec)> { run_steps!(&mut self, abort, [ - _01_terrain::TerrainStep, - _02_water::WaterStep, - _03_caves::CaveStep, - _04_layers::LayersStep, - _05_decorate::DecorateStep, + steps::_01_terrain::TerrainStep, + steps::_02_water::WaterStep, + steps::_03_caves::CaveStep, + steps::_04_layers::LayersStep, + steps::_05_decorate::DecorateStep, + steps::_06_trees::TreesStep, ]).then_some((self.blocks, self.queue)) } } diff --git a/kubi-shared/src/worldgen/steps.rs b/kubi-shared/src/worldgen/steps.rs new file mode 100644 index 0000000..147f85d --- /dev/null +++ b/kubi-shared/src/worldgen/steps.rs @@ -0,0 +1,6 @@ +pub mod _01_terrain; +pub mod _02_water; +pub mod _03_caves; +pub mod _04_layers; +pub mod _05_decorate; +pub mod _06_trees; diff --git a/kubi-shared/src/worldgen/_01_terrain.rs b/kubi-shared/src/worldgen/steps/_01_terrain.rs similarity index 92% rename from kubi-shared/src/worldgen/_01_terrain.rs rename to kubi-shared/src/worldgen/steps/_01_terrain.rs index dc1da1d..0a0bc36 100644 --- a/kubi-shared/src/worldgen/_01_terrain.rs +++ b/kubi-shared/src/worldgen/steps/_01_terrain.rs @@ -1,7 +1,7 @@ use fastnoise_lite::{FastNoiseLite, FractalType}; use glam::ivec3; use crate::{block::Block, chunk::CHUNK_SIZE}; -use super::{SeedThingy, WorldGenStep, WorldGenerator}; +use super::super::{SeedThingy, WorldGenStep, WorldGenerator}; pub struct TerrainStep { noise: FastNoiseLite, diff --git a/kubi-shared/src/worldgen/_02_water.rs b/kubi-shared/src/worldgen/steps/_02_water.rs similarity index 87% rename from kubi-shared/src/worldgen/_02_water.rs rename to kubi-shared/src/worldgen/steps/_02_water.rs index f761f5e..80c6a3a 100644 --- a/kubi-shared/src/worldgen/_02_water.rs +++ b/kubi-shared/src/worldgen/steps/_02_water.rs @@ -1,6 +1,6 @@ use glam::ivec3; use crate::{block::Block, chunk::CHUNK_SIZE}; -use super::{WorldGenerator, WorldGenStep}; +use super::super::{WorldGenerator, WorldGenStep}; pub const WATER_LEVEL: i32 = 0; diff --git a/kubi-shared/src/worldgen/_03_caves.rs b/kubi-shared/src/worldgen/steps/_03_caves.rs similarity index 93% rename from kubi-shared/src/worldgen/_03_caves.rs rename to kubi-shared/src/worldgen/steps/_03_caves.rs index bfb0a75..41d0be2 100644 --- a/kubi-shared/src/worldgen/_03_caves.rs +++ b/kubi-shared/src/worldgen/steps/_03_caves.rs @@ -1,7 +1,7 @@ use fastnoise_lite::{FastNoiseLite, FractalType}; use glam::{ivec3, FloatExt, IVec3}; use crate::{block::Block, chunk::CHUNK_SIZE}; -use super::{SeedThingy, WorldGenStep, WorldGenerator}; +use super::super::{SeedThingy, WorldGenStep, WorldGenerator}; pub struct CaveStep { a: FastNoiseLite, diff --git a/kubi-shared/src/worldgen/_04_layers.rs b/kubi-shared/src/worldgen/steps/_04_layers.rs similarity index 91% rename from kubi-shared/src/worldgen/_04_layers.rs rename to kubi-shared/src/worldgen/steps/_04_layers.rs index d9a2dc8..a80354f 100644 --- a/kubi-shared/src/worldgen/_04_layers.rs +++ b/kubi-shared/src/worldgen/steps/_04_layers.rs @@ -1,6 +1,10 @@ use glam::ivec3; use crate::{block::Block, chunk::CHUNK_SIZE}; -use super::{WorldGenStep, WorldGenerator, _02_water::WATER_LEVEL}; +use super::{ + _02_water::WATER_LEVEL, + super::{WorldGenStep, WorldGenerator} +}; + pub struct LayersStep; impl WorldGenStep for LayersStep { diff --git a/kubi-shared/src/worldgen/_05_decorate.rs b/kubi-shared/src/worldgen/steps/_05_decorate.rs similarity index 88% rename from kubi-shared/src/worldgen/_05_decorate.rs rename to kubi-shared/src/worldgen/steps/_05_decorate.rs index a4850de..20e9b32 100644 --- a/kubi-shared/src/worldgen/_05_decorate.rs +++ b/kubi-shared/src/worldgen/steps/_05_decorate.rs @@ -1,6 +1,9 @@ use glam::ivec3; use crate::{block::Block, chunk::CHUNK_SIZE}; -use super::{WorldGenStep, WorldGenerator, _02_water::WATER_LEVEL}; +use super::{ + _02_water::WATER_LEVEL, + super::{WorldGenStep, WorldGenerator}, +}; pub struct DecorateStep; diff --git a/kubi-shared/src/worldgen/steps/_06_trees.rs b/kubi-shared/src/worldgen/steps/_06_trees.rs new file mode 100644 index 0000000..08b547b --- /dev/null +++ b/kubi-shared/src/worldgen/steps/_06_trees.rs @@ -0,0 +1,45 @@ +use bincode::de; +use fastnoise_lite::{FastNoiseLite, NoiseType}; +use glam::ivec3; +use crate::{block::Block, chunk::CHUNK_SIZE, worldgen::SeedThingy}; +use super::_02_water::WATER_LEVEL; +use crate::worldgen::{ + WorldGenStep, WorldGenerator, + structures::{Structure, TreeStructure}, +}; + + +pub struct TreesStep { + density_noise: FastNoiseLite, +} + +impl WorldGenStep for TreesStep { + fn initialize(gen: &WorldGenerator) -> Self { + let mut seeder = SeedThingy::new(gen.seed.rotate_left(5)); + let mut density_noise = FastNoiseLite::with_seed(seeder.next_seed()); + density_noise.set_noise_type(Some(NoiseType::OpenSimplex2)); + density_noise.set_frequency(Some(0.008)); + Self { density_noise } + } + + 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]; + if terrain_height < WATER_LEVEL { continue } + + let global_xz = gen.global_position(ivec3(x, 0, z)); + let mut density = self.density_noise.get_noise_2d(global_xz.x as f64, global_xz.z as f64) * 0.5 + 0.5; + density = density.powi(3); + if gen.seeded_hash((global_xz.x, global_xz.z, 0xfef)) & 0xff >= (density * 7.).round() as u64 { + continue + } + + let tree = TreeStructure::default(); + if let Some(local_y) = gen.local_y_position(terrain_height) { + tree.place(gen, ivec3(x, local_y, z)); + } + } + } + } +} diff --git a/kubi-shared/src/worldgen/structures.rs b/kubi-shared/src/worldgen/structures.rs new file mode 100644 index 0000000..744cab6 --- /dev/null +++ b/kubi-shared/src/worldgen/structures.rs @@ -0,0 +1,9 @@ +use glam::IVec3; +use super::WorldGenerator; + +mod tree; +pub use tree::TreeStructure; + +pub trait Structure { + fn place(&self, gen: &mut WorldGenerator, root_pos: IVec3); +} diff --git a/kubi-shared/src/worldgen/structures/tree.rs b/kubi-shared/src/worldgen/structures/tree.rs new file mode 100644 index 0000000..78083b3 --- /dev/null +++ b/kubi-shared/src/worldgen/structures/tree.rs @@ -0,0 +1,58 @@ +use glam::IVec3; +use super::Structure; +use crate::{block::Block, worldgen::WorldGenerator}; + +#[derive(Clone, Copy, Debug)] +pub struct TreeStructure { + pub height: i32, +} + +impl Default for TreeStructure { + fn default() -> Self { + Self { height: 5 } + } +} + +impl Structure for TreeStructure { + fn place(&self, gen: &mut WorldGenerator, root: IVec3) { + //check the block below the tree, if it's grass, replace it with dirt + //XXX: This won't work if root.y == 0 + if root.y != 0 && gen.query(root - IVec3::Y) == Block::Grass { + gen.place(root - IVec3::Y, Block::Dirt); + } + + //Tree stem + for y in root.y..root.y + self.height { + gen.place_or_queue(IVec3::new(root.x, y, root.z), Block::Wood); + } + + //Tree leaves + //Try to create the following shape: + //(a 5x2x5 cube that wraps around the stem with a 3x1x3 cube on top) + // xxx + // xx|xx + // xx|xx + // | + + for y in 0..=4_i32 { + for x in -2..=2_i32 { + for z in -2..=2_i32 { + //Do not overwrite the stem + if y < 3 && x == 0 && z == 0 { + continue + } + // Cut off the corners of the top layer + if y >= 3 && (x.abs() > 1 || z.abs() > 1) { + continue + } + let position = IVec3::new( + root.x + x, + root.y + self.height - 3 + y, + root.z + z + ); + gen.place_or_queue(position, Block::Leaf); + } + } + } + } +}