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, pub portal_room_exists: bool, pub pieces: Vec>, } 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> { 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, last_piece_type: &mut Option, _has_portal_room: &mut bool, collector: &mut StructurePiecesCollector, pieces_to_process: &mut Vec>, ) { 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); } }