86 lines
3.7 KiB
Rust
86 lines
3.7 KiB
Rust
use crate::generation::proto_chunk::GenerationCache;
|
|
use pumpkin_data::{Block, BlockState};
|
|
use pumpkin_util::{
|
|
math::position::BlockPos,
|
|
random::{RandomGenerator, RandomImpl},
|
|
};
|
|
|
|
pub struct KelpFeature;
|
|
|
|
impl KelpFeature {
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub fn generate<T: GenerationCache>(
|
|
chunk: &mut T,
|
|
_min_y: i8,
|
|
_height: u16,
|
|
_feature: pumpkin_data::placed_feature::PlacedFeature,
|
|
random: &mut RandomGenerator,
|
|
pos: BlockPos,
|
|
) -> bool {
|
|
let mut placed = 0;
|
|
|
|
// Start on the ocean floor
|
|
let y = chunk.ocean_floor_height_exclusive(pos.0.x, pos.0.z);
|
|
let mut kelp_pos = BlockPos::new(pos.0.x, y, pos.0.z);
|
|
|
|
// Must be in water
|
|
if GenerationCache::get_block_state(chunk, &kelp_pos.0).to_block_id() == Block::WATER {
|
|
let height_rand = 1 + random.next_bounded_i32(10);
|
|
|
|
// Iterate from base up to height_rand
|
|
for h in 0..=height_rand {
|
|
// Check there is water at this position and one above
|
|
if GenerationCache::get_block_state(chunk, &kelp_pos.0).to_block_id()
|
|
== Block::WATER
|
|
&& GenerationCache::get_block_state(
|
|
chunk,
|
|
&BlockPos::new(kelp_pos.0.x, kelp_pos.0.y + 1, kelp_pos.0.z).0,
|
|
)
|
|
.to_block_id()
|
|
== Block::WATER
|
|
{
|
|
// If this is the last iteration place the kelp head with age
|
|
if h == height_rand {
|
|
let age = random.next_bounded_i32(4) + 20;
|
|
// Clamp in case it goes past available states
|
|
let age = age.min((Block::KELP.states.len() - 1) as i32) as usize;
|
|
let state_id = Block::KELP.states[age].id;
|
|
let state = BlockState::from_id(state_id);
|
|
chunk.set_block_state(&kelp_pos.0, state);
|
|
placed += 1;
|
|
} else {
|
|
// Place kelp plant body
|
|
let state_id = Block::KELP_PLANT.default_state.id;
|
|
let state = BlockState::from_id(state_id);
|
|
chunk.set_block_state(&kelp_pos.0, state);
|
|
}
|
|
} else if h > 0 {
|
|
// Can't place further but we have already placed at least one segment, try to put head below
|
|
let below = BlockPos::new(kelp_pos.0.x, kelp_pos.0.y - 1, kelp_pos.0.z);
|
|
// Check head block can survive and that below-below is not a kelp head
|
|
if GenerationCache::get_block_state(chunk, &below.0).to_block_id()
|
|
== Block::WATER
|
|
&& GenerationCache::get_block_state(
|
|
chunk,
|
|
&BlockPos::new(below.0.x, below.0.y - 1, below.0.z).0,
|
|
)
|
|
.to_block_id()
|
|
!= Block::KELP
|
|
{
|
|
let age = random.next_bounded_i32(4) + 20;
|
|
let age = age.min((Block::KELP.states.len() - 1) as i32) as usize;
|
|
let state_id = Block::KELP.states[age].id;
|
|
let state = BlockState::from_id(state_id);
|
|
chunk.set_block_state(&below.0, state);
|
|
placed += 1;
|
|
}
|
|
break;
|
|
}
|
|
kelp_pos = BlockPos::new(kelp_pos.0.x, kelp_pos.0.y + 1, kelp_pos.0.z);
|
|
}
|
|
}
|
|
|
|
placed > 0
|
|
}
|
|
}
|