mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
Add Experimental Plains biome
Also add Perlin noise
This commit is contained in:
22
Cargo.lock
generated
22
Cargo.lock
generated
@@ -1543,6 +1543,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
@@ -1977,9 +1988,11 @@ dependencies = [
|
||||
"futures",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"noise",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"pumpkin-core",
|
||||
"rand",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2075,6 +2088,15 @@ dependencies = [
|
||||
"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]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
|
||||
@@ -19,5 +19,9 @@ serde_json = "1.0"
|
||||
static_assertions = "1.1.0"
|
||||
log.workspace = true
|
||||
|
||||
noise = "0.9.0"
|
||||
|
||||
rand = "0.8.5"
|
||||
|
||||
num-traits = "0.2"
|
||||
num-derive = "0.4"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use noise::Perlin;
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
use static_assertions::assert_obj_safe;
|
||||
|
||||
@@ -20,6 +21,17 @@ pub(crate) trait BiomeGenerator: Sync + Send {
|
||||
fn generate_biome(&self, at: XZBlockCoordinates) -> Biome;
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub(crate) trait TerrainGenerator: Sync + Send {
|
||||
fn prepare_chunk(&self, at: &Vector2<i32>);
|
||||
|
||||
/// Is static
|
||||
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,35 +1,46 @@
|
||||
use noise::{NoiseFn, Perlin};
|
||||
use pumpkin_core::math::vector2::Vector2;
|
||||
|
||||
use crate::{
|
||||
chunk::{ChunkBlocks, ChunkData},
|
||||
coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates},
|
||||
WORLD_LOWEST_Y, WORLD_MAX_Y,
|
||||
WORLD_LOWEST_Y,
|
||||
};
|
||||
|
||||
use super::{
|
||||
generator::{BiomeGenerator, GeneratorInit, TerrainGenerator, WorldGenerator},
|
||||
generator::{BiomeGenerator, GeneratorInit, PerlinTerrainGenerator, WorldGenerator},
|
||||
Seed,
|
||||
};
|
||||
|
||||
pub struct GenericGenerator<B: BiomeGenerator, T: TerrainGenerator> {
|
||||
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: TerrainGenerator + GeneratorInit> GeneratorInit
|
||||
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: TerrainGenerator> WorldGenerator for GenericGenerator<B, T> {
|
||||
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 * height_variation + base_height) as i32;
|
||||
|
||||
for x in 0..16u8 {
|
||||
for z in 0..16u8 {
|
||||
@@ -42,7 +53,7 @@ impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator
|
||||
);
|
||||
|
||||
// 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() {
|
||||
for y in (WORLD_LOWEST_Y..chunk_height as i16).rev() {
|
||||
let coordinates = ChunkRelativeBlockCoordinates {
|
||||
x: x.into(),
|
||||
y: y.into(),
|
||||
@@ -51,8 +62,11 @@ impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator
|
||||
|
||||
blocks.set_block(
|
||||
coordinates,
|
||||
self.terrain_generator
|
||||
.generate_block(coordinates.with_chunk_coordinates(at), biome),
|
||||
self.terrain_generator.generate_block(
|
||||
coordinates.with_chunk_coordinates(at),
|
||||
chunk_height as i16,
|
||||
biome,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -64,3 +78,42 @@ impl<B: BiomeGenerator, T: TerrainGenerator> WorldGenerator for GenericGenerator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
pub mod overworld;
|
||||
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::{
|
||||
biome::Biome,
|
||||
block::BlockId,
|
||||
@@ -9,6 +11,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub type SuperflatGenerator = GenericGenerator<SuperflatBiomeGenerator, SuperflatTerrainGenerator>;
|
||||
|
||||
pub(crate) struct SuperflatBiomeGenerator {}
|
||||
@@ -35,6 +38,7 @@ impl GeneratorInit 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.
|
||||
fn generate_block(&self, at: BlockCoordinates, _: Biome) -> BlockId {
|
||||
match *at.y {
|
||||
@@ -1,15 +1,15 @@
|
||||
mod generator;
|
||||
mod generic_generator;
|
||||
mod implementations;
|
||||
mod implementation;
|
||||
mod seed;
|
||||
|
||||
pub use generator::WorldGenerator;
|
||||
use implementation::overworld::biome::plains::PlainsGenerator;
|
||||
pub use seed::Seed;
|
||||
|
||||
use generator::GeneratorInit;
|
||||
use implementations::superflat::SuperflatGenerator;
|
||||
|
||||
pub fn get_world_gen(seed: Seed) -> Box<dyn WorldGenerator> {
|
||||
// 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};
|
||||
|
||||
#[expect(dead_code)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Seed(pub i64);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user