From d9b3d0494d6c601403a4187232d9393f6abd9609 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Tue, 22 Oct 2024 16:41:53 +0200 Subject: [PATCH] Improved: Plains biome - Flowers - Grass - More natural height variation --- pumpkin-world/src/coordinates.rs | 2 +- pumpkin-world/src/world_gen/generator.rs | 17 +++- .../src/world_gen/generic_generator.rs | 20 ++--- .../implementation/overworld/biome/mod.rs | 54 ++++++++++++ .../implementation/overworld/biome/plains.rs | 82 ++++++++++++++++--- 5 files changed, 150 insertions(+), 25 deletions(-) diff --git a/pumpkin-world/src/coordinates.rs b/pumpkin-world/src/coordinates.rs index f35c1145..87d9e090 100644 --- a/pumpkin-world/src/coordinates.rs +++ b/pumpkin-world/src/coordinates.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, AsRef, AsMut, Into, Display, )] #[serde(transparent)] -pub struct Height(i16); +pub struct Height(pub i16); impl Height { pub fn from_absolute(height: u16) -> Self { diff --git a/pumpkin-world/src/world_gen/generator.rs b/pumpkin-world/src/world_gen/generator.rs index eb746772..d035842a 100644 --- a/pumpkin-world/src/world_gen/generator.rs +++ b/pumpkin-world/src/world_gen/generator.rs @@ -3,8 +3,8 @@ use pumpkin_core::math::vector2::Vector2; use crate::biome::Biome; use crate::block::block_state::BlockState; -use crate::chunk::ChunkData; -use crate::coordinates::{BlockCoordinates, XZBlockCoordinates}; +use crate::chunk::{ChunkBlocks, ChunkData}; +use crate::coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates}; use crate::world_gen::Seed; pub trait GeneratorInit { @@ -28,8 +28,19 @@ pub(crate) trait TerrainGenerator: Sync + Send { } pub(crate) trait PerlinTerrainGenerator: Sync + Send { + fn height_variation(&self) -> f64 { + 4.0 + } + fn prepare_chunk(&self, at: &Vector2, perlin: &Perlin); /// Dependens on the perlin noise height - fn generate_block(&self, at: BlockCoordinates, chunk_height: i16, biome: Biome) -> BlockState; + fn generate_block( + &self, + coordinates: ChunkRelativeBlockCoordinates, + at: BlockCoordinates, + blocks: &mut ChunkBlocks, + chunk_height: i16, + biome: Biome, + ); } diff --git a/pumpkin-world/src/world_gen/generic_generator.rs b/pumpkin-world/src/world_gen/generic_generator.rs index 4888e536..de3f02ca 100644 --- a/pumpkin-world/src/world_gen/generic_generator.rs +++ b/pumpkin-world/src/world_gen/generic_generator.rs @@ -39,8 +39,8 @@ impl WorldGenerator for GenericGen let noise_value = self.perlin.get([at.x as f64 / 16.0, at.z as f64 / 16.0]); let base_height = 64.0; - let height_variation = 16.0; - let chunk_height = noise_value.mul_add(height_variation, base_height) as i32; + let chunk_height = + noise_value.mul_add(self.terrain_generator.height_variation(), base_height) as i16; for x in 0..16u8 { for z in 0..16u8 { @@ -53,22 +53,20 @@ impl WorldGenerator for GenericGen ); // Iterate from the highest block to the lowest, in order to minimize the heightmap updates - for y in (WORLD_LOWEST_Y..chunk_height as i16).rev() { + for y in (WORLD_LOWEST_Y..chunk_height).rev() { let coordinates = ChunkRelativeBlockCoordinates { x: x.into(), y: y.into(), z: z.into(), }; - blocks.set_block( + //coordinates, + self.terrain_generator.generate_block( coordinates, - self.terrain_generator - .generate_block( - coordinates.with_chunk_coordinates(at), - chunk_height as i16, - biome, - ) - .into(), + coordinates.with_chunk_coordinates(at), + &mut blocks, + chunk_height, + biome, ); } } diff --git a/pumpkin-world/src/world_gen/implementation/overworld/biome/mod.rs b/pumpkin-world/src/world_gen/implementation/overworld/biome/mod.rs index df9a5d69..b6a526f5 100644 --- a/pumpkin-world/src/world_gen/implementation/overworld/biome/mod.rs +++ b/pumpkin-world/src/world_gen/implementation/overworld/biome/mod.rs @@ -1 +1,55 @@ +use std::ops::Add; + +use crate::{block::BlockState, coordinates::ChunkRelativeBlockCoordinates}; + pub mod plains; + +pub fn generate_tree( + chunk_relative_coordinates: ChunkRelativeBlockCoordinates, +) -> Vec<(ChunkRelativeBlockCoordinates, BlockState)> { + let x = chunk_relative_coordinates.x; + let z = chunk_relative_coordinates.z; + + // TODO: Adjust tree height and trunk width based on biome + let tree_height: i8 = 7; + let trunk_width: i8 = 1; + + let mut tree_blocks = Vec::new(); + + // Generate trunk + for y in 0..tree_height { + for dx in 0 - trunk_width..=trunk_width { + for dz in 0 - trunk_width..=trunk_width { + let block_coordinates = ChunkRelativeBlockCoordinates { + x: x.add(dx as u8).into(), + y: (chunk_relative_coordinates.y.add(y as i16)).into(), + z: z.add(dz as u8).into(), + }; + tree_blocks.push(( + block_coordinates, + pumpkin_macros::block!("minecraft:oak_log"), + )); + } + } + } + + // Generate leaves + let leaf_radius = trunk_width + 1; + for y in tree_height..tree_height + 3 { + for dx in 0 - leaf_radius..=leaf_radius { + for dz in 0 - leaf_radius..=leaf_radius { + let block_coordinates = ChunkRelativeBlockCoordinates { + x: x.add(dx as u8).into(), + y: (chunk_relative_coordinates.y.add(y as i16)).into(), + z: z.add(dz as u8).into(), + }; + tree_blocks.push(( + block_coordinates, + pumpkin_macros::block!("minecraft:oak_leaves"), + )); + } + } + } + + tree_blocks +} diff --git a/pumpkin-world/src/world_gen/implementation/overworld/biome/plains.rs b/pumpkin-world/src/world_gen/implementation/overworld/biome/plains.rs index 001c71be..bfd43b87 100644 --- a/pumpkin-world/src/world_gen/implementation/overworld/biome/plains.rs +++ b/pumpkin-world/src/world_gen/implementation/overworld/biome/plains.rs @@ -1,10 +1,11 @@ use noise::Perlin; use pumpkin_core::math::vector2::Vector2; +use rand::Rng; use crate::{ biome::Biome, - block::block_state::BlockState, - coordinates::{BlockCoordinates, XZBlockCoordinates}, + chunk::ChunkBlocks, + coordinates::{BlockCoordinates, ChunkRelativeBlockCoordinates, XZBlockCoordinates}, world_gen::{ generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator}, generic_generator::GenericGenerator, @@ -40,21 +41,82 @@ impl GeneratorInit for PlainsTerrainGenerator { impl PerlinTerrainGenerator for PlainsTerrainGenerator { fn prepare_chunk(&self, _at: &Vector2, _perlin: &Perlin) {} // TODO allow specifying which blocks should be at which height in the config. - fn generate_block(&self, at: BlockCoordinates, chunk_height: i16, _: Biome) -> BlockState { + fn generate_block( + &self, + coordinates: ChunkRelativeBlockCoordinates, + at: BlockCoordinates, + blocks: &mut ChunkBlocks, + chunk_height: i16, + _: Biome, + ) { let begin_stone_height = chunk_height - 5; - let begin_dirt_height = chunk_height - 1; + let begin_dirt_height = chunk_height - 2; let y = *at.y; if y == -64 { - pumpkin_macros::block!("minecraft:bedrock") + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:bedrock").into(), + ); } else if y >= -63 && y <= begin_stone_height { - pumpkin_macros::block!("minecraft:stone") + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:stone").into(), + ); } else if y >= begin_stone_height && y < begin_dirt_height { - pumpkin_macros::block!("minecraft:dirt") + blocks.set_block(coordinates, pumpkin_macros::block!("minecraft:dirt").into()); + } else if y == chunk_height - 2 { + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:grass_block").into(), + ); } else if y == chunk_height - 1 { - pumpkin_macros::block!("minecraft:grass_block") - } else { - BlockState::AIR + // TODO: generate flowers and grass + let grass: u8 = rand::thread_rng().gen_range(0..7); + if grass == 3 { + let flower: u8 = rand::thread_rng().gen_range(0..20); + if flower == 6 { + match rand::thread_rng().gen_range(0..4) { + 0 => { + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:dandelion").into(), + ); + } + 1 => { + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:oxeye_daisy").into(), + ); + } + 2 => { + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:cornflower").into(), + ); + } + 3 => { + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:poppy").into(), + ); + } + _ => { + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:azure_bluet").into(), + ); + } + } + } else { + // TODO: Tall grass, Tall grass data called `half`, There is `upper` and `lower` + blocks.set_block( + coordinates, + pumpkin_macros::block!("minecraft:short_grass").into(), + ); + } + } } + // BlockState::AIR } }