Made Chunks faster
Moreeee Speeeedddddd
This commit is contained in:
parent
43e8d9b6d9
commit
9f94ce1d0d
@ -3,7 +3,7 @@ use pumpkin_data::noise_router::OVERWORLD_BASE_NOISE_ROUTER;
|
|||||||
use pumpkin_world::{
|
use pumpkin_world::{
|
||||||
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoNoiseRouters,
|
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoNoiseRouters,
|
||||||
bench_create_and_populate_biome, bench_create_and_populate_noise,
|
bench_create_and_populate_biome, bench_create_and_populate_noise,
|
||||||
bench_create_and_populate_noise_with_surface,
|
bench_create_and_populate_noise_with_surface, generation::proto_chunk::TerrainCache,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn bench_terrain_gen(c: &mut Criterion) {
|
fn bench_terrain_gen(c: &mut Criterion) {
|
||||||
@ -13,13 +13,31 @@ fn bench_terrain_gen(c: &mut Criterion) {
|
|||||||
let surface_config = GENERATION_SETTINGS
|
let surface_config = GENERATION_SETTINGS
|
||||||
.get(&GeneratorSetting::Overworld)
|
.get(&GeneratorSetting::Overworld)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let terrain_cache = TerrainCache::from_random(&random_config);
|
||||||
|
let default_block = surface_config.default_block.get_state();
|
||||||
|
|
||||||
c.bench_function("overworld biome", |b| {
|
c.bench_function("overworld biome", |b| {
|
||||||
b.iter(|| bench_create_and_populate_biome(&base_router, &random_config, surface_config));
|
b.iter(|| {
|
||||||
|
bench_create_and_populate_biome(
|
||||||
|
&base_router,
|
||||||
|
&random_config,
|
||||||
|
surface_config,
|
||||||
|
&terrain_cache,
|
||||||
|
default_block,
|
||||||
|
)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
c.bench_function("overworld noise", |b| {
|
c.bench_function("overworld noise", |b| {
|
||||||
b.iter(|| bench_create_and_populate_noise(&base_router, &random_config, surface_config));
|
b.iter(|| {
|
||||||
|
bench_create_and_populate_noise(
|
||||||
|
&base_router,
|
||||||
|
&random_config,
|
||||||
|
surface_config,
|
||||||
|
&terrain_cache,
|
||||||
|
default_block,
|
||||||
|
)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
c.bench_function("overworld surface", |b| {
|
c.bench_function("overworld surface", |b| {
|
||||||
@ -28,6 +46,8 @@ fn bench_terrain_gen(c: &mut Criterion) {
|
|||||||
&base_router,
|
&base_router,
|
||||||
&random_config,
|
&random_config,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&terrain_cache,
|
||||||
|
default_block,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -64,9 +64,12 @@ mod test {
|
|||||||
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoChunk,
|
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoChunk,
|
||||||
chunk::palette::BIOME_NETWORK_MAX_BITS,
|
chunk::palette::BIOME_NETWORK_MAX_BITS,
|
||||||
dimension::Dimension,
|
dimension::Dimension,
|
||||||
generation::noise_router::{
|
generation::{
|
||||||
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
|
noise_router::{
|
||||||
proto_noise_router::ProtoNoiseRouters,
|
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
|
||||||
|
proto_noise_router::ProtoNoiseRouters,
|
||||||
|
},
|
||||||
|
proto_chunk::TerrainCache,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,11 +111,19 @@ mod test {
|
|||||||
let surface_settings = GENERATION_SETTINGS
|
let surface_settings = GENERATION_SETTINGS
|
||||||
.get(&GeneratorSetting::Overworld)
|
.get(&GeneratorSetting::Overworld)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let terrain_cache = TerrainCache::from_random(&random_config);
|
||||||
|
let default_block = surface_settings.default_block.get_state();
|
||||||
|
|
||||||
for data in expected_data.into_iter() {
|
for data in expected_data.into_iter() {
|
||||||
let chunk_pos = Vector2::new(data.x, data.z);
|
let chunk_pos = Vector2::new(data.x, data.z);
|
||||||
let mut chunk =
|
let mut chunk = ProtoChunk::new(
|
||||||
ProtoChunk::new(chunk_pos, &noise_router, &random_config, surface_settings);
|
chunk_pos,
|
||||||
|
&noise_router,
|
||||||
|
&random_config,
|
||||||
|
surface_settings,
|
||||||
|
&terrain_cache,
|
||||||
|
default_block,
|
||||||
|
);
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
|
|
||||||
for (biome_x, biome_y, biome_z, biome_id) in data.data {
|
for (biome_x, biome_y, biome_z, biome_id) in data.data {
|
||||||
|
|||||||
@ -40,9 +40,12 @@ mod test {
|
|||||||
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoChunk,
|
GENERATION_SETTINGS, GeneratorSetting, GlobalRandomConfig, ProtoChunk,
|
||||||
biome::{BiomeSupplier, MultiNoiseBiomeSupplier},
|
biome::{BiomeSupplier, MultiNoiseBiomeSupplier},
|
||||||
dimension::Dimension,
|
dimension::Dimension,
|
||||||
generation::noise_router::{
|
generation::{
|
||||||
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
|
noise_router::{
|
||||||
proto_noise_router::ProtoNoiseRouters,
|
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
|
||||||
|
proto_noise_router::ProtoNoiseRouters,
|
||||||
|
},
|
||||||
|
proto_chunk::TerrainCache,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,8 +64,15 @@ mod test {
|
|||||||
let surface_config = GENERATION_SETTINGS
|
let surface_config = GENERATION_SETTINGS
|
||||||
.get(&GeneratorSetting::Overworld)
|
.get(&GeneratorSetting::Overworld)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let terrain_cache = TerrainCache::from_random(&random_config);
|
||||||
let mut chunk = ProtoChunk::new(chunk_pos, &noise_rounter, &random_config, surface_config);
|
let mut chunk = ProtoChunk::new(
|
||||||
|
chunk_pos,
|
||||||
|
&noise_rounter,
|
||||||
|
&random_config,
|
||||||
|
surface_config,
|
||||||
|
&terrain_cache,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
|
);
|
||||||
|
|
||||||
for (x, y, z, tem, hum, con, ero, dep, wei) in expected_data.into_iter() {
|
for (x, y, z, tem, hum, con, ero, dep, wei) in expected_data.into_iter() {
|
||||||
let point = chunk.multi_noise_sampler.sample(x, y, z);
|
let point = chunk.multi_noise_sampler.sample(x, y, z);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::BlockState;
|
||||||
use pumpkin_data::noise_router::{
|
use pumpkin_data::noise_router::{
|
||||||
END_BASE_NOISE_ROUTER, NETHER_BASE_NOISE_ROUTER, OVERWORLD_BASE_NOISE_ROUTER,
|
END_BASE_NOISE_ROUTER, NETHER_BASE_NOISE_ROUTER, OVERWORLD_BASE_NOISE_ROUTER,
|
||||||
};
|
};
|
||||||
@ -11,6 +12,7 @@ use super::{
|
|||||||
settings::gen_settings_from_dimension,
|
settings::gen_settings_from_dimension,
|
||||||
};
|
};
|
||||||
use crate::chunk::format::LightContainer;
|
use crate::chunk::format::LightContainer;
|
||||||
|
use crate::generation::proto_chunk::TerrainCache;
|
||||||
use crate::level::Level;
|
use crate::level::Level;
|
||||||
use crate::world::BlockRegistryExt;
|
use crate::world::BlockRegistryExt;
|
||||||
use crate::{chunk::ChunkLight, dimension::Dimension};
|
use crate::{chunk::ChunkLight, dimension::Dimension};
|
||||||
@ -40,11 +42,16 @@ pub struct VanillaGenerator {
|
|||||||
random_config: GlobalRandomConfig,
|
random_config: GlobalRandomConfig,
|
||||||
base_router: ProtoNoiseRouters,
|
base_router: ProtoNoiseRouters,
|
||||||
dimension: Dimension,
|
dimension: Dimension,
|
||||||
|
|
||||||
|
terrain_cache: TerrainCache,
|
||||||
|
|
||||||
|
default_block: &'static BlockState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GeneratorInit for VanillaGenerator {
|
impl GeneratorInit for VanillaGenerator {
|
||||||
fn new(seed: Seed, dimension: Dimension) -> Self {
|
fn new(seed: Seed, dimension: Dimension) -> Self {
|
||||||
let random_config = GlobalRandomConfig::new(seed.0, false);
|
let random_config = GlobalRandomConfig::new(seed.0, false);
|
||||||
|
|
||||||
// TODO: The generation settings contains (part of?) the noise routers too; do we keep the separate or
|
// TODO: The generation settings contains (part of?) the noise routers too; do we keep the separate or
|
||||||
// use only the generation settings?
|
// use only the generation settings?
|
||||||
let base = match dimension {
|
let base = match dimension {
|
||||||
@ -52,11 +59,17 @@ impl GeneratorInit for VanillaGenerator {
|
|||||||
Dimension::Nether => NETHER_BASE_NOISE_ROUTER,
|
Dimension::Nether => NETHER_BASE_NOISE_ROUTER,
|
||||||
Dimension::End => END_BASE_NOISE_ROUTER,
|
Dimension::End => END_BASE_NOISE_ROUTER,
|
||||||
};
|
};
|
||||||
|
let terrain_cache = TerrainCache::from_random(&random_config);
|
||||||
|
let generation_settings = gen_settings_from_dimension(&dimension);
|
||||||
|
|
||||||
|
let default_block = generation_settings.default_block.get_state();
|
||||||
let base_router = ProtoNoiseRouters::generate(&base, &random_config);
|
let base_router = ProtoNoiseRouters::generate(&base, &random_config);
|
||||||
Self {
|
Self {
|
||||||
random_config,
|
random_config,
|
||||||
base_router,
|
base_router,
|
||||||
dimension,
|
dimension,
|
||||||
|
terrain_cache,
|
||||||
|
default_block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,6 +96,8 @@ impl WorldGenerator for VanillaGenerator {
|
|||||||
&self.base_router,
|
&self.base_router,
|
||||||
&self.random_config,
|
&self.random_config,
|
||||||
generation_settings,
|
generation_settings,
|
||||||
|
&self.terrain_cache,
|
||||||
|
self.default_block,
|
||||||
);
|
);
|
||||||
proto_chunk.populate_biomes(self.dimension);
|
proto_chunk.populate_biomes(self.dimension);
|
||||||
proto_chunk.populate_noise();
|
proto_chunk.populate_noise();
|
||||||
|
|||||||
@ -8,9 +8,10 @@ use pumpkin_data::{
|
|||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
HeightMap,
|
HeightMap,
|
||||||
math::{position::BlockPos, vector2::Vector2, vector3::Vector3},
|
math::{position::BlockPos, vector2::Vector2, vector3::Vector3},
|
||||||
random::{RandomGenerator, RandomImpl, get_decorator_seed, xoroshiro128::Xoroshiro},
|
random::{RandomGenerator, get_decorator_seed, xoroshiro128::Xoroshiro},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::generation::noise::perlin::DoublePerlinNoiseSampler;
|
||||||
use crate::{
|
use crate::{
|
||||||
BlockStateId,
|
BlockStateId,
|
||||||
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier, hash_seed},
|
biome::{BiomeSupplier, MultiNoiseBiomeSupplier, end::TheEndBiomeSupplier, hash_seed},
|
||||||
@ -102,6 +103,7 @@ impl FluidLevelSamplerImpl for StandardChunkFluidLevelSampler {
|
|||||||
pub struct ProtoChunk<'a> {
|
pub struct ProtoChunk<'a> {
|
||||||
pub chunk_pos: Vector2<i32>,
|
pub chunk_pos: Vector2<i32>,
|
||||||
pub noise_sampler: ChunkNoiseGenerator<'a>,
|
pub noise_sampler: ChunkNoiseGenerator<'a>,
|
||||||
|
pub terrain_cache: &'a TerrainCache,
|
||||||
// TODO: These can technically go to an even higher level and we can reuse them across chunks
|
// TODO: These can technically go to an even higher level and we can reuse them across chunks
|
||||||
pub multi_noise_sampler: MultiNoiseSampler<'a>,
|
pub multi_noise_sampler: MultiNoiseSampler<'a>,
|
||||||
pub surface_height_estimate_sampler: SurfaceHeightEstimateSampler<'a>,
|
pub surface_height_estimate_sampler: SurfaceHeightEstimateSampler<'a>,
|
||||||
@ -122,12 +124,35 @@ pub struct ProtoChunk<'a> {
|
|||||||
// may want to use chunk status
|
// may want to use chunk status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TerrainCache {
|
||||||
|
pub terrain_builder: SurfaceTerrainBuilder,
|
||||||
|
pub surface_noise: DoublePerlinNoiseSampler,
|
||||||
|
pub secondary_noise: DoublePerlinNoiseSampler,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TerrainCache {
|
||||||
|
pub fn from_random(random_config: &GlobalRandomConfig) -> Self {
|
||||||
|
let random = &random_config.base_random_deriver;
|
||||||
|
let mut noise_builder = DoublePerlinNoiseBuilder::new(random_config);
|
||||||
|
let terrain_builder = SurfaceTerrainBuilder::new(&mut noise_builder, random);
|
||||||
|
let surface_noise = noise_builder.get_noise_sampler_for_id("surface");
|
||||||
|
let secondary_noise = noise_builder.get_noise_sampler_for_id("surface_secondary");
|
||||||
|
Self {
|
||||||
|
terrain_builder,
|
||||||
|
surface_noise,
|
||||||
|
secondary_noise,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> ProtoChunk<'a> {
|
impl<'a> ProtoChunk<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
chunk_pos: Vector2<i32>,
|
chunk_pos: Vector2<i32>,
|
||||||
base_router: &'a ProtoNoiseRouters,
|
base_router: &'a ProtoNoiseRouters,
|
||||||
random_config: &'a GlobalRandomConfig,
|
random_config: &'a GlobalRandomConfig,
|
||||||
settings: &'a GenerationSettings,
|
settings: &'a GenerationSettings,
|
||||||
|
terrain_cache: &'a TerrainCache,
|
||||||
|
default_block: &'static BlockState,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let generation_shape = &settings.shape;
|
let generation_shape = &settings.shape;
|
||||||
|
|
||||||
@ -184,11 +209,11 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
let surface_height_estimate_sampler =
|
let surface_height_estimate_sampler =
|
||||||
SurfaceHeightEstimateSampler::generate(&base_router.surface_estimator, &surface_config);
|
SurfaceHeightEstimateSampler::generate(&base_router.surface_estimator, &surface_config);
|
||||||
|
|
||||||
let default_block = settings.default_block.get_state();
|
|
||||||
let default_heightmap = vec![i16::MIN; CHUNK_AREA].into_boxed_slice();
|
let default_heightmap = vec![i16::MIN; CHUNK_AREA].into_boxed_slice();
|
||||||
Self {
|
Self {
|
||||||
chunk_pos,
|
chunk_pos,
|
||||||
settings,
|
settings,
|
||||||
|
terrain_cache,
|
||||||
default_block,
|
default_block,
|
||||||
random_config,
|
random_config,
|
||||||
noise_sampler: sampler,
|
noise_sampler: sampler,
|
||||||
@ -463,61 +488,68 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
pub fn populate_noise(&mut self) {
|
pub fn populate_noise(&mut self) {
|
||||||
let horizontal_cell_block_count = self.noise_sampler.horizontal_cell_block_count();
|
let horizontal_cell_block_count = self.noise_sampler.horizontal_cell_block_count();
|
||||||
let vertical_cell_block_count = self.noise_sampler.vertical_cell_block_count();
|
let vertical_cell_block_count = self.noise_sampler.vertical_cell_block_count();
|
||||||
|
|
||||||
let horizontal_cells = CHUNK_DIM / horizontal_cell_block_count;
|
let horizontal_cells = CHUNK_DIM / horizontal_cell_block_count;
|
||||||
|
|
||||||
let min_y = self.noise_sampler.min_y();
|
let min_y = self.noise_sampler.min_y();
|
||||||
let minimum_cell_y = min_y / vertical_cell_block_count as i8;
|
let minimum_cell_y = min_y / vertical_cell_block_count as i8;
|
||||||
let cell_height = self.noise_sampler.height() / vertical_cell_block_count as u16;
|
let cell_height = self.noise_sampler.height() / vertical_cell_block_count as u16;
|
||||||
|
|
||||||
|
let start_block_x = self.start_block_x();
|
||||||
|
let start_block_z = self.start_block_z();
|
||||||
|
let start_cell_x = self.start_cell_x();
|
||||||
|
let start_cell_z = self.start_cell_z();
|
||||||
|
|
||||||
// TODO: Block state updates when we implement those
|
// TODO: Block state updates when we implement those
|
||||||
self.noise_sampler.sample_start_density();
|
self.noise_sampler.sample_start_density();
|
||||||
for cell_x in 0..horizontal_cells {
|
for cell_x in 0..horizontal_cells {
|
||||||
self.noise_sampler.sample_end_density(cell_x);
|
self.noise_sampler.sample_end_density(cell_x);
|
||||||
let sample_start_x =
|
let sample_start_x =
|
||||||
(self.start_cell_x() + cell_x as i32) * horizontal_cell_block_count as i32;
|
(start_cell_x + cell_x as i32) * horizontal_cell_block_count as i32;
|
||||||
|
|
||||||
for cell_z in 0..horizontal_cells {
|
for cell_z in 0..horizontal_cells {
|
||||||
|
let sample_start_z =
|
||||||
|
(start_cell_z + cell_z as i32) * horizontal_cell_block_count as i32;
|
||||||
|
|
||||||
for cell_y in (0..cell_height).rev() {
|
for cell_y in (0..cell_height).rev() {
|
||||||
self.noise_sampler
|
self.noise_sampler
|
||||||
.on_sampled_cell_corners(cell_x, cell_y, cell_z);
|
.on_sampled_cell_corners(cell_x, cell_y, cell_z);
|
||||||
let sample_start_y =
|
let sample_start_y =
|
||||||
(minimum_cell_y as i32 + cell_y as i32) * vertical_cell_block_count as i32;
|
(minimum_cell_y as i32 + cell_y as i32) * vertical_cell_block_count as i32;
|
||||||
let sample_start_z =
|
|
||||||
(self.start_cell_z() + cell_z as i32) * horizontal_cell_block_count as i32;
|
let block_y_base = sample_start_y;
|
||||||
|
let delta_y_step = 1.0 / vertical_cell_block_count as f64;
|
||||||
|
|
||||||
for local_y in (0..vertical_cell_block_count).rev() {
|
for local_y in (0..vertical_cell_block_count).rev() {
|
||||||
let block_y = (minimum_cell_y as i32 + cell_y as i32)
|
let block_y = block_y_base + local_y as i32;
|
||||||
* vertical_cell_block_count as i32
|
let delta_y = local_y as f64 * delta_y_step;
|
||||||
+ local_y as i32;
|
|
||||||
let delta_y = local_y as f64 / vertical_cell_block_count as f64;
|
|
||||||
self.noise_sampler.interpolate_y(delta_y);
|
self.noise_sampler.interpolate_y(delta_y);
|
||||||
|
|
||||||
|
let block_x_base =
|
||||||
|
start_block_x + cell_x as i32 * horizontal_cell_block_count as i32;
|
||||||
|
let delta_x_step = 1.0 / horizontal_cell_block_count as f64;
|
||||||
|
|
||||||
for local_x in 0..horizontal_cell_block_count {
|
for local_x in 0..horizontal_cell_block_count {
|
||||||
let block_x = self.start_block_x()
|
let block_x = block_x_base + local_x as i32;
|
||||||
+ cell_x as i32 * horizontal_cell_block_count as i32
|
let delta_x = local_x as f64 * delta_x_step;
|
||||||
+ local_x as i32;
|
|
||||||
let delta_x = local_x as f64 / horizontal_cell_block_count as f64;
|
|
||||||
self.noise_sampler.interpolate_x(delta_x);
|
self.noise_sampler.interpolate_x(delta_x);
|
||||||
|
|
||||||
|
let block_z_base =
|
||||||
|
start_block_z + cell_z as i32 * horizontal_cell_block_count as i32;
|
||||||
|
let delta_z_step = 1.0 / horizontal_cell_block_count as f64;
|
||||||
|
|
||||||
for local_z in 0..horizontal_cell_block_count {
|
for local_z in 0..horizontal_cell_block_count {
|
||||||
let block_z = self.start_block_z()
|
let block_z = block_z_base + local_z as i32;
|
||||||
+ cell_z as i32 * horizontal_cell_block_count as i32
|
let delta_z = local_z as f64 * delta_z_step;
|
||||||
+ local_z as i32;
|
|
||||||
let delta_z = local_z as f64 / horizontal_cell_block_count as f64;
|
|
||||||
self.noise_sampler.interpolate_z(delta_z);
|
self.noise_sampler.interpolate_z(delta_z);
|
||||||
|
|
||||||
// TODO: Can the math here be simplified? Do the above values come
|
// The `cell_offset` calculations are still a good idea for clarity and correctness
|
||||||
// to the same results?
|
// but let's confirm the values.
|
||||||
let cell_offset_x = block_x - sample_start_x;
|
// block_x = start_block_x + cell_x*H + local_x
|
||||||
|
// sample_start_x = start_cell_x*H + cell_x*H = (start_cell_x+cell_x)*H
|
||||||
|
// These can be simplified.
|
||||||
|
let cell_offset_x = local_x as i32;
|
||||||
let cell_offset_y = block_y - sample_start_y;
|
let cell_offset_y = block_y - sample_start_y;
|
||||||
let cell_offset_z = block_z - sample_start_z;
|
let cell_offset_z = local_z as i32;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
{
|
|
||||||
assert!(cell_offset_x >= 0);
|
|
||||||
assert!(cell_offset_y >= 0);
|
|
||||||
assert!(cell_offset_z >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let block_state = self
|
let block_state = self
|
||||||
.noise_sampler
|
.noise_sampler
|
||||||
@ -540,27 +572,10 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.noise_sampler.swap_buffers();
|
self.noise_sampler.swap_buffers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_entities(&self) {
|
|
||||||
let start_x = self.start_block_x();
|
|
||||||
let start_z = self.start_block_z();
|
|
||||||
|
|
||||||
let population_seed =
|
|
||||||
Xoroshiro::get_population_seed(self.random_config.seed, start_x, start_z);
|
|
||||||
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(population_seed));
|
|
||||||
let biome = self.get_biome(&Vector3::new(
|
|
||||||
start_x,
|
|
||||||
self.bottom_section_coord() as i32 + self.height() as i32 - 1,
|
|
||||||
start_z,
|
|
||||||
));
|
|
||||||
while random.next_f32() < biome.creature_spawn_probability {}
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_biome_for_terrain_gen(&self, global_block_pos: &Vector3<i32>) -> &'static Biome {
|
pub fn get_biome_for_terrain_gen(&self, global_block_pos: &Vector3<i32>) -> &'static Biome {
|
||||||
let seed_biome_pos = biome::get_biome_blend(
|
let seed_biome_pos = biome::get_biome_blend(
|
||||||
self.bottom_y(),
|
self.bottom_y(),
|
||||||
@ -582,14 +597,15 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
let min_y = self.bottom_y();
|
let min_y = self.bottom_y();
|
||||||
|
|
||||||
let random = &self.random_config.base_random_deriver;
|
let random = &self.random_config.base_random_deriver;
|
||||||
let mut noise_builder = DoublePerlinNoiseBuilder::new(self.random_config);
|
let noise_builder = DoublePerlinNoiseBuilder::new(self.random_config);
|
||||||
let terrain_builder = SurfaceTerrainBuilder::new(&mut noise_builder, random);
|
|
||||||
let mut context = MaterialRuleContext::new(
|
let mut context = MaterialRuleContext::new(
|
||||||
min_y,
|
min_y,
|
||||||
self.height(),
|
self.height(),
|
||||||
noise_builder,
|
noise_builder,
|
||||||
random,
|
random,
|
||||||
&terrain_builder,
|
&self.terrain_cache.terrain_builder,
|
||||||
|
&self.terrain_cache.surface_noise,
|
||||||
|
&self.terrain_cache.secondary_noise,
|
||||||
);
|
);
|
||||||
for local_x in 0..16 {
|
for local_x in 0..16 {
|
||||||
for local_z in 0..16 {
|
for local_z in 0..16 {
|
||||||
@ -607,7 +623,9 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
|
|
||||||
let this_biome = self.get_biome_for_terrain_gen(&Vector3::new(x, biome_y, z));
|
let this_biome = self.get_biome_for_terrain_gen(&Vector3::new(x, biome_y, z));
|
||||||
if this_biome == &Biome::ERODED_BADLANDS {
|
if this_biome == &Biome::ERODED_BADLANDS {
|
||||||
terrain_builder.place_badlands_pillar(self, x, z, top_block);
|
self.terrain_cache
|
||||||
|
.terrain_builder
|
||||||
|
.place_badlands_pillar(self, x, z, top_block);
|
||||||
// Get the top block again if we placed a pillar!
|
// Get the top block again if we placed a pillar!
|
||||||
|
|
||||||
top_block = self.top_block_height_exclusive(&Vector2::new(local_x, local_z));
|
top_block = self.top_block_height_exclusive(&Vector2::new(local_x, local_z));
|
||||||
@ -678,7 +696,7 @@ impl<'a> ProtoChunk<'a> {
|
|||||||
&mut self.surface_height_estimate_sampler,
|
&mut self.surface_height_estimate_sampler,
|
||||||
);
|
);
|
||||||
|
|
||||||
terrain_builder.place_iceberg(
|
self.terrain_cache.terrain_builder.place_iceberg(
|
||||||
self,
|
self,
|
||||||
this_biome,
|
this_biome,
|
||||||
x,
|
x,
|
||||||
@ -787,6 +805,7 @@ mod test {
|
|||||||
density_function::{NoiseFunctionComponentRange, PassThrough},
|
density_function::{NoiseFunctionComponentRange, PassThrough},
|
||||||
proto_noise_router::{ProtoNoiseFunctionComponent, ProtoNoiseRouters},
|
proto_noise_router::{ProtoNoiseFunctionComponent, ProtoNoiseRouters},
|
||||||
},
|
},
|
||||||
|
proto_chunk::TerrainCache,
|
||||||
settings::{GENERATION_SETTINGS, GeneratorSetting},
|
settings::{GENERATION_SETTINGS, GeneratorSetting},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -796,6 +815,8 @@ mod test {
|
|||||||
const SEED: u64 = 0;
|
const SEED: u64 = 0;
|
||||||
static RANDOM_CONFIG: LazyLock<GlobalRandomConfig> =
|
static RANDOM_CONFIG: LazyLock<GlobalRandomConfig> =
|
||||||
LazyLock::new(|| GlobalRandomConfig::new(SEED, false)); // TODO: use legacy when needed
|
LazyLock::new(|| GlobalRandomConfig::new(SEED, false)); // TODO: use legacy when needed
|
||||||
|
static TERRAIN_CACHE: LazyLock<TerrainCache> =
|
||||||
|
LazyLock::new(|| TerrainCache::from_random(&RANDOM_CONFIG));
|
||||||
static BASE_NOISE_ROUTER: LazyLock<ProtoNoiseRouters> =
|
static BASE_NOISE_ROUTER: LazyLock<ProtoNoiseRouters> =
|
||||||
LazyLock::new(|| ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &RANDOM_CONFIG));
|
LazyLock::new(|| ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &RANDOM_CONFIG));
|
||||||
|
|
||||||
@ -847,6 +868,8 @@ mod test {
|
|||||||
&base_router,
|
&base_router,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -904,6 +927,8 @@ mod test {
|
|||||||
&base_router,
|
&base_router,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -961,6 +986,8 @@ mod test {
|
|||||||
&base_router,
|
&base_router,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1018,6 +1045,8 @@ mod test {
|
|||||||
&base_router,
|
&base_router,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1075,6 +1104,8 @@ mod test {
|
|||||||
&base_router,
|
&base_router,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1101,6 +1132,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER,
|
&BASE_NOISE_ROUTER,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1122,6 +1155,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER,
|
&BASE_NOISE_ROUTER,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1143,6 +1178,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER,
|
&BASE_NOISE_ROUTER,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1169,6 +1206,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER,
|
&BASE_NOISE_ROUTER,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1195,6 +1234,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER2,
|
&BASE_NOISE_ROUTER2,
|
||||||
&RANDOM_CONFIG2,
|
&RANDOM_CONFIG2,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1221,6 +1262,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER2,
|
&BASE_NOISE_ROUTER2,
|
||||||
&RANDOM_CONFIG2,
|
&RANDOM_CONFIG2,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
|
|
||||||
@ -1247,6 +1290,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER,
|
&BASE_NOISE_ROUTER,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
@ -1276,6 +1321,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER,
|
&BASE_NOISE_ROUTER,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
@ -1300,11 +1347,14 @@ mod test {
|
|||||||
let surface_config = GENERATION_SETTINGS
|
let surface_config = GENERATION_SETTINGS
|
||||||
.get(&GeneratorSetting::Overworld)
|
.get(&GeneratorSetting::Overworld)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let terrain_cache = TerrainCache::from_random(&RANDOM_CONFIG2);
|
||||||
let mut chunk = ProtoChunk::new(
|
let mut chunk = ProtoChunk::new(
|
||||||
Vector2::new(-6, 11),
|
Vector2::new(-6, 11),
|
||||||
&BASE_NOISE_ROUTER2,
|
&BASE_NOISE_ROUTER2,
|
||||||
&RANDOM_CONFIG2,
|
&RANDOM_CONFIG2,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&terrain_cache,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
@ -1329,11 +1379,15 @@ mod test {
|
|||||||
let surface_config = GENERATION_SETTINGS
|
let surface_config = GENERATION_SETTINGS
|
||||||
.get(&GeneratorSetting::Overworld)
|
.get(&GeneratorSetting::Overworld)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let terrain_cache = TerrainCache::from_random(&RANDOM_CONFIG2);
|
||||||
|
|
||||||
let mut chunk = ProtoChunk::new(
|
let mut chunk = ProtoChunk::new(
|
||||||
Vector2::new(-7, 9),
|
Vector2::new(-7, 9),
|
||||||
&BASE_NOISE_ROUTER2,
|
&BASE_NOISE_ROUTER2,
|
||||||
&RANDOM_CONFIG2,
|
&RANDOM_CONFIG2,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&terrain_cache,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
@ -1358,11 +1412,15 @@ mod test {
|
|||||||
let surface_config = GENERATION_SETTINGS
|
let surface_config = GENERATION_SETTINGS
|
||||||
.get(&GeneratorSetting::Overworld)
|
.get(&GeneratorSetting::Overworld)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let terrain_cache = TerrainCache::from_random(&RANDOM_CONFIG2);
|
||||||
|
|
||||||
let mut chunk = ProtoChunk::new(
|
let mut chunk = ProtoChunk::new(
|
||||||
Vector2::new(-2, 15),
|
Vector2::new(-2, 15),
|
||||||
&BASE_NOISE_ROUTER2,
|
&BASE_NOISE_ROUTER2,
|
||||||
&RANDOM_CONFIG2,
|
&RANDOM_CONFIG2,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&terrain_cache,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
@ -1393,6 +1451,8 @@ mod test {
|
|||||||
&BASE_NOISE_ROUTER,
|
&BASE_NOISE_ROUTER,
|
||||||
&RANDOM_CONFIG,
|
&RANDOM_CONFIG,
|
||||||
surface_config,
|
surface_config,
|
||||||
|
&TERRAIN_CACHE,
|
||||||
|
surface_config.default_block.get_state(),
|
||||||
);
|
);
|
||||||
|
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
|
|||||||
@ -44,8 +44,8 @@ pub struct MaterialRuleContext<'a> {
|
|||||||
last_est_heiht_unique_horizontal_pos_value: i64,
|
last_est_heiht_unique_horizontal_pos_value: i64,
|
||||||
unique_horizontal_pos_value: i64,
|
unique_horizontal_pos_value: i64,
|
||||||
surface_min_y: i32,
|
surface_min_y: i32,
|
||||||
pub surface_noise: DoublePerlinNoiseSampler,
|
pub surface_noise: &'a DoublePerlinNoiseSampler,
|
||||||
pub secondary_noise: DoublePerlinNoiseSampler,
|
pub secondary_noise: &'a DoublePerlinNoiseSampler,
|
||||||
pub stone_depth_below: i32,
|
pub stone_depth_below: i32,
|
||||||
pub stone_depth_above: i32,
|
pub stone_depth_above: i32,
|
||||||
pub terrain_builder: &'a SurfaceTerrainBuilder,
|
pub terrain_builder: &'a SurfaceTerrainBuilder,
|
||||||
@ -55,9 +55,11 @@ impl<'a> MaterialRuleContext<'a> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
min_y: i8,
|
min_y: i8,
|
||||||
height: u16,
|
height: u16,
|
||||||
mut noise_builder: DoublePerlinNoiseBuilder<'a>,
|
noise_builder: DoublePerlinNoiseBuilder<'a>,
|
||||||
random_deriver: &'a RandomDeriver,
|
random_deriver: &'a RandomDeriver,
|
||||||
terrain_builder: &'a SurfaceTerrainBuilder,
|
terrain_builder: &'a SurfaceTerrainBuilder,
|
||||||
|
surface_noise: &'a DoublePerlinNoiseSampler,
|
||||||
|
secondary_noise: &'a DoublePerlinNoiseSampler,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
const HORIZONTAL_POS: i64 = -i64::MAX; // Vanilla
|
const HORIZONTAL_POS: i64 = -i64::MAX; // Vanilla
|
||||||
Self {
|
Self {
|
||||||
@ -76,8 +78,8 @@ impl<'a> MaterialRuleContext<'a> {
|
|||||||
biome: &Biome::PLAINS,
|
biome: &Biome::PLAINS,
|
||||||
run_depth: 0,
|
run_depth: 0,
|
||||||
secondary_depth: 0.0,
|
secondary_depth: 0.0,
|
||||||
surface_noise: noise_builder.get_noise_sampler_for_id("surface"),
|
surface_noise,
|
||||||
secondary_noise: noise_builder.get_noise_sampler_for_id("surface_secondary"),
|
secondary_noise,
|
||||||
noise_builder,
|
noise_builder,
|
||||||
stone_depth_below: 0,
|
stone_depth_below: 0,
|
||||||
stone_depth_above: 0,
|
stone_depth_above: 0,
|
||||||
@ -325,6 +327,7 @@ pub struct NoiseThresholdMaterialCondition {
|
|||||||
|
|
||||||
impl NoiseThresholdMaterialCondition {
|
impl NoiseThresholdMaterialCondition {
|
||||||
pub fn test(&self, context: &mut MaterialRuleContext) -> bool {
|
pub fn test(&self, context: &mut MaterialRuleContext) -> bool {
|
||||||
|
// TODO: we want to cache these
|
||||||
let sampler = context
|
let sampler = context
|
||||||
.noise_builder
|
.noise_builder
|
||||||
.get_noise_sampler_for_id(self.noise.strip_prefix("minecraft:").unwrap());
|
.get_noise_sampler_for_id(self.noise.strip_prefix("minecraft:").unwrap());
|
||||||
|
|||||||
@ -31,7 +31,7 @@ use std::{
|
|||||||
use tokio::{
|
use tokio::{
|
||||||
select,
|
select,
|
||||||
sync::{
|
sync::{
|
||||||
Mutex, Notify, RwLock,
|
Notify, RwLock,
|
||||||
mpsc::{self, UnboundedReceiver},
|
mpsc::{self, UnboundedReceiver},
|
||||||
},
|
},
|
||||||
task::JoinHandle,
|
task::JoinHandle,
|
||||||
@ -73,7 +73,7 @@ pub struct Level {
|
|||||||
/// Semaphore to limit concurrent chunk generation tasks
|
/// Semaphore to limit concurrent chunk generation tasks
|
||||||
//chunk_generation_semaphore: Arc<Semaphore>,
|
//chunk_generation_semaphore: Arc<Semaphore>,
|
||||||
/// Map to deduplicate chunk generation and avoid DashMap write lock
|
/// Map to deduplicate chunk generation and avoid DashMap write lock
|
||||||
chunk_generation_locks: Arc<Mutex<HashMap<Vector2<i32>, Arc<Notify>>>>,
|
//chunk_generation_locks: Arc<Mutex<HashMap<Vector2<i32>, Arc<Notify>>>>,
|
||||||
/// Tracks tasks associated with this world instance
|
/// Tracks tasks associated with this world instance
|
||||||
tasks: TaskTracker,
|
tasks: TaskTracker,
|
||||||
/// Notification that interrupts tasks for shutdown
|
/// Notification that interrupts tasks for shutdown
|
||||||
@ -155,7 +155,7 @@ impl Level {
|
|||||||
shutdown_notifier: Notify::new(),
|
shutdown_notifier: Notify::new(),
|
||||||
// Limits concurrent chunk generation tasks to 2x the number of CPUs
|
// Limits concurrent chunk generation tasks to 2x the number of CPUs
|
||||||
//chunk_generation_semaphore: Arc::new(Semaphore::new(num_cpus::get())),
|
//chunk_generation_semaphore: Arc::new(Semaphore::new(num_cpus::get())),
|
||||||
chunk_generation_locks: Arc::new(Mutex::new(HashMap::new())),
|
//chunk_generation_locks: Arc::new(Mutex::new(HashMap::new())),
|
||||||
world_gen_pool: Arc::new(
|
world_gen_pool: Arc::new(
|
||||||
ThreadPoolBuilder::new()
|
ThreadPoolBuilder::new()
|
||||||
//.num_threads((num_cpus::get() - 1).min(1))
|
//.num_threads((num_cpus::get() - 1).min(1))
|
||||||
@ -785,83 +785,81 @@ impl Level {
|
|||||||
let block_registry = block_registry.clone();
|
let block_registry = block_registry.clone();
|
||||||
let self_clone = self_clone.clone();
|
let self_clone = self_clone.clone();
|
||||||
|
|
||||||
let notify = {
|
// let notify = {
|
||||||
let mut locks = self_clone.chunk_generation_locks.lock().await;
|
// let mut locks = self_clone.chunk_generation_locks.lock().await;
|
||||||
if let Some(existing) = locks.get(&pos) {
|
// if let Some(existing) = locks.get(&pos) {
|
||||||
Some(existing.clone())
|
// Some(existing.clone())
|
||||||
} else {
|
// } else {
|
||||||
let notify = Arc::new(Notify::new());
|
// let notify = Arc::new(Notify::new());
|
||||||
locks.insert(pos, notify.clone());
|
// locks.insert(pos, notify.clone());
|
||||||
None
|
// None
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// if let Some(notify) = notify {
|
||||||
|
// // Wait for the chunk to be generated by another task
|
||||||
|
// notify.notified().await;
|
||||||
|
// // After being notified, the chunk should be in loaded_chunks
|
||||||
|
// // However, it might have been unloaded between notification and access
|
||||||
|
// if let Some(chunk) = loaded_chunks.get(&pos) {
|
||||||
|
// let chunk = chunk.clone();
|
||||||
|
// if !send_chunk(true, chunk, &channel) {
|
||||||
|
// // Stop any additional queued generations
|
||||||
|
// cloned_continue_to_generate.store(false, Ordering::Relaxed);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// // Chunk was unloaded after notification, skip this iteration
|
||||||
|
// // The chunk generation will be retried if needed
|
||||||
|
// log::info!("Chunk at {pos:?} was unloaded after generation notification");
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
//let _permit = chunk_generation_semaphore
|
||||||
|
// .acquire()
|
||||||
|
// .await
|
||||||
|
// .expect("Semaphore closed");
|
||||||
|
// let handle = tokio::runtime::Handle::current();
|
||||||
|
world_gen_pool.spawn(move || {
|
||||||
|
// Acquire a permit from the semaphore to limit concurrent generation
|
||||||
|
|
||||||
|
// Rayon tasks are queued, so also check it here
|
||||||
|
if !cloned_continue_to_generate.load(Ordering::Relaxed) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(notify) = notify {
|
let result = {
|
||||||
// Wait for the chunk to be generated by another task
|
// Deduplicate chunk generation using chunk_generation_locks
|
||||||
notify.notified().await;
|
|
||||||
// After being notified, the chunk should be in loaded_chunks
|
// We are responsible for generating the chunk
|
||||||
// However, it might have been unloaded between notification and access
|
let mut generated_chunk =
|
||||||
if let Some(chunk) = loaded_chunks.get(&pos) {
|
world_gen.generate_chunk(&self_clone, block_registry.as_ref(), &pos);
|
||||||
let chunk = chunk.clone();
|
generated_chunk.heightmap = generated_chunk.calculate_heightmap();
|
||||||
if !send_chunk(true, chunk, &channel) {
|
let arc_chunk = Arc::new(RwLock::new(generated_chunk));
|
||||||
// Stop any additional queued generations
|
loaded_chunks.insert(pos, arc_chunk.clone());
|
||||||
cloned_continue_to_generate.store(false, Ordering::Relaxed);
|
|
||||||
}
|
// Store the notify for later removal
|
||||||
} else {
|
(arc_chunk, pos)
|
||||||
// Chunk was unloaded after notification, skip this iteration
|
};
|
||||||
// The chunk generation will be retried if needed
|
|
||||||
log::info!("Chunk at {pos:?} was unloaded after generation notification");
|
// TODO: this is slow and causes dead locks
|
||||||
|
// Remove the notify and wake up any waiters
|
||||||
|
// Do this outside the rayon thread to avoid deadlock
|
||||||
|
// let (arc_chunk, pos) = result;
|
||||||
|
// {
|
||||||
|
// let self_clone = self_clone.clone();
|
||||||
|
// handle.spawn(async move {
|
||||||
|
// let mut locks = self_clone.chunk_generation_locks.lock().await;
|
||||||
|
// if let Some(notify) = locks.remove(&pos) {
|
||||||
|
// notify.notify_waiters();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
if !send_chunk(true, result.0, &channel) {
|
||||||
|
// Stop any additional queued generations
|
||||||
|
cloned_continue_to_generate.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
//let _permit = chunk_generation_semaphore
|
//}
|
||||||
// .acquire()
|
|
||||||
// .await
|
|
||||||
// .expect("Semaphore closed");
|
|
||||||
let handle = tokio::runtime::Handle::current();
|
|
||||||
world_gen_pool.spawn(move || {
|
|
||||||
// Acquire a permit from the semaphore to limit concurrent generation
|
|
||||||
|
|
||||||
// Rayon tasks are queued, so also check it here
|
|
||||||
if !cloned_continue_to_generate.load(Ordering::Relaxed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = {
|
|
||||||
// Deduplicate chunk generation using chunk_generation_locks
|
|
||||||
|
|
||||||
// We are responsible for generating the chunk
|
|
||||||
let mut generated_chunk = world_gen.generate_chunk(
|
|
||||||
&self_clone,
|
|
||||||
block_registry.as_ref(),
|
|
||||||
&pos,
|
|
||||||
);
|
|
||||||
generated_chunk.heightmap = generated_chunk.calculate_heightmap();
|
|
||||||
let arc_chunk = Arc::new(RwLock::new(generated_chunk));
|
|
||||||
loaded_chunks.insert(pos, arc_chunk.clone());
|
|
||||||
|
|
||||||
// Store the notify for later removal
|
|
||||||
(arc_chunk, pos)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove the notify and wake up any waiters
|
|
||||||
// Do this outside the rayon thread to avoid deadlock
|
|
||||||
let (arc_chunk, pos) = result;
|
|
||||||
{
|
|
||||||
let self_clone = self_clone.clone();
|
|
||||||
handle.spawn(async move {
|
|
||||||
let mut locks = self_clone.chunk_generation_locks.lock().await;
|
|
||||||
if let Some(notify) = locks.remove(&pos) {
|
|
||||||
notify.notify_waiters();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if !send_chunk(true, arc_chunk, &channel) {
|
|
||||||
// Stop any additional queued generations
|
|
||||||
cloned_continue_to_generate.store(false, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -922,6 +920,7 @@ impl Level {
|
|||||||
|
|
||||||
let load_channel = channel.clone();
|
let load_channel = channel.clone();
|
||||||
let loaded_chunks = self.loaded_entity_chunks.clone();
|
let loaded_chunks = self.loaded_entity_chunks.clone();
|
||||||
|
let world_gen_pool = self.world_gen_pool.clone();
|
||||||
let handle_load = async move {
|
let handle_load = async move {
|
||||||
while let Some(data) = load_bridge_recv.recv().await {
|
while let Some(data) = load_bridge_recv.recv().await {
|
||||||
let is_ok = match data {
|
let is_ok = match data {
|
||||||
@ -977,7 +976,7 @@ impl Level {
|
|||||||
let cloned_continue_to_generate = continue_to_generate.clone();
|
let cloned_continue_to_generate = continue_to_generate.clone();
|
||||||
//let semaphore = chunk_generation_semaphore.clone();
|
//let semaphore = chunk_generation_semaphore.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
world_gen_pool.spawn(move || {
|
||||||
// Acquire a permit from the semaphore to limit concurrent generation
|
// Acquire a permit from the semaphore to limit concurrent generation
|
||||||
//let _permit = semaphore.acquire().await.expect("Semaphore closed");
|
//let _permit = semaphore.acquire().await.expect("Semaphore closed");
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use dimension::Dimension;
|
use dimension::Dimension;
|
||||||
use generation::settings::GenerationSettings;
|
use generation::settings::GenerationSettings;
|
||||||
|
use pumpkin_data::BlockState;
|
||||||
use pumpkin_util::math::vector2::Vector2;
|
use pumpkin_util::math::vector2::Vector2;
|
||||||
|
|
||||||
pub mod biome;
|
pub mod biome;
|
||||||
@ -43,12 +44,23 @@ pub use generation::{
|
|||||||
GlobalRandomConfig, noise_router::proto_noise_router::ProtoNoiseRouters,
|
GlobalRandomConfig, noise_router::proto_noise_router::ProtoNoiseRouters,
|
||||||
proto_chunk::ProtoChunk, settings::GENERATION_SETTINGS, settings::GeneratorSetting,
|
proto_chunk::ProtoChunk, settings::GENERATION_SETTINGS, settings::GeneratorSetting,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::generation::proto_chunk::TerrainCache;
|
||||||
pub fn bench_create_and_populate_noise(
|
pub fn bench_create_and_populate_noise(
|
||||||
base_router: &ProtoNoiseRouters,
|
base_router: &ProtoNoiseRouters,
|
||||||
random_config: &GlobalRandomConfig,
|
random_config: &GlobalRandomConfig,
|
||||||
settings: &GenerationSettings,
|
settings: &GenerationSettings,
|
||||||
|
terrain_cache: &TerrainCache,
|
||||||
|
default_block: &'static BlockState,
|
||||||
) {
|
) {
|
||||||
let mut chunk = ProtoChunk::new(Vector2::new(0, 0), base_router, random_config, settings);
|
let mut chunk = ProtoChunk::new(
|
||||||
|
Vector2::new(0, 0),
|
||||||
|
base_router,
|
||||||
|
random_config,
|
||||||
|
settings,
|
||||||
|
terrain_cache,
|
||||||
|
default_block,
|
||||||
|
);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +68,17 @@ pub fn bench_create_and_populate_biome(
|
|||||||
base_router: &ProtoNoiseRouters,
|
base_router: &ProtoNoiseRouters,
|
||||||
random_config: &GlobalRandomConfig,
|
random_config: &GlobalRandomConfig,
|
||||||
settings: &GenerationSettings,
|
settings: &GenerationSettings,
|
||||||
|
terrain_cache: &TerrainCache,
|
||||||
|
default_block: &'static BlockState,
|
||||||
) {
|
) {
|
||||||
let mut chunk = ProtoChunk::new(Vector2::new(0, 0), base_router, random_config, settings);
|
let mut chunk = ProtoChunk::new(
|
||||||
|
Vector2::new(0, 0),
|
||||||
|
base_router,
|
||||||
|
random_config,
|
||||||
|
settings,
|
||||||
|
terrain_cache,
|
||||||
|
default_block,
|
||||||
|
);
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +86,17 @@ pub fn bench_create_and_populate_noise_with_surface(
|
|||||||
base_router: &ProtoNoiseRouters,
|
base_router: &ProtoNoiseRouters,
|
||||||
random_config: &GlobalRandomConfig,
|
random_config: &GlobalRandomConfig,
|
||||||
settings: &GenerationSettings,
|
settings: &GenerationSettings,
|
||||||
|
terrain_cache: &TerrainCache,
|
||||||
|
default_block: &'static BlockState,
|
||||||
) {
|
) {
|
||||||
let mut chunk = ProtoChunk::new(Vector2::new(0, 0), base_router, random_config, settings);
|
let mut chunk = ProtoChunk::new(
|
||||||
|
Vector2::new(0, 0),
|
||||||
|
base_router,
|
||||||
|
random_config,
|
||||||
|
settings,
|
||||||
|
terrain_cache,
|
||||||
|
default_block,
|
||||||
|
);
|
||||||
chunk.populate_biomes(Dimension::Overworld);
|
chunk.populate_biomes(Dimension::Overworld);
|
||||||
chunk.populate_noise();
|
chunk.populate_noise();
|
||||||
chunk.build_surface();
|
chunk.build_surface();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user