feat(chunk-gen): add mob spawn step

This commit is contained in:
Alexander Medvedev 2026-05-09 20:59:34 +02:00
parent bec18d2443
commit c23c7c429d
55 changed files with 477 additions and 227 deletions

25
Cargo.lock generated
View File

@ -348,9 +348,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.61" version = "1.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d" checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@ -1534,9 +1534,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.17.0" version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
dependencies = [ dependencies = [
"foldhash 0.2.0", "foldhash 0.2.0",
"serde", "serde",
@ -1867,7 +1867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.17.0", "hashbrown 0.17.1",
"serde", "serde",
"serde_core", "serde_core",
] ]
@ -2407,7 +2407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"hashbrown 0.17.0", "hashbrown 0.17.1",
"indexmap", "indexmap",
"memchr", "memchr",
] ]
@ -3028,6 +3028,7 @@ dependencies = [
name = "pumpkin-world" name = "pumpkin-world"
version = "0.1.0-dev+26.1" version = "0.1.0-dev+26.1"
dependencies = [ dependencies = [
"arc-swap",
"bitflags", "bitflags",
"bytes", "bytes",
"criterion", "criterion",
@ -3186,7 +3187,7 @@ checksum = "de2c52737737f8609e94f975dee22854a2d5c125772d4b1cf292120f4d45c186"
dependencies = [ dependencies = [
"allocator-api2", "allocator-api2",
"bumpalo", "bumpalo",
"hashbrown 0.17.0", "hashbrown 0.17.1",
"log", "log",
"rustc-hash", "rustc-hash",
"smallvec", "smallvec",
@ -3904,9 +3905,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.52.2" version = "1.52.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "110a78583f19d5cdb2c5ccf321d1290344e71313c6c37d43520d386027d18386" checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
dependencies = [ dependencies = [
"bytes", "bytes",
"libc", "libc",
@ -4516,7 +4517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80" checksum = "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"hashbrown 0.17.0", "hashbrown 0.17.1",
"indexmap", "indexmap",
"semver", "semver",
] ]
@ -4528,7 +4529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa4439c5eee9df71ee0c6efb37f63b1fcb1fec38f85f5142c54e7ed05d33091a" checksum = "aa4439c5eee9df71ee0c6efb37f63b1fcb1fec38f85f5142c54e7ed05d33091a"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"hashbrown 0.17.0", "hashbrown 0.17.1",
"indexmap", "indexmap",
"semver", "semver",
"serde", "serde",
@ -5408,7 +5409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ffe4064318cdf3c08cb99343b44c039fcefe61ccdf58aa9975285f13d74d1fc" checksum = "8ffe4064318cdf3c08cb99343b44c039fcefe61ccdf58aa9975285f13d74d1fc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"hashbrown 0.17.0", "hashbrown 0.17.1",
"id-arena", "id-arena",
"indexmap", "indexmap",
"log", "log",

View File

@ -34,6 +34,7 @@ crossbeam.workspace = true
sha2.workspace = true sha2.workspace = true
bitflags.workspace = true bitflags.workspace = true
arc-swap.workspace = true
dashmap.workspace = true dashmap.workspace = true

View File

@ -4,7 +4,7 @@ use pumpkin_util::world_seed::Seed;
use pumpkin_world::biome::hash_seed; use pumpkin_world::biome::hash_seed;
use pumpkin_world::chunk_system::{StagedChunkEnum, generate_single_chunk}; use pumpkin_world::chunk_system::{StagedChunkEnum, generate_single_chunk};
use pumpkin_world::generation::get_world_gen; use pumpkin_world::generation::get_world_gen;
use pumpkin_world::world::BlockRegistryExt; use pumpkin_world::world::WorldPortalExt;
use std::hint::black_box; use std::hint::black_box;
use std::sync::Arc; use std::sync::Arc;
@ -32,7 +32,7 @@ fn bench_full_chunk_generation(c: &mut Criterion) {
} }
struct BlockRegistry; struct BlockRegistry;
impl BlockRegistryExt for BlockRegistry { impl WorldPortalExt for BlockRegistry {
fn can_place_at( fn can_place_at(
&self, &self,
_block: &pumpkin_data::Block, _block: &pumpkin_data::Block,
@ -42,6 +42,15 @@ impl BlockRegistryExt for BlockRegistry {
) -> bool { ) -> bool {
true true
} }
fn spawn_mobs_for_chunk_generation(
&self,
_cache: &mut dyn pumpkin_world::generation::proto_chunk::GenerationCache,
_biome: &'static pumpkin_data::chunk::Biome,
_chunk_x: i32,
_chunk_z: i32,
) {
}
} }
criterion_group!(benches, bench_full_chunk_generation,); criterion_group!(benches, bench_full_chunk_generation,);

View File

@ -129,7 +129,7 @@ pub struct ChunkLoading {
impl ChunkLoading { impl ChunkLoading {
// pub const FULL_CHUNK_LEVEL: i8 = 33; // pub const FULL_CHUNK_LEVEL: i8 = 33;
pub const FULL_CHUNK_LEVEL: i8 = 43; pub const FULL_CHUNK_LEVEL: i8 = 43;
pub const MAX_LEVEL: i8 = 48; // level 48 will be unloaded. pub const MAX_LEVEL: i8 = 49; // level 49 will be unloaded.
fn debug_check_error(&self) -> bool { fn debug_check_error(&self) -> bool {
let mut temp = ChunkLevel::default(); let mut temp = ChunkLevel::default();
for (ticket_pos, levels) in &self.ticket { for (ticket_pos, levels) in &self.ticket {

View File

@ -29,9 +29,11 @@ pub enum StagedChunkEnum {
/// Chunk with carvers applied, ready for features and structures /// Chunk with carvers applied, ready for features and structures
Carvers, Carvers,
/// Chunk with features and structures, ready for lighting /// Chunk with features and structures, ready for lighting
Features, // FEATURES SPAWN Features, // FEATURES
/// Chunk with lighting calculated, ready for finalization /// Chunk with lighting calculated, ready for spawning
Lighting, // INITIALIZE LIGHT Lighting, // INITIALIZE LIGHT
/// Chunk with mobs spawned, ready for finalization
Spawn, // SPAWN
/// Fully generated chunk /// Fully generated chunk
Full, Full,
} }
@ -48,7 +50,8 @@ impl From<u8> for StagedChunkEnum {
7 => Self::Carvers, 7 => Self::Carvers,
8 => Self::Features, 8 => Self::Features,
9 => Self::Lighting, 9 => Self::Lighting,
10 => Self::Full, 10 => Self::Spawn,
11 => Self::Full,
_ => panic!(), _ => panic!(),
} }
} }
@ -65,9 +68,9 @@ impl From<ChunkStatus> for StagedChunkEnum {
ChunkStatus::Surface => Self::Surface, ChunkStatus::Surface => Self::Surface,
ChunkStatus::Carvers => Self::Carvers, ChunkStatus::Carvers => Self::Carvers,
ChunkStatus::Features => Self::Features, ChunkStatus::Features => Self::Features,
ChunkStatus::Spawn => Self::Features,
ChunkStatus::InitializeLight => Self::Lighting, ChunkStatus::InitializeLight => Self::Lighting,
ChunkStatus::Light => Self::Lighting, ChunkStatus::Light => Self::Lighting,
ChunkStatus::Spawn => Self::Spawn,
ChunkStatus::Full => Self::Full, ChunkStatus::Full => Self::Full,
} }
} }
@ -85,6 +88,7 @@ impl From<StagedChunkEnum> for ChunkStatus {
StagedChunkEnum::Carvers => Self::Carvers, StagedChunkEnum::Carvers => Self::Carvers,
StagedChunkEnum::Features => Self::Features, StagedChunkEnum::Features => Self::Features,
StagedChunkEnum::Lighting => Self::Light, StagedChunkEnum::Lighting => Self::Light,
StagedChunkEnum::Spawn => Self::Spawn,
StagedChunkEnum::Full => Self::Full, StagedChunkEnum::Full => Self::Full,
_ => panic!(), _ => panic!(),
} }
@ -97,22 +101,25 @@ impl StagedChunkEnum {
if level <= 43 { if level <= 43 {
Self::Full Self::Full
} else if level <= 44 { } else if level <= 44 {
Self::Lighting Self::Spawn
} else if level <= 45 { } else if level <= 45 {
Self::Features Self::Lighting
} else if level <= 46 { } else if level <= 46 {
Self::Carvers Self::Features
} else if level <= 47 { } else if level <= 47 {
Self::Carvers
} else if level <= 48 {
Self::Surface Self::Surface
} else { } else {
Self::None Self::None
} }
} }
/// Total number of state values (0 = None … 10 = Full). /// Total number of state values (0 = None … 11 = Full).
pub const COUNT: usize = Self::Full as usize + 1; pub const COUNT: usize = Self::Full as usize + 1;
pub const FULL_DEPENDENCIES: &'static [Self] = &[ pub const FULL_DEPENDENCIES: &'static [Self] = &[
Self::Full, Self::Full,
Self::Spawn,
Self::Lighting, Self::Lighting,
Self::Features, Self::Features,
Self::Carvers, Self::Carvers,
@ -132,6 +139,7 @@ impl StagedChunkEnum {
Self::Carvers => 0, Self::Carvers => 0,
Self::Features => 1, Self::Features => 1,
Self::Lighting => 1, Self::Lighting => 1,
Self::Spawn => 1,
Self::Full => 1, Self::Full => 1,
_ => panic!(), _ => panic!(),
} }
@ -149,6 +157,7 @@ impl StagedChunkEnum {
Self::Carvers => 0, Self::Carvers => 0,
Self::Features => 1, Self::Features => 1,
Self::Lighting => 1, Self::Lighting => 1,
Self::Spawn => 1,
Self::Full => 0, Self::Full => 0,
_ => panic!(), _ => panic!(),
} }
@ -176,7 +185,8 @@ impl StagedChunkEnum {
Self::Carvers => &[Self::Surface], Self::Carvers => &[Self::Surface],
Self::Features => &[Self::Carvers, Self::Carvers], Self::Features => &[Self::Carvers, Self::Carvers],
Self::Lighting => &[Self::Features, Self::Features], Self::Lighting => &[Self::Features, Self::Features],
Self::Full => &[Self::Lighting, Self::Lighting], Self::Spawn => &[Self::Lighting, Self::Lighting],
Self::Full => &[Self::Spawn, Self::Spawn],
_ => panic!(), _ => panic!(),
} }
} }

