mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-31 08:22:33 +00:00
rebase master
This commit is contained in:
@@ -2,6 +2,7 @@ pub mod boundingbox;
|
||||
pub mod position;
|
||||
pub mod vector2;
|
||||
pub mod vector3;
|
||||
pub mod voxel_shape;
|
||||
|
||||
pub fn wrap_degrees(var: f32) -> f32 {
|
||||
let mut var1 = var % 360.0;
|
||||
|
||||
9
pumpkin-core/src/math/voxel_shape.rs
Normal file
9
pumpkin-core/src/math/voxel_shape.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
pub struct VoxelShape {
|
||||
// TODO
|
||||
}
|
||||
|
||||
impl VoxelShape {
|
||||
pub fn is_empty() -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// TODO make this work with the protocol
|
||||
@@ -9,3 +10,26 @@ pub enum Biome {
|
||||
SnowyTiga,
|
||||
// TODO list all Biomes
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[enum_dispatch(BiomeSupplierImpl)]
|
||||
pub enum BiomeSupplier {
|
||||
Debug(DebugBiomeSupplier),
|
||||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait BiomeSupplierImpl {
|
||||
fn biome(&self, x: i32, y: i32, z: i32, noise: &MultiNoiseSampler) -> Biome;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DebugBiomeSupplier {}
|
||||
|
||||
impl BiomeSupplierImpl for DebugBiomeSupplier {
|
||||
fn biome(&self, _x: i32, _y: i32, _z: i32, _noise: &MultiNoiseSampler) -> Biome {
|
||||
Biome::Plains
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement
|
||||
pub struct MultiNoiseSampler {}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<<<<<<< HEAD
|
||||
use std::collections::HashMap;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -5,7 +5,6 @@ pub mod coordinates;
|
||||
pub mod cylindrical_chunk_iterator;
|
||||
pub mod dimension;
|
||||
pub mod global_registry;
|
||||
mod height;
|
||||
pub mod item;
|
||||
pub mod level;
|
||||
mod world_gen;
|
||||
|
||||
@@ -1,391 +0,0 @@
|
||||
use crate::{
|
||||
self as pumpkin_world,
|
||||
biome::Biome,
|
||||
block::BlockId,
|
||||
height::{HeightLimitView, HeightLimitViewImpl, StandardHeightLimitView},
|
||||
world_gen::{
|
||||
chunk::{BlockPos, Chunk, GenerationState, HeightMapType},
|
||||
Direction,
|
||||
},
|
||||
};
|
||||
use num_traits::PrimInt;
|
||||
use pumpkin_macros::block_id;
|
||||
|
||||
pub const SURFACE_BLOCKS: [BlockId; 11] = [
|
||||
block_id!("minecraft:podzol"),
|
||||
block_id!("minecraft:gravel"),
|
||||
block_id!("minecraft:grass_block"),
|
||||
block_id!("minecraft:stone"),
|
||||
block_id!("minecraft:coarse_dirt"),
|
||||
block_id!("minecraft:sand"),
|
||||
block_id!("minecraft:red_sand"),
|
||||
block_id!("minecraft:mycelium"),
|
||||
block_id!("minecraft:snow_block"),
|
||||
block_id!("minecraft:terracotta"),
|
||||
block_id!("minecraft:dirt"),
|
||||
];
|
||||
|
||||
const BIOMES_PER_CHUNK: usize = 16 >> 2;
|
||||
const LAST_CHUNK_BIOME_INDEX: usize = BIOMES_PER_CHUNK - 1;
|
||||
const CHUNK_BIOME_END_INDEX: usize = BIOMES_PER_CHUNK;
|
||||
const NORTH_WEST_END_INDEX: usize = 2 * LAST_CHUNK_BIOME_INDEX + 1;
|
||||
const SOUTH_EAST_END_INDEX_PART: usize = 2 * CHUNK_BIOME_END_INDEX + 1;
|
||||
const HORIZONTAL_BIOME_COUNT: usize = NORTH_WEST_END_INDEX + SOUTH_EAST_END_INDEX_PART;
|
||||
|
||||
pub struct BlendingData {
|
||||
pub(crate) height_limit: HeightLimitView,
|
||||
pub(crate) surface_heights: Box<[f64; HORIZONTAL_BIOME_COUNT]>,
|
||||
pub(crate) biomes: Box<[Option<Vec<Biome>>; HORIZONTAL_BIOME_COUNT]>,
|
||||
pub(crate) collidable_block_densities: Box<[Option<Vec<f64>>; HORIZONTAL_BIOME_COUNT]>,
|
||||
initialized: bool,
|
||||
}
|
||||
|
||||
impl BlendingData {
|
||||
pub fn get_blending_data(chunk: &Chunk, _chunk_x: i32, _chunk_z: i32) -> Option<Self> {
|
||||
// TODO: We currently assume all chunks have new noise. valid assumption?
|
||||
if let Some(mut data) = chunk.blending_data() {
|
||||
if chunk.status() >= GenerationState::Biome {
|
||||
data.init_chunk_blending_data(
|
||||
chunk,
|
||||
&[
|
||||
Direction::North,
|
||||
Direction::NorthWest,
|
||||
Direction::West,
|
||||
Direction::SouthWest,
|
||||
Direction::South,
|
||||
Direction::SouthEast,
|
||||
Direction::East,
|
||||
Direction::NorthEast,
|
||||
],
|
||||
);
|
||||
Some(data)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn method_39355(i: usize) -> usize {
|
||||
i & !(i.unsigned_shr(31))
|
||||
}
|
||||
|
||||
pub(crate) fn x(index: usize) -> usize {
|
||||
if index < NORTH_WEST_END_INDEX {
|
||||
Self::method_39355(LAST_CHUNK_BIOME_INDEX - index)
|
||||
} else {
|
||||
let i = index - NORTH_WEST_END_INDEX;
|
||||
CHUNK_BIOME_END_INDEX - Self::method_39355(CHUNK_BIOME_END_INDEX - i)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn z(index: usize) -> usize {
|
||||
if index < NORTH_WEST_END_INDEX {
|
||||
Self::method_39355(index - LAST_CHUNK_BIOME_INDEX)
|
||||
} else {
|
||||
let i = index - NORTH_WEST_END_INDEX;
|
||||
CHUNK_BIOME_END_INDEX - Self::method_39355(i - CHUNK_BIOME_END_INDEX)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn height(&self, biome_x: usize, _biome_y: usize, biome_z: usize) -> f64 {
|
||||
if biome_x == CHUNK_BIOME_END_INDEX || biome_z == CHUNK_BIOME_END_INDEX {
|
||||
self.surface_heights[Self::south_east_index(biome_x, biome_z)]
|
||||
} else if biome_x != 0 && biome_z != 0 {
|
||||
f64::MAX
|
||||
} else {
|
||||
self.surface_heights[Self::north_west_index(biome_x, biome_z)]
|
||||
}
|
||||
}
|
||||
|
||||
fn collidable_block_density_from_column(
|
||||
&self,
|
||||
column: Option<&[f64]>,
|
||||
half_section_y: i32,
|
||||
) -> f64 {
|
||||
if let Some(column) = column {
|
||||
let i = self.half_section_height(half_section_y);
|
||||
if (i >= 0) && ((i as usize) < column.len()) {
|
||||
column[i as usize] * 0.1f64
|
||||
} else {
|
||||
f64::MAX
|
||||
}
|
||||
} else {
|
||||
f64::MAX
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collidable_block_density(
|
||||
&self,
|
||||
biome_x: usize,
|
||||
half_section_y: i32,
|
||||
biome_z: usize,
|
||||
) -> f64 {
|
||||
if half_section_y == self.bottom_half_section_y() {
|
||||
0.1f64
|
||||
} else if biome_x == CHUNK_BIOME_END_INDEX || biome_z == CHUNK_BIOME_END_INDEX {
|
||||
self.collidable_block_density_from_column(
|
||||
self.collidable_block_densities[Self::south_east_index(biome_x, biome_z)]
|
||||
.as_deref(),
|
||||
half_section_y,
|
||||
)
|
||||
} else if biome_x != 0 && biome_z != 0 {
|
||||
f64::MAX
|
||||
} else {
|
||||
self.collidable_block_density_from_column(
|
||||
self.collidable_block_densities[Self::north_west_index(biome_x, biome_z)]
|
||||
.as_deref(),
|
||||
half_section_y,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn new(bottom_section_y: i32, top_section_y: i32, heights: Option<&[f64]>) -> Self {
|
||||
let heights = match heights {
|
||||
Some(heights) => {
|
||||
let mut owned_heights = [0f64; HORIZONTAL_BIOME_COUNT];
|
||||
assert!(
|
||||
heights.len() == HORIZONTAL_BIOME_COUNT,
|
||||
"Heights needs to be the right length"
|
||||
);
|
||||
owned_heights
|
||||
.iter_mut()
|
||||
.zip(heights)
|
||||
.for_each(|(new, old)| {
|
||||
*new = *old;
|
||||
});
|
||||
owned_heights
|
||||
}
|
||||
None => [f64::MAX; HORIZONTAL_BIOME_COUNT],
|
||||
};
|
||||
|
||||
let collidable_block_densities: [Option<Vec<f64>>; HORIZONTAL_BIOME_COUNT] =
|
||||
[const { None }; HORIZONTAL_BIOME_COUNT];
|
||||
let biomes: [Option<Vec<Biome>>; HORIZONTAL_BIOME_COUNT] =
|
||||
[const { None }; HORIZONTAL_BIOME_COUNT];
|
||||
|
||||
let i = bottom_section_y << 4;
|
||||
let j = (top_section_y << 4) - i;
|
||||
let height_limit = HeightLimitView::Standard(StandardHeightLimitView::new(i, j));
|
||||
|
||||
Self {
|
||||
height_limit,
|
||||
surface_heights: Box::new(heights.clone()),
|
||||
biomes: Box::new(biomes),
|
||||
collidable_block_densities: Box::new(collidable_block_densities),
|
||||
initialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vertical_half_section_count(&self) -> i32 {
|
||||
self.height_limit.vertical_section_count() * 2
|
||||
}
|
||||
|
||||
fn collidable_and_not_tree(chunk: &Chunk, pos: &BlockPos) -> bool {
|
||||
let state = chunk.get_block_state(pos);
|
||||
if state.is_air()
|
||||
|| state.has_tag("leaves")
|
||||
|| state.has_tag("logs")
|
||||
|| state.is_block(block_id!("minecraft:brown_mushroom_block"))
|
||||
|| state.is_block(block_id!("minecraft:red_mushroom_block"))
|
||||
{
|
||||
false
|
||||
} else {
|
||||
state.collision_shape(chunk, pos).is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
fn above_collidable_block_value(chunk: &Chunk, pos: &BlockPos) -> (f64, BlockPos) {
|
||||
let pos = pos.down();
|
||||
let val = if Self::collidable_and_not_tree(chunk, &pos) {
|
||||
1f64
|
||||
} else {
|
||||
-1f64
|
||||
};
|
||||
(val, pos)
|
||||
}
|
||||
|
||||
fn north_west_index(biome_x: usize, biome_z: usize) -> usize {
|
||||
LAST_CHUNK_BIOME_INDEX + biome_x + biome_z
|
||||
}
|
||||
|
||||
fn south_east_index(biome_x: usize, biome_z: usize) -> usize {
|
||||
NORTH_WEST_END_INDEX + biome_x + CHUNK_BIOME_END_INDEX - biome_z
|
||||
}
|
||||
|
||||
fn init_chunk_blending_data(&mut self, chunk: &Chunk, directions: &[Direction]) {
|
||||
if !self.initialized {
|
||||
if directions.contains(&Direction::North)
|
||||
|| directions.contains(&Direction::West)
|
||||
|| directions.contains(&Direction::NorthWest)
|
||||
{
|
||||
self.init_block_column(Self::north_west_index(0, 0), chunk, 0, 0);
|
||||
}
|
||||
|
||||
if directions.contains(&Direction::North) {
|
||||
for i in 1..BIOMES_PER_CHUNK {
|
||||
self.init_block_column(Self::north_west_index(i, 0), chunk, (4 * i) as i32, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if directions.contains(&Direction::West) {
|
||||
for i in 1..BIOMES_PER_CHUNK {
|
||||
self.init_block_column(Self::north_west_index(0, i), chunk, 0, (4 * i) as i32);
|
||||
}
|
||||
}
|
||||
|
||||
if directions.contains(&Direction::East) {
|
||||
for i in 1..BIOMES_PER_CHUNK {
|
||||
self.init_block_column(
|
||||
Self::south_east_index(CHUNK_BIOME_END_INDEX, i),
|
||||
chunk,
|
||||
15,
|
||||
(4 * i) as i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if directions.contains(&Direction::South) {
|
||||
for i in 1..BIOMES_PER_CHUNK {
|
||||
self.init_block_column(
|
||||
Self::south_east_index(i, CHUNK_BIOME_END_INDEX),
|
||||
chunk,
|
||||
(4 * i) as i32,
|
||||
15,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if directions.contains(&Direction::East) && directions.contains(&Direction::NorthEast) {
|
||||
self.init_block_column(
|
||||
Self::south_east_index(CHUNK_BIOME_END_INDEX, 0),
|
||||
chunk,
|
||||
15,
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
if directions.contains(&Direction::East)
|
||||
&& directions.contains(&Direction::South)
|
||||
&& directions.contains(&Direction::SouthEast)
|
||||
{
|
||||
self.init_block_column(
|
||||
Self::south_east_index(CHUNK_BIOME_END_INDEX, CHUNK_BIOME_END_INDEX),
|
||||
chunk,
|
||||
15,
|
||||
15,
|
||||
);
|
||||
}
|
||||
|
||||
self.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn collidable_block_density_below(chunk: &Chunk, pos: &BlockPos) -> (f64, BlockPos) {
|
||||
let (val, new_pos) = Self::above_collidable_block_value(chunk, &pos);
|
||||
let mut d = val;
|
||||
let mut pos = new_pos;
|
||||
|
||||
for _ in 0..6 {
|
||||
let (val, new_pos) = Self::above_collidable_block_value(chunk, &pos);
|
||||
d += val;
|
||||
pos = new_pos;
|
||||
}
|
||||
|
||||
(d, pos)
|
||||
}
|
||||
|
||||
pub fn bottom_half_section_y(&self) -> i32 {
|
||||
self.height_limit.bottom_section_coord() * 2
|
||||
}
|
||||
|
||||
fn half_section_height(&self, section_y: i32) -> i32 {
|
||||
section_y - (self.bottom_half_section_y() + 1)
|
||||
}
|
||||
|
||||
fn init_block_column(&mut self, index: usize, chunk: &Chunk, chunk_x: i32, chunk_z: i32) {
|
||||
if self.surface_heights[index] == f64::MAX {
|
||||
self.surface_heights[index] = self.surface_block_y(chunk, chunk_x, chunk_z) as f64;
|
||||
}
|
||||
self.collidable_block_densities[index] = Some(self.collidable_block_density_column(
|
||||
chunk,
|
||||
chunk_x,
|
||||
chunk_z,
|
||||
self.surface_heights[index].floor() as i32,
|
||||
));
|
||||
self.biomes[index] = Some(self.vertical_biome_sections(chunk, chunk_x, chunk_z));
|
||||
}
|
||||
|
||||
fn vertical_biome_sections(&self, chunk: &Chunk, block_x: i32, block_z: i32) -> Vec<Biome> {
|
||||
(0..self.vertical_biome_count())
|
||||
.map(|i| {
|
||||
let j = i + (self.height_limit.bottom_y() >> 2);
|
||||
chunk.biome_for_noise_gen(block_x >> 2, j, block_z >> 2)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn vertical_biome_count(&self) -> i32 {
|
||||
self.height_limit.vertical_section_count() << 2
|
||||
}
|
||||
|
||||
fn collidable_block_density_column(
|
||||
&self,
|
||||
chunk: &Chunk,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
height: i32,
|
||||
) -> Vec<f64> {
|
||||
let mut ds: Vec<f64> = (0..self.vertical_half_section_count())
|
||||
.map(|_| -1f64)
|
||||
.collect();
|
||||
|
||||
let pos = BlockPos::new(chunk_x, self.height_limit.top_y(), chunk_z);
|
||||
let (mut d, mut pos) = Self::collidable_block_density_below(chunk, &pos);
|
||||
|
||||
for i in (0..=(ds.len() - 2)).rev() {
|
||||
let (e, local_pos) = Self::above_collidable_block_value(chunk, &pos);
|
||||
let (f, local_pos) = Self::collidable_block_density_below(chunk, &local_pos);
|
||||
ds[i] = (d + e + f) / 15f64;
|
||||
d = f;
|
||||
pos = local_pos;
|
||||
}
|
||||
|
||||
let i = self.half_section_height(height / 8);
|
||||
if i >= 0 && (i as usize) < (ds.len() - 1) {
|
||||
let e = (height as f64 + 0.5f64) % 8f64 / 8f64;
|
||||
let f = (1f64 - e) / e;
|
||||
let g = f.max(1f64) * 0.25f64;
|
||||
ds[(i + 1) as usize] = -f / g;
|
||||
ds[i as usize] = 1f64 / g;
|
||||
}
|
||||
|
||||
ds
|
||||
}
|
||||
|
||||
fn surface_block_y(&self, chunk: &Chunk, block_x: i32, block_z: i32) -> i32 {
|
||||
let i = if let Some(value) =
|
||||
chunk.sample_height_map(HeightMapType::WorldGenSurface, block_x, block_z)
|
||||
{
|
||||
value
|
||||
} else {
|
||||
self.height_limit.top_y()
|
||||
};
|
||||
|
||||
let j = self.height_limit.bottom_y();
|
||||
|
||||
for height in (j..=i).rev() {
|
||||
if SURFACE_BLOCKS.contains(
|
||||
&chunk
|
||||
.get_block_state(&BlockPos::new(block_x, height, block_z))
|
||||
.block(),
|
||||
) {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
j
|
||||
}
|
||||
}
|
||||
@@ -1,351 +1,11 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, LazyLock},
|
||||
};
|
||||
use super::noise::density::NoisePos;
|
||||
|
||||
use data::BlendingData;
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use pumpkin_core::{
|
||||
math::{hypot, magnitude},
|
||||
random::{xoroshiro128::Xoroshiro, RandomGenerator, RandomImpl},
|
||||
};
|
||||
|
||||
use crate::{biome::Biome, height::HeightLimitViewImpl};
|
||||
|
||||
use super::{
|
||||
biome_coords,
|
||||
chunk::{Chunk, ChunkPos},
|
||||
noise::{
|
||||
density::NoisePosImpl,
|
||||
lerp,
|
||||
perlin::{DoublePerlinNoiseParameters, DoublePerlinNoiseSampler},
|
||||
},
|
||||
supplier::{BiomeSupplier, StaticBiomeSupplier},
|
||||
};
|
||||
|
||||
pub mod data;
|
||||
|
||||
static OFFSET_NOISE: LazyLock<DoublePerlinNoiseSampler> = LazyLock::new(|| {
|
||||
DoublePerlinNoiseSampler::new(
|
||||
&mut RandomGenerator::Xoroshiro(Xoroshiro::from_seed(42)),
|
||||
&DoublePerlinNoiseParameters::new(-3, &[1f64; 4]),
|
||||
)
|
||||
});
|
||||
const BLENDING_BIOME_DISTANCE_THRESHOLD: i32 = (7 << 2) - 1;
|
||||
const BLENDING_CHUNK_DISTANCE_THRESHOLD: i32 = (BLENDING_BIOME_DISTANCE_THRESHOLD + 3) >> 2;
|
||||
const CLOSE_BLENDING_DISTANCE_THRESHOLD: i32 = 5 >> 2;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BlendResult {
|
||||
alpha: f64,
|
||||
offset: f64,
|
||||
pub struct Blender {
|
||||
// TODO
|
||||
}
|
||||
|
||||
impl BlendResult {
|
||||
pub fn new(alpha: f64, offset: f64) -> Self {
|
||||
Self { alpha, offset }
|
||||
}
|
||||
|
||||
pub fn alpha(&self) -> f64 {
|
||||
self.alpha
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> f64 {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_dispatch(BlenderImpl)]
|
||||
#[derive(Clone)]
|
||||
pub enum Blender {
|
||||
None(NoBlendBlender),
|
||||
Standard(StandardBlender),
|
||||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait BlenderImpl {
|
||||
fn apply_blend_density(&self, pos: &impl NoisePosImpl, density: f64) -> f64;
|
||||
fn calculate(&self, block_x: i32, block_z: i32) -> BlendResult;
|
||||
fn biome_supplier(&self, supplier: &BiomeSupplier) -> BiomeSupplier;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NoBlendBlender {}
|
||||
impl BlenderImpl for NoBlendBlender {
|
||||
fn calculate(&self, _block_x: i32, _block_z: i32) -> BlendResult {
|
||||
BlendResult {
|
||||
alpha: 1f64,
|
||||
offset: 0f64,
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_blend_density(&self, _pos: &impl NoisePosImpl, density: f64) -> f64 {
|
||||
density
|
||||
}
|
||||
|
||||
fn biome_supplier(&self, supplier: &BiomeSupplier) -> BiomeSupplier {
|
||||
supplier.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct StandardBlender {
|
||||
blend_data: Arc<HashMap<u64, BlendingData>>,
|
||||
close_blend_data: Arc<HashMap<u64, BlendingData>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum BlendingSampleType {
|
||||
Height,
|
||||
Density,
|
||||
}
|
||||
|
||||
impl StandardBlender {
|
||||
fn new(
|
||||
blend_data: HashMap<u64, BlendingData>,
|
||||
close_blend_data: HashMap<u64, BlendingData>,
|
||||
) -> Self {
|
||||
Self {
|
||||
blend_data: Arc::new(blend_data),
|
||||
close_blend_data: Arc::new(close_blend_data),
|
||||
}
|
||||
}
|
||||
|
||||
fn blend_offset(height: f64) -> f64 {
|
||||
let e = height + 0.5f64;
|
||||
let f = ((e % 8f64) + 8f64) % 8f64;
|
||||
(32f64 * (e - 128f64) - 3f64 * (e - 128f64) * f + 3f64 * f * f)
|
||||
/ (128f64 * (32f64 - 3f64 * f))
|
||||
}
|
||||
|
||||
fn sample_closest(
|
||||
&self,
|
||||
sample_type: BlendingSampleType,
|
||||
biome_x: i32,
|
||||
biome_y: i32,
|
||||
biome_z: i32,
|
||||
) -> f64 {
|
||||
let i = biome_coords::to_chunk(biome_x);
|
||||
let j = biome_coords::to_chunk(biome_z);
|
||||
|
||||
let bl = (biome_x & 3) == 0;
|
||||
let bl2 = (biome_z & 3) == 0;
|
||||
|
||||
let mut d = self.sample(sample_type.clone(), i, j, biome_x, biome_y, biome_z);
|
||||
|
||||
if d == f64::MAX {
|
||||
if bl && bl2 {
|
||||
d = self.sample(sample_type.clone(), i - 1, j - 1, biome_x, biome_y, biome_z);
|
||||
}
|
||||
|
||||
if d == f64::MAX && bl {
|
||||
d = self.sample(sample_type.clone(), i - 1, j, biome_x, biome_y, biome_z);
|
||||
}
|
||||
|
||||
if d == f64::MAX && bl2 {
|
||||
d = self.sample(sample_type.clone(), i, j - 1, biome_x, biome_y, biome_z);
|
||||
}
|
||||
}
|
||||
|
||||
d
|
||||
}
|
||||
|
||||
fn sample(
|
||||
&self,
|
||||
sample_type: BlendingSampleType,
|
||||
chunk_x: i32,
|
||||
chunk_z: i32,
|
||||
biome_x: i32,
|
||||
biome_y: i32,
|
||||
biome_z: i32,
|
||||
) -> f64 {
|
||||
if let Some(blending_data) = self
|
||||
.blend_data
|
||||
.get(&ChunkPos::new(chunk_x, chunk_z).to_long())
|
||||
{
|
||||
match sample_type {
|
||||
BlendingSampleType::Height => blending_data.height(
|
||||
(biome_x - biome_coords::from_chunk(chunk_x)) as usize,
|
||||
biome_y as usize,
|
||||
(biome_z - biome_coords::from_chunk(chunk_z)) as usize,
|
||||
),
|
||||
BlendingSampleType::Density => blending_data.collidable_block_density(
|
||||
(biome_x - biome_coords::from_chunk(chunk_x)) as usize,
|
||||
biome_y,
|
||||
(biome_z - biome_coords::from_chunk(chunk_z)) as usize,
|
||||
),
|
||||
}
|
||||
} else {
|
||||
f64::MAX
|
||||
}
|
||||
}
|
||||
|
||||
fn blend_biome(&self, x: i32, y: i32, z: i32) -> Option<Biome> {
|
||||
for (k, v) in self.blend_data.iter() {
|
||||
let biome_x = biome_coords::from_chunk(ChunkPos::packed_x(*k));
|
||||
let biome_z = biome_coords::from_chunk(ChunkPos::packed_z(*k));
|
||||
|
||||
if y >= biome_coords::from_block(v.height_limit.bottom_y())
|
||||
&& y < biome_coords::from_block(v.height_limit.top_y())
|
||||
{
|
||||
let mut val = f64::INFINITY;
|
||||
let mut biome: Option<Biome> = None;
|
||||
|
||||
let i = biome_coords::from_block(v.height_limit.bottom_y());
|
||||
|
||||
for (j, biome_list) in v.biomes.iter().enumerate() {
|
||||
if let Some(biome_list) = biome_list {
|
||||
if let Some(internal_biome) = biome_list.get(i as usize) {
|
||||
let biome_x = biome_x + BlendingData::x(j) as i32;
|
||||
let biome_z = biome_z + BlendingData::z(j) as i32;
|
||||
|
||||
let dx = hypot((x - biome_x) as f64, (z - biome_z) as f64);
|
||||
if dx <= BLENDING_BIOME_DISTANCE_THRESHOLD as f64 && dx < val {
|
||||
val = dx;
|
||||
biome = Some(*internal_biome)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if val < f64::MAX {
|
||||
let d = OFFSET_NOISE.sample(x as f64, 0f64, z as f64) * 12f64;
|
||||
let e = ((val + d) / (BLENDING_BIOME_DISTANCE_THRESHOLD + 1) as f64)
|
||||
.clamp(0f64, 1f64);
|
||||
if e <= 0.5f64 {
|
||||
return Some(biome.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl BlenderImpl for StandardBlender {
|
||||
fn calculate(&self, block_x: i32, block_z: i32) -> BlendResult {
|
||||
let i = biome_coords::from_block(block_x);
|
||||
let j = biome_coords::from_block(block_z);
|
||||
|
||||
let d = self.sample_closest(BlendingSampleType::Height, i, 0, j);
|
||||
if d != f64::MAX {
|
||||
BlendResult {
|
||||
alpha: 0f64,
|
||||
offset: Self::blend_offset(d),
|
||||
}
|
||||
} else {
|
||||
let mut val1 = 0f64;
|
||||
let mut val2 = 0f64;
|
||||
let mut val3 = f64::INFINITY;
|
||||
|
||||
for (chunk_pos, data) in self.blend_data.iter() {
|
||||
let biome_x = biome_coords::from_chunk(ChunkPos::packed_x(*chunk_pos));
|
||||
let biome_z = biome_coords::from_chunk(ChunkPos::packed_z(*chunk_pos));
|
||||
|
||||
for (index, height) in data.surface_heights.iter().enumerate() {
|
||||
if *height != f64::MAX {
|
||||
let biome_x = biome_x + BlendingData::x(index) as i32;
|
||||
let biome_z = biome_z + BlendingData::z(index) as i32;
|
||||
|
||||
let dx = hypot((i - biome_x) as f64, (j - biome_z) as f64);
|
||||
if dx <= BLENDING_BIOME_DISTANCE_THRESHOLD as f64 {
|
||||
if dx < val3 {
|
||||
val3 = dx;
|
||||
}
|
||||
let ex = 1f64 / (dx * dx * dx * dx);
|
||||
val2 += *height * ex;
|
||||
val1 += ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if val3 == f64::INFINITY {
|
||||
BlendResult {
|
||||
alpha: 1f64,
|
||||
offset: 0f64,
|
||||
}
|
||||
} else {
|
||||
let e = val2 / val1;
|
||||
let f = (val3 / (BLENDING_BIOME_DISTANCE_THRESHOLD + 1) as f64).clamp(0f64, 1f64);
|
||||
let f = 3f64 * f * f - 2f64 * f * f * f;
|
||||
BlendResult {
|
||||
alpha: f,
|
||||
offset: Self::blend_offset(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_blend_density(&self, pos: &impl NoisePosImpl, density: f64) -> f64 {
|
||||
let i = biome_coords::from_block(pos.x());
|
||||
let j = pos.y() / 8;
|
||||
let k = biome_coords::from_block(pos.z());
|
||||
|
||||
let d = self.sample_closest(BlendingSampleType::Density, i, j, k);
|
||||
|
||||
if d != f64::MAX {
|
||||
d
|
||||
} else {
|
||||
let mut val1 = 0f64;
|
||||
let mut val2 = 0f64;
|
||||
let mut val3 = f64::INFINITY;
|
||||
|
||||
for (chunk_pos, data) in self.close_blend_data.iter() {
|
||||
let biome_x = biome_coords::from_chunk(ChunkPos::packed_z(*chunk_pos));
|
||||
let biome_y = biome_coords::from_chunk(ChunkPos::packed_z(*chunk_pos));
|
||||
let min_half_section_y = j - 1;
|
||||
let max_half_section_y = j + 1;
|
||||
|
||||
let one_above = data.bottom_half_section_y() + 1;
|
||||
let j = 0.max(min_half_section_y - one_above);
|
||||
let k = data
|
||||
.vertical_half_section_count()
|
||||
.min(max_half_section_y - one_above);
|
||||
|
||||
for (index, density_vec) in data.collidable_block_densities.iter().enumerate() {
|
||||
if let Some(density_vec) = density_vec {
|
||||
let m = biome_x + BlendingData::x(index) as i32;
|
||||
let n = biome_y + BlendingData::z(index) as i32;
|
||||
|
||||
for o in j..k {
|
||||
let biome_x = m;
|
||||
let half_section_y = o + one_above;
|
||||
let biome_z = n;
|
||||
let density = density_vec[o as usize] * 0.1f64;
|
||||
|
||||
let dx = magnitude(
|
||||
(i - biome_x) as f64,
|
||||
((j - half_section_y) * 2) as f64,
|
||||
(k - biome_z) as f64,
|
||||
);
|
||||
|
||||
if dx <= 2f64 {
|
||||
if dx < val3 {
|
||||
val3 = dx;
|
||||
}
|
||||
|
||||
let ex = 1f64 / (dx * dx * dx * dx);
|
||||
val2 += density * ex;
|
||||
val1 += ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if val3 == f64::INFINITY {
|
||||
density
|
||||
} else {
|
||||
let e = val2 / val1;
|
||||
let f = (val3 / 3f64).clamp(0f64, 1f64);
|
||||
lerp(f, e, density)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn biome_supplier(&self, _supplier: &BiomeSupplier) -> BiomeSupplier {
|
||||
BiomeSupplier::Static(StaticBiomeSupplier {})
|
||||
impl Blender {
|
||||
pub fn apply_blend_density(&self, _pos: &NoisePos, _density: f64) -> f64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
use std::{ops::Add, sync::Arc};
|
||||
|
||||
use num_traits::PrimInt;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::{
|
||||
biome::Biome, block::BlockId, chunk::ChunkData, height::HeightLimitViewImpl,
|
||||
world_gen::noise::chunk_sampler::ChunkNoiseSampler,
|
||||
};
|
||||
|
||||
use super::{biome_coords, blender::data::BlendingData, heightmap::HeightMap};
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd)]
|
||||
pub enum GenerationState {
|
||||
Empty,
|
||||
StructureStart,
|
||||
StructureRef,
|
||||
Biome,
|
||||
Noise,
|
||||
Surface,
|
||||
Carver,
|
||||
Feature,
|
||||
InitLight,
|
||||
Light,
|
||||
Spawn,
|
||||
Full,
|
||||
}
|
||||
|
||||
pub struct BlockPos {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
|
||||
impl BlockPos {
|
||||
pub fn new(x: i32, y: i32, z: i32) -> Self {
|
||||
Self { x, y, z }
|
||||
}
|
||||
|
||||
pub fn x(&self) -> i32 {
|
||||
self.x
|
||||
}
|
||||
|
||||
pub fn y(&self) -> i32 {
|
||||
self.y
|
||||
}
|
||||
|
||||
pub fn z(&self) -> i32 {
|
||||
self.z
|
||||
}
|
||||
|
||||
pub fn down(&self) -> Self {
|
||||
self.down_by(1)
|
||||
}
|
||||
|
||||
pub fn down_by(&self, count: i32) -> Self {
|
||||
Self {
|
||||
x: self.x,
|
||||
y: self.y - count,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn up(&self) -> Self {
|
||||
self.up_by(1)
|
||||
}
|
||||
|
||||
pub fn up_by(&self, count: i32) -> Self {
|
||||
Self {
|
||||
x: self.x,
|
||||
y: self.y + count,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn north(&self) -> Self {
|
||||
self.north_by(1)
|
||||
}
|
||||
|
||||
pub fn north_by(&self, count: i32) -> Self {
|
||||
Self {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
z: self.z - count,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn south(&self) -> Self {
|
||||
self.south_by(1)
|
||||
}
|
||||
|
||||
pub fn south_by(&self, count: i32) -> Self {
|
||||
Self {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
z: self.z + count,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn west(&self) -> Self {
|
||||
self.west_by(1)
|
||||
}
|
||||
|
||||
pub fn west_by(&self, count: i32) -> Self {
|
||||
Self {
|
||||
x: self.x - count,
|
||||
y: self.y,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn east(&self) -> Self {
|
||||
self.east_by(1)
|
||||
}
|
||||
|
||||
pub fn east_by(&self, count: i32) -> Self {
|
||||
Self {
|
||||
x: self.x + count,
|
||||
y: self.y,
|
||||
z: self.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for BlockPos {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self {
|
||||
x: self.x + rhs.x,
|
||||
y: self.y + rhs.y,
|
||||
z: self.z + rhs.z,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum HeightMapType {
|
||||
WorldGenSurface,
|
||||
WorldSurface,
|
||||
WorldGenOceanFloor,
|
||||
OceanFloor,
|
||||
MotionBlocking,
|
||||
MotionBlockingNoLeaves,
|
||||
}
|
||||
|
||||
pub struct VoxelShape {}
|
||||
|
||||
impl VoxelShape {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BlockState {}
|
||||
|
||||
impl BlockState {
|
||||
pub fn block(&self) -> BlockId {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn is_air(&self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn has_tag(&self, tag: &str) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn is_block(&self, id: BlockId) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn collision_shape(&self, chunk: &Chunk, pos: &BlockPos) -> VoxelShape {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub const CHUNK_MARKER: u64 = ChunkPos {
|
||||
x: 1875066,
|
||||
z: 1875066,
|
||||
}
|
||||
.to_long();
|
||||
|
||||
pub struct ChunkPos {
|
||||
x: i32,
|
||||
z: i32,
|
||||
}
|
||||
|
||||
impl ChunkPos {
|
||||
pub const fn new(x: i32, z: i32) -> Self {
|
||||
Self { x, z }
|
||||
}
|
||||
|
||||
pub const fn to_long(&self) -> u64 {
|
||||
(self.x as u64 & 4294967295u64) | ((self.z as u64 & 4294967295u64) << 32)
|
||||
}
|
||||
|
||||
pub fn packed_x(pos: u64) -> i32 {
|
||||
(pos & 4294967295u64) as i32
|
||||
}
|
||||
|
||||
pub fn packed_z(pos: u64) -> i32 {
|
||||
(pos.unsigned_shr(32) & 4294967295u64) as i32
|
||||
}
|
||||
|
||||
pub fn get_start_x(&self) -> i32 {
|
||||
self.x << 4
|
||||
}
|
||||
|
||||
pub fn get_start_z(&self) -> i32 {
|
||||
self.z << 4
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Chunk {
|
||||
pos: ChunkPos,
|
||||
data: ChunkData,
|
||||
state: GenerationState,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
pub fn get_block_state(&self, pos: &BlockPos) -> BlockState {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn sample_height_map(&self, map: HeightMapType, x: i32, y: i32) -> Option<i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn biome_for_noise_gen(&self, biome_x: i32, biome_y: i32, biome_z: i32) -> Biome {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn blending_data(&self) -> Option<BlendingData> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn status(&self) -> GenerationState {
|
||||
self.state.clone()
|
||||
}
|
||||
|
||||
pub fn get_or_create_noise_sampler(&self) -> Arc<Mutex<ChunkNoiseSampler>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn get_height_map(&self, map: HeightMapType) -> &HeightMap {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn pos(&self) -> &ChunkPos {
|
||||
&self.pos
|
||||
}
|
||||
}
|
||||
|
||||
impl HeightLimitViewImpl for Chunk {
|
||||
fn bottom_y(&self) -> i32 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn height(&self) -> i32 {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GenerationShapeConfig {
|
||||
y_min: i32,
|
||||
height: i32,
|
||||
horizontal: i32,
|
||||
vertical: i32,
|
||||
}
|
||||
|
||||
//Bits avaliable to encode y-pos
|
||||
pub const SIZE_BITS_Y: i32 = 12;
|
||||
pub const MAX_HEIGHT: i32 = (1 << SIZE_BITS_Y) - 32;
|
||||
pub const MAX_COLUMN_HEIGHT: i32 = (MAX_HEIGHT >> 1) - 1;
|
||||
pub const MIN_HEIGHT: i32 = MAX_COLUMN_HEIGHT - MAX_HEIGHT + 1;
|
||||
|
||||
impl GenerationShapeConfig {
|
||||
fn new(y_min: i32, height: i32, horizontal: i32, vertical: i32) -> Self {
|
||||
if (y_min + height) > (MAX_COLUMN_HEIGHT + 1) {
|
||||
panic!("Cannot be higher than max column height");
|
||||
} else if height % 16 != 0 {
|
||||
panic!("Height must be a multiple of 16");
|
||||
} else if y_min % 16 != 0 {
|
||||
panic!("Y min must be a multiple of 16");
|
||||
}
|
||||
Self {
|
||||
y_min,
|
||||
height,
|
||||
horizontal,
|
||||
vertical,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trim_height(&self, view: &impl HeightLimitViewImpl) -> Self {
|
||||
let i = self.y_min.max(view.bottom_y());
|
||||
let j = (self.y_min + self.height).min(view.top_y()) - i;
|
||||
Self {
|
||||
y_min: i,
|
||||
height: j,
|
||||
horizontal: self.horizontal,
|
||||
vertical: self.vertical,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn min_y(&self) -> i32 {
|
||||
self.y_min
|
||||
}
|
||||
|
||||
pub fn height(&self) -> i32 {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn vertical_cell_block_count(&self) -> i32 {
|
||||
biome_coords::to_block(self.vertical)
|
||||
}
|
||||
|
||||
pub fn horizontal_cell_block_count(&self) -> i32 {
|
||||
biome_coords::to_block(self.horizontal)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod shape_configs {
|
||||
use super::GenerationShapeConfig;
|
||||
|
||||
pub const surface_config: GenerationShapeConfig = GenerationShapeConfig {
|
||||
y_min: -64,
|
||||
height: 384,
|
||||
horizontal: 1,
|
||||
vertical: 2,
|
||||
};
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
use enum_dispatch::enum_dispatch;
|
||||
|
||||
use crate::world_gen::chunk::Chunk;
|
||||
|
||||
#[enum_dispatch]
|
||||
pub enum HeightLimitView {
|
||||
Standard(StandardHeightLimitView),
|
||||
Chunk(Chunk),
|
||||
}
|
||||
|
||||
#[enum_dispatch(HeightLimitView)]
|
||||
@@ -1 +0,0 @@
|
||||
pub enum HeightMap {}
|
||||
@@ -1,72 +0,0 @@
|
||||
use crate::{self as pumpkin_world, world_gen::noise::density::NoisePosImpl};
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use pumpkin_macros::block_id;
|
||||
|
||||
use crate::block::BlockId;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FluidLevel {
|
||||
y: i32,
|
||||
state: BlockId,
|
||||
}
|
||||
|
||||
impl FluidLevel {
|
||||
fn get_block(&self, y: i32) -> BlockId {
|
||||
if y < self.y {
|
||||
self.state
|
||||
} else {
|
||||
block_id!("minecraft:air")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FluidLevelSampler {
|
||||
sea_level: i32,
|
||||
fluid_level_1: FluidLevel,
|
||||
fluid_level_2: FluidLevel,
|
||||
}
|
||||
|
||||
impl FluidLevelSampler {
|
||||
fn get_fluid_level(&self, _x: i32, y: i32, _z: i32) -> FluidLevel {
|
||||
if y < (-51).min(self.sea_level) {
|
||||
self.fluid_level_1.clone()
|
||||
} else {
|
||||
self.fluid_level_2.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_dispatch(AquiferSamplerImpl)]
|
||||
pub enum AquifierSampler {
|
||||
SeaLevel(AquiferSeaLevel),
|
||||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait AquiferSamplerImpl {
|
||||
fn apply(&self, pos: &impl NoisePosImpl, density: f64) -> Option<BlockId>;
|
||||
}
|
||||
|
||||
pub struct AquiferSeaLevel {
|
||||
level_sampler: FluidLevelSampler,
|
||||
}
|
||||
|
||||
impl AquiferSeaLevel {
|
||||
pub fn new(level_sampler: FluidLevelSampler) -> Self {
|
||||
Self { level_sampler }
|
||||
}
|
||||
}
|
||||
|
||||
impl AquiferSamplerImpl for AquiferSeaLevel {
|
||||
fn apply(&self, pos: &impl NoisePosImpl, density: f64) -> Option<BlockId> {
|
||||
if density > 0f64 {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
self.level_sampler
|
||||
.get_fluid_level(pos.x(), pos.y(), pos.z())
|
||||
.get_block(pos.y()),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,2 @@
|
||||
use crate::height::HeightLimitViewImpl;
|
||||
|
||||
use super::{
|
||||
blender::Blender,
|
||||
chunk::{Chunk, GenerationShapeConfig, HeightMapType},
|
||||
noise::config::NoiseConfig,
|
||||
};
|
||||
|
||||
pub mod aquifer;
|
||||
pub mod overworld;
|
||||
pub mod superflat;
|
||||
mod surface_builder;
|
||||
|
||||
pub fn populate_noise(
|
||||
chunk: &mut Chunk,
|
||||
blender: &Blender,
|
||||
config: &NoiseConfig,
|
||||
shape: &GenerationShapeConfig,
|
||||
) {
|
||||
let shape = shape.trim_height(chunk);
|
||||
let i = shape.min_y();
|
||||
let j = i / shape.vertical_cell_block_count();
|
||||
let k = shape.height() / shape.vertical_cell_block_count();
|
||||
|
||||
internal_populate_noise(chunk, blender, config, j, k);
|
||||
}
|
||||
|
||||
fn internal_populate_noise(
|
||||
chunk: &mut Chunk,
|
||||
blender: &Blender,
|
||||
config: &NoiseConfig,
|
||||
min_cell_y: i32,
|
||||
cell_height: i32,
|
||||
) {
|
||||
let sampler = chunk.get_or_create_noise_sampler();
|
||||
let height_map = chunk.get_height_map(HeightMapType::WorldGenOceanFloor);
|
||||
let height_map2 = chunk.get_height_map(HeightMapType::WorldGenSurface);
|
||||
let pos = chunk.pos();
|
||||
|
||||
let i = pos.get_start_x();
|
||||
let j = pos.get_start_z();
|
||||
|
||||
let mut sampler = sampler.lock();
|
||||
sampler.sample_start_density();
|
||||
|
||||
let k = sampler.horizontal_cell_block_count();
|
||||
let l = sampler.vertical_cell_block_count();
|
||||
let m = 16 / k;
|
||||
let n = 16 / k;
|
||||
|
||||
for o in 0..m {
|
||||
sampler.sample_end_density(o);
|
||||
|
||||
for p in 0..n {
|
||||
let q = chunk.vertical_section_count() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
pub mod biome;
|
||||
pub mod terrain_params;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod blender;
|
||||
pub mod chunk;
|
||||
mod generator;
|
||||
mod generic_generator;
|
||||
mod heightmap;
|
||||
pub mod height_limit;
|
||||
mod implementation;
|
||||
mod noise;
|
||||
pub mod sampler;
|
||||
mod positions;
|
||||
mod proto_chunk;
|
||||
mod sampler;
|
||||
mod seed;
|
||||
mod supplier;
|
||||
|
||||
pub use generator::WorldGenerator;
|
||||
use implementation::overworld::biome::plains::PlainsGenerator;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
||||
use pumpkin_core::random::RandomDeriver;
|
||||
|
||||
use crate::world_gen::supplier::MultiNoiseSampler;
|
||||
|
||||
use super::router::NoiseRouter;
|
||||
|
||||
pub struct NoiseConfig<'a> {
|
||||
random_deriver: RandomDeriver,
|
||||
router: NoiseRouter<'a>,
|
||||
}
|
||||
|
||||
impl<'a> NoiseConfig<'a> {
|
||||
pub fn noise_router(&self) -> NoiseRouter<'a> {
|
||||
self.router.clone()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::world_gen::blender::BlenderImpl;
|
||||
|
||||
use super::{
|
||||
Applier, ApplierImpl, DensityFunction, DensityFunctionImpl, NoisePos, NoisePosImpl, Visitor,
|
||||
VisitorImpl,
|
||||
|
||||
@@ -8,28 +8,13 @@ use math::{BinaryFunction, BinaryType, LinearFunction};
|
||||
use noise::{InternalNoise, InterpolatedNoiseSampler, NoiseFunction, ShiftedNoiseFunction};
|
||||
use offset::{ShiftAFunction, ShiftBFunction};
|
||||
use spline::SplineFunction;
|
||||
use terrain_helpers::{create_factor_spline, create_jaggedness_spline, create_offset_spline};
|
||||
use unary::{ClampFunction, UnaryFunction, UnaryType};
|
||||
use weird::{RarityMapper, WierdScaledFunction};
|
||||
|
||||
use crate::world_gen::{
|
||||
blender::{Blender, NoBlendBlender},
|
||||
chunk::{MAX_COLUMN_HEIGHT, MIN_HEIGHT},
|
||||
implementation::overworld::terrain_params::{
|
||||
create_factor_spline, create_jaggedness_spline, create_offset_spline,
|
||||
},
|
||||
};
|
||||
use crate::world_gen::blender::Blender;
|
||||
|
||||
use super::{
|
||||
chunk_sampler::{
|
||||
BlendAlphaDensityFunction, BlendOffsetDensityFunction, Cache2DDensityFunction,
|
||||
CacheOnceDensityFunction, CellCacheDensityFunctionWrapper, ChunkNoiseSamplerWrapper,
|
||||
ChunkSamplerDensityFunctionConverter, FlatCacheDensityFunction, InterpolationApplier,
|
||||
InterpolatorDensityFunctionWrapper,
|
||||
},
|
||||
clamped_map,
|
||||
perlin::DoublePerlinNoiseParameters,
|
||||
BuiltInNoiseParams,
|
||||
};
|
||||
use super::{clamped_map, perlin::DoublePerlinNoiseParameters, BuiltInNoiseParams};
|
||||
|
||||
pub mod blend;
|
||||
mod end;
|
||||
@@ -37,6 +22,7 @@ mod math;
|
||||
pub mod noise;
|
||||
mod offset;
|
||||
pub mod spline;
|
||||
mod terrain_helpers;
|
||||
mod unary;
|
||||
mod weird;
|
||||
|
||||
@@ -90,6 +76,12 @@ pub struct BuiltInNoiseFunctions<'a> {
|
||||
caves_pillars_overworld: Arc<DensityFunction<'a>>,
|
||||
}
|
||||
|
||||
//Bits avaliable to encode y-pos
|
||||
pub const SIZE_BITS_Y: i32 = 12;
|
||||
pub const MAX_HEIGHT: i32 = (1 << SIZE_BITS_Y) - 32;
|
||||
pub const MAX_COLUMN_HEIGHT: i32 = (MAX_HEIGHT >> 1) - 1;
|
||||
pub const MIN_HEIGHT: i32 = MAX_COLUMN_HEIGHT - MAX_HEIGHT + 1;
|
||||
|
||||
impl<'a> BuiltInNoiseFunctions<'a> {
|
||||
pub fn new(built_in_noise_params: &BuiltInNoiseParams<'a>) -> Self {
|
||||
let blend_alpha = Arc::new(DensityFunction::BlendAlpha(BlendAlphaFunction {}));
|
||||
@@ -626,6 +618,7 @@ impl<'a> BuiltInNoiseFunctions<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn sloped_cheese_function<'a>(
|
||||
jagged_noise: Arc<DensityFunction<'a>>,
|
||||
continents: Arc<DensityFunction<'a>>,
|
||||
@@ -640,13 +633,14 @@ fn sloped_cheese_function<'a>(
|
||||
) -> SlopedCheeseResult<'a> {
|
||||
let offset = Arc::new(apply_blending(
|
||||
Arc::new(
|
||||
DensityFunction::Spline(SplineFunction::new(Arc::new(create_offset_spline(
|
||||
continents.clone(),
|
||||
erosion.clone(),
|
||||
ridges.clone(),
|
||||
amplified,
|
||||
))))
|
||||
.add_const(-0.50375f32 as f64),
|
||||
DensityFunction::Constant(ConstantFunction::new(-0.50375f32 as f64)).add(Arc::new(
|
||||
DensityFunction::Spline(SplineFunction::new(Arc::new(create_offset_spline(
|
||||
continents.clone(),
|
||||
erosion.clone(),
|
||||
ridges_folded.clone(),
|
||||
amplified,
|
||||
)))),
|
||||
)),
|
||||
),
|
||||
blend_offset,
|
||||
));
|
||||
@@ -734,7 +728,6 @@ fn apply_blending<'a>(
|
||||
function: Arc<DensityFunction<'a>>,
|
||||
blend: Arc<DensityFunction<'a>>,
|
||||
) -> DensityFunction<'a> {
|
||||
//let function = lerp_density(built_in_noises::BLEND_ALPHA.clone(), blend, function);
|
||||
let function = lerp_density(
|
||||
Arc::new(DensityFunction::BlendAlpha(BlendAlphaFunction {})),
|
||||
blend,
|
||||
@@ -799,14 +792,6 @@ pub enum DensityFunction<'a> {
|
||||
Wierd(WierdScaledFunction<'a>),
|
||||
Range(RangeFunction<'a>),
|
||||
Wrapper(WrapperFunction<'a>),
|
||||
ChunkCacheFlatCache(FlatCacheDensityFunction<'a>),
|
||||
ChunkCacheInterpolator(InterpolatorDensityFunctionWrapper<'a>),
|
||||
ChunkCacheBlendAlpha(BlendAlphaDensityFunction<'a>),
|
||||
ChunkCacheBlendOffset(BlendOffsetDensityFunction<'a>),
|
||||
ChunkCacheCellCache(CellCacheDensityFunctionWrapper<'a>),
|
||||
ChunkCache2DCache(Cache2DDensityFunction<'a>),
|
||||
ChunkCacheOnceCache(CacheOnceDensityFunction<'a>),
|
||||
Beardifyer(BeardifyerFunction),
|
||||
}
|
||||
|
||||
impl<'a> DensityFunction<'a> {
|
||||
@@ -885,10 +870,44 @@ impl<'a> DensityFunction<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Unused<'a> {
|
||||
_x: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> NoisePosImpl for Unused<'a> {
|
||||
fn x(&self) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn y(&self) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn z(&self) -> i32 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ApplierImpl<'a> for Unused<'a> {
|
||||
fn at(&self, _index: usize) -> NoisePos<'a> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn fill(&self, _densities: &mut [f64], _function: &DensityFunction<'a>) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VisitorImpl<'a> for Unused<'a> {
|
||||
fn apply(&self, _function: Arc<DensityFunction<'a>>) -> Arc<DensityFunction<'a>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_dispatch(NoisePosImpl)]
|
||||
pub enum NoisePos<'a> {
|
||||
Unblended(UnblendedNoisePos),
|
||||
ChunkNoise(ChunkNoiseSamplerWrapper<'a>),
|
||||
Todo(Unused<'a>),
|
||||
}
|
||||
|
||||
pub struct UnblendedNoisePos {
|
||||
@@ -924,14 +943,13 @@ pub trait NoisePosImpl {
|
||||
fn z(&self) -> i32;
|
||||
|
||||
fn get_blender(&self) -> Blender {
|
||||
Blender::None(NoBlendBlender {})
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_dispatch(ApplierImpl)]
|
||||
pub enum Applier<'a> {
|
||||
ChunkNoise(ChunkNoiseSamplerWrapper<'a>),
|
||||
Interpolation(InterpolationApplier<'a>),
|
||||
Todo(Unused<'a>),
|
||||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
@@ -944,7 +962,7 @@ pub trait ApplierImpl<'a> {
|
||||
#[enum_dispatch(VisitorImpl)]
|
||||
pub enum Visitor<'a> {
|
||||
Unwrap(UnwrapVisitor),
|
||||
ChunkSampler(ChunkSamplerDensityFunctionConverter<'a>),
|
||||
Todo(Unused<'a>),
|
||||
}
|
||||
|
||||
pub struct UnwrapVisitor {}
|
||||
@@ -1134,31 +1152,6 @@ impl<'a> DensityFunctionImpl<'a> for RangeFunction<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BeardifyerFunction {}
|
||||
|
||||
impl<'a> DensityFunctionImpl<'a> for BeardifyerFunction {
|
||||
fn sample(&self, _pos: &NoisePos) -> f64 {
|
||||
0f64
|
||||
}
|
||||
|
||||
fn fill(&self, densities: &mut [f64], _applier: &Applier<'a>) {
|
||||
densities.fill(0f64)
|
||||
}
|
||||
|
||||
fn min(&self) -> f64 {
|
||||
0f64
|
||||
}
|
||||
|
||||
fn max(&self) -> f64 {
|
||||
0f64
|
||||
}
|
||||
|
||||
fn apply(&self, visitor: &Visitor<'a>) -> Arc<DensityFunction<'a>> {
|
||||
visitor.apply(Arc::new(DensityFunction::Beardifyer(BeardifyerFunction {})))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct YClampedFunction {
|
||||
from: i32,
|
||||
@@ -1244,3 +1237,129 @@ pub fn lerp_density_static_start<'a>(
|
||||
) -> DensityFunction<'a> {
|
||||
delta.mul(Arc::new(end.add_const(-start))).add_const(start)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::world_gen::noise::{density::DensityFunctionImpl, BuiltInNoiseParams};
|
||||
|
||||
use super::{BuiltInNoiseFunctions, NoisePos, UnblendedNoisePos};
|
||||
|
||||
#[test]
|
||||
fn test_density_function_correctness() {
|
||||
let noise_params = BuiltInNoiseParams::new();
|
||||
let noise_functions = BuiltInNoiseFunctions::new(&noise_params);
|
||||
|
||||
let pos = NoisePos::Unblended(UnblendedNoisePos { x: 0, y: 0, z: 0 });
|
||||
|
||||
assert_eq!(noise_functions.blend_alpha.sample(&pos), 1f64);
|
||||
assert_eq!(noise_functions.blend_alpha.min(), 1f64);
|
||||
assert_eq!(noise_functions.blend_alpha.max(), 1f64);
|
||||
|
||||
assert_eq!(noise_functions.blend_offset.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.blend_offset.min(), 0f64);
|
||||
assert_eq!(noise_functions.blend_offset.max(), 0f64);
|
||||
|
||||
assert_eq!(noise_functions.zero.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.zero.min(), 0f64);
|
||||
assert_eq!(noise_functions.zero.max(), 0f64);
|
||||
|
||||
assert_eq!(noise_functions.y.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.y.min(), -4064f64);
|
||||
assert_eq!(noise_functions.y.max(), 4062f64);
|
||||
|
||||
assert_eq!(noise_functions.shift_x.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.shift_x.min(), -8f64);
|
||||
assert_eq!(noise_functions.shift_x.max(), 8f64);
|
||||
|
||||
assert_eq!(noise_functions.shift_z.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.shift_z.min(), -8f64);
|
||||
assert_eq!(noise_functions.shift_z.max(), 8f64);
|
||||
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_overworld.sample(&pos),
|
||||
0.05283727086562935f64
|
||||
);
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_overworld.min(),
|
||||
-87.55150000000002f64
|
||||
);
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_overworld.max(),
|
||||
87.55150000000002f64
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_nether.sample(&pos),
|
||||
0.05283727086562935f64
|
||||
);
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_nether.min(),
|
||||
-258.65450000000004f64
|
||||
);
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_nether.max(),
|
||||
258.65450000000004f64
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_end.sample(&pos),
|
||||
0.05283727086562935f64
|
||||
);
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_end.min(),
|
||||
-173.10299999999998f64
|
||||
);
|
||||
assert_eq!(
|
||||
noise_functions.base_3d_noise_end.max(),
|
||||
173.10299999999998f64
|
||||
);
|
||||
|
||||
assert_eq!(noise_functions.continents_overworld.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.continents_overworld.min(), -2f64);
|
||||
assert_eq!(noise_functions.continents_overworld.max(), 2f64);
|
||||
|
||||
assert_eq!(noise_functions.erosion_overworld.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.erosion_overworld.min(), -2f64);
|
||||
assert_eq!(noise_functions.erosion_overworld.max(), 2f64);
|
||||
|
||||
assert_eq!(noise_functions.ridges_overworld.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.ridges_overworld.min(), -2f64);
|
||||
assert_eq!(noise_functions.ridges_overworld.max(), 2f64);
|
||||
|
||||
assert_eq!(noise_functions.ridges_folded_overworld.sample(&pos), -1f64);
|
||||
assert_eq!(
|
||||
noise_functions.ridges_folded_overworld.min(),
|
||||
-3.000000000000001f64
|
||||
);
|
||||
assert_eq!(noise_functions.ridges_folded_overworld.max(), 1f64);
|
||||
|
||||
assert_eq!(
|
||||
noise_functions.offset_overworld.sample(&pos),
|
||||
-0.6037500277161598f64
|
||||
);
|
||||
assert_eq!(
|
||||
noise_functions.offset_overworld.min(),
|
||||
-1.3752707839012146f64
|
||||
);
|
||||
assert_eq!(
|
||||
noise_functions.offset_overworld.max(),
|
||||
0.9962499737739563f64
|
||||
);
|
||||
|
||||
assert_eq!(noise_functions.y.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.y.min(), -4064f64);
|
||||
assert_eq!(noise_functions.y.max(), 4062f64);
|
||||
|
||||
assert_eq!(noise_functions.y.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.y.min(), -4064f64);
|
||||
assert_eq!(noise_functions.y.max(), 4062f64);
|
||||
|
||||
assert_eq!(noise_functions.y.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.y.min(), -4064f64);
|
||||
assert_eq!(noise_functions.y.max(), 4062f64);
|
||||
|
||||
assert_eq!(noise_functions.y.sample(&pos), 0f64);
|
||||
assert_eq!(noise_functions.y.min(), -4064f64);
|
||||
assert_eq!(noise_functions.y.max(), 4062f64);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::world_gen::noise::lerp_32;
|
||||
use crate::world_gen::noise::lerp;
|
||||
|
||||
use super::{
|
||||
Applier, ApplierImpl, DensityFunction, DensityFunctionImpl, NoisePos, Visitor, VisitorImpl,
|
||||
@@ -56,6 +56,11 @@ pub struct Spline<'a> {
|
||||
max: f32,
|
||||
}
|
||||
|
||||
enum Range {
|
||||
In(usize),
|
||||
Below,
|
||||
}
|
||||
|
||||
impl<'a> Spline<'a> {
|
||||
fn sample_outside_range(point: f32, value: f32, points: &[SplinePoint], i: usize) -> f32 {
|
||||
let f = points[i].derivative;
|
||||
@@ -66,8 +71,29 @@ impl<'a> Spline<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn find_range_for_location(locations: &[f32], x: f32) -> i32 {
|
||||
locations.partition_point(|val| x < *val) as i32 - 1
|
||||
fn binary_walk(min: usize, max: usize, pred: impl Fn(usize) -> bool) -> usize {
|
||||
let mut i = max - min;
|
||||
let mut min = min;
|
||||
while i > 0 {
|
||||
let j = i / 2;
|
||||
let k = min + j;
|
||||
if pred(k) {
|
||||
i = j;
|
||||
} else {
|
||||
min = k + 1;
|
||||
i -= j + 1;
|
||||
}
|
||||
}
|
||||
min
|
||||
}
|
||||
|
||||
fn find_range_for_location(points: &[SplinePoint], x: f32) -> Range {
|
||||
let index_greater_than_x = Self::binary_walk(0, points.len(), |i| x < points[i].location);
|
||||
if index_greater_than_x == 0 {
|
||||
Range::Below
|
||||
} else {
|
||||
Range::In(index_greater_than_x - 1)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(function: Arc<DensityFunction<'a>>, points: &[SplinePoint<'a>]) -> Self {
|
||||
@@ -143,31 +169,34 @@ impl<'a> Spline<'a> {
|
||||
|
||||
pub fn apply(&self, pos: &NoisePos) -> f32 {
|
||||
let f = self.function.sample(pos) as f32;
|
||||
let i = Self::find_range_for_location(
|
||||
self.points
|
||||
.iter()
|
||||
.map(|p| p.location)
|
||||
.collect::<Vec<f32>>()
|
||||
.as_ref(),
|
||||
f,
|
||||
);
|
||||
let j = self.points.len() - 1;
|
||||
let i = Self::find_range_for_location(&self.points, f);
|
||||
|
||||
if i < 0 {
|
||||
Self::sample_outside_range(f, self.points[0].value.apply(pos), &self.points, 0)
|
||||
} else if i == j as i32 {
|
||||
Self::sample_outside_range(f, self.points[j].value.apply(pos), &self.points, j)
|
||||
} else {
|
||||
let point_1 = &self.points[i as usize];
|
||||
let point_2 = &self.points[i as usize + 1];
|
||||
let k = (f - point_1.location) / (point_2.location - point_1.location);
|
||||
match i {
|
||||
Range::In(index) => {
|
||||
let last_index = self.points.len() - 1;
|
||||
if index == last_index {
|
||||
Self::sample_outside_range(
|
||||
f,
|
||||
self.points[last_index].value.apply(pos),
|
||||
&self.points,
|
||||
last_index,
|
||||
)
|
||||
} else {
|
||||
let point_1 = &self.points[index];
|
||||
let point_2 = &self.points[index + 1];
|
||||
let k = (f - point_1.location) / (point_2.location - point_1.location);
|
||||
|
||||
let n = point_1.value.apply(pos);
|
||||
let o = point_2.value.apply(pos);
|
||||
let n = point_1.value.apply(pos);
|
||||
let o = point_2.value.apply(pos);
|
||||
|
||||
let p = point_1.derivative * (point_2.location - point_1.location) - (o - n);
|
||||
let q = -point_2.derivative * (point_2.location - point_1.location) + (o - n);
|
||||
lerp_32(k, n, o) + k * (1f32 - k) * lerp_32(k, p, q)
|
||||
let p = point_1.derivative * (point_2.location - point_1.location) - (o - n);
|
||||
let q = -point_2.derivative * (point_2.location - point_1.location) + (o - n);
|
||||
lerp(k, n, o) + k * (1f32 - k) * lerp(k, p, q)
|
||||
}
|
||||
}
|
||||
Range::Below => {
|
||||
Self::sample_outside_range(f, self.points[0].value.apply(pos), &self.points, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +254,9 @@ impl<'a> DensityFunctionImpl<'a> for SplineFunction<'a> {
|
||||
#[derive(Clone)]
|
||||
pub enum FloatAmplifier {
|
||||
Identity,
|
||||
Amplifier,
|
||||
OffsetAmplifier,
|
||||
FactorAmplifier,
|
||||
JaggednessAmplifier,
|
||||
}
|
||||
|
||||
impl FloatAmplifier {
|
||||
@@ -233,13 +264,15 @@ impl FloatAmplifier {
|
||||
pub fn apply(&self, f: f32) -> f32 {
|
||||
match self {
|
||||
Self::Identity => f,
|
||||
Self::Amplifier => {
|
||||
Self::OffsetAmplifier => {
|
||||
if f < 0f32 {
|
||||
f
|
||||
} else {
|
||||
f * 2f32
|
||||
}
|
||||
}
|
||||
Self::FactorAmplifier => 1.25f32 - 6.25f32 / (f + 5f32),
|
||||
Self::JaggednessAmplifier => f * 2f32,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,3 +326,34 @@ impl<'a> SplineBuilder<'a> {
|
||||
Spline::new(self.function.clone(), &self.points)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use crate::world_gen::noise::{
|
||||
density::{BuiltInNoiseFunctions, NoisePos, UnblendedNoisePos},
|
||||
BuiltInNoiseParams,
|
||||
};
|
||||
|
||||
use super::{FloatAmplifier, SplineBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_correctness() {
|
||||
let noise_params = BuiltInNoiseParams::new();
|
||||
let noise_functions = BuiltInNoiseFunctions::new(&noise_params);
|
||||
let pos = NoisePos::Unblended(UnblendedNoisePos { x: 0, y: 0, z: 0 });
|
||||
|
||||
let spline = SplineBuilder::new(
|
||||
noise_functions.continents_overworld,
|
||||
FloatAmplifier::Identity,
|
||||
)
|
||||
.add_value(-1.1f32, 0.044f32, 0f32)
|
||||
.add_value(-1.02f32, -0.2222f32, 0f32)
|
||||
.add_value(-0.51f32, -0.2222f32, 0f32)
|
||||
.add_value(-0.44f32, -0.12f32, 0f32)
|
||||
.add_value(-0.18f32, -0.12f32, 0f32)
|
||||
.build();
|
||||
|
||||
assert_eq!(spline.apply(&pos), -0.12f32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::world_gen::noise::density::spline::{
|
||||
FloatAmplifier, Spline, SplineBuilder, SplineValue,
|
||||
};
|
||||
use crate::world_gen::noise::density::{peaks_valleys_noise, DensityFunction};
|
||||
use crate::world_gen::noise::lerp_32;
|
||||
use crate::world_gen::noise::lerp;
|
||||
|
||||
#[inline]
|
||||
fn get_offset_value(f: f32, g: f32, h: f32) -> f32 {
|
||||
@@ -69,7 +69,7 @@ fn meth_42050(
|
||||
let builder = if bl {
|
||||
builder
|
||||
.add_value(-1f32, 0.2f32.max(i), 0f32)
|
||||
.add_value(0f32, lerp_32(0.5f32, i, k), n)
|
||||
.add_value(0f32, lerp(0.5f32, i, k), n)
|
||||
} else {
|
||||
builder.add_value(-1f32, i, n)
|
||||
};
|
||||
@@ -216,11 +216,8 @@ fn method_42052<'a>(
|
||||
builder.build()
|
||||
}
|
||||
|
||||
fn method_42049<'a>(
|
||||
ridges: Arc<DensityFunction<'a>>,
|
||||
f: f32,
|
||||
amplifier: FloatAmplifier,
|
||||
) -> Spline<'a> {
|
||||
#[inline]
|
||||
fn method_42049(ridges: Arc<DensityFunction>, f: f32, amplifier: FloatAmplifier) -> Spline {
|
||||
let g = 0.63f32 * f;
|
||||
let h = 0.3f32 * f;
|
||||
SplineBuilder::new(ridges, amplifier)
|
||||
@@ -229,6 +226,8 @@ fn method_42049<'a>(
|
||||
.build()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[inline]
|
||||
fn method_42053<'a>(
|
||||
erosion: Arc<DensityFunction<'a>>,
|
||||
ridges: Arc<DensityFunction<'a>>,
|
||||
@@ -257,7 +256,7 @@ fn method_42053<'a>(
|
||||
SplineBuilder::new(erosion, amplifier)
|
||||
.add_spline(-1f32, SplineValue::Spline(spline), 0f32)
|
||||
.add_spline(-0.78, SplineValue::Spline(spline2.clone()), 0f32)
|
||||
.add_spline(-05775f32, SplineValue::Spline(spline2), 0f32)
|
||||
.add_spline(-0.5775f32, SplineValue::Spline(spline2), 0f32)
|
||||
.add_value(-0.375f32, 0f32, 0f32)
|
||||
.build()
|
||||
}
|
||||
@@ -278,13 +277,13 @@ fn create_continental_offset_spline<'a>(
|
||||
) -> Spline<'a> {
|
||||
let spline = meth_42050(
|
||||
ridges.clone(),
|
||||
lerp_32(h, 0.6f32, 1.5f32),
|
||||
lerp(h, 0.6f32, 1.5f32),
|
||||
bl2,
|
||||
amplifier.clone(),
|
||||
);
|
||||
let spline2 = meth_42050(
|
||||
ridges.clone(),
|
||||
lerp_32(h, 0.6f32, 1f32),
|
||||
lerp(h, 0.6f32, 1f32),
|
||||
bl2,
|
||||
amplifier.clone(),
|
||||
);
|
||||
@@ -293,7 +292,7 @@ fn create_continental_offset_spline<'a>(
|
||||
ridges.clone(),
|
||||
continental - 0.15f32,
|
||||
0.5f32 * h,
|
||||
lerp_32(0.5f32, 0.5f32, 0.5f32) * h,
|
||||
lerp(0.5f32, 0.5f32, 0.5f32) * h,
|
||||
0.5f32 * h,
|
||||
0.6f32 * h,
|
||||
0.5f32,
|
||||
@@ -378,7 +377,7 @@ pub fn create_offset_spline<'a>(
|
||||
amplified: bool,
|
||||
) -> Spline<'a> {
|
||||
let amplification = if amplified {
|
||||
FloatAmplifier::Amplifier
|
||||
FloatAmplifier::OffsetAmplifier
|
||||
} else {
|
||||
FloatAmplifier::Identity
|
||||
};
|
||||
@@ -458,7 +457,7 @@ pub fn create_factor_spline<'a>(
|
||||
amplified: bool,
|
||||
) -> Spline<'a> {
|
||||
let amplification = if amplified {
|
||||
FloatAmplifier::Amplifier
|
||||
FloatAmplifier::FactorAmplifier
|
||||
} else {
|
||||
FloatAmplifier::Identity
|
||||
};
|
||||
@@ -524,7 +523,7 @@ pub fn create_jaggedness_spline<'a>(
|
||||
amplified: bool,
|
||||
) -> Spline<'a> {
|
||||
let amplification = if amplified {
|
||||
FloatAmplifier::Amplifier
|
||||
FloatAmplifier::JaggednessAmplifier
|
||||
} else {
|
||||
FloatAmplifier::Identity
|
||||
};
|
||||
@@ -561,3 +560,82 @@ pub fn create_jaggedness_spline<'a>(
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::world_gen::noise::{
|
||||
density::{
|
||||
spline::FloatAmplifier, terrain_helpers::create_offset_spline, BuiltInNoiseFunctions,
|
||||
NoisePos, UnblendedNoisePos,
|
||||
},
|
||||
BuiltInNoiseParams,
|
||||
};
|
||||
|
||||
use super::create_continental_offset_spline;
|
||||
|
||||
#[test]
|
||||
fn test_offset_correctness() {
|
||||
let noise_params = BuiltInNoiseParams::new();
|
||||
let noise_functions = BuiltInNoiseFunctions::new(&noise_params);
|
||||
|
||||
let pos = NoisePos::Unblended(UnblendedNoisePos { x: 0, y: 0, z: 0 });
|
||||
|
||||
let spline = create_continental_offset_spline(
|
||||
noise_functions.erosion_overworld.clone(),
|
||||
noise_functions.ridges_folded_overworld.clone(),
|
||||
1f32,
|
||||
1f32,
|
||||
1f32,
|
||||
1f32,
|
||||
1f32,
|
||||
1f32,
|
||||
true,
|
||||
true,
|
||||
FloatAmplifier::Identity,
|
||||
);
|
||||
|
||||
assert_eq!(spline.apply(&pos), 1f32);
|
||||
|
||||
let pos = NoisePos::Unblended(UnblendedNoisePos {
|
||||
x: 10,
|
||||
y: 10,
|
||||
z: 10,
|
||||
});
|
||||
|
||||
let spline = create_continental_offset_spline(
|
||||
noise_functions.erosion_overworld.clone(),
|
||||
noise_functions.ridges_folded_overworld.clone(),
|
||||
2f32,
|
||||
2f32,
|
||||
2f32,
|
||||
2f32,
|
||||
2f32,
|
||||
2f32,
|
||||
true,
|
||||
true,
|
||||
FloatAmplifier::Identity,
|
||||
);
|
||||
|
||||
assert_eq!(spline.apply(&pos), 2f32);
|
||||
|
||||
let pos = NoisePos::Unblended(UnblendedNoisePos { x: 0, y: 0, z: 0 });
|
||||
|
||||
let spline = create_offset_spline(
|
||||
noise_functions.continents_overworld.clone(),
|
||||
noise_functions.erosion_overworld.clone(),
|
||||
noise_functions.ridges_folded_overworld.clone(),
|
||||
true,
|
||||
);
|
||||
|
||||
assert_eq!(spline.apply(&pos), -0.1f32);
|
||||
|
||||
let spline = create_offset_spline(
|
||||
noise_functions.continents_overworld,
|
||||
noise_functions.erosion_overworld.clone(),
|
||||
noise_functions.ridges_folded_overworld.clone(),
|
||||
false,
|
||||
);
|
||||
|
||||
assert_eq!(spline.apply(&pos), -0.1f32);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use derive_getters::Getters;
|
||||
use num_traits::Float;
|
||||
use perlin::DoublePerlinNoiseParameters;
|
||||
pub mod chunk_sampler;
|
||||
pub mod config;
|
||||
pub mod density;
|
||||
pub mod perlin;
|
||||
mod router;
|
||||
@@ -188,11 +185,10 @@ impl<'a> BuiltInNoiseParams<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lerp_32(delta: f32, start: f32, end: f32) -> f32 {
|
||||
start + delta * (end - start)
|
||||
}
|
||||
|
||||
pub fn lerp(delta: f64, start: f64, end: f64) -> f64 {
|
||||
pub fn lerp<T>(delta: T, start: T, end: T) -> T
|
||||
where
|
||||
T: Float,
|
||||
{
|
||||
start + delta * (end - start)
|
||||
}
|
||||
|
||||
|
||||
28
pumpkin-world/src/world_gen/positions.rs
Normal file
28
pumpkin-world/src/world_gen/positions.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
pub mod chunk_pos {
|
||||
use noise::Vector2;
|
||||
|
||||
const MARKER: u64 = packed(Vector2 {
|
||||
x: 1875066,
|
||||
y: 1875066,
|
||||
});
|
||||
|
||||
pub const fn packed(vec: Vector2<i32>) -> u64 {
|
||||
(vec.x as u64 & 4294967295u64) | ((vec.y as u64 & 4294967295u64) << 32)
|
||||
}
|
||||
|
||||
pub const fn unpack_x(packed: u64) -> i32 {
|
||||
(packed & 4294967295u64) as i32
|
||||
}
|
||||
|
||||
pub const fn unpack_z(packed: u64) -> i32 {
|
||||
((packed >> 32) & 4294967295u64) as i32
|
||||
}
|
||||
|
||||
pub const fn start_x(vec: Vector2<i32>) -> i32 {
|
||||
vec.x << 4
|
||||
}
|
||||
|
||||
pub const fn start_y(vec: Vector2<i32>) -> i32 {
|
||||
vec.y << 4
|
||||
}
|
||||
}
|
||||
29
pumpkin-world/src/world_gen/proto_chunk.rs
Normal file
29
pumpkin-world/src/world_gen/proto_chunk.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use pumpkin_core::math::vector3::Vector3;
|
||||
|
||||
use crate::block::block_state::BlockState;
|
||||
|
||||
pub struct ProtoChunk {
|
||||
state: GenerationState,
|
||||
}
|
||||
|
||||
impl ProtoChunk {
|
||||
pub fn get_block_state(&self, _pos: &Vector3<i32>) -> BlockState {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, PartialOrd)]
|
||||
pub enum GenerationState {
|
||||
Empty,
|
||||
StructureStart,
|
||||
StructureRef,
|
||||
Biome,
|
||||
Noise,
|
||||
Surface,
|
||||
Carver,
|
||||
Feature,
|
||||
InitLight,
|
||||
Light,
|
||||
Spawn,
|
||||
Full,
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
use enum_dispatch::enum_dispatch;
|
||||
|
||||
use crate::biome::Biome;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[enum_dispatch]
|
||||
pub enum BiomeSupplier {
|
||||
Static(StaticBiomeSupplier),
|
||||
}
|
||||
|
||||
#[enum_dispatch(BiomeSupplier)]
|
||||
pub trait BiomeSupplierImpl {
|
||||
fn biome(&self, x: i32, y: i32, z: i32, noise: &MultiNoiseSampler) -> Biome;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StaticBiomeSupplier {}
|
||||
impl BiomeSupplierImpl for StaticBiomeSupplier {
|
||||
fn biome(&self, _x: i32, _y: i32, _z: i32, _noise: &MultiNoiseSampler) -> Biome {
|
||||
Biome::Plains
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MultiNoiseSampler {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user