Add Experimental Plains biome
Also add Perlin noise
This commit is contained in:
parent
91d190c212
commit
b40c2fa988
22
Cargo.lock
generated
22
Cargo.lock
generated
@ -1543,6 +1543,17 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "noise"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6da45c8333f2e152fc665d78a380be060eb84fad8ca4c9f7ac8ca29216cff0cc"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
|
"rand_xorshift",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
@ -1977,9 +1988,11 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"itertools 0.13.0",
|
"itertools 0.13.0",
|
||||||
"log",
|
"log",
|
||||||
|
"noise",
|
||||||
"num-derive",
|
"num-derive",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"pumpkin-core",
|
"pumpkin-core",
|
||||||
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -2075,6 +2088,15 @@ dependencies = [
|
|||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_xorshift"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.10.0"
|
version = "1.10.0"
|
||||||
|
|||||||
@ -19,5 +19,9 @@ serde_json = "1.0"
|
|||||||
static_assertions = "1.1.0"
|
static_assertions = "1.1.0"
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
|
||||||
|
noise = "0.9.0"
|
||||||
|
|
||||||
|
rand = "0.8.5"
|
||||||
|
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use noise::Perlin;
|
||||||
use pumpkin_core::math::vector2::Vector2;
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
use static_assertions::assert_obj_safe;
|
use static_assertions::assert_obj_safe;
|
||||||
|
|
||||||
@ -20,6 +21,17 @@ pub(crate) trait BiomeGenerator: Sync + Send {
|
|||||||
fn generate_biome(&self, at: XZBlockCoordinates) -> Biome;
|
fn generate_biome(&self, at: XZBlockCoordinates) -> Biome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
pub(crate) trait TerrainGenerator: Sync + Send {
|
pub(crate) trait TerrainGenerator: Sync + Send {
|
||||||
|
fn prepare_chunk(&self, at: &Vector2<i32>);
|
||||||
|
|
||||||
|
/// Is static
|
||||||
fn generate_block(&self, at: BlockCoordinates, biome: Biome) -> BlockId;
|
fn generate_block(&self, at: BlockCoordinates, biome: Biome) -> BlockId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) trait PerlinTerrainGenerator: Sync + Send {
|
||||||
|
fn prepare_chunk(&self, at: &Vector2<i32>, perlin: &Perlin);
|
||||||
|
|
||||||
|
/// Dependens on the perlin noise height
|
||||||
|
fn generate_block(&self, at: BlockCoordinates, chunk_height: i16, biome: Biome) -> BlockId;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,36 +1,89 @@
|
|||||||
|
use noise::{NoiseFn, Perlin};
|
||||||
use pumpkin_core::math::vector2::Vector2;
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
chunk::{ChunkBlocks, ChunkData},
|
chunk::{ChunkBlocks, ChunkData},
|
||||||
coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates},
|
coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates},
|
||||||
WORLD_LOWEST_Y, WORLD_MAX_Y,
|
WORLD_LOWEST_Y,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
generator::{BiomeGenerator, GeneratorInit, TerrainGenerator, WorldGenerator},
|
generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator, WorldGenerator},
|
||||||
Seed,
|
Seed,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct GenericGenerator<B: BiomeGenerator, T: TerrainGenerator> {
|
pub struct GenericGenerator<B: BiomeGenerator, T: PerlinTerrainGenerator> {
|
||||||
biome_generator: B,
|
biome_generator: B,
|
||||||
terrain_generator: T,
|
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: TerrainGenerator + GeneratorInit> GeneratorInit
|
impl<B: BiomeGenerator + GeneratorInit, T: PerlinTerrainGenerator + GeneratorInit> GeneratorInit
|
||||||
for GenericGenerator<B, T>
|
for GenericGenerator<B, T>
|
||||||
{
|
{
|
||||||
fn new(seed: Seed) -> Self {
|
fn new(seed: Seed) -> Self {
|
||||||
Self {
|
Self {
|
||||||
biome_generator: B::new(seed),
|
biome_generator: B::new(seed),
|
||||||
terrain_generator: T::new(seed),
|
terrain_generator: T::new(seed),
|
||||||
|
perlin: Perlin::new(seed.0 as u32),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator<B, T> {
|
impl<B: BiomeGenerator, T: PerlinTerrainGenerator> WorldGenerator for GenericGenerator<B, T> {
|
||||||
fn generate_chunk(&self, at: Vector2<i32>) -> ChunkData {
|
fn generate_chunk(&self, at: Vector2<i32>) -> ChunkData {
|
||||||
let mut blocks = ChunkBlocks::default();
|
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 * 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,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 x in 0..16u8 {
|
||||||
for z in 0..16u8 {
|
for z in 0..16u8 {
|
||||||
let biome = self.biome_generator.generate_biome(
|
let biome = self.biome_generator.generate_biome(
|
||||||
@ -63,4 +116,4 @@ impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator
|
|||||||
position: at,
|
position: at,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
|
pub mod overworld;
|
||||||
pub mod superflat;
|
pub mod superflat;
|
||||||
@ -0,0 +1 @@
|
|||||||
|
pub mod plains;
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
use noise::Perlin;
|
||||||
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
biome::Biome,
|
||||||
|
block::BlockId,
|
||||||
|
coordinates::{BlockCoordinates, XZBlockCoordinates},
|
||||||
|
world_gen::{
|
||||||
|
generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator},
|
||||||
|
generic_generator::GenericGenerator,
|
||||||
|
Seed,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type PlainsGenerator = GenericGenerator<PlainsBiomeGenerator, PlainsTerrainGenerator>;
|
||||||
|
|
||||||
|
pub(crate) struct PlainsBiomeGenerator {}
|
||||||
|
|
||||||
|
impl GeneratorInit for PlainsBiomeGenerator {
|
||||||
|
fn new(_: Seed) -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BiomeGenerator for PlainsBiomeGenerator {
|
||||||
|
// TODO make generic over Biome and allow changing the Biome in the config.
|
||||||
|
fn generate_biome(&self, _: XZBlockCoordinates) -> Biome {
|
||||||
|
Biome::Plains
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct PlainsTerrainGenerator {}
|
||||||
|
|
||||||
|
impl GeneratorInit for PlainsTerrainGenerator {
|
||||||
|
fn new(_: Seed) -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PerlinTerrainGenerator for PlainsTerrainGenerator {
|
||||||
|
fn prepare_chunk(&self, _at: &Vector2<i32>, _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) -> BlockId {
|
||||||
|
let begin_stone_height = chunk_height - 5;
|
||||||
|
let begin_dirt_height = chunk_height - 1;
|
||||||
|
|
||||||
|
let y = *at.y;
|
||||||
|
if y == -64 {
|
||||||
|
BlockId::from_id(79) // BEDROCK
|
||||||
|
} else if y >= -63 && y <= begin_stone_height {
|
||||||
|
return BlockId::from_id(1); // STONE
|
||||||
|
} else if y >= begin_stone_height && y < begin_dirt_height {
|
||||||
|
return BlockId::from_id(10); // DIRT;
|
||||||
|
} else if y == chunk_height - 1 {
|
||||||
|
return BlockId::from_id(9); // GRASS BLOCK
|
||||||
|
} else {
|
||||||
|
BlockId::AIR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
pub mod biome;
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
use pumpkin_core::math::vector2::Vector2;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
biome::Biome,
|
biome::Biome,
|
||||||
block::BlockId,
|
block::BlockId,
|
||||||
@ -9,6 +11,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[expect(dead_code)]
|
||||||
pub type SuperflatGenerator = GenericGenerator<SuperflatBiomeGenerator, SuperflatTerrainGenerator>;
|
pub type SuperflatGenerator = GenericGenerator<SuperflatBiomeGenerator, SuperflatTerrainGenerator>;
|
||||||
|
|
||||||
pub(crate) struct SuperflatBiomeGenerator {}
|
pub(crate) struct SuperflatBiomeGenerator {}
|
||||||
@ -35,6 +38,7 @@ impl GeneratorInit for SuperflatTerrainGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TerrainGenerator for SuperflatTerrainGenerator {
|
impl TerrainGenerator for SuperflatTerrainGenerator {
|
||||||
|
fn prepare_chunk(&self, _at: &Vector2<i32>) {}
|
||||||
// TODO allow specifying which blocks should be at which height in the config.
|
// TODO allow specifying which blocks should be at which height in the config.
|
||||||
fn generate_block(&self, at: BlockCoordinates, _: Biome) -> BlockId {
|
fn generate_block(&self, at: BlockCoordinates, _: Biome) -> BlockId {
|
||||||
match *at.y {
|
match *at.y {
|
||||||
@ -1,15 +1,15 @@
|
|||||||
mod generator;
|
mod generator;
|
||||||
mod generic_generator;
|
mod generic_generator;
|
||||||
mod implementations;
|
mod implementation;
|
||||||
mod seed;
|
mod seed;
|
||||||
|
|
||||||
pub use generator::WorldGenerator;
|
pub use generator::WorldGenerator;
|
||||||
|
use implementation::overworld::biome::plains::PlainsGenerator;
|
||||||
pub use seed::Seed;
|
pub use seed::Seed;
|
||||||
|
|
||||||
use generator::GeneratorInit;
|
use generator::GeneratorInit;
|
||||||
use implementations::superflat::SuperflatGenerator;
|
|
||||||
|
|
||||||
pub fn get_world_gen(seed: Seed) -> Box<dyn WorldGenerator> {
|
pub fn get_world_gen(seed: Seed) -> Box<dyn WorldGenerator> {
|
||||||
// TODO decide which WorldGenerator to pick based on config.
|
// TODO decide which WorldGenerator to pick based on config.
|
||||||
Box::new(SuperflatGenerator::new(seed))
|
Box::new(PlainsGenerator::new(seed))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use std::hash::{DefaultHasher, Hash, Hasher};
|
use std::hash::{DefaultHasher, Hash, Hasher};
|
||||||
|
|
||||||
#[expect(dead_code)]
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Seed(pub i64);
|
pub struct Seed(pub i64);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user