View File

@ -2,7 +2,7 @@ use pumpkin_data::dimension::Dimension;
use crate::ProtoChunk; use crate::ProtoChunk;
use crate::generation::generator::VanillaGenerator; use crate::generation::generator::VanillaGenerator;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
use pumpkin_config::lighting::LightingEngineConfig; use pumpkin_config::lighting::LightingEngineConfig;
use super::{Cache, Chunk, StagedChunkEnum}; use super::{Cache, Chunk, StagedChunkEnum};
@ -11,7 +11,7 @@ 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 WorldPortalExt,
chunk_x: i32, chunk_x: i32,
chunk_z: i32, chunk_z: i32,
target_stage: StagedChunkEnum, target_stage: StagedChunkEnum,
@ -39,6 +39,7 @@ pub fn generate_single_chunk(
StagedChunkEnum::Surface, StagedChunkEnum::Surface,
StagedChunkEnum::Features, StagedChunkEnum::Features,
StagedChunkEnum::Lighting, StagedChunkEnum::Lighting,
StagedChunkEnum::Spawn,
StagedChunkEnum::Full, StagedChunkEnum::Full,
]; ];
@ -64,13 +65,13 @@ mod tests {
use crate::biome::hash_seed; use crate::biome::hash_seed;
use crate::chunk_system::{StagedChunkEnum, generate_single_chunk}; use crate::chunk_system::{StagedChunkEnum, generate_single_chunk};
use crate::generation::get_world_gen; use crate::generation::get_world_gen;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
use pumpkin_data::dimension::Dimension; use pumpkin_data::dimension::Dimension;
use pumpkin_util::world_seed::Seed; use pumpkin_util::world_seed::Seed;
use std::sync::Arc; use std::sync::Arc;
struct BlockRegistry; struct BlockRegistry;
impl BlockRegistryExt for BlockRegistry { impl WorldPortalExt for BlockRegistry {
fn can_place_at( fn can_place_at(
&self, &self,
_block: &pumpkin_data::Block, _block: &pumpkin_data::Block,
@ -80,6 +81,15 @@ mod tests {
) -> bool { ) -> bool {
true true
} }
fn spawn_mobs_for_chunk_generation(
&self,
_cache: &mut dyn crate::generation::proto_chunk::GenerationCache,
_biome: &'static pumpkin_data::chunk::Biome,
_chunk_x: i32,
_chunk_z: i32,
) {
}
} }
#[test] #[test]

View File

@ -4,7 +4,7 @@ use crate::chunk::ChunkHeightmapType;
use crate::generation::generator; use crate::generation::generator;
use crate::generation::height_limit::HeightLimitView; use crate::generation::height_limit::HeightLimitView;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::{BlockAccessor, BlockRegistryExt}; use crate::world::{BlockAccessor, WorldPortalExt};
use crate::{BlockStateId, ProtoChunk}; use crate::{BlockStateId, ProtoChunk};
use pumpkin_config::lighting::LightingEngineConfig; use pumpkin_config::lighting::LightingEngineConfig;
use pumpkin_data::biome::Biome; use pumpkin_data::biome::Biome;
@ -360,7 +360,7 @@ impl Cache {
&mut self, &mut self,
stage: StagedChunkEnum, stage: StagedChunkEnum,
generator: &generator::VanillaGenerator, generator: &generator::VanillaGenerator,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
lighting_config: &LightingEngineConfig, lighting_config: &LightingEngineConfig,
) { ) {
let mid = ((self.size * self.size) >> 1) as usize; let mid = ((self.size * self.size) >> 1) as usize;
@ -407,9 +407,12 @@ impl Cache {
// Engine's internal state is cleared by initialize_light() and will be dropped here // Engine's internal state is cleared by initialize_light() and will be dropped here
drop(engine); drop(engine);
} }
StagedChunkEnum::Spawn => {
ProtoChunk::spawn_mobs(self, block_registry);
}
StagedChunkEnum::Full => { StagedChunkEnum::Full => {
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::Spawn);
chunk.stage = StagedChunkEnum::Full; chunk.stage = StagedChunkEnum::Full;
self.chunks[mid].upgrade_to_level_chunk(&generator.dimension, lighting_config); self.chunks[mid].upgrade_to_level_chunk(&generator.dimension, lighting_config);
} }

View File

@ -721,14 +721,14 @@ impl GenerationSchedule {
Chunk::Level(chunk) => { Chunk::Level(chunk) => {
let mut holder = self.chunk_map.remove(&new_pos).unwrap(); let mut holder = self.chunk_map.remove(&new_pos).unwrap();
if new_pos == pos { if new_pos == pos {
if holder.current_stage != StagedChunkEnum::Lighting { if holder.current_stage != StagedChunkEnum::Spawn {
warn!( warn!(
"receive_chunk(Level): holder at {:?} for pos {:?} expected {:?}; aligning", "receive_chunk(Level): holder at {:?} for pos {:?} expected {:?}; aligning",
holder.current_stage, holder.current_stage,
new_pos, new_pos,
StagedChunkEnum::Lighting StagedChunkEnum::Spawn
); );
holder.current_stage = StagedChunkEnum::Lighting; holder.current_stage = StagedChunkEnum::Spawn;
} }
self.drop_node(holder.tasks[StagedChunkEnum::Full as usize]); self.drop_node(holder.tasks[StagedChunkEnum::Full as usize]);
holder.tasks[StagedChunkEnum::Full as usize] = NodeKey::null(); holder.tasks[StagedChunkEnum::Full as usize] = NodeKey::null();

View File

@ -229,14 +229,11 @@ pub fn run_generation(
level: &Level, level: &Level,
_settings: &GenerationSettings, _settings: &GenerationSettings,
) -> RecvChunk { ) -> RecvChunk {
let portal = level.world_portal.load_full();
let portal_ref = portal.as_deref().expect("Portal should be initialized");
// 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, &level.world_gen, portal_ref, &level.lighting_config);
stage,
&level.world_gen,
level.block_registry.as_ref(),
&level.lighting_config,
);
cache // Return cache on success cache // Return cache on success
})); }));

View File

@ -3,13 +3,12 @@ use std::{path::PathBuf, sync::Arc};
use pumpkin_config::world::LevelConfig; use pumpkin_config::world::LevelConfig;
use pumpkin_data::dimension::Dimension; use pumpkin_data::dimension::Dimension;
use crate::{level::Level, world::BlockRegistryExt}; use crate::level::Level;
pub fn into_level( pub fn into_level(
dimension: Dimension, dimension: Dimension,
level_config: &LevelConfig, level_config: &LevelConfig,
mut base_directory: PathBuf, mut base_directory: PathBuf,
block_registry: Arc<dyn BlockRegistryExt>,
seed: i64, seed: i64,
gen_pool: Option<Arc<rayon::ThreadPool>>, gen_pool: Option<Arc<rayon::ThreadPool>>,
) -> Arc<Level> { ) -> Arc<Level> {
@ -19,12 +18,5 @@ pub fn into_level(
} else if dimension == Dimension::THE_END { } else if dimension == Dimension::THE_END {
base_directory.push("DIM1"); base_directory.push("DIM1");
} }
Level::from_root_folder( Level::from_root_folder(level_config, base_directory, seed, dimension, gen_pool)
level_config,
base_directory,
block_registry,
seed,
dimension,
gen_pool,
)
} }

