Pumpkin/pumpkin-world/src/world_gen/generic_generator.rs

122 lines
3.8 KiB
Rust

use noise::{NoiseFn, Perlin};
use pumpkin_core::math::vector2::Vector2;
use crate::{
chunk::{ChunkBlocks, ChunkData},
coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates},
WORLD_LOWEST_Y,
};
use super::{
generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator, WorldGenerator},
Seed,
};
pub struct GenericGenerator<B: BiomeGenerator, T: PerlinTerrainGenerator> {
biome_generator: B,
terrain_generator: T,
// TODO: May make this optional?. But would be pain to use in most biomes then. Maybe make a new trait like
// PerlinTerrainGenerator
perlin: Perlin,
}
impl<B: BiomeGenerator + GeneratorInit, T: PerlinTerrainGenerator + GeneratorInit> GeneratorInit
for GenericGenerator<B, T>
{
fn new(seed: Seed) -> Self {
Self {
biome_generator: B::new(seed),
terrain_generator: T::new(seed),
perlin: Perlin::new(seed.0 as u32),
}
}
}
impl<B: BiomeGenerator, T: PerlinTerrainGenerator> WorldGenerator for GenericGenerator<B, T> {
fn generate_chunk(&self, at: Vector2<i32>) -> ChunkData {
let mut blocks = ChunkBlocks::default();
self.terrain_generator.prepare_chunk(&at, &self.perlin);
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;
for x in 0..16u8 {
for z in 0..16u8 {
let biome = self.biome_generator.generate_biome(
ChunkRelativeXZBlockCoordinates {
x: x.into(),
z: z.into(),
}
.with_chunk_coordinates(at),
);
// 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() {
let coordinates = ChunkRelativeBlockCoordinates {
x: x.into(),
y: y.into(),
z: z.into(),
};
blocks.set_block(
coordinates,
self.terrain_generator
.generate_block(
coordinates.with_chunk_coordinates(at),
chunk_height as i16,
biome,
)
.into(),
);
}
}
}
ChunkData {
blocks,
position: at,
}
}
}
// TODO: implement static terrain generator
/*
fn generate_chunk(&mut self, at: Vector2<i32>) -> ChunkData {
let mut blocks = ChunkBlocks::default();
self.terrain_generator.prepare_chunk(&at, &self.perlin);
for x in 0..16u8 {
for z in 0..16u8 {
let biome = self.biome_generator.generate_biome(
ChunkRelativeXZBlockCoordinates {
x: x.into(),
z: z.into(),
}
.with_chunk_coordinates(at),
);
// Iterate from the highest block to the lowest, in order to minimize the heightmap updates
for y in (WORLD_LOWEST_Y..WORLD_MAX_Y).rev() {
let coordinates = ChunkRelativeBlockCoordinates {
x: x.into(),
y: y.into(),
z: z.into(),
};
blocks.set_block(
coordinates,
self.terrain_generator
.generate_block(coordinates.with_chunk_coordinates(at), biome),
);
}
}
}
ChunkData {
blocks,
position: at,
}
}
*/