mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
148 lines
4.5 KiB
Rust
148 lines
4.5 KiB
Rust
use decorator::TreeDecorator;
|
|
use foliage::FoliagePlacer;
|
|
use pumpkin_data::tag;
|
|
use pumpkin_data::{Block, BlockState};
|
|
use pumpkin_util::{math::position::BlockPos, random::RandomGenerator};
|
|
|
|
use trunk::TrunkPlacer;
|
|
|
|
use crate::generation::proto_chunk::GenerationCache;
|
|
use crate::generation::{block_state_provider::BlockStateProvider, feature::size::FeatureSize};
|
|
use crate::world::BlockRegistryExt;
|
|
|
|
pub mod decorator;
|
|
pub mod foliage;
|
|
pub mod trunk;
|
|
|
|
pub struct TreeFeature {
|
|
pub trunk_provider: BlockStateProvider,
|
|
pub trunk_placer: TrunkPlacer,
|
|
pub foliage_provider: BlockStateProvider,
|
|
pub foliage_placer: FoliagePlacer,
|
|
pub minimum_size: FeatureSize,
|
|
pub ignore_vines: bool,
|
|
pub decorators: Vec<TreeDecorator>,
|
|
pub below_trunk_provider: BlockStateProvider,
|
|
}
|
|
|
|
pub struct TreeNode {
|
|
center: BlockPos,
|
|
foliage_radius: i32,
|
|
giant_trunk: bool,
|
|
}
|
|
|
|
impl TreeFeature {
|
|
#[expect(clippy::too_many_arguments)]
|
|
pub fn generate<T: GenerationCache>(
|
|
&self,
|
|
block_registry: &dyn BlockRegistryExt,
|
|
chunk: &mut T,
|
|
min_y: i8,
|
|
height: u16,
|
|
feature_name: &str, // This placed feature
|
|
random: &mut RandomGenerator,
|
|
pos: BlockPos,
|
|
) -> bool {
|
|
// TODO
|
|
let log_positions = self.generate_main(
|
|
block_registry,
|
|
chunk,
|
|
min_y,
|
|
height,
|
|
feature_name,
|
|
random,
|
|
pos,
|
|
);
|
|
|
|
for decorator in &self.decorators {
|
|
decorator.generate(chunk, random, &[], &log_positions);
|
|
}
|
|
true
|
|
}
|
|
|
|
pub fn can_replace_or_log(state: &BlockState, block: u16) -> bool {
|
|
Self::can_replace(state, block) || tag::Block::MINECRAFT_LOGS.1.contains(&block)
|
|
}
|
|
|
|
pub fn is_air_or_leaves(state: &BlockState, block: u16) -> bool {
|
|
state.is_air() || tag::Block::MINECRAFT_LEAVES.1.contains(&block)
|
|
}
|
|
|
|
pub fn can_replace(state: &BlockState, block: u16) -> bool {
|
|
state.is_air()
|
|
|| tag::Block::MINECRAFT_REPLACEABLE_BY_TREES
|
|
.1
|
|
.contains(&block)
|
|
}
|
|
|
|
#[expect(clippy::too_many_arguments)]
|
|
fn generate_main<T: GenerationCache>(
|
|
&self,
|
|
block_registry: &dyn BlockRegistryExt,
|
|
chunk: &mut T,
|
|
_min_y: i8,
|
|
_height: u16,
|
|
_feature_name: &str, // This placed feature
|
|
random: &mut RandomGenerator,
|
|
pos: BlockPos,
|
|
) -> Vec<BlockPos> {
|
|
let height = self.trunk_placer.get_height(random);
|
|
|
|
let clipped_height = self.minimum_size.min_clipped_height;
|
|
let top = self.get_top(height, chunk, pos); // TODO: roots
|
|
if top < height && (clipped_height.is_none() || top < clipped_height.unwrap() as u32) {
|
|
return vec![];
|
|
}
|
|
let trunk_state = self.trunk_provider.get(random, pos);
|
|
|
|
let (nodes, logs) = self.trunk_placer.generate(
|
|
block_registry,
|
|
top,
|
|
pos,
|
|
chunk,
|
|
random,
|
|
&self.below_trunk_provider,
|
|
trunk_state,
|
|
);
|
|
|
|
let foliage_height = self
|
|
.foliage_placer
|
|
.r#type
|
|
.get_random_height(random, height as i32);
|
|
let base_height = height as i32 - foliage_height;
|
|
let foliage_radius = self.foliage_placer.get_random_radius(random, base_height);
|
|
let foliage_state = self.foliage_provider.get(random, pos);
|
|
for node in nodes {
|
|
self.foliage_placer.generate(
|
|
chunk,
|
|
random,
|
|
&node,
|
|
foliage_height,
|
|
foliage_radius,
|
|
foliage_state,
|
|
);
|
|
}
|
|
logs
|
|
}
|
|
|
|
fn get_top<T: GenerationCache>(&self, height: u32, chunk: &T, init_pos: BlockPos) -> u32 {
|
|
for y in 0..=height + 1 {
|
|
let j = self.minimum_size.r#type.get_radius(height, y as i32);
|
|
for x in -j..=j {
|
|
for z in -j..=j {
|
|
let pos = BlockPos(init_pos.0.add_raw(x, y as i32, z));
|
|
let rstate = GenerationCache::get_block_state(chunk, &pos.0);
|
|
let block = rstate.to_block_id();
|
|
if Self::can_replace_or_log(rstate.to_state(), block)
|
|
&& (self.ignore_vines || block != Block::VINE)
|
|
{
|
|
continue;
|
|
}
|
|
return y.saturating_sub(2);
|
|
}
|
|
}
|
|
}
|
|
height
|
|
}
|
|
}
|