fix: tests

This commit is contained in:
Alexander Medvedev 2026-04-29 23:18:24 +02:00
parent 427df56935
commit 1d671504d1
12 changed files with 369 additions and 420 deletions

View File

@ -231,14 +231,15 @@ pub trait RandomDeriverImpl {
/// # Returns /// # Returns
/// A 64-bit hash value. /// A 64-bit hash value.
#[must_use] #[must_use]
pub fn hash_block_pos(x: i32, y: i32, z: i32) -> i64 { pub const fn hash_block_pos(x: i32, y: i32, z: i32) -> i64 {
let l = i64::from(x.wrapping_mul(3129871)) let l =
^ (i64::from(z).wrapping_mul(116129781i64)) ((x.wrapping_mul(3129871)) as i64) ^ ((z as i64).wrapping_mul(116129781i64)) ^ (y as i64);
^ i64::from(y);
let l = l let l = l
.wrapping_mul(l) .wrapping_mul(l)
.wrapping_mul(42317861i64) .wrapping_mul(42317861i64)
.wrapping_add(l.wrapping_mul(11i64)); .wrapping_add(l.wrapping_mul(11i64));
l >> 16 l >> 16
} }

View File

@ -240,7 +240,7 @@ impl XoroshiroSplitter {
} }
#[must_use] #[must_use]
pub fn split_pos(&self, x: i32, y: i32, z: i32) -> Xoroshiro { pub const fn split_pos(&self, x: i32, y: i32, z: i32) -> Xoroshiro {
let l = hash_block_pos(x, y, z) as u64; let l = hash_block_pos(x, y, z) as u64;
let m = l ^ self.lo; let m = l ^ self.lo;

View File

@ -51,19 +51,15 @@ pub fn hash_seed(seed: u64) -> i64 {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use pumpkin_data::{ use pumpkin_data::{chunk::Biome, dimension::Dimension};
chunk::Biome, chunk_gen_settings::GenerationSettings, dimension::Dimension,
noise_router::OVERWORLD_BASE_NOISE_ROUTER,
};
use pumpkin_util::read_data_from_file; use pumpkin_util::read_data_from_file;
use serde::Deserialize; use serde::Deserialize;
use crate::{ use crate::{
GlobalRandomConfig, ProtoChunk, ProtoChunk,
chunk::palette::BIOME_NETWORK_MAX_BITS, chunk::palette::BIOME_NETWORK_MAX_BITS,
generation::noise::router::{ generation::noise::router::multi_noise_sampler::{
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions}, MultiNoiseSampler, MultiNoiseSamplerBuilderOptions,
proto_noise_router::ProtoNoiseRouters,
}, },
}; };
@ -71,20 +67,19 @@ mod test {
#[test] #[test]
fn biome_desert() { fn biome_desert() {
use crate::generation::generator::{GeneratorInit, VanillaGenerator};
use pumpkin_util::world_seed::Seed;
let seed = 13579; let seed = 13579;
let random_config = GlobalRandomConfig::new(seed, false); let generator = VanillaGenerator::new(Seed(seed as u64), Dimension::OVERWORLD);
let noise_router =
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(1, 1, 1); let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(1, 1, 1);
let mut sampler = let mut sampler =
MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config); MultiNoiseSampler::generate(&generator.base_router.multi_noise, &multi_noise_config);
let biome = MultiNoiseBiomeSupplier::OVERWORLD.biome(-24, 1, 8, &mut sampler); let biome = MultiNoiseBiomeSupplier::OVERWORLD.biome(-24, 1, 8, &mut sampler);
assert_eq!(biome, &Biome::DESERT); assert_eq!(biome, &Biome::DESERT);
} }
#[test] #[test]
fn wide_area_surface() { fn wide_area_surface() {
use crate::biome::hash_seed;
use crate::generation::noise::router::multi_noise_sampler::{ use crate::generation::noise::router::multi_noise_sampler::{
MultiNoiseSampler, MultiNoiseSamplerBuilderOptions, MultiNoiseSampler, MultiNoiseSamplerBuilderOptions,
}; };
@ -100,28 +95,15 @@ mod test {
read_data_from_file!("../../assets/biome_no_blend_no_beard_0.json"); read_data_from_file!("../../assets/biome_no_blend_no_beard_0.json");
let seed = 0; let seed = 0;
let random_config = GlobalRandomConfig::new(seed, false); use crate::generation::generator::{GeneratorInit, VanillaGenerator};
let noise_router = use pumpkin_util::world_seed::Seed;
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config); let generator = VanillaGenerator::new(Seed(seed as u64), Dimension::OVERWORLD);
let surface_settings = GenerationSettings::from_dimension(&Dimension::OVERWORLD);
//let _terrain_cache = TerrainCache::from_random(&random_config);
let default_block = surface_settings.default_block;
for data in expected_data { for data in expected_data {
let chunk_x = data.x; let chunk_x = data.x;
let chunk_z = data.z; let chunk_z = data.z;
// Calculate biome mixer seed let mut chunk = ProtoChunk::new(chunk_x, chunk_z, &generator);
let biome_mixer_seed = hash_seed(random_config.seed);
let mut chunk = ProtoChunk::new(
chunk_x,
chunk_z,
&Dimension::OVERWORLD,
default_block,
biome_mixer_seed,
);
// Create MultiNoiseSampler for populate_biomes // Create MultiNoiseSampler for populate_biomes
@ -134,10 +116,12 @@ mod test {
biome_coords::from_block(start_z), biome_coords::from_block(start_z),
horizontal_biome_end as usize, horizontal_biome_end as usize,
); );
let mut multi_noise_sampler = let mut multi_noise_sampler = MultiNoiseSampler::generate(
MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config); &generator.base_router.multi_noise,
&multi_noise_config,
);
chunk.populate_biomes(Dimension::OVERWORLD, &mut multi_noise_sampler); chunk.populate_biomes(&generator, &mut multi_noise_sampler);
for (biome_x, biome_y, biome_z, biome_id) in data.data { for (biome_x, biome_y, biome_z, biome_id) in data.data {
let calculated_biome = chunk.get_biome(biome_x, biome_y, biome_z); let calculated_biome = chunk.get_biome(biome_x, biome_y, biome_z);

View File

@ -32,31 +32,25 @@ impl NoiseValuePoint {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use pumpkin_data::{ use pumpkin_data::{chunk::Biome, dimension::Dimension};
chunk::Biome, chunk_gen_settings::GenerationSettings, dimension::Dimension,
noise_router::OVERWORLD_BASE_NOISE_ROUTER,
};
use pumpkin_util::read_data_from_file; use pumpkin_util::read_data_from_file;
use crate::{ use crate::{
GlobalRandomConfig, ProtoChunk, ProtoChunk,
biome::{BiomeSupplier, MultiNoiseBiomeSupplier}, biome::{BiomeSupplier, MultiNoiseBiomeSupplier},
generation::{ generation::noise::router::multi_noise_sampler::{
noise::router::{ MultiNoiseSampler, MultiNoiseSamplerBuilderOptions,
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
proto_noise_router::ProtoNoiseRouters,
},
proto_chunk::TerrainCache,
}, },
}; };
#[test] #[test]
fn sample_value() { fn sample_value() {
use crate::biome::hash_seed; use crate::generation::generator::{GeneratorInit, VanillaGenerator};
use crate::generation::noise::router::multi_noise_sampler::{ use crate::generation::noise::router::multi_noise_sampler::{
MultiNoiseSampler, MultiNoiseSamplerBuilderOptions, MultiNoiseSampler, MultiNoiseSamplerBuilderOptions,
}; };
use crate::generation::{biome_coords, positions::chunk_pos}; use crate::generation::{biome_coords, positions::chunk_pos};
use pumpkin_util::world_seed::Seed;
type PosToPoint = (i32, i32, i32, i64, i64, i64, i64, i64, i64); type PosToPoint = (i32, i32, i32, i64, i64, i64, i64, i64, i64);
let expected_data: Vec<PosToPoint> = let expected_data: Vec<PosToPoint> =
read_data_from_file!("../../assets/multi_noise_sample_no_blend_no_beard_0_0_0.json"); read_data_from_file!("../../assets/multi_noise_sample_no_blend_no_beard_0_0_0.json");
@ -65,23 +59,9 @@ mod test {
let chunk_x = 0; let chunk_x = 0;
let chunk_z = 0; let chunk_z = 0;
let random_config = GlobalRandomConfig::new(seed, false); let generator = VanillaGenerator::new(Seed(seed as u64), Dimension::OVERWORLD);
let noise_router =
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
let surface_config = GenerationSettings::from_dimension(&Dimension::OVERWORLD); let _chunk = ProtoChunk::new(chunk_x, chunk_z, &generator);
let _terrain_cache = TerrainCache::from_random(&random_config);
// Calculate biome mixer seed
let biome_mixer_seed = hash_seed(random_config.seed);
let _chunk = ProtoChunk::new(
chunk_x,
chunk_z,
&Dimension::OVERWORLD,
surface_config.default_block,
biome_mixer_seed,
);
let start_x = chunk_pos::start_block_x(chunk_x); let start_x = chunk_pos::start_block_x(chunk_x);
let start_z = chunk_pos::start_block_z(chunk_z); let start_z = chunk_pos::start_block_z(chunk_z);
@ -92,7 +72,7 @@ mod test {
horizontal_biome_end as usize, horizontal_biome_end as usize,
); );
let mut multi_noise_sampler = let mut multi_noise_sampler =
MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config); MultiNoiseSampler::generate(&generator.base_router.multi_noise, &multi_noise_config);
for (x, y, z, tem, hum, con, ero, dep, wei) in expected_data { for (x, y, z, tem, hum, con, ero, dep, wei) in expected_data {
let point = multi_noise_sampler.sample(x, y, z); let point = multi_noise_sampler.sample(x, y, z);
@ -107,16 +87,17 @@ mod test {
#[test] #[test]
fn sample_multinoise_biome() { fn sample_multinoise_biome() {
use crate::generation::generator::{GeneratorInit, VanillaGenerator};
use pumpkin_util::world_seed::Seed;
let expected_data: Vec<(i32, i32, i32, u8)> = let expected_data: Vec<(i32, i32, i32, u8)> =
read_data_from_file!("../../assets/multi_noise_biome_source_test.json"); read_data_from_file!("../../assets/multi_noise_biome_source_test.json");
let seed = 0; let seed = 0;
let random_config = GlobalRandomConfig::new(seed, false); let generator = VanillaGenerator::new(Seed(seed as u64), Dimension::OVERWORLD);
let noise_router =
ProtoNoiseRouters::generate(&OVERWORLD_BASE_NOISE_ROUTER, &random_config);
let mut sampler = MultiNoiseSampler::generate( let mut sampler = MultiNoiseSampler::generate(
&noise_router.multi_noise, &generator.base_router.multi_noise,
&MultiNoiseSamplerBuilderOptions::new(0, 0, 4), &MultiNoiseSamplerBuilderOptions::new(0, 0, 4),
); );

View File

@ -1,4 +1,3 @@
use pumpkin_data::chunk_gen_settings::GenerationSettings;
use pumpkin_data::dimension::Dimension; use pumpkin_data::dimension::Dimension;
use crate::ProtoChunk; use crate::ProtoChunk;
@ -9,15 +8,14 @@ use pumpkin_config::lighting::LightingEngineConfig;
use super::{Cache, Chunk, StagedChunkEnum}; use super::{Cache, Chunk, StagedChunkEnum};
pub fn generate_single_chunk( pub fn generate_single_chunk(
dimension: &Dimension, _dimension: &Dimension,
biome_mixer_seed: i64, _biome_mixer_seed: i64,
generator: &VanillaGenerator, generator: &VanillaGenerator,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn BlockRegistryExt,
chunk_x: i32, chunk_x: i32,
chunk_z: i32, chunk_z: i32,
target_stage: StagedChunkEnum, target_stage: StagedChunkEnum,
) -> Chunk { ) -> Chunk {
let settings = GenerationSettings::from_dimension(dimension);
let radius = target_stage.get_direct_radius(); let radius = target_stage.get_direct_radius();
let mut cache = Cache::new(chunk_x - radius, chunk_z - radius, radius * 2 + 1); let mut cache = Cache::new(chunk_x - radius, chunk_z - radius, radius * 2 + 1);
@ -27,13 +25,7 @@ pub fn generate_single_chunk(
let new_x = chunk_x + dx; let new_x = chunk_x + dx;
let new_z = chunk_z + dz; let new_z = chunk_z + dz;
let proto_chunk = Box::new(ProtoChunk::new( let proto_chunk = Box::new(ProtoChunk::new(new_x, new_z, generator));
new_x,
new_z,
dimension,
generator.default_block,
biome_mixer_seed,
));
cache.chunks.push(Chunk::Proto(proto_chunk)); cache.chunks.push(Chunk::Proto(proto_chunk));
} }
@ -57,14 +49,9 @@ pub fn generate_single_chunk(
cache.advance( cache.advance(
stage, stage,
&LightingEngineConfig::Default, generator,
block_registry, block_registry,
settings, &LightingEngineConfig::Default,
&generator.random_config,
&generator.terrain_cache,
&generator.base_router,
*dimension,
&generator.global_structure_cache,
); );
} }

View File

@ -1,16 +1,14 @@
use super::chunk_state::{Chunk, StagedChunkEnum}; use super::chunk_state::{Chunk, StagedChunkEnum};
use crate::block::RawBlockState; use crate::block::RawBlockState;
use crate::chunk::ChunkHeightmapType; use crate::chunk::ChunkHeightmapType;
use crate::generation::generator;
use crate::generation::height_limit::HeightLimitView; use crate::generation::height_limit::HeightLimitView;
use crate::generation::proto_chunk::{GenerationCache, TerrainCache}; use crate::generation::proto_chunk::GenerationCache;
use crate::generation::structure::placement::GlobalStructureCache;
use crate::world::{BlockAccessor, BlockRegistryExt}; use crate::world::{BlockAccessor, BlockRegistryExt};
use crate::{BlockStateId, GlobalRandomConfig, ProtoChunk, ProtoNoiseRouters}; use crate::{BlockStateId, ProtoChunk};
use pumpkin_config::lighting::LightingEngineConfig; use pumpkin_config::lighting::LightingEngineConfig;
use pumpkin_data::biome::Biome; use pumpkin_data::biome::Biome;
use pumpkin_data::block_properties::is_air; use pumpkin_data::block_properties::is_air;
use pumpkin_data::chunk_gen_settings::GenerationSettings;
use pumpkin_data::dimension::Dimension;
use pumpkin_data::fluid::{Fluid, FluidState}; use pumpkin_data::fluid::{Fluid, FluidState};
use pumpkin_data::{Block, BlockState}; use pumpkin_data::{Block, BlockState};
use pumpkin_nbt::compound::NbtCompound; use pumpkin_nbt::compound::NbtCompound;
@ -340,54 +338,41 @@ impl Cache {
chunks: Vec::with_capacity((size * size) as usize), chunks: Vec::with_capacity((size * size) as usize),
} }
} }
#[expect(clippy::too_many_arguments)]
pub fn advance( pub fn advance(
&mut self, &mut self,
stage: StagedChunkEnum, stage: StagedChunkEnum,
lighting_config: &LightingEngineConfig, generator: &generator::VanillaGenerator,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn BlockRegistryExt,
settings: &GenerationSettings, lighting_config: &LightingEngineConfig,
random_config: &GlobalRandomConfig,
terrain_cache: &TerrainCache,
noise_router: &ProtoNoiseRouters,
dimension: Dimension,
global_structure_cache: &GlobalStructureCache, // <--- NEW PARAMETER HERE
) { ) {
let mid = ((self.size * self.size) >> 1) as usize; let mid = ((self.size * self.size) >> 1) as usize;
match stage { match stage {
StagedChunkEnum::Empty => panic!("empty stage"), StagedChunkEnum::Empty => panic!("empty stage"),
StagedChunkEnum::StructureStart => { StagedChunkEnum::StructureStart => {
self.chunks[mid].get_proto_chunk_mut().set_structure_starts( self.chunks[mid]
random_config,
settings,
global_structure_cache,
);
}
StagedChunkEnum::StructureReferences => self.chunks[mid]
.get_proto_chunk_mut() .get_proto_chunk_mut()
.set_structure_references( .set_structure_starts(generator);
random_config, }
settings, StagedChunkEnum::StructureReferences => {
&dimension, self.chunks[mid]
noise_router, .get_proto_chunk_mut()
global_structure_cache, .set_structure_references(generator);
), // <--- PASSED HERE }
StagedChunkEnum::Biomes => self.chunks[mid] StagedChunkEnum::Biomes => self.chunks[mid]
.get_proto_chunk_mut() .get_proto_chunk_mut()
.step_to_biomes(dimension, noise_router), .step_to_biomes(generator),
StagedChunkEnum::Noise => self.chunks[mid].get_proto_chunk_mut().step_to_noise( StagedChunkEnum::Noise => self.chunks[mid]
settings, .get_proto_chunk_mut()
random_config, .step_to_noise(generator),
noise_router, StagedChunkEnum::Surface => self.chunks[mid]
), .get_proto_chunk_mut()
StagedChunkEnum::Surface => self.chunks[mid].get_proto_chunk_mut().step_to_surface( .step_to_surface(generator),
settings,
random_config,
terrain_cache,
noise_router,
),
StagedChunkEnum::Features => { StagedChunkEnum::Features => {
ProtoChunk::generate_features_and_structure(self, block_registry, random_config); ProtoChunk::generate_features_and_structure(
self,
block_registry,
&generator.random_config,
);
} }
StagedChunkEnum::Lighting => { StagedChunkEnum::Lighting => {
let mut engine = crate::lighting::LightEngine::new(); let mut engine = crate::lighting::LightEngine::new();
@ -405,7 +390,7 @@ impl Cache {
let chunk = self.chunks[mid].get_proto_chunk_mut(); let chunk = self.chunks[mid].get_proto_chunk_mut();
debug_assert_eq!(chunk.stage, StagedChunkEnum::Lighting); debug_assert_eq!(chunk.stage, StagedChunkEnum::Lighting);
chunk.stage = StagedChunkEnum::Full; chunk.stage = StagedChunkEnum::Full;
self.chunks[mid].upgrade_to_level_chunk(&dimension, lighting_config); self.chunks[mid].upgrade_to_level_chunk(&generator.dimension, lighting_config);
} }
StagedChunkEnum::None => {} StagedChunkEnum::None => {}
} }

View File

@ -59,10 +59,7 @@ pub async fn io_read_work(
level: Arc<Level>, level: Arc<Level>,
lock: IOLock, lock: IOLock,
) { ) {
use crate::biome::hash_seed;
debug!("io read thread start"); debug!("io read thread start");
let biome_mixer_seed = hash_seed(level.world_gen.random_config.seed);
let dimension = &level.world_gen.dimension;
// Cleaner loop and async recv // Cleaner loop and async recv
while let Ok(batch) = recv.recv().await { while let Ok(batch) = recv.recv().await {
@ -108,12 +105,7 @@ pub async fn io_read_work(
); );
// Create ProtoChunk using the async method // Create ProtoChunk using the async method
let mut proto = ProtoChunk::from_chunk_data( let mut proto = ProtoChunk::from_chunk_data(&chunk, &level.world_gen);
&chunk,
dimension,
level.world_gen.default_block,
biome_mixer_seed,
);
// Clear all lighting data // Clear all lighting data
let section_count = proto.light.sky_light.len(); let section_count = proto.light.sky_light.len();
@ -144,13 +136,9 @@ pub async fn io_read_work(
} }
} else { } else {
// Standard ProtoChunk handling for non-full chunks // Standard ProtoChunk handling for non-full chunks
let val = let val = RecvChunk::IO(Chunk::Proto(Box::new(
RecvChunk::IO(Chunk::Proto(Box::new(ProtoChunk::from_chunk_data( ProtoChunk::from_chunk_data(&chunk, &level.world_gen),
&chunk, )));
dimension,
level.world_gen.default_block,
biome_mixer_seed,
))));
if send.send((pos, val)).is_err() { if send.send((pos, val)).is_err() {
break; break;
} }
@ -163,9 +151,7 @@ pub async fn io_read_work(
RecvChunk::IO(Chunk::Proto(Box::new(ProtoChunk::new( RecvChunk::IO(Chunk::Proto(Box::new(ProtoChunk::new(
pos.x, pos.x,
pos.y, pos.y,
dimension, &level.world_gen,
level.world_gen.default_block,
biome_mixer_seed,
)))), )))),
)) ))
.is_err() .is_err()
@ -241,20 +227,15 @@ pub fn run_generation(
mut cache: Cache, mut cache: Cache,
stage: StagedChunkEnum, stage: StagedChunkEnum,
level: &Level, level: &Level,
settings: &GenerationSettings, _settings: &GenerationSettings,
) -> RecvChunk { ) -> RecvChunk {
// Run generation with panic catching // Run generation with panic catching
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
cache.advance( cache.advance(
stage, stage,
&level.lighting_config, &level.world_gen,
level.block_registry.as_ref(), level.block_registry.as_ref(),
settings, &level.lighting_config,
&level.world_gen.random_config,
&level.world_gen.terrain_cache,
&level.world_gen.base_router,
level.world_gen.dimension,
&level.world_gen.global_structure_cache,
); );
cache // Return cache on success cache // Return cache on success
})); }));

View File

@ -15,23 +15,29 @@ pub trait GeneratorInit {
fn new(seed: Seed, dimension: Dimension) -> Self; fn new(seed: Seed, dimension: Dimension) -> Self;
} }
use pumpkin_data::structures::{StructurePlacementCalculator, StructureSet};
use rustc_hash::FxHashMap;
pub struct VanillaGenerator { pub struct VanillaGenerator {
pub random_config: GlobalRandomConfig, pub random_config: GlobalRandomConfig,
pub base_router: ProtoNoiseRouters, pub base_router: ProtoNoiseRouters,
pub dimension: Dimension, pub dimension: Dimension,
pub settings: &'static GenerationSettings,
pub biome_mixer_seed: i64,
pub terrain_cache: TerrainCache, pub terrain_cache: TerrainCache,
pub default_block: &'static BlockState, pub default_block: &'static BlockState,
pub global_structure_cache: crate::generation::structure::placement::GlobalStructureCache, pub global_structure_cache: crate::generation::structure::placement::GlobalStructureCache,
pub structure_calculator: StructurePlacementCalculator,
pub structure_allowed_biomes: FxHashMap<usize, Vec<u16>>,
} }
impl GeneratorInit for VanillaGenerator { impl GeneratorInit for VanillaGenerator {
fn new(seed: Seed, dimension: Dimension) -> Self { fn new(seed: Seed, dimension: Dimension) -> Self {
let generation_settings = GenerationSettings::from_dimension(&dimension); let settings = GenerationSettings::from_dimension(&dimension);
let random_config = let random_config = GlobalRandomConfig::new(seed.0, settings.legacy_random_source);
GlobalRandomConfig::new(seed.0, generation_settings.legacy_random_source);
// 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?
@ -46,16 +52,30 @@ impl GeneratorInit for VanillaGenerator {
}; };
let terrain_cache = TerrainCache::from_random(&random_config); let terrain_cache = TerrainCache::from_random(&random_config);
let default_block = generation_settings.default_block; let default_block = settings.default_block;
let base_router = ProtoNoiseRouters::generate(&base, &random_config); let base_router = ProtoNoiseRouters::generate(&base, &random_config);
let biome_mixer_seed = crate::biome::hash_seed(seed.0);
let mut structure_allowed_biomes = FxHashMap::default();
for (i, set) in StructureSet::ALL.iter().enumerate() {
structure_allowed_biomes.insert(
i,
crate::generation::proto_chunk::ProtoChunk::get_allowed_biomes(set),
);
}
Self { Self {
random_config, random_config,
base_router, base_router,
dimension, dimension,
settings,
biome_mixer_seed,
terrain_cache, terrain_cache,
default_block, default_block,
global_structure_cache: global_structure_cache:
crate::generation::structure::placement::GlobalStructureCache::new(), crate::generation::structure::placement::GlobalStructureCache::new(),
structure_calculator: StructurePlacementCalculator::new(seed.0 as i64),
structure_allowed_biomes,
} }
} }
} }

View File

@ -451,8 +451,9 @@ impl WorldAquiferSampler {
density: f64, density: f64,
) -> Option<&'static BlockState> { ) -> Option<&'static BlockState> {
if density > 0f64 { if density > 0f64 {
None return None;
} else { }
let sample_x = pos.x; let sample_x = pos.x;
let sample_y = pos.y; let sample_y = pos.y;
let sample_z = pos.z; let sample_z = pos.z;
@ -461,73 +462,93 @@ impl WorldAquiferSampler {
.fluid_level_sampler .fluid_level_sampler
.get_fluid_level(sample_x, sample_y, sample_z); .get_fluid_level(sample_x, sample_y, sample_z);
if fluid_level.get_block(sample_y) == &LAVA_BLOCK { if fluid_level.get_block(sample_y) == &LAVA_BLOCK {
Some(LAVA_BLOCK.default_state) return Some(LAVA_BLOCK.default_state);
} else { }
let scaled_x = local_xz!(sample_x - 5); let scaled_x = local_xz!(sample_x - 5);
let scaled_y = local_y!(sample_y + 1); let scaled_y = local_y!(sample_y + 1);
let scaled_z = local_xz!(sample_z - 5); let scaled_z = local_xz!(sample_z - 5);
let mut random_positions_and_hypot = [(0, i32::MAX); 3]; // Inline random_positions_for_pos: read directly from packed_positions with a
for packed_random in self.random_positions_for_pos(scaled_x, scaled_y, scaled_z) { // single bounds check instead of stack-allocating and copying a [i64; 12].
let unpacked_x = block_pos::unpack_x(packed_random); let sy = self.size_y;
let unpacked_y = block_pos::unpack_y(packed_random); let syz = sy * self.size_z;
let unpacked_z = block_pos::unpack_z(packed_random); let i00 = self.packed_position_index(scaled_x, scaled_y - 1, scaled_z);
let i01 = i00 + sy;
let i10 = i00 + syz;
let i11 = i10 + sy;
let local_x = unpacked_x - sample_x; let p = &self.packed_positions;
let local_y = unpacked_y - sample_y; // i11 + 2 is the largest index we ever access; all others are strictly smaller.
let local_z = unpacked_z - sample_z; assert!(i11 + 2 < p.len(), "Index out of bounds");
let hypot_squared = local_x * local_x + local_y * local_y + local_z * local_z; let mut nearest = [(0i64, i32::MAX); 3];
if random_positions_and_hypot[2].1 > hypot_squared { // SAFETY: every index passed to this macro is <= i11 + 2, checked by the assert above.
random_positions_and_hypot[2] = (packed_random, hypot_squared); macro_rules! process {
($idx:expr) => {{
let packed = unsafe { *p.get_unchecked($idx) };
let dx = block_pos::unpack_x(packed) - sample_x;
let dy = block_pos::unpack_y(packed) - sample_y;
let dz = block_pos::unpack_z(packed) - sample_z;
let h = dx * dx + dy * dy + dz * dz;
if nearest[2].1 > h {
nearest[2] = (packed, h);
}
if nearest[1].1 > h {
nearest[2] = nearest[1];
nearest[1] = (packed, h);
}
if nearest[0].1 > h {
nearest[1] = nearest[0];
nearest[0] = (packed, h);
}
}};
} }
if random_positions_and_hypot[1].1 > hypot_squared { // Same insertion order as the original array literal — sort behaviour is preserved.
random_positions_and_hypot[2] = random_positions_and_hypot[1]; process!(i11 + 2);
random_positions_and_hypot[1] = (packed_random, hypot_squared); process!(i10 + 2);
} process!(i01 + 2);
process!(i00 + 2);
process!(i11 + 1);
process!(i10 + 1);
process!(i01 + 1);
process!(i00 + 1);
process!(i11);
process!(i10);
process!(i01);
process!(i00);
// Precompute all three pairwise distances before fetching any water levels so we
// can skip the third get_water_level call entirely when neither f nor g_dist > 0.
let d = Self::max_distance(nearest[0].1, nearest[1].1);
let f = Self::max_distance(nearest[0].1, nearest[2].1);
let g_dist = Self::max_distance(nearest[1].1, nearest[2].1);
if random_positions_and_hypot[0].1 > hypot_squared {
random_positions_and_hypot[1] = random_positions_and_hypot[0];
random_positions_and_hypot[0] = (packed_random, hypot_squared);
}
}
let fluid_level2 = self let fluid_level2 = self
.get_water_level( .get_water_level(nearest[0].0, router, height_estimator, sample_options)
random_positions_and_hypot[0].0,
router,
height_estimator,
sample_options,
)
.clone(); .clone();
let d = Self::max_distance(
random_positions_and_hypot[0].1,
random_positions_and_hypot[1].1,
);
let block_state = fluid_level2.get_block(sample_y); let block_state = fluid_level2.get_block(sample_y);
if d <= 0f64 { if d <= 0f64 {
// TODO: Handle fluid tick // TODO: Handle fluid tick
return Some(block_state.default_state);
}
Some(block_state.default_state) if block_state == &WATER_BLOCK
} else if block_state == &WATER_BLOCK
&& self && self
.fluid_level_sampler .fluid_level_sampler
.get_fluid_level(sample_x, sample_y - 1, sample_z) .get_fluid_level(sample_x, sample_y - 1, sample_z)
.get_block(sample_y - 1) .get_block(sample_y - 1)
== &LAVA_BLOCK == &LAVA_BLOCK
{ {
Some(block_state.default_state) return Some(block_state.default_state);
} else { }
let mut barrier_sample = None; let mut barrier_sample = None;
let fluid_level3 = self let fluid_level3 = self
.get_water_level( .get_water_level(nearest[1].0, router, height_estimator, sample_options)
random_positions_and_hypot[1].0,
router,
height_estimator,
sample_options,
)
.clone(); .clone();
let e = d * Self::calculate_density( let e = d * Self::calculate_density(
&mut barrier_sample, &mut barrier_sample,
@ -539,20 +560,17 @@ impl WorldAquiferSampler {
); );
if density + e > 0f64 { if density + e > 0f64 {
None return None;
} else { }
let fluid_level4 = self.get_water_level(
random_positions_and_hypot[2].0, // Only pay for the cache/noise lookup when at least one distance weight is positive;
router, // when both are <= 0 the third centre cannot affect the result.
height_estimator, if f > 0f64 || g_dist > 0f64 {
sample_options, let fluid_level4 =
); self.get_water_level(nearest[2].0, router, height_estimator, sample_options);
let f = Self::max_distance(
random_positions_and_hypot[0].1,
random_positions_and_hypot[2].1,
);
if f > 0f64 { if f > 0f64 {
let g = d let contrib = d
* f * f
* Self::calculate_density( * Self::calculate_density(
&mut barrier_sample, &mut barrier_sample,
@ -562,18 +580,14 @@ impl WorldAquiferSampler {
&fluid_level2, &fluid_level2,
fluid_level4, fluid_level4,
); );
if density + g > 0f64 { if density + contrib > 0f64 {
return None; return None;
} }
} }
let g = Self::max_distance( if g_dist > 0f64 {
random_positions_and_hypot[1].1, let contrib = d
random_positions_and_hypot[2].1, * g_dist
);
if g > 0f64 {
let h = d
* g
* Self::calculate_density( * Self::calculate_density(
&mut barrier_sample, &mut barrier_sample,
pos, pos,
@ -582,19 +596,15 @@ impl WorldAquiferSampler {
&fluid_level3, &fluid_level3,
fluid_level4, fluid_level4,
); );
if density + h > 0f64 { if density + contrib > 0f64 {
return None; return None;
} }
} }
}
//TODO Handle fluid tick // TODO: Handle fluid tick
Some(block_state.default_state) Some(block_state.default_state)
} }
}
}
}
}
} }
impl AquiferSamplerImpl for WorldAquiferSampler { impl AquiferSamplerImpl for WorldAquiferSampler {

View File

@ -32,6 +32,20 @@ impl DoublePerlinNoiseSampler {
) )
} }
pub fn get_amplitude(amplitudes: &[f64]) -> f64 {
let mut j = i32::MAX;
let mut k = i32::MIN;
for (index, amplitude) in amplitudes.iter().enumerate() {
if *amplitude != 0f64 {
j = i32::min(j, index as i32);
k = i32::max(k, index as i32);
}
}
0.16666666666666666f64 / Self::create_amplitude(k - j)
}
pub fn new( pub fn new(
rand: &mut impl RandomImpl, rand: &mut impl RandomImpl,
first_octave: i32, first_octave: i32,
@ -76,7 +90,14 @@ mod double_perlin_noise_sampler_test {
assert_eq!(rand.next_i32(), -1302745855); assert_eq!(rand.next_i32(), -1302745855);
let mut rand_gen = RandomGenerator::Legacy(rand); let mut rand_gen = RandomGenerator::Legacy(rand);
let params = DoublePerlinNoiseParameters::new(0, 0, &[4f64], 1, 1, 1.0); let params = DoublePerlinNoiseParameters::new(
0,
0,
&[4f64],
0,
0,
DoublePerlinNoiseSampler::get_amplitude(&[4f64]),
);
let sampler = DoublePerlinNoiseSampler::from_params(&mut rand_gen, &params, true); let sampler = DoublePerlinNoiseSampler::from_params(&mut rand_gen, &params, true);
let values = [ let values = [
@ -174,7 +195,14 @@ mod double_perlin_noise_sampler_test {
let mut rand_gen = RandomGenerator::Xoroshiro(rand); let mut rand_gen = RandomGenerator::Xoroshiro(rand);
let params = DoublePerlinNoiseParameters::new(0, 1, &[2f64, 4f64], 1, 1, 1.0); let params = DoublePerlinNoiseParameters::new(
0,
1,
&[2f64, 4f64],
0,
0,
DoublePerlinNoiseSampler::get_amplitude(&[2f64, 4f64]),
);
let sampler = DoublePerlinNoiseSampler::from_params(&mut rand_gen, &params, false); let sampler = DoublePerlinNoiseSampler::from_params(&mut rand_gen, &params, false);

View File

@ -3,12 +3,10 @@ use std::sync::Arc;
use pumpkin_data::block_properties::is_air; use pumpkin_data::block_properties::is_air;
use pumpkin_data::chunk::DoublePerlinNoiseParameters; use pumpkin_data::chunk::DoublePerlinNoiseParameters;
use pumpkin_data::chunk_gen_settings::GenerationSettings;
use pumpkin_data::dimension::Dimension; use pumpkin_data::dimension::Dimension;
use pumpkin_data::fluid::{Fluid, FluidState}; use pumpkin_data::fluid::{Fluid, FluidState};
use pumpkin_data::structures::{ use pumpkin_data::structures::{
Structure, StructureKeys, StructurePlacementCalculator, StructurePlacementType, StructureSet, Structure, StructureKeys, StructurePlacementType, StructureSet, WeightedEntry,
WeightedEntry,
}; };
use pumpkin_data::tag; use pumpkin_data::tag;
use pumpkin_data::tag::RegistryKey; use pumpkin_data::tag::RegistryKey;
@ -45,7 +43,6 @@ use crate::generation::noise::router::multi_noise_sampler::MultiNoiseSamplerBuil
use crate::generation::noise::router::surface_height_sampler::SurfaceHeightSamplerBuilderOptions; use crate::generation::noise::router::surface_height_sampler::SurfaceHeightSamplerBuilderOptions;
use crate::generation::noise::{CHUNK_DIM, ChunkNoiseGenerator, LAVA_BLOCK, WATER_BLOCK}; use crate::generation::noise::{CHUNK_DIM, ChunkNoiseGenerator, LAVA_BLOCK, WATER_BLOCK};
use crate::generation::structure::lazily_generate_structure; use crate::generation::structure::lazily_generate_structure;
use crate::generation::structure::placement::GlobalStructureCache;
use crate::generation::structure::placement::should_generate_structure; use crate::generation::structure::placement::should_generate_structure;
use crate::generation::structure::structures::{ use crate::generation::structure::structures::{
StructureGeneratorContext, StructureInstance, create_chunk_random, StructureGeneratorContext, StructureInstance, create_chunk_random,
@ -53,7 +50,7 @@ use crate::generation::structure::structures::{
use crate::generation::structure::try_generate_structure; use crate::generation::structure::try_generate_structure;
use crate::generation::surface::evaluate_surface_rule; use crate::generation::surface::evaluate_surface_rule;
use crate::{ use crate::{
BlockStateId, ProtoNoiseRouters, BlockStateId,
block::RawBlockState, block::RawBlockState,
chunk::CHUNK_AREA, chunk::CHUNK_AREA,
generation::{biome, positions::chunk_pos}, generation::{biome, positions::chunk_pos},
@ -205,13 +202,8 @@ impl TerrainCache {
impl ProtoChunk { impl ProtoChunk {
#[must_use] #[must_use]
pub fn new( pub fn new(x: i32, z: i32, generator: &super::generator::VanillaGenerator) -> Self {
x: i32, let dimension = &generator.dimension;
z: i32,
dimension: &Dimension,
default_block: &'static BlockState,
biome_mixer_seed: i64,
) -> Self {
let height = dimension.logical_height as u16; let height = dimension.logical_height as u16;
let section_count = (height as usize) / 16; let section_count = (height as usize) / 16;
@ -219,7 +211,8 @@ impl ProtoChunk {
Self { Self {
x, x,
z, z,
default_block, default_block: generator.default_block,
biome_mixer_seed: generator.biome_mixer_seed,
flat_block_map: vec![0; CHUNK_AREA * height as usize].into_boxed_slice(), flat_block_map: vec![0; CHUNK_AREA * height as usize].into_boxed_slice(),
flat_biome_map: vec![ flat_biome_map: vec![
Biome::PLAINS.id; Biome::PLAINS.id;
@ -228,7 +221,6 @@ impl ProtoChunk {
* biome_coords::from_block(height as i32) as usize * biome_coords::from_block(height as i32) as usize
] ]
.into_boxed_slice(), .into_boxed_slice(),
biome_mixer_seed,
flat_surface_height_map: default_heightmap.clone(), flat_surface_height_map: default_heightmap.clone(),
flat_ocean_floor_height_map: default_heightmap.clone(), flat_ocean_floor_height_map: default_heightmap.clone(),
flat_motion_blocking_height_map: default_heightmap.clone(), flat_motion_blocking_height_map: default_heightmap.clone(),
@ -241,38 +233,29 @@ impl ProtoChunk {
sky_light: (0..section_count) sky_light: (0..section_count)
.map(|_| { .map(|_| {
if dimension.has_skylight { if dimension.has_skylight {
// Pre-allocate full arrays for sky light in dimensions with skylight // Sky light starts at 0 and is calculated by the lighting engine
// Initialize to 0 - lighting engine will calculate proper values LightContainer::new_empty(0)
LightContainer::new_filled(0)
} else { } else {
// No skylight in Nether/End, can use Empty // No skylight in Nether/End
LightContainer::new_empty(0) LightContainer::new_empty(0)
} }
}) })
.collect(), .collect(),
block_light: (0..section_count) block_light: (0..section_count)
// Pre-allocate full arrays for block light // Block light starts at 0 and is set by emissive blocks
// Initialize to 0 - lighting engine will set emissive blocks .map(|_| LightContainer::new_empty(0))
.map(|_| LightContainer::new_filled(0))
.collect(), .collect(),
}, },
pending_block_entities: Vec::new(), pending_block_entities: Vec::new(),
} }
} }
#[must_use]
pub fn from_chunk_data( pub fn from_chunk_data(
chunk_data: &ChunkData, chunk_data: &ChunkData,
dimension: &Dimension, generator: &super::generator::VanillaGenerator,
default_block: &'static BlockState,
biome_mixer_seed: i64,
) -> Self { ) -> Self {
let mut proto_chunk = Self::new( let mut proto_chunk = Self::new(chunk_data.x, chunk_data.z, generator);
chunk_data.x,
chunk_data.z,
dimension,
default_block,
biome_mixer_seed,
);
proto_chunk.light = chunk_data.light_engine.lock().unwrap().clone(); proto_chunk.light = chunk_data.light_engine.lock().unwrap().clone();
let section_data = &chunk_data.section; let section_data = &chunk_data.section;
@ -549,7 +532,7 @@ impl ProtoChunk {
self.flat_biome_map[index] self.flat_biome_map[index]
} }
pub fn step_to_biomes(&mut self, dimension: Dimension, noise_router: &ProtoNoiseRouters) { pub fn step_to_biomes(&mut self, generator: &super::generator::VanillaGenerator) {
let start_x = start_block_x(self.x); let start_x = start_block_x(self.x);
let start_z = start_block_z(self.z); let start_z = start_block_z(self.z);
let horizontal_biome_end = biome_coords::from_block(16); let horizontal_biome_end = biome_coords::from_block(16);
@ -560,19 +543,15 @@ impl ProtoChunk {
horizontal_biome_end as usize, horizontal_biome_end as usize,
); );
let mut multi_noise_sampler = let mut multi_noise_sampler =
MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config); MultiNoiseSampler::generate(&generator.base_router.multi_noise, &multi_noise_config);
self.populate_biomes(dimension, &mut multi_noise_sampler); self.populate_biomes(generator, &mut multi_noise_sampler);
self.stage = StagedChunkEnum::Biomes; self.stage = StagedChunkEnum::Biomes;
} }
pub fn step_to_noise( pub fn step_to_noise(&mut self, generator: &super::generator::VanillaGenerator) {
&mut self,
settings: &GenerationSettings,
random_config: &GlobalRandomConfig,
noise_router: &ProtoNoiseRouters,
) {
//debug_assert_eq!(self.stage, StagedChunkEnum::Biomes); //debug_assert_eq!(self.stage, StagedChunkEnum::Biomes);
let settings = generator.settings;
let generation_shape = &settings.shape; let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let start_x = start_block_x(self.x); let start_x = start_block_x(self.x);
@ -587,8 +566,8 @@ impl ProtoChunk {
); );
let mut noise_sampler = ChunkNoiseGenerator::new( let mut noise_sampler = ChunkNoiseGenerator::new(
&noise_router.noise, &generator.base_router.noise,
random_config, &generator.random_config,
horizontal_cell_count as usize, horizontal_cell_count as usize,
start_x, start_x,
start_z, start_z,
@ -610,30 +589,25 @@ impl ProtoChunk {
generation_shape.vertical_cell_block_count() as usize, generation_shape.vertical_cell_block_count() as usize,
); );
let mut surface_height_estimate_sampler = SurfaceHeightEstimateSampler::generate( let mut surface_height_estimate_sampler = SurfaceHeightEstimateSampler::generate(
&noise_router.surface_estimator, &generator.base_router.surface_estimator,
&surface_config, &surface_config,
); );
self.populate_noise( self.populate_noise(
generator,
&mut noise_sampler, &mut noise_sampler,
&random_config.ore_random_deriver, &generator.random_config.ore_random_deriver,
&mut surface_height_estimate_sampler, &mut surface_height_estimate_sampler,
); );
self.stage = StagedChunkEnum::Noise; self.stage = StagedChunkEnum::Noise;
} }
pub fn step_to_surface( pub fn step_to_surface(&mut self, generator: &super::generator::VanillaGenerator) {
&mut self,
settings: &GenerationSettings,
random_config: &GlobalRandomConfig,
terrain_cache: &TerrainCache,
noise_router: &ProtoNoiseRouters,
) {
debug_assert_eq!(self.stage, StagedChunkEnum::Noise); debug_assert_eq!(self.stage, StagedChunkEnum::Noise);
// Build surface // Build surface
let start_x = start_block_x(self.x); let start_x = start_block_x(self.x);
let start_z = start_block_z(self.z); let start_z = start_block_z(self.z);
let generation_shape = &settings.shape; let generation_shape = &generator.settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let horizontal_biome_end = biome_coords::from_block( let horizontal_biome_end = biome_coords::from_block(
@ -648,24 +622,20 @@ impl ProtoChunk {
generation_shape.vertical_cell_block_count() as usize, generation_shape.vertical_cell_block_count() as usize,
); );
let mut surface_height_estimate_sampler = SurfaceHeightEstimateSampler::generate( let mut surface_height_estimate_sampler = SurfaceHeightEstimateSampler::generate(
&noise_router.surface_estimator, &generator.base_router.surface_estimator,
&surface_config, &surface_config,
); );
self.build_surface( self.build_surface(generator, &mut surface_height_estimate_sampler);
settings,
random_config,
terrain_cache,
&mut surface_height_estimate_sampler,
);
self.stage = StagedChunkEnum::Surface; self.stage = StagedChunkEnum::Surface;
} }
pub fn populate_biomes( pub fn populate_biomes(
&mut self, &mut self,
dimension: Dimension, generator: &super::generator::VanillaGenerator,
multi_noise_sampler: &mut MultiNoiseSampler, multi_noise_sampler: &mut MultiNoiseSampler,
) { ) {
let dimension = generator.dimension;
// Instantiate ONLY the supplier we actually need // Instantiate ONLY the supplier we actually need
let active_supplier = if dimension == Dimension::THE_END { let active_supplier = if dimension == Dimension::THE_END {
ActiveSupplier::End(TheEndBiomeSupplier) ActiveSupplier::End(TheEndBiomeSupplier)
@ -721,6 +691,7 @@ impl ProtoChunk {
#[expect(clippy::similar_names)] #[expect(clippy::similar_names)]
pub fn populate_noise( pub fn populate_noise(
&mut self, &mut self,
generator: &super::generator::VanillaGenerator,
noise_sampler: &mut ChunkNoiseGenerator, noise_sampler: &mut ChunkNoiseGenerator,
ore_random_deriver: &XoroshiroSplitter, ore_random_deriver: &XoroshiroSplitter,
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler, surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
@ -773,7 +744,7 @@ impl ProtoChunk {
local_z, local_z,
surface_height_estimate_sampler, surface_height_estimate_sampler,
) )
.unwrap_or(self.default_block); .unwrap_or(generator.default_block);
self.set_block_state(block_x, block_y, block_z, block_state); self.set_block_state(block_x, block_y, block_z, block_state);
} }
} }
@ -798,6 +769,7 @@ impl ProtoChunk {
self.get_biome_id(seed_biome_pos.x, seed_biome_pos.y, seed_biome_pos.z) self.get_biome_id(seed_biome_pos.x, seed_biome_pos.y, seed_biome_pos.z)
} }
#[must_use] #[must_use]
pub fn get_terrain_gen_biome(&self, x: i32, y: i32, z: i32) -> &'static Biome { pub fn get_terrain_gen_biome(&self, x: i32, y: i32, z: i32) -> &'static Biome {
Biome::from_id(self.get_terrain_gen_biome_id(x, y, z)).unwrap() Biome::from_id(self.get_terrain_gen_biome_id(x, y, z)).unwrap()
@ -809,15 +781,17 @@ impl ProtoChunk {
/// It is crucial that biome assignments are determined before this process begins. /// It is crucial that biome assignments are determined before this process begins.
pub fn build_surface( pub fn build_surface(
&mut self, &mut self,
settings: &GenerationSettings, generator: &super::generator::VanillaGenerator,
random_config: &GlobalRandomConfig,
terrain_cache: &TerrainCache,
surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler, surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler,
) { ) {
let start_x = chunk_pos::start_block_x(self.x); let start_x = chunk_pos::start_block_x(self.x);
let start_z = chunk_pos::start_block_z(self.z); let start_z = chunk_pos::start_block_z(self.z);
let min_y = self.bottom_y(); let min_y = self.bottom_y();
let settings = generator.settings;
let random_config = &generator.random_config;
let terrain_cache = &generator.terrain_cache;
let random = &random_config.base_random_deriver; let random = &random_config.base_random_deriver;
let mut context = MaterialRuleContext::new( let mut context = MaterialRuleContext::new(
min_y, min_y,
@ -1100,7 +1074,7 @@ impl ProtoChunk {
} }
} }
fn get_allowed_biomes(set: &StructureSet) -> Vec<u16> { pub fn get_allowed_biomes(set: &StructureSet) -> Vec<u16> {
let mut allowed_biomes = Vec::new(); let mut allowed_biomes = Vec::new();
for entry in set.structures { for entry in set.structures {
let structure = Structure::get(&entry.structure); let structure = Structure::get(&entry.structure);
@ -1117,26 +1091,25 @@ impl ProtoChunk {
allowed_biomes allowed_biomes
} }
pub fn set_structure_starts( pub fn set_structure_starts(&mut self, generator: &super::generator::VanillaGenerator) {
&mut self, let random_config = &generator.random_config;
random_config: &GlobalRandomConfig, let settings = generator.settings;
settings: &GenerationSettings, let global_cache = &generator.global_structure_cache;
global_cache: &GlobalStructureCache, let calculator = &generator.structure_calculator;
) {
let seed = random_config.seed;
let calculator = StructurePlacementCalculator::new(seed as i64);
for set in StructureSet::ALL { let seed = random_config.seed;
let allowed_biomes = Self::get_allowed_biomes(set);
for (i, set) in StructureSet::ALL.iter().enumerate() {
let allowed_biomes = &generator.structure_allowed_biomes[&i];
if !should_generate_structure( if !should_generate_structure(
&set.placement, &set.placement,
&calculator, calculator,
self.x, self.x,
self.z, self.z,
global_cache, global_cache,
self, self,
&allowed_biomes, allowed_biomes,
) { ) {
continue; continue;
} }
@ -1205,14 +1178,13 @@ impl ProtoChunk {
false false
} }
pub fn set_structure_references( pub fn set_structure_references(&mut self, generator: &super::generator::VanillaGenerator) {
&mut self, let random_config = &generator.random_config;
random_config: &GlobalRandomConfig, let settings = generator.settings;
settings: &GenerationSettings, let dimension = &generator.dimension;
dimension: &Dimension, let noise_router = &generator.base_router;
noise_router: &ProtoNoiseRouters, let global_cache = &generator.global_structure_cache;
global_cache: &GlobalStructureCache,
) {
let start_x = chunk_pos::start_block_x(self.x); let start_x = chunk_pos::start_block_x(self.x);
let start_z = chunk_pos::start_block_z(self.z); let start_z = chunk_pos::start_block_z(self.z);
let end_x = start_x + 15; let end_x = start_x + 15;

View File

@ -55,22 +55,24 @@ use crate::generation::{
}; };
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, _terrain_cache: &TerrainCache,
default_block: &'static BlockState, _default_block: &'static BlockState,
) { ) {
use crate::biome::hash_seed; use crate::generation::generator::{GeneratorInit, VanillaGenerator};
use crate::generation::noise::router::surface_height_sampler::{ use crate::generation::noise::router::surface_height_sampler::{
SurfaceHeightEstimateSampler, SurfaceHeightSamplerBuilderOptions, SurfaceHeightEstimateSampler, SurfaceHeightSamplerBuilderOptions,
}; };
use crate::generation::proto_chunk::StandardChunkFluidLevelSampler; use crate::generation::proto_chunk::StandardChunkFluidLevelSampler;
use pumpkin_util::world_seed::Seed;
let biome_mixer_seed = hash_seed(random_config.seed); let generator = VanillaGenerator::new(Seed(random_config.seed), Dimension::OVERWORLD);
let mut chunk = ProtoChunk::new(0, 0, &Dimension::OVERWORLD, default_block, biome_mixer_seed); let mut chunk = ProtoChunk::new(0, 0, &generator);
// Create noise sampler and other required components // Create noise sampler and other required components
let settings = generator.settings;
let generation_shape = &settings.shape; let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let sampler = StandardChunkFluidLevelSampler::new( let sampler = StandardChunkFluidLevelSampler::new(
@ -85,8 +87,8 @@ pub fn bench_create_and_populate_noise(
let start_z = chunk_pos::start_block_z(0); let start_z = chunk_pos::start_block_z(0);
let mut noise_sampler = ChunkNoiseGenerator::new( let mut noise_sampler = ChunkNoiseGenerator::new(
&base_router.noise, &generator.base_router.noise,
random_config, &generator.random_config,
horizontal_cell_count as usize, horizontal_cell_count as usize,
start_x, start_x,
start_z, start_z,
@ -112,63 +114,63 @@ pub fn bench_create_and_populate_noise(
generation_shape.max_y() as i32, generation_shape.max_y() as i32,
generation_shape.vertical_cell_block_count() as usize, generation_shape.vertical_cell_block_count() as usize,
); );
let mut surface_height_estimate_sampler = let mut surface_height_estimate_sampler = SurfaceHeightEstimateSampler::generate(
SurfaceHeightEstimateSampler::generate(&base_router.surface_estimator, &surface_config); &generator.base_router.surface_estimator,
&surface_config,
);
chunk.populate_noise( chunk.populate_noise(
&generator,
&mut noise_sampler, &mut noise_sampler,
&random_config.ore_random_deriver, &generator.random_config.ore_random_deriver,
&mut surface_height_estimate_sampler, &mut surface_height_estimate_sampler,
); );
} }
pub fn bench_create_and_populate_biome( 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, _terrain_cache: &TerrainCache,
default_block: &'static BlockState, _default_block: &'static BlockState,
) { ) {
use crate::biome::hash_seed; use crate::generation::generator::{GeneratorInit, VanillaGenerator};
use crate::generation::noise::router::multi_noise_sampler::{ use crate::generation::noise::router::multi_noise_sampler::{
MultiNoiseSampler, MultiNoiseSamplerBuilderOptions, MultiNoiseSampler, MultiNoiseSamplerBuilderOptions,
}; };
use crate::generation::{biome_coords, positions::chunk_pos}; use crate::generation::{biome_coords, positions::chunk_pos};
use pumpkin_util::world_seed::Seed;
let biome_mixer_seed = hash_seed(random_config.seed); let generator = VanillaGenerator::new(Seed(random_config.seed), Dimension::OVERWORLD);
let mut chunk = ProtoChunk::new(0, 0, &Dimension::OVERWORLD, default_block, biome_mixer_seed); let mut chunk = ProtoChunk::new(0, 0, &generator);
// Create multi-noise sampler // Create multi-noise sampler
let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let start_x = chunk_pos::start_block_x(0); let start_x = chunk_pos::start_block_x(0);
let start_z = chunk_pos::start_block_z(0); let start_z = chunk_pos::start_block_z(0);
let biome_pos = Vector2::new( let biome_pos = Vector2::new(
biome_coords::from_block(start_x), biome_coords::from_block(start_x),
biome_coords::from_block(start_z), biome_coords::from_block(start_z),
); );
let horizontal_biome_end = biome_coords::from_block( let horizontal_biome_end = biome_coords::from_block(16);
horizontal_cell_count as i32 * generation_shape.horizontal_cell_block_count() as i32,
);
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new( let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(
biome_pos.x, biome_pos.x,
biome_pos.y, biome_pos.y,
horizontal_biome_end as usize, horizontal_biome_end as usize,
); );
let mut multi_noise_sampler = let mut multi_noise_sampler =
MultiNoiseSampler::generate(&base_router.multi_noise, &multi_noise_config); MultiNoiseSampler::generate(&generator.base_router.multi_noise, &multi_noise_config);
chunk.populate_biomes(Dimension::OVERWORLD, &mut multi_noise_sampler); chunk.populate_biomes(&generator, &mut multi_noise_sampler);
} }
pub fn bench_create_and_populate_noise_with_surface( 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, _terrain_cache: &TerrainCache,
default_block: &'static BlockState, _default_block: &'static BlockState,
) { ) {
use crate::biome::hash_seed; use crate::generation::generator::{GeneratorInit, VanillaGenerator};
use crate::generation::noise::router::{ use crate::generation::noise::router::{
multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions}, multi_noise_sampler::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions},
surface_height_sampler::{ surface_height_sampler::{
@ -176,11 +178,13 @@ pub fn bench_create_and_populate_noise_with_surface(
}, },
}; };
use crate::generation::proto_chunk::StandardChunkFluidLevelSampler; use crate::generation::proto_chunk::StandardChunkFluidLevelSampler;
use pumpkin_util::world_seed::Seed;
let biome_mixer_seed = hash_seed(random_config.seed); let generator = VanillaGenerator::new(Seed(random_config.seed), Dimension::OVERWORLD);
let mut chunk = ProtoChunk::new(0, 0, &Dimension::OVERWORLD, default_block, biome_mixer_seed); let mut chunk = ProtoChunk::new(0, 0, &generator);
// Create all required components // Create all required components
let settings = generator.settings;
let generation_shape = &settings.shape; let generation_shape = &settings.shape;
let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count(); let horizontal_cell_count = CHUNK_DIM / generation_shape.horizontal_cell_block_count();
let start_x = chunk_pos::start_block_x(0); let start_x = chunk_pos::start_block_x(0);
@ -191,16 +195,14 @@ pub fn bench_create_and_populate_noise_with_surface(
biome_coords::from_block(start_x), biome_coords::from_block(start_x),
biome_coords::from_block(start_z), biome_coords::from_block(start_z),
); );
let horizontal_biome_end = biome_coords::from_block( let horizontal_biome_end = biome_coords::from_block(16);
horizontal_cell_count as i32 * generation_shape.horizontal_cell_block_count() as i32,
);
let multi_noise_config = MultiNoiseSamplerBuilderOptions::new( let multi_noise_config = MultiNoiseSamplerBuilderOptions::new(
biome_pos.x, biome_pos.x,
biome_pos.y, biome_pos.y,
horizontal_biome_end as usize, horizontal_biome_end as usize,
); );
let mut multi_noise_sampler = let mut multi_noise_sampler =
MultiNoiseSampler::generate(&base_router.multi_noise, &multi_noise_config); MultiNoiseSampler::generate(&generator.base_router.multi_noise, &multi_noise_config);
// Noise sampler // Noise sampler
let sampler = StandardChunkFluidLevelSampler::new( let sampler = StandardChunkFluidLevelSampler::new(
@ -208,12 +210,12 @@ pub fn bench_create_and_populate_noise_with_surface(
settings.sea_level, settings.sea_level,
Block::from_state_id(settings.default_fluid.id), Block::from_state_id(settings.default_fluid.id),
), ),
FluidLevel::new(-54, &pumpkin_data::Block::LAVA), FluidLevel::new(-54, &Block::LAVA),
); );
let mut noise_sampler = ChunkNoiseGenerator::new( let mut noise_sampler = ChunkNoiseGenerator::new(
&base_router.noise, &generator.base_router.noise,
random_config, &generator.random_config,
horizontal_cell_count as usize, horizontal_cell_count as usize,
start_x, start_x,
start_z, start_z,
@ -232,19 +234,17 @@ pub fn bench_create_and_populate_noise_with_surface(
generation_shape.max_y() as i32, generation_shape.max_y() as i32,
generation_shape.vertical_cell_block_count() as usize, generation_shape.vertical_cell_block_count() as usize,
); );
let mut surface_height_estimate_sampler = let mut surface_height_estimate_sampler = SurfaceHeightEstimateSampler::generate(
SurfaceHeightEstimateSampler::generate(&base_router.surface_estimator, &surface_config); &generator.base_router.surface_estimator,
&surface_config,
);
chunk.populate_biomes(Dimension::OVERWORLD, &mut multi_noise_sampler); chunk.populate_biomes(&generator, &mut multi_noise_sampler);
chunk.populate_noise( chunk.populate_noise(
&generator,
&mut noise_sampler, &mut noise_sampler,
&random_config.ore_random_deriver, &generator.random_config.ore_random_deriver,
&mut surface_height_estimate_sampler,
);
chunk.build_surface(
settings,
random_config,
terrain_cache,
&mut surface_height_estimate_sampler, &mut surface_height_estimate_sampler,
); );
chunk.build_surface(&generator, &mut surface_height_estimate_sampler);
} }