View File

@ -6,7 +6,7 @@ use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
use crate::block::RawBlockState; use crate::block::RawBlockState;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{block::BlockStateCodec, world::BlockRegistryExt}; use crate::{block::BlockStateCodec, world::WorldPortalExt};
pub enum BlockPredicate { pub enum BlockPredicate {
MatchingBlocks(MatchingBlocksBlockPredicate), MatchingBlocks(MatchingBlocksBlockPredicate),
@ -28,7 +28,7 @@ pub enum BlockPredicate {
impl BlockPredicate { impl BlockPredicate {
pub fn test<T: GenerationCache>( pub fn test<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
pos: &BlockPos, pos: &BlockPos,
) -> bool { ) -> bool {
@ -131,7 +131,7 @@ pub struct AnyOfBlockPredicate {
impl AnyOfBlockPredicate { impl AnyOfBlockPredicate {
pub fn test<T: GenerationCache>( pub fn test<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
pos: &BlockPos, pos: &BlockPos,
) -> bool { ) -> bool {
@ -152,7 +152,7 @@ pub struct AllOfBlockPredicate {
impl AllOfBlockPredicate { impl AllOfBlockPredicate {
pub fn test<T: GenerationCache>( pub fn test<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
pos: &BlockPos, pos: &BlockPos,
) -> bool { ) -> bool {
@ -173,7 +173,7 @@ pub struct NotBlockPredicate {
impl NotBlockPredicate { impl NotBlockPredicate {
pub fn test<T: GenerationCache>( pub fn test<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
pos: &BlockPos, pos: &BlockPos,
) -> bool { ) -> bool {
@ -200,7 +200,7 @@ pub struct WouldSurviveBlockPredicate {
impl WouldSurviveBlockPredicate { impl WouldSurviveBlockPredicate {
pub fn test<T: GenerationCache>( pub fn test<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
pos: &BlockPos, pos: &BlockPos,
) -> bool { ) -> bool {

View File

@ -13,7 +13,7 @@ use pumpkin_util::{
use super::noise::perlin::DoublePerlinNoiseSampler; use super::noise::perlin::DoublePerlinNoiseSampler;
use crate::generation::block_predicate::BlockPredicate; use crate::generation::block_predicate::BlockPredicate;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub enum BlockStateProvider { pub enum BlockStateProvider {
Simple(SimpleStateProvider), Simple(SimpleStateProvider),
@ -43,7 +43,7 @@ impl BlockStateProvider {
pub fn get_with_context<T: GenerationCache>( pub fn get_with_context<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
@ -56,7 +56,7 @@ impl BlockStateProvider {
pub fn get_optional<T: GenerationCache>( pub fn get_optional<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
@ -76,7 +76,7 @@ pub struct RuleBasedBlockStateProvider {
impl RuleBasedBlockStateProvider { impl RuleBasedBlockStateProvider {
pub fn get<T: GenerationCache>( pub fn get<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
@ -88,7 +88,7 @@ impl RuleBasedBlockStateProvider {
} }
pub fn get_optional<T: GenerationCache>( pub fn get_optional<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,

View File

@ -69,7 +69,7 @@ use super::features::{
weeping_vines::WeepingVinesFeature, weeping_vines::WeepingVinesFeature,
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub static CONFIGURED_FEATURES: LazyLock<HashMap<String, ConfiguredFeature>> = pub static CONFIGURED_FEATURES: LazyLock<HashMap<String, ConfiguredFeature>> =
LazyLock::new(build_configured_features); LazyLock::new(build_configured_features);
@ -147,7 +147,7 @@ impl ConfiguredFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, // This placed feature feature_name: &str, // This placed feature

View File

@ -9,7 +9,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct BambooFeature { pub struct BambooFeature {
pub probability: f32, pub probability: f32,
@ -20,7 +20,7 @@ impl BambooFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, // This placed feature _feature: &str, // This placed feature

View File

@ -4,7 +4,7 @@ use pumpkin_util::{
random::{RandomGenerator, RandomImpl}, random::{RandomGenerator, RandomImpl},
}; };
use crate::{generation::proto_chunk::GenerationCache, world::BlockRegistryExt}; use crate::{generation::proto_chunk::GenerationCache, world::WorldPortalExt};
const LAVA_SEA_LEVEL: i32 = 32; // TODO: use getSeaLevel() instead of hardcoding this const LAVA_SEA_LEVEL: i32 = 32; // TODO: use getSeaLevel() instead of hardcoding this
const CLUSTERED_REACH: i32 = 5; const CLUSTERED_REACH: i32 = 5;
@ -22,7 +22,7 @@ impl BasaltColumnsFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height_limit: u16, _height_limit: u16,
_feature: &str, _feature: &str,

View File

@ -7,7 +7,7 @@ use pumpkin_util::{
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{ use crate::{
generation::{block_predicate::BlockPredicate, block_state_provider::BlockStateProvider}, generation::{block_predicate::BlockPredicate, block_state_provider::BlockStateProvider},
world::BlockRegistryExt, world::WorldPortalExt,
}; };
pub struct BlockColumnFeature { pub struct BlockColumnFeature {
@ -27,7 +27,7 @@ impl BlockColumnFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, // This placed feature _feature: &str, // This placed feature

View File

@ -5,7 +5,7 @@ use crate::generation::{
block_predicate::BlockPredicate, block_state_provider::BlockStateProvider, block_predicate::BlockPredicate, block_state_provider::BlockStateProvider,
proto_chunk::GenerationCache, proto_chunk::GenerationCache,
}; };
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct DiskFeature { pub struct DiskFeature {
pub state_provider: BlockStateProvider, pub state_provider: BlockStateProvider,
@ -19,7 +19,7 @@ impl DiskFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, _feature: &str,
@ -55,7 +55,7 @@ impl DiskFeature {
fn place_column<T: GenerationCache>( fn place_column<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
random: &mut RandomGenerator, random: &mut RandomGenerator,
top: i32, top: i32,
bottom: i32, bottom: i32,

View File

@ -5,7 +5,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct EndPlatformFeature; pub struct EndPlatformFeature;
@ -14,7 +14,7 @@ impl EndPlatformFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, // This placed feature _feature: &str, // This placed feature

View File

@ -8,7 +8,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{generation::section_coords, world::BlockRegistryExt}; use crate::{generation::section_coords, world::WorldPortalExt};
pub struct EndSpikeFeature { pub struct EndSpikeFeature {
pub crystal_invulnerable: bool, pub crystal_invulnerable: bool,
@ -37,7 +37,7 @@ impl EndSpikeFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, // This placed feature _feature: &str, // This placed feature

View File

@ -9,7 +9,7 @@ use pumpkin_util::{
use crate::generation::feature::features::spring_feature::BlockWrapper; use crate::generation::feature::features::spring_feature::BlockWrapper;
use crate::{ use crate::{
block::BlockStateCodec, generation::proto_chunk::GenerationCache, world::BlockRegistryExt, block::BlockStateCodec, generation::proto_chunk::GenerationCache, world::WorldPortalExt,
}; };
use pumpkin_util::random::RandomImpl; use pumpkin_util::random::RandomImpl;
use std::cmp::Ordering; use std::cmp::Ordering;
@ -102,7 +102,7 @@ impl GeodeFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature_name: &str, _feature_name: &str,

View File

@ -5,7 +5,7 @@ use pumpkin_util::{
}; };
use crate::generation::{block_state_provider::BlockStateProvider, proto_chunk::GenerationCache}; use crate::generation::{block_state_provider::BlockStateProvider, proto_chunk::GenerationCache};
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct LakeFeature { pub struct LakeFeature {
pub fluid: BlockStateProvider, pub fluid: BlockStateProvider,
@ -15,7 +15,7 @@ pub struct LakeFeature {
impl LakeFeature { impl LakeFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &mut T, chunk: &mut T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,

View File

@ -5,7 +5,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{generation::block_state_provider::BlockStateProvider, world::BlockRegistryExt}; use crate::{generation::block_state_provider::BlockStateProvider, world::WorldPortalExt};
pub struct NetherForestVegetationFeature { pub struct NetherForestVegetationFeature {
pub state_provider: BlockStateProvider, pub state_provider: BlockStateProvider,
@ -18,7 +18,7 @@ impl NetherForestVegetationFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, _feature: &str,

View File

@ -5,7 +5,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct ReplaceBlobsFeature { pub struct ReplaceBlobsFeature {
pub target: &'static BlockState, pub target: &'static BlockState,
@ -18,7 +18,7 @@ impl ReplaceBlobsFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, // This placed feature _feature: &str, // This placed feature

View File

@ -7,7 +7,7 @@ use pumpkin_util::{
}; };
use crate::{block::RawBlockState, generation::proto_chunk::GenerationCache}; use crate::{block::RawBlockState, generation::proto_chunk::GenerationCache};
use crate::{generation::rule::RuleTest, world::BlockRegistryExt}; use crate::{generation::rule::RuleTest, world::WorldPortalExt};
pub struct OreFeature { pub struct OreFeature {
pub size: i32, pub size: i32,
@ -25,7 +25,7 @@ impl OreFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, // This placed feature _feature: &str, // This placed feature

View File

@ -4,7 +4,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{generation::feature::placed_features::PlacedFeatureWrapper, world::BlockRegistryExt}; use crate::{generation::feature::placed_features::PlacedFeatureWrapper, world::WorldPortalExt};
pub struct RandomBooleanFeature { pub struct RandomBooleanFeature {
pub feature_true: Box<PlacedFeatureWrapper>, pub feature_true: Box<PlacedFeatureWrapper>,
@ -16,7 +16,7 @@ impl RandomBooleanFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, // This placed feature feature_name: &str, // This placed feature

View File

@ -4,7 +4,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{generation::feature::placed_features::PlacedFeature, world::BlockRegistryExt}; use crate::{generation::feature::placed_features::PlacedFeature, world::WorldPortalExt};
pub struct RandomPatchFeature { pub struct RandomPatchFeature {
pub tries: u8, pub tries: u8,
@ -18,7 +18,7 @@ impl RandomPatchFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature: &str, feature: &str,

View File

@ -4,7 +4,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{generation::feature::placed_features::PlacedFeatureWrapper, world::BlockRegistryExt}; use crate::{generation::feature::placed_features::PlacedFeatureWrapper, world::WorldPortalExt};
pub struct RandomFeature { pub struct RandomFeature {
pub features: Vec<RandomFeatureEntry>, pub features: Vec<RandomFeatureEntry>,
@ -21,7 +21,7 @@ impl RandomFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, // This placed feature feature_name: &str, // This placed feature

View File

@ -6,7 +6,7 @@ use pumpkin_util::{
use crate::generation::block_predicate::BlockPredicate; use crate::generation::block_predicate::BlockPredicate;
use crate::generation::block_state_provider::BlockStateProvider; use crate::generation::block_state_provider::BlockStateProvider;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct RootSystemFeature { pub struct RootSystemFeature {
pub feature: Box<crate::generation::feature::placed_features::PlacedFeature>, pub feature: Box<crate::generation::feature::placed_features::PlacedFeature>,
@ -29,7 +29,7 @@ impl RootSystemFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, feature_name: &str,
@ -87,7 +87,7 @@ impl RootSystemFeature {
fn place_roots<T: GenerationCache>( fn place_roots<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
) { ) {
@ -98,7 +98,7 @@ impl RootSystemFeature {
fn place_rooted_dirt<T: GenerationCache>( fn place_rooted_dirt<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
) { ) {
@ -151,7 +151,7 @@ impl RootSystemFeature {
fn place_hanging_roots<T: GenerationCache>( fn place_hanging_roots<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,
) { ) {

View File

@ -4,7 +4,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
use super::ore::{OreFeature, OreTarget}; use super::ore::{OreFeature, OreTarget};
@ -19,7 +19,7 @@ impl ScatteredOreFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, _feature: &str,

View File

@ -6,7 +6,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct SculkPatchFeature { pub struct SculkPatchFeature {
pub charge_count: i32, pub charge_count: i32,
@ -21,7 +21,7 @@ pub struct SculkPatchFeature {
impl SculkPatchFeature { impl SculkPatchFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
chunk: &mut T, chunk: &mut T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,

View File

@ -4,7 +4,7 @@ use pumpkin_util::{math::position::BlockPos, random::RandomGenerator};
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{ use crate::{
generation::block_state_provider::BlockStateProvider, generation::block_state_provider::BlockStateProvider,
world::{BlockAccessor, BlockRegistryExt}, world::{BlockAccessor, WorldPortalExt},
}; };
pub struct SimpleBlockFeature { pub struct SimpleBlockFeature {
@ -15,7 +15,7 @@ pub struct SimpleBlockFeature {
impl SimpleBlockFeature { impl SimpleBlockFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &mut T, chunk: &mut T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,

View File

@ -4,7 +4,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::{generation::feature::placed_features::PlacedFeature, world::BlockRegistryExt}; use crate::{generation::feature::placed_features::PlacedFeature, world::WorldPortalExt};
pub struct SimpleRandomFeature { pub struct SimpleRandomFeature {
pub features: Vec<PlacedFeature>, pub features: Vec<PlacedFeature>,
@ -15,7 +15,7 @@ impl SimpleRandomFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, // This placed feature feature_name: &str, // This placed feature

View File

@ -2,7 +2,7 @@ use pumpkin_data::{BlockDirection, BlockState};
use pumpkin_util::{math::position::BlockPos, random::RandomGenerator}; use pumpkin_util::{math::position::BlockPos, random::RandomGenerator};
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct SpringFeatureFeature { pub struct SpringFeatureFeature {
pub state: &'static BlockState, pub state: &'static BlockState,
@ -30,7 +30,7 @@ impl BlockWrapper {
impl SpringFeatureFeature { impl SpringFeatureFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
chunk: &mut T, chunk: &mut T,
_random: &mut RandomGenerator, _random: &mut RandomGenerator,
pos: BlockPos, pos: BlockPos,

View File

@ -8,7 +8,7 @@ use trunk::TrunkPlacer;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::generation::{block_state_provider::BlockStateProvider, feature::size::FeatureSize}; use crate::generation::{block_state_provider::BlockStateProvider, feature::size::FeatureSize};
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub mod decorator; pub mod decorator;
pub mod foliage; pub mod foliage;
@ -35,7 +35,7 @@ impl TreeFeature {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &mut T, chunk: &mut T,
min_y: i8, min_y: i8,
height: u16, height: u16,
@ -78,7 +78,7 @@ impl TreeFeature {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
fn generate_main<T: GenerationCache>( fn generate_main<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &mut T, chunk: &mut T,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,

View File

@ -10,7 +10,7 @@ use crate::{
block_state_provider::BlockStateProvider, block_state_provider::BlockStateProvider,
feature::features::tree::{TreeNode, trunk::TrunkPlacer}, feature::features::tree::{TreeNode, trunk::TrunkPlacer},
}, },
world::BlockRegistryExt, world::WorldPortalExt,
}; };
pub struct BendingTrunkPlacer { pub struct BendingTrunkPlacer {
@ -22,7 +22,7 @@ impl BendingTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -7,7 +7,7 @@ use super::TrunkPlacer;
use crate::generation::block_state_provider::BlockStateProvider; use crate::generation::block_state_provider::BlockStateProvider;
use crate::generation::feature::features::tree::TreeNode; use crate::generation::feature::features::tree::TreeNode;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
use pumpkin_data::block_properties::Axis; use pumpkin_data::block_properties::Axis;
pub struct CherryTrunkPlacer { pub struct CherryTrunkPlacer {
@ -21,7 +21,7 @@ impl CherryTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -10,7 +10,7 @@ use crate::{
block_state_provider::BlockStateProvider, block_state_provider::BlockStateProvider,
feature::features::tree::{TreeFeature, TreeNode, trunk::TrunkPlacer}, feature::features::tree::{TreeFeature, TreeNode, trunk::TrunkPlacer},
}, },
world::BlockRegistryExt, world::WorldPortalExt,
}; };
pub struct DarkOakTrunkPlacer; pub struct DarkOakTrunkPlacer;
@ -18,7 +18,7 @@ pub struct DarkOakTrunkPlacer;
impl DarkOakTrunkPlacer { impl DarkOakTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -16,7 +16,7 @@ use crate::{
block_state_provider::BlockStateProvider, block_state_provider::BlockStateProvider,
feature::features::tree::{TreeFeature, TreeNode}, feature::features::tree::{TreeFeature, TreeNode},
}, },
world::BlockRegistryExt, world::WorldPortalExt,
}; };
pub struct FancyTrunkPlacer; pub struct FancyTrunkPlacer;
@ -24,7 +24,7 @@ pub struct FancyTrunkPlacer;
impl FancyTrunkPlacer { impl FancyTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -6,7 +6,7 @@ use super::TrunkPlacer;
use crate::generation::block_state_provider::BlockStateProvider; use crate::generation::block_state_provider::BlockStateProvider;
use crate::generation::feature::features::tree::TreeNode; use crate::generation::feature::features::tree::TreeNode;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
use pumpkin_data::BlockDirection; use pumpkin_data::BlockDirection;
pub struct ForkingTrunkPlacer; pub struct ForkingTrunkPlacer;
@ -14,7 +14,7 @@ pub struct ForkingTrunkPlacer;
impl ForkingTrunkPlacer { impl ForkingTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -7,7 +7,7 @@ use crate::{
block_state_provider::BlockStateProvider, block_state_provider::BlockStateProvider,
feature::features::tree::{TreeNode, trunk::TrunkPlacer}, feature::features::tree::{TreeNode, trunk::TrunkPlacer},
}, },
world::BlockRegistryExt, world::WorldPortalExt,
}; };
pub struct GiantTrunkPlacer; pub struct GiantTrunkPlacer;
@ -15,7 +15,7 @@ pub struct GiantTrunkPlacer;
impl GiantTrunkPlacer { impl GiantTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -15,7 +15,7 @@ use crate::{
trunk::{TrunkPlacer, giant::GiantTrunkPlacer}, trunk::{TrunkPlacer, giant::GiantTrunkPlacer},
}, },
}, },
world::BlockRegistryExt, world::WorldPortalExt,
}; };
pub struct MegaJungleTrunkPlacer; pub struct MegaJungleTrunkPlacer;
@ -23,7 +23,7 @@ pub struct MegaJungleTrunkPlacer;
impl MegaJungleTrunkPlacer { impl MegaJungleTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -15,7 +15,7 @@ use crate::generation::feature::features::tree::trunk::{
upwards_branching::UpwardsBranchingTrunkPlacer, upwards_branching::UpwardsBranchingTrunkPlacer,
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub mod bending; pub mod bending;
pub mod cherry; pub mod cherry;
@ -43,7 +43,7 @@ impl TrunkPlacer {
pub fn set_dirt<T: GenerationCache>( pub fn set_dirt<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &mut T, chunk: &mut T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
pos: &BlockPos, pos: &BlockPos,
@ -85,7 +85,7 @@ impl TrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,
chunk: &mut T, chunk: &mut T,
@ -122,7 +122,7 @@ impl TrunkType {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -6,14 +6,14 @@ use super::TrunkPlacer;
use crate::generation::block_state_provider::BlockStateProvider; use crate::generation::block_state_provider::BlockStateProvider;
use crate::generation::feature::features::tree::TreeNode; use crate::generation::feature::features::tree::TreeNode;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct StraightTrunkPlacer; pub struct StraightTrunkPlacer;
impl StraightTrunkPlacer { impl StraightTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -7,7 +7,7 @@ use super::TrunkPlacer;
use crate::generation::block_state_provider::BlockStateProvider; use crate::generation::block_state_provider::BlockStateProvider;
use crate::generation::feature::features::tree::{TreeFeature, TreeNode}; use crate::generation::feature::features::tree::{TreeFeature, TreeNode};
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
use pumpkin_data::BlockDirection; use pumpkin_data::BlockDirection;
pub struct UpwardsBranchingTrunkPlacer { pub struct UpwardsBranchingTrunkPlacer {
@ -21,7 +21,7 @@ impl UpwardsBranchingTrunkPlacer {
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
placer: &TrunkPlacer, placer: &TrunkPlacer,
height: u32, height: u32,
start_pos: BlockPos, start_pos: BlockPos,

View File

@ -8,7 +8,7 @@ use pumpkin_util::{
use crate::generation::block_predicate::BlockPredicate; use crate::generation::block_predicate::BlockPredicate;
use crate::generation::block_state_provider::BlockStateProvider; use crate::generation::block_state_provider::BlockStateProvider;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct VegetationPatchFeature { pub struct VegetationPatchFeature {
pub replaceable: BlockPredicate, pub replaceable: BlockPredicate,
@ -41,7 +41,7 @@ impl VegetationPatchFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, feature_name: &str,
@ -79,7 +79,7 @@ impl VegetationPatchFeature {
pub(crate) fn place_ground_patch<T: GenerationCache>( pub(crate) fn place_ground_patch<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
random: &mut RandomGenerator, random: &mut RandomGenerator,
origin: BlockPos, origin: BlockPos,
replaceable: &BlockPredicate, replaceable: &BlockPredicate,
@ -166,7 +166,7 @@ impl VegetationPatchFeature {
fn place_ground<T: GenerationCache>( fn place_ground<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
replaceable: &BlockPredicate, replaceable: &BlockPredicate,
random: &mut RandomGenerator, random: &mut RandomGenerator,
mut below_pos: BlockPos, mut below_pos: BlockPos,
@ -196,7 +196,7 @@ impl VegetationPatchFeature {
pub(crate) fn distribute_vegetation<T: GenerationCache>( pub(crate) fn distribute_vegetation<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
random: &mut RandomGenerator, random: &mut RandomGenerator,
min_y: i8, min_y: i8,
height: u16, height: u16,

View File

@ -2,7 +2,7 @@ use pumpkin_data::{Block, BlockDirection, BlockState, block_properties::BlockPro
use pumpkin_util::{math::position::BlockPos, random::RandomGenerator}; use pumpkin_util::{math::position::BlockPos, random::RandomGenerator};
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
pub struct VinesFeature; pub struct VinesFeature;
@ -11,7 +11,7 @@ impl VinesFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_min_y: i8, _min_y: i8,
_height: u16, _height: u16,
_feature: &str, _feature: &str,

View File

@ -6,7 +6,7 @@ use pumpkin_util::{
}; };
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
use pumpkin_data::BlockDirection; use pumpkin_data::BlockDirection;
use super::vegetation_patch::VegetationPatchFeature; use super::vegetation_patch::VegetationPatchFeature;
@ -20,7 +20,7 @@ impl WaterloggedVegetationPatchFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, feature_name: &str,
@ -64,7 +64,7 @@ impl WaterloggedVegetationPatchFeature {
fn place_ground_patch<T: GenerationCache>( fn place_ground_patch<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
random: &mut RandomGenerator, random: &mut RandomGenerator,
origin: BlockPos, origin: BlockPos,
replaceable: &crate::generation::block_predicate::BlockPredicate, replaceable: &crate::generation::block_predicate::BlockPredicate,
@ -98,7 +98,7 @@ impl WaterloggedVegetationPatchFeature {
fn place_vegetation<T: GenerationCache>( fn place_vegetation<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, feature_name: &str,

View File

@ -15,7 +15,7 @@ use crate::block::RawBlockState;
use crate::generation::block_predicate::BlockPredicate; use crate::generation::block_predicate::BlockPredicate;
use crate::generation::height_provider::HeightProvider; use crate::generation::height_provider::HeightProvider;
use crate::generation::proto_chunk::GenerationCache; use crate::generation::proto_chunk::GenerationCache;
use crate::world::BlockRegistryExt; use crate::world::WorldPortalExt;
use super::configured_features::{CONFIGURED_FEATURES, ConfiguredFeature}; use super::configured_features::{CONFIGURED_FEATURES, ConfiguredFeature};
@ -54,7 +54,7 @@ impl PlacedFeature {
pub fn generate<T: GenerationCache>( pub fn generate<T: GenerationCache>(
&self, &self,
chunk: &mut T, chunk: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature_name: &str, // This placed feature feature_name: &str, // This placed feature
@ -129,7 +129,7 @@ impl PlacementModifier {
pub fn get_positions<T: GenerationCache>( pub fn get_positions<T: GenerationCache>(
&self, &self,
chunk: &T, chunk: &T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
min_y: i8, min_y: i8,
height: u16, height: u16,
feature: &str, feature: &str,
@ -213,7 +213,7 @@ impl EnvironmentScanPlacementModifier {
pub fn get_positions<T: GenerationCache>( pub fn get_positions<T: GenerationCache>(
&self, &self,
chunk: &T, chunk: &T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
pos: BlockPos, pos: BlockPos,
) -> Box<dyn Iterator<Item = BlockPos>> { ) -> Box<dyn Iterator<Item = BlockPos>> {
let allowed_search_condition = self let allowed_search_condition = self
@ -339,7 +339,7 @@ pub struct BlockFilterPlacementModifier {
impl ConditionalPlacementModifier for BlockFilterPlacementModifier { impl ConditionalPlacementModifier for BlockFilterPlacementModifier {
fn should_place<T: GenerationCache>( fn should_place<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
_feature: &str, _feature: &str,
chunk: &T, chunk: &T,
_random: &mut RandomGenerator, _random: &mut RandomGenerator,
@ -358,7 +358,7 @@ pub struct SurfaceThresholdFilterPlacementModifier {
impl ConditionalPlacementModifier for SurfaceThresholdFilterPlacementModifier { impl ConditionalPlacementModifier for SurfaceThresholdFilterPlacementModifier {
fn should_place<T: GenerationCache>( fn should_place<T: GenerationCache>(
&self, &self,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_feature: &str, _feature: &str,
chunk: &T, chunk: &T,
_random: &mut RandomGenerator, _random: &mut RandomGenerator,
@ -378,7 +378,7 @@ pub struct RarityFilterPlacementModifier {
impl ConditionalPlacementModifier for RarityFilterPlacementModifier { impl ConditionalPlacementModifier for RarityFilterPlacementModifier {
fn should_place<T: GenerationCache>( fn should_place<T: GenerationCache>(
&self, &self,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_feature: &str, _feature: &str,
_chunk: &T, _chunk: &T,
random: &mut RandomGenerator, random: &mut RandomGenerator,
@ -418,7 +418,7 @@ pub struct SurfaceWaterDepthFilterPlacementModifier {
impl ConditionalPlacementModifier for SurfaceWaterDepthFilterPlacementModifier { impl ConditionalPlacementModifier for SurfaceWaterDepthFilterPlacementModifier {
fn should_place<T: GenerationCache>( fn should_place<T: GenerationCache>(
&self, &self,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
_feature: &str, _feature: &str,
chunk: &T, chunk: &T,
_random: &mut RandomGenerator, _random: &mut RandomGenerator,
@ -435,7 +435,7 @@ pub struct BiomePlacementModifier;
impl ConditionalPlacementModifier for BiomePlacementModifier { impl ConditionalPlacementModifier for BiomePlacementModifier {
fn should_place<T: GenerationCache>( fn should_place<T: GenerationCache>(
&self, &self,
_block_registry: &dyn BlockRegistryExt, _block_registry: &dyn WorldPortalExt,
this_feature: &str, this_feature: &str,
chunk: &T, chunk: &T,
_random: &mut RandomGenerator, _random: &mut RandomGenerator,
@ -510,7 +510,7 @@ pub trait CountPlacementModifierBase {
pub trait ConditionalPlacementModifier { pub trait ConditionalPlacementModifier {
fn get_positions<T: GenerationCache>( fn get_positions<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
chunk: &T, chunk: &T,
feature: &str, feature: &str,
random: &mut RandomGenerator, random: &mut RandomGenerator,
@ -525,7 +525,7 @@ pub trait ConditionalPlacementModifier {
fn should_place<T: GenerationCache>( fn should_place<T: GenerationCache>(
&self, &self,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
feature: &str, feature: &str,
chunk: &T, chunk: &T,
random: &mut RandomGenerator, random: &mut RandomGenerator,

View File

@ -42,6 +42,7 @@ use crate::generation::noise::perlin::DoublePerlinNoiseSampler;
use crate::generation::noise::router::multi_noise_sampler::MultiNoiseSamplerBuilderOptions; use crate::generation::noise::router::multi_noise_sampler::MultiNoiseSamplerBuilderOptions;
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::section_coords::section_to_block;
use crate::generation::structure::lazily_generate_structure; use crate::generation::structure::lazily_generate_structure;
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::{
@ -54,7 +55,7 @@ use crate::{
block::RawBlockState, block::RawBlockState,
chunk::CHUNK_AREA, chunk::CHUNK_AREA,
generation::{biome, positions::chunk_pos}, generation::{biome, positions::chunk_pos},
world::{BlockAccessor, BlockRegistryExt}, world::{BlockAccessor, WorldPortalExt},
}; };
use pumpkin_data::tag::get_tag_ids; use pumpkin_data::tag::get_tag_ids;
use pumpkin_nbt::compound::NbtCompound; use pumpkin_nbt::compound::NbtCompound;
@ -777,6 +778,23 @@ impl ProtoChunk {
} }
} }
pub fn spawn_mobs<T: GenerationCache>(cache: &mut T, block_registry: &dyn WorldPortalExt) {
let chunk = cache.get_center_chunk();
debug_assert_eq!(chunk.stage, StagedChunkEnum::Lighting);
let biome = chunk.get_terrain_gen_biome(
section_to_block(chunk.x),
chunk.bottom_y() as i32 + chunk.height() as i32 - 1,
section_to_block(chunk.z),
);
let x = chunk.x;
let z = chunk.z;
block_registry.spawn_mobs_for_chunk_generation(cache, biome, x, z);
cache.get_center_chunk_mut().stage = StagedChunkEnum::Spawn;
}
#[must_use] #[must_use]
pub fn get_terrain_gen_biome_id(&self, x: i32, y: i32, z: i32) -> u8 { pub fn get_terrain_gen_biome_id(&self, x: i32, y: i32, z: i32) -> u8 {
// TODO: See if we can cache this value // TODO: See if we can cache this value
@ -943,7 +961,7 @@ impl ProtoChunk {
/// 2. Then, using the second file, we determine **how** to generate the feature. /// 2. Then, using the second file, we determine **how** to generate the feature.
pub fn generate_features_and_structure<T: GenerationCache>( pub fn generate_features_and_structure<T: GenerationCache>(
cache: &mut T, cache: &mut T,
block_registry: &dyn BlockRegistryExt, block_registry: &dyn WorldPortalExt,
random_config: &GlobalRandomConfig, random_config: &GlobalRandomConfig,
) { ) {
let (center_x, center_z, min_y, height, biomes_in_chunk) = { let (center_x, center_z, min_y, height, biomes_in_chunk) = {

View File

@ -14,8 +14,9 @@ use crate::{
}, },
generation::get_world_gen, generation::get_world_gen,
tick::{OrderedTick, ScheduledTick, TickPriority}, tick::{OrderedTick, ScheduledTick, TickPriority},
world::BlockRegistryExt, world::WorldPortalExt,
}; };
use arc_swap::ArcSwap;
use dashmap::{DashMap, Entry}; use dashmap::{DashMap, Entry};
use pumpkin_config::{chunk::ChunkConfig, lighting::LightingEngineConfig, world::LevelConfig}; use pumpkin_config::{chunk::ChunkConfig, lighting::LightingEngineConfig, world::LevelConfig};
use pumpkin_data::biome::Biome; use pumpkin_data::biome::Biome;
@ -24,14 +25,11 @@ use pumpkin_data::{Block, block_properties::has_random_ticks, fluid::Fluid};
use pumpkin_util::math::{position::BlockPos, vector2::Vector2}; use pumpkin_util::math::{position::BlockPos, vector2::Vector2};
use pumpkin_util::world_seed::Seed; use pumpkin_util::world_seed::Seed;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use std::sync::Mutex; use std::sync::{Arc, Mutex};
use std::time::Duration; use std::time::Duration;
use std::{ use std::{
path::PathBuf, path::PathBuf,
sync::{ sync::atomic::{AtomicBool, AtomicU64, Ordering},
Arc,
atomic::{AtomicBool, AtomicU64, Ordering},
},
thread, thread,
}; };
use tokio::time::timeout; use tokio::time::timeout;
@ -62,7 +60,7 @@ pub type SyncEntityChunk = Arc<ChunkEntityData>;
/// For more details on world generation, refer to the `WorldGenerator` module. /// For more details on world generation, refer to the `WorldGenerator` module.
pub struct Level { pub struct Level {
pub seed: Seed, pub seed: Seed,
pub block_registry: Arc<dyn BlockRegistryExt>, pub world_portal: ArcSwap<Option<Arc<dyn WorldPortalExt>>>,
pub level_folder: LevelFolder, pub level_folder: LevelFolder,
pub lighting_config: LightingEngineConfig, pub lighting_config: LightingEngineConfig,
@ -143,7 +141,6 @@ impl Level {
pub fn from_root_folder( pub fn from_root_folder(
level_config: &LevelConfig, level_config: &LevelConfig,
root_folder: PathBuf, root_folder: PathBuf,
block_registry: Arc<dyn BlockRegistryExt>,
seed: i64, seed: i64,
dimension: Dimension, dimension: Dimension,
gen_pool: Option<Arc<rayon::ThreadPool>>, gen_pool: Option<Arc<rayon::ThreadPool>>,
@ -187,7 +184,7 @@ impl Level {
let level_ref = Arc::new(Self { let level_ref = Arc::new(Self {
seed, seed,
block_registry, world_portal: ArcSwap::new(Arc::new(None)),
world_gen, world_gen,
level_folder, level_folder,
lighting_config: level_config.lighting, lighting_config: level_config.lighting,

View File

@ -1,8 +1,8 @@
use std::pin::Pin; use std::pin::Pin;
use crate::BlockStateId; use crate::{BlockStateId, generation::proto_chunk::GenerationCache};
use bitflags::bitflags; use bitflags::bitflags;
use pumpkin_data::{Block, BlockState}; use pumpkin_data::{Block, BlockState, chunk::Biome};
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
use thiserror::Error; use thiserror::Error;
@ -55,7 +55,7 @@ impl std::fmt::Display for GetBlockError {
pub type WorldFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>; pub type WorldFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub trait BlockRegistryExt: Send + Sync { pub trait WorldPortalExt: Send + Sync {
fn can_place_at( fn can_place_at(
&self, &self,
block: &Block, block: &Block,
@ -63,6 +63,14 @@ pub trait BlockRegistryExt: Send + Sync {
block_accessor: &dyn BlockAccessor, block_accessor: &dyn BlockAccessor,
block_pos: &BlockPos, block_pos: &BlockPos,
) -> bool; ) -> bool;
fn spawn_mobs_for_chunk_generation(
&self,
cache: &mut dyn GenerationCache,
biome: &'static Biome,
chunk_x: i32,
chunk_z: i32,
);
} }
pub trait BlockAccessor: Send + Sync { pub trait BlockAccessor: Send + Sync {

View File

@ -139,7 +139,7 @@ use pumpkin_protocol::java::server::play::SUseItemOn;
use pumpkin_util::math::boundingbox::BoundingBox; use pumpkin_util::math::boundingbox::BoundingBox;
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId; use pumpkin_world::BlockStateId;
use pumpkin_world::world::{BlockAccessor, BlockFlags, BlockRegistryExt}; use pumpkin_world::world::{BlockAccessor, BlockFlags};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
@ -372,31 +372,6 @@ pub struct BlockRegistry {
fluids: FxHashMap<u16, Arc<dyn FluidBehaviour>>, fluids: FxHashMap<u16, Arc<dyn FluidBehaviour>>,
} }
impl BlockRegistryExt for BlockRegistry {
fn can_place_at(
&self,
block: &pumpkin_data::Block,
state: &BlockState,
block_accessor: &dyn BlockAccessor,
block_pos: &BlockPos,
) -> bool {
futures::executor::block_on(async move {
self.can_place_at(
None,
None,
block_accessor,
None,
block,
state,
block_pos,
None,
None,
)
.await
})
}
}
impl BlockRegistry { impl BlockRegistry {
pub fn register<T: BlockBehaviour + BlockMetadata + 'static>(&mut self, block: T) { pub fn register<T: BlockBehaviour + BlockMetadata + 'static>(&mut self, block: T) {
let ids = T::ids(); let ids = T::ids();

View File

@ -11,6 +11,7 @@ use crate::plugin::PluginManager;
use crate::plugin::player::player_login::PlayerLoginEvent; use crate::plugin::player::player_login::PlayerLoginEvent;
use crate::plugin::server::server_broadcast::ServerBroadcastEvent; use crate::plugin::server::server_broadcast::ServerBroadcastEvent;
use crate::server::tick_rate_manager::ServerTickRateManager; use crate::server::tick_rate_manager::ServerTickRateManager;
use crate::world::WorldPortal;
use crate::world::custom_bossbar::CustomBossbars; use crate::world::custom_bossbar::CustomBossbars;
use crate::{ use crate::{
command::node::dispatcher::CommandDispatcher, entity::player::Player, world::World, command::node::dispatcher::CommandDispatcher, entity::player::Player, world::World,
@ -25,6 +26,7 @@ use pumpkin_data::entity::EntityType;
use pumpkin_util::permission::{PermissionManager, PermissionRegistry}; use pumpkin_util::permission::{PermissionManager, PermissionRegistry};
use pumpkin_util::text::color::NamedColor; use pumpkin_util::text::color::NamedColor;
use pumpkin_world::dimension::into_level; use pumpkin_world::dimension::into_level;
use pumpkin_world::world::WorldPortalExt;
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, warn};
use crate::command::CommandSender; use crate::command::CommandSender;
@ -284,13 +286,14 @@ impl Server {
.color_named(NamedColor::DarkGreen) .color_named(NamedColor::DarkGreen)
.to_pretty_console() .to_pretty_console()
); );
World::load( let level = into_level(dim, &config, path, seed, Some(pool));
into_level(dim, &config, path, registry.clone(), seed, Some(pool)), let world = Arc::new(World::load(level.clone(), l_info, dim, registry, weak));
l_info, let portal: Arc<dyn WorldPortalExt> = Arc::new(WorldPortal(
dim, world.clone(),
registry, tokio::runtime::Handle::current(),
weak, ));
) level.world_portal.store(Arc::new(Some(portal)));
world
}) })
}; };
@ -303,9 +306,9 @@ impl Server {
); );
let worlds_vec = vec![ let worlds_vec = vec![
Arc::new(overworld.expect("Overworld panicked")), overworld.expect("Overworld panicked"),
Arc::new(nether.expect("Nether panicked")), nether.expect("Nether panicked"),
Arc::new(end.expect("End panicked")), end.expect("End panicked"),
]; ];
server.worlds.store(Arc::new(worlds_vec)); server.worlds.store(Arc::new(worlds_vec));
if let Ok(k) = keys { if let Ok(k) = keys {
@ -380,27 +383,21 @@ impl Server {
let seed = server.level_info.load().world_gen_settings.seed; let seed = server.level_info.load().world_gen_settings.seed;
// TODO: gen_pool should be reused // TODO: gen_pool should be reused
let world = World::load( let level =
pumpkin_world::dimension::into_level( pumpkin_world::dimension::into_level(dimension, &config, world_path, seed, None);
dimension, let world: World = World::load(level.clone(), l_info, dimension, registry, weak);
&config, let world = Arc::new(world);
world_path, let portal: Arc<dyn WorldPortalExt> = Arc::new(WorldPortal(
registry.clone(), world.clone(),
seed, tokio::runtime::Handle::current(),
None, ));
), level.world_portal.store(Arc::new(Some(portal)));
l_info,
dimension,
registry,
weak,
);
let world_arc = Arc::new(world);
server.worlds.rcu(|worlds| { server.worlds.rcu(|worlds| {
let mut new_worlds = (**worlds).clone(); let mut new_worlds = (**worlds).clone();
new_worlds.push(world_arc.clone()); new_worlds.push(world.clone());
new_worlds new_worlds
}); });
world_arc world
}) })
.await .await
.expect("World creation panicked") .expect("World creation panicked")

View File

@ -1,7 +1,9 @@
use crate::block::entities::BlockEntity; use crate::block::entities::BlockEntity;
use dashmap::DashMap; use dashmap::DashMap;
use pumpkin_data::chunk::Biome;
use pumpkin_protocol::bedrock::client::level_event::{CLevelEvent, LevelEvent}; use pumpkin_protocol::bedrock::client::level_event::{CLevelEvent, LevelEvent};
use pumpkin_protocol::codec::data_component::data_to_proto_sound; use pumpkin_protocol::codec::data_component::data_to_proto_sound;
use pumpkin_world::generation::proto_chunk::GenerationCache;
use std::pin::Pin; use std::pin::Pin;
use std::sync::atomic::Ordering::Relaxed; use std::sync::atomic::Ordering::Relaxed;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
@ -9,6 +11,7 @@ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
sync::atomic::Ordering, sync::atomic::Ordering,
}; };
use tokio::runtime::Handle;
use tracing::{debug, error, info, trace, warn}; use tracing::{debug, error, info, trace, warn};
pub mod chunker; pub mod chunker;
@ -121,7 +124,7 @@ use pumpkin_util::{
random::{RandomImpl, get_seed, xoroshiro128::Xoroshiro}, random::{RandomImpl, get_seed, xoroshiro128::Xoroshiro},
}; };
use pumpkin_world::inventory::Clearable; use pumpkin_world::inventory::Clearable;
use pumpkin_world::world::GetBlockError; use pumpkin_world::world::{GetBlockError, WorldPortalExt};
use pumpkin_world::{ use pumpkin_world::{
BlockStateId, CURRENT_BEDROCK_MC_VERSION, biome, chunk::io::Dirtiable, inventory::Inventory, BlockStateId, CURRENT_BEDROCK_MC_VERSION, biome, chunk::io::Dirtiable, inventory::Inventory,
}; };
@ -3187,12 +3190,7 @@ impl World {
pub async fn add_entity_silent(&self, entity: Arc<dyn EntityBase>) { pub async fn add_entity_silent(&self, entity: Arc<dyn EntityBase>) {
let base_entity = entity.get_entity(); let base_entity = entity.get_entity();
// Update biome
let block_pos = base_entity.block_pos.load(); let block_pos = base_entity.block_pos.load();
let biome = self.level.get_rough_biome(&block_pos).await;
base_entity.current_biome.store(Arc::new(biome));
base_entity.last_biome_update_pos.store(block_pos);
let chunk_coordinate = block_pos.chunk_position(); let chunk_coordinate = block_pos.chunk_position();
let mut nbt = PNbtCompound::new(); let mut nbt = PNbtCompound::new();
entity.write_nbt(&mut nbt).await; entity.write_nbt(&mut nbt).await;
@ -4303,3 +4301,52 @@ impl BlockAccessor for World {
Box::pin(async move { self.get_block_and_state(position).await }) Box::pin(async move { self.get_block_and_state(position).await })
} }
} }
pub struct WorldPortal(pub Arc<World>, pub Handle);
// Pure Beauty :cap:
impl WorldPortalExt for WorldPortal {
fn can_place_at(
&self,
block: &pumpkin_data::Block,
state: &BlockState,
block_accessor: &dyn BlockAccessor,
block_pos: &BlockPos,
) -> bool {
let handle = &self.1;
handle.block_on(async move {
self.0
.block_registry
.can_place_at(
None,
None,
block_accessor,
None,
block,
state,
block_pos,
None,
None,
)
.await
})
}
fn spawn_mobs_for_chunk_generation(
&self,
cache: &mut dyn GenerationCache,
biome: &'static Biome,
chunk_x: i32,
chunk_z: i32,
) {
let handle = &self.1;
handle.block_on(async move {
natural_spawner::spawn_mobs_for_chunk_generation(
&self.0, cache, biome, chunk_x, chunk_z,
)
.await;
});
}
}

View File

@ -3,6 +3,7 @@ use crate::entity::r#type::from_type;
use crate::world::World; use crate::world::World;
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use pumpkin_data::biome::Spawner; use pumpkin_data::biome::Spawner;
use pumpkin_data::chunk::Biome;
use pumpkin_data::entity::{EntityType, MobCategory, SpawnLocation}; use pumpkin_data::entity::{EntityType, MobCategory, SpawnLocation};
use pumpkin_data::tag::Block::MINECRAFT_PREVENT_MOB_SPAWNING_INSIDE; use pumpkin_data::tag::Block::MINECRAFT_PREVENT_MOB_SPAWNING_INSIDE;
use pumpkin_data::tag::Fluid::{MINECRAFT_LAVA, MINECRAFT_WATER}; use pumpkin_data::tag::Fluid::{MINECRAFT_LAVA, MINECRAFT_WATER};
@ -20,6 +21,7 @@ use pumpkin_util::random::xoroshiro128::Xoroshiro;
use pumpkin_util::random::{RandomImpl, get_seed}; use pumpkin_util::random::{RandomImpl, get_seed};
use pumpkin_world::chunk::io::Dirtiable; use pumpkin_world::chunk::io::Dirtiable;
use pumpkin_world::chunk::{ChunkData, ChunkHeightmapType}; use pumpkin_world::chunk::{ChunkData, ChunkHeightmapType};
use pumpkin_world::generation::proto_chunk::GenerationCache;
use rand::seq::IndexedRandom; use rand::seq::IndexedRandom;
use rand::{RngExt, rng}; use rand::{RngExt, rng};
use std::fmt; use std::fmt;
@ -503,6 +505,126 @@ pub fn get_random_pos_within(
BlockPos::new(x, y, z) BlockPos::new(x, y, z)
} }
pub async fn spawn_mobs_for_chunk_generation(
world: &Arc<World>,
cache: &mut dyn GenerationCache,
biome: &'static Biome,
chunk_x: i32,
chunk_z: i32,
) {
let mob_settings = &biome.spawners;
let creatures = &mob_settings.creature;
if creatures.is_empty() {
return;
}
let xo = chunk_x << 4;
let zo = chunk_z << 4;
while rand::random::<f32>() < biome.creature_spawn_probability {
let Some(spawner_data) = creatures.choose(&mut rand::rng()) else {
continue;
};
let count = spawner_data.min_count
+ rand::random_range(0..(1 + spawner_data.max_count - spawner_data.min_count).max(1));
let entity_type = EntityType::from_name(
spawner_data
.r#type
.strip_prefix("minecraft:")
.unwrap_or(spawner_data.r#type),
)
.unwrap();
let mut x = xo + rand::random_range(0..16);
let mut z = zo + rand::random_range(0..16);
let start_x = x;
let start_z = z;
for _ in 0..count {
let mut success = false;
// Try 4 times to find a valid spot in the immediate area
for _ in 0..4 {
if success {
break;
}
let pos = get_top_non_colliding_pos(world, cache, entity_type, x, z);
if is_spawn_position_ok_cache(cache, &pos, entity_type) {
let spawn_pos_f64 = Vector3::new(
f64::from(pos.0.x) + 0.5,
f64::from(pos.0.y),
f64::from(pos.0.z) + 0.5,
);
let entity = from_type(entity_type, spawn_pos_f64, world, Uuid::new_v4()).await;
entity
.get_entity()
.set_rotation(rand::random::<f32>() * 360., 0.);
world.spawn_entity(entity).await;
success = true;
}
// Random jitter for the next mob in the group
x += rand::random_range(0..5) - rand::random_range(0..5);
z += rand::random_range(0..5) - rand::random_range(0..5);
// Keep group within the chunk bounds
if x < xo || x >= xo + 16 || z < zo || z >= zo + 16 {
x = start_x;
z = start_z;
}
}
}
}
}
pub fn get_top_non_colliding_pos(
world: &World,
cache: &dyn GenerationCache,
entity_type: &'static EntityType,
x: i32,
z: i32,
) -> BlockPos {
let mut y = cache.get_top_y(&entity_type.spawn_restriction.heightmap, x, z);
let mut pos_vec = Vector3::new(x, y, z);
let min_y = world.min_y;
if world.dimension.has_ceiling {
loop {
y -= 1;
pos_vec.y = y;
// Use UFCS to avoid the ambiguity error from earlier
if GenerationCache::get_block_state(cache, &pos_vec)
.to_state()
.is_air()
|| y <= min_y
{
break;
}
}
loop {
y -= 1;
pos_vec.y = y;
if !GenerationCache::get_block_state(cache, &pos_vec)
.to_state()
.is_air()
|| y <= min_y
{
break;
}
}
}
let pos = BlockPos::new(x, y, z);
adjust_spawn_position_cache(cache, pos, entity_type)
}
pub async fn spawn_category_for_position( pub async fn spawn_category_for_position(
category: &'static MobCategory, category: &'static MobCategory,
world: &Arc<World>, world: &Arc<World>,
@ -768,6 +890,69 @@ pub async fn is_spawn_position_ok(
} }
} }
/// Cache-based version of `is_spawn_position_ok` used during world generation.
pub fn is_spawn_position_ok_cache(
cache: &dyn GenerationCache,
block_pos: &BlockPos,
entity_type: &'static EntityType,
) -> bool {
let pos_vec = block_pos.0;
let state = GenerationCache::get_block_state(cache, &pos_vec).to_state();
match entity_type.spawn_restriction.location {
SpawnLocation::InLava => {
// During generation, we check the block state's liquid property and tag
state.is_liquid() && Block::from_state_id(state.id).has_tag(&MINECRAFT_LAVA)
}
SpawnLocation::InWater => {
let above_pos = block_pos.up().0;
let above_state = GenerationCache::get_block_state(cache, &above_pos).to_state();
state.is_liquid()
&& Block::from_state_id(state.id).has_tag(&MINECRAFT_WATER)
&& !above_state.is_full_cube()
}
SpawnLocation::OnGround => {
let down_pos = block_pos.down().0;
let up_pos = block_pos.up().0;
let down = GenerationCache::get_block_state(cache, &down_pos).to_state();
let up = GenerationCache::get_block_state(cache, &up_pos).to_state();
// Logic: solid surface below and low enough light level (if applicable in generation)
let is_valid_spawn_below =
down.is_side_solid(BlockDirection::Up) && down.luminance < 14;
if is_valid_spawn_below {
is_valid_empty_spawn_block(state) && is_valid_empty_spawn_block(up)
} else {
false
}
}
SpawnLocation::Unrestricted => true,
}
}
/// Cache-based version of `adjust_spawn_position` used during world generation.
pub fn adjust_spawn_position_cache(
cache: &dyn GenerationCache,
pos: BlockPos,
entity_type: &'static EntityType,
) -> BlockPos {
if matches!(
entity_type.spawn_restriction.location,
SpawnLocation::OnGround
) {
let below = pos.down();
let state = GenerationCache::get_block_state(cache, &below.0).to_state();
if !state.is_full_cube() && !state.is_liquid() {
return below;
}
}
pos
}
pub async fn adjust_spawn_position( pub async fn adjust_spawn_position(
world: &World, world: &World,
pos: BlockPos, pos: BlockPos,