Pumpkin/pumpkin-world/src/generation/structure/structures/stronghold/spiral_staircase.rs
2026-05-15 18:24:28 +02:00

181 lines
5.5 KiB
Rust

use pumpkin_data::Block;
use pumpkin_util::{
BlockDirection,
math::block_box::BlockBox,
random::{RandomGenerator, RandomImpl},
};
use crate::{
ProtoChunk,
generation::structure::{
piece::StructurePieceType,
structures::{
StructurePiece, StructurePieceBase, StructurePiecesCollector,
stronghold::{
EntranceType, PieceWeight, StoneBrickRandomizer, StrongholdPiece,
StrongholdPieceType,
},
},
},
};
pub struct SpiralStaircasePiece {
pub piece: StrongholdPiece,
orientation: BlockDirection,
is_structure_start: bool,
// Start-specific fields
pub last_piece_data_idx: Option<usize>,
pub portal_room_exists: bool,
pub pieces: Vec<Box<dyn StructurePieceBase>>,
}
impl SpiralStaircasePiece {
/// Matches Start(Random random, int i, int j)
pub fn new_start(random: &mut impl RandomImpl, x: i32, z: i32) -> Self {
let orientation = BlockDirection::get_random_horizontal_direction(random);
let bounding_box = BlockBox::create_box(x, 64, z, orientation.get_axis(), 5, 11, 5);
let mut piece = StrongholdPiece::new(StructurePieceType::StrongholdStart, 0, bounding_box);
piece.piece.set_facing(Some(orientation));
Self {
piece,
orientation,
is_structure_start: true,
last_piece_data_idx: None,
portal_room_exists: false,
pieces: Vec::new(),
}
}
pub fn create(
collector: &mut StructurePiecesCollector,
random: &mut impl RandomImpl,
x: i32,
y: i32,
z: i32,
orientation: BlockDirection,
chain_length: u32,
) -> Option<Box<dyn StructurePieceBase>> {
let bounding_box = BlockBox::rotated(x, y, z, -1, -7, 0, 5, 11, 5, &orientation);
if !StrongholdPiece::is_in_bounds(&bounding_box)
|| collector.get_intersecting(&bounding_box).is_some()
{
return None;
}
let mut piece = StrongholdPiece::new(
StructurePieceType::StrongholdSpiralStaircase,
chain_length,
bounding_box,
);
piece.piece.set_facing(Some(orientation));
piece.entry_door = EntranceType::get_random(random);
Some(Box::new(Self {
piece,
orientation,
is_structure_start: false,
last_piece_data_idx: None,
portal_room_exists: false,
pieces: Vec::new(),
}))
}
#[must_use]
pub const fn has_portal_room(&self) -> bool {
self.portal_room_exists
}
}
impl StructurePieceBase for SpiralStaircasePiece {
fn get_structure_piece(&self) -> &StructurePiece {
&self.piece.piece
}
fn get_structure_piece_mut(&mut self) -> &mut StructurePiece {
&mut self.piece.piece
}
fn fill_openings(
&self,
start: &StructurePiece,
random: &mut RandomGenerator,
weights: &mut Vec<PieceWeight>,
last_piece_type: &mut Option<StrongholdPieceType>,
_has_portal_room: &mut bool,
collector: &mut StructurePiecesCollector,
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
) {
self.piece.fill_forward_opening(
start,
collector,
random,
weights,
last_piece_type,
1,
1,
pieces_to_process,
self.is_structure_start
.then_some(StrongholdPieceType::FiveWayCrossing),
);
}
fn place(
&mut self,
chunk: &mut ProtoChunk,
random: &mut RandomGenerator,
_seed: i64,
chunk_box: &BlockBox,
) {
let randomizer = StoneBrickRandomizer;
let box_limit = *chunk_box;
let p = &self.piece;
// 1. fillWithOutline (5x11x5 box)
p.piece.fill_outline_random(
0,
0,
0,
4,
10,
4,
&randomizer,
chunk,
true,
random,
&box_limit,
);
p.generate_entrance(chunk, &box_limit, self.piece.entry_door, 1, 7, 0);
p.generate_entrance(chunk, &box_limit, EntranceType::Opening, 1, 1, 4);
// 4. Spiral Staircase Blocks
let stone = Block::STONE_BRICKS.default_state;
let slab = Block::SMOOTH_STONE_SLAB.default_state;
// Use the inner StructurePiece for block placement helpers
let inner = &p.piece;
inner.add_block(chunk, stone, 2, 6, 1, &box_limit);
inner.add_block(chunk, stone, 1, 5, 1, &box_limit);
inner.add_block(chunk, slab, 1, 6, 1, &box_limit);
inner.add_block(chunk, stone, 1, 5, 2, &box_limit);
inner.add_block(chunk, stone, 1, 4, 3, &box_limit);
inner.add_block(chunk, slab, 1, 5, 3, &box_limit);
inner.add_block(chunk, stone, 2, 4, 3, &box_limit);
inner.add_block(chunk, stone, 3, 3, 3, &box_limit);
inner.add_block(chunk, slab, 3, 4, 3, &box_limit);
inner.add_block(chunk, stone, 3, 3, 2, &box_limit);
inner.add_block(chunk, stone, 3, 2, 1, &box_limit);
inner.add_block(chunk, slab, 3, 3, 1, &box_limit);
inner.add_block(chunk, stone, 2, 2, 1, &box_limit);
inner.add_block(chunk, stone, 1, 1, 1, &box_limit);
inner.add_block(chunk, slab, 1, 2, 1, &box_limit);
// Final bottom blocks from Java source
inner.add_block(chunk, stone, 1, 1, 2, &box_limit);
inner.add_block(chunk, slab, 1, 1, 3, &box_limit);
}
}