feat: Nether Fortress
Co-Authored-By: Richard Marshall <29306641+Purdze@users.noreply.github.com>
This commit is contained in:
parent
e125ca19be
commit
3f4cdd0695
@ -7,7 +7,7 @@ pub use difficulty::Difficulty;
|
||||
pub use gamemode::GameMode;
|
||||
pub use permission::PermissionLvl;
|
||||
|
||||
use crate::math::vector3::Axis;
|
||||
use crate::{math::vector3::Axis, random::RandomImpl};
|
||||
|
||||
pub mod biome;
|
||||
pub mod difficulty;
|
||||
@ -131,6 +131,15 @@ impl BlockDirection {
|
||||
Self::East | Self::West => Axis::X,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_random_horizontal_direction(random: &mut impl RandomImpl) -> Self {
|
||||
match random.next_bounded_i32(4) {
|
||||
0 => Self::North,
|
||||
1 => Self::East,
|
||||
2 => Self::South,
|
||||
_ => Self::West,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A mutable slice split into three parts: the element at the split index, the start, and the end.
|
||||
|
||||
@ -90,8 +90,14 @@ impl GenerationCache for Cache {
|
||||
let dx = chunk_x - self.x;
|
||||
let dz = chunk_z - self.z;
|
||||
|
||||
(dx >= 0 && dx < self.size && dz >= 0 && dz < self.size)
|
||||
.then(|| self.chunks[(dx * self.size + dz) as usize].get_proto_chunk())
|
||||
if dx < 0 || dx >= self.size || dz < 0 || dz >= self.size {
|
||||
return None;
|
||||
}
|
||||
|
||||
match &self.chunks[(dx * self.size + dz) as usize] {
|
||||
Chunk::Proto(chunk) => Some(chunk),
|
||||
Chunk::Level(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn try_get_proto_chunk(&self, chunk_x: i32, chunk_z: i32) -> Option<&ProtoChunk> {
|
||||
|
||||
@ -1022,14 +1022,10 @@ impl ProtoChunk {
|
||||
|
||||
match instance {
|
||||
StructureInstance::Start(pos) => tasks.push(pos.collector.clone()),
|
||||
StructureInstance::Reference(origin_block_pos) => {
|
||||
let origin_chunk_x = origin_block_pos.0.x >> 4;
|
||||
let origin_chunk_z = origin_block_pos.0.z >> 4;
|
||||
if let Some(neighbor) = cache.get_chunk(origin_chunk_x, origin_chunk_z)
|
||||
&& let Some(StructureInstance::Start(pos)) =
|
||||
neighbor.structure_starts.get(id)
|
||||
{
|
||||
tasks.push(pos.collector.clone());
|
||||
StructureInstance::Reference(collector) => {
|
||||
let collector_arc = collector.clone();
|
||||
if !tasks.iter().any(|t| Arc::ptr_eq(t, &collector_arc)) {
|
||||
tasks.push(collector_arc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1069,29 +1065,10 @@ impl ProtoChunk {
|
||||
}
|
||||
}
|
||||
}
|
||||
StructureInstance::Reference(origin_block_pos) => {
|
||||
let origin_chunk_x = origin_block_pos.0.x >> 4;
|
||||
let origin_chunk_z = origin_block_pos.0.z >> 4;
|
||||
if let Some(origin_neighbor) =
|
||||
cache.try_get_proto_chunk(origin_chunk_x, origin_chunk_z)
|
||||
&& let Some(StructureInstance::Start(pos)) =
|
||||
origin_neighbor.structure_starts.get(id)
|
||||
{
|
||||
let start_x = chunk_pos::start_block_x(center_x);
|
||||
let start_z = chunk_pos::start_block_z(center_z);
|
||||
let end_x = start_x + 15;
|
||||
let end_z = start_z + 15;
|
||||
|
||||
if pos
|
||||
.get_bounding_box()
|
||||
.intersects_raw_xz(start_x, start_z, end_x, end_z)
|
||||
{
|
||||
let collector_arc = pos.collector.clone();
|
||||
if !tasks.iter().any(|t| Arc::ptr_eq(t, &collector_arc))
|
||||
{
|
||||
tasks.push(collector_arc);
|
||||
}
|
||||
}
|
||||
StructureInstance::Reference(collector) => {
|
||||
let collector_arc = collector.clone();
|
||||
if !tasks.iter().any(|t| Arc::ptr_eq(t, &collector_arc)) {
|
||||
tasks.push(collector_arc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1218,7 +1195,7 @@ impl ProtoChunk {
|
||||
.get_bounding_box()
|
||||
.intersects_raw_xz(start_x, start_z, end_x, end_z)
|
||||
{
|
||||
references.push((*key, start_data.start_pos));
|
||||
references.push((*key, start_data.collector.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,8 +10,8 @@ use crate::{
|
||||
structure::structures::{
|
||||
StructureGenerator, StructureGeneratorContext, StructurePosition,
|
||||
buried_treasure::BuriedTreasureGenerator, create_chunk_random, igloo::IglooGenerator,
|
||||
nether_fossil::NetherFossilGenerator, stronghold::StrongholdGenerator,
|
||||
swamp_hut::SwampHutGenerator,
|
||||
nether_fortress::NetherFortressGenerator, nether_fossil::NetherFossilGenerator,
|
||||
stronghold::StrongholdGenerator, swamp_hut::SwampHutGenerator,
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -49,6 +49,9 @@ pub fn try_generate_structure(
|
||||
StructureKeys::Stronghold => {
|
||||
StrongholdGenerator::get_structure_position(&StrongholdGenerator, context)
|
||||
}
|
||||
StructureKeys::Fortress => {
|
||||
NetherFortressGenerator::get_structure_position(&NetherFortressGenerator, context)
|
||||
}
|
||||
StructureKeys::NetherFossil => {
|
||||
NetherFossilGenerator::get_structure_position(&NetherFossilGenerator, context)
|
||||
}
|
||||
|
||||
@ -56,7 +56,13 @@ impl StructurePieceBase for BuriedTreasurePiece {
|
||||
Box::new((*self).clone())
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, _random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
_chunk_box: &BlockBox,
|
||||
) {
|
||||
let boundingbox = self.bounding_box();
|
||||
let y = chunk.get_top_y(
|
||||
&HeightMap::OceanFloorWg,
|
||||
|
||||
@ -8,7 +8,10 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use pumpkin_util::{math::position::BlockPos, math::vector3::Vector3, random::RandomGenerator};
|
||||
use pumpkin_util::{
|
||||
math::{block_box::BlockBox, position::BlockPos, vector3::Vector3},
|
||||
random::RandomGenerator,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
@ -142,7 +145,13 @@ impl StructurePieceBase for IglooPiece {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, _random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
_chunk_box: &BlockBox,
|
||||
) {
|
||||
let origin = self.shiftable_structure_piece.piece.bounding_box.min;
|
||||
|
||||
// Vanilla samples height at the entrance position (3, 0, 5 in template space)
|
||||
|
||||
@ -10,7 +10,6 @@ use pumpkin_util::{
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::generation::structure::structures::stronghold::PieceWeight;
|
||||
use crate::generation::structure::structures::stronghold::StrongholdPieceType;
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
@ -49,7 +48,13 @@ pub trait StructurePieceBase: Send + Sync {
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase>;
|
||||
|
||||
/// Places the blocks for this piece into the chunk.
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, seed: i64);
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
seed: i64,
|
||||
_chunk_box: &BlockBox,
|
||||
);
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn fill_openings(
|
||||
@ -57,7 +62,7 @@ pub trait StructurePieceBase: Send + Sync {
|
||||
_start: &StructurePiece,
|
||||
_random: &mut RandomGenerator,
|
||||
// TODO: this is only for Stronghold and should not be here
|
||||
_weights: &mut Vec<PieceWeight>,
|
||||
_weights: &mut Vec<crate::generation::structure::structures::stronghold::PieceWeight>,
|
||||
_last_piece_type: &mut Option<StrongholdPieceType>,
|
||||
_has_portal_room: &mut bool,
|
||||
|
||||
@ -65,6 +70,21 @@ pub trait StructurePieceBase: Send + Sync {
|
||||
_pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn fill_openings_nether(
|
||||
&self,
|
||||
_start: &StructurePiece,
|
||||
_random: &mut RandomGenerator,
|
||||
_bridge_pieces: &mut Vec<
|
||||
crate::generation::structure::structures::nether_fortress::PieceWeight,
|
||||
>,
|
||||
_corridor_pieces: &mut Vec<
|
||||
crate::generation::structure::structures::nether_fortress::PieceWeight,
|
||||
>,
|
||||
_collector: &mut StructurePiecesCollector,
|
||||
_pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -366,15 +386,6 @@ impl StructurePiece {
|
||||
// world.mark_block_for_post_processing(&block_pos);
|
||||
// }
|
||||
}
|
||||
|
||||
pub fn get_random_horizontal_direction(random: &mut impl RandomImpl) -> BlockDirection {
|
||||
match random.next_bounded_i32(4) {
|
||||
0 => BlockDirection::North,
|
||||
1 => BlockDirection::East,
|
||||
2 => BlockDirection::South,
|
||||
_ => BlockDirection::West,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for StructurePiece {
|
||||
@ -382,7 +393,14 @@ impl StructurePieceBase for StructurePiece {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn place(&mut self, _chunk: &mut ProtoChunk, _random: &mut RandomGenerator, _seed: i64) {}
|
||||
fn place(
|
||||
&mut self,
|
||||
_chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
_chunk_box: &BlockBox,
|
||||
) {
|
||||
}
|
||||
|
||||
fn translate(&mut self, x: i32, y: i32, z: i32) {
|
||||
self.bounding_box.move_pos(x, y, z);
|
||||
@ -451,7 +469,7 @@ impl StructurePiecesCollector {
|
||||
|
||||
for piece in &mut self.pieces {
|
||||
if piece.bounding_box().intersects(&chunk_box) {
|
||||
piece.place(chunk, random, seed);
|
||||
piece.place(chunk, random, seed, &chunk_box);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -552,5 +570,5 @@ pub enum StructureInstance {
|
||||
Start(StructurePosition),
|
||||
/// This chunk just contains a piece of a structure starting elsewhere.
|
||||
/// Stores the `BlockPos` of the 'Start' so you can look it up.
|
||||
Reference(BlockPos),
|
||||
Reference(Arc<Mutex<StructurePiecesCollector>>),
|
||||
}
|
||||
|
||||
@ -1,188 +0,0 @@
|
||||
// use std::sync::Arc;
|
||||
|
||||
// use pumpkin_data::Block;
|
||||
// use pumpkin_util::{
|
||||
// math::{block_box::BlockBox, position::BlockPos, vector3::Vector3},
|
||||
// random::RandomGenerator,
|
||||
// };
|
||||
// use serde::Deserialize;
|
||||
|
||||
// use crate::{
|
||||
// ProtoChunk,
|
||||
// generation::{
|
||||
// positions::chunk_pos,
|
||||
// structure::structures::{
|
||||
// StructureGenerator, StructureGeneratorContext, StructurePiece, StructurePieceBase,
|
||||
// StructurePiecesCollector, StructurePosition,
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
|
||||
// #[derive(Deserialize, Clone, Debug)]
|
||||
// pub struct NetherFortressGenerator;
|
||||
|
||||
// impl StructureGenerator for NetherFortressGenerator {
|
||||
// fn get_structure_position(
|
||||
// &self,
|
||||
// context: StructureGeneratorContext,
|
||||
// ) -> Option<StructurePosition> {
|
||||
// let start_x = chunk_pos::start_block_x(context.chunk_x);
|
||||
// let start_z = chunk_pos::start_block_z(context.chunk_z);
|
||||
// let start_y = 64;
|
||||
|
||||
// let mut collector = StructurePiecesCollector::default();
|
||||
|
||||
// // Add a Bridge Platform piece
|
||||
// let box_min = BlockPos::new(start_x, start_y, start_z);
|
||||
// let box_max = BlockPos::new(start_x + 8, start_y + 10, start_z + 8);
|
||||
|
||||
// todo!();
|
||||
|
||||
// Some(StructurePosition {
|
||||
// start_pos: box_min,
|
||||
// collector: Arc::new(collector.into()),
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[derive(Debug, Clone)]
|
||||
// pub enum NetherFortressPieceType {
|
||||
// BridgePlatform,
|
||||
// SmallCorridor,
|
||||
// }
|
||||
|
||||
// struct NetherFortressPiece {
|
||||
// piece: StructurePiece,
|
||||
// piece_type: NetherFortressPieceType,
|
||||
// }
|
||||
|
||||
// impl StructurePieceBase for NetherFortressPiece {
|
||||
// fn place(&mut self, chunk: &mut ProtoChunk, _seed: i64) {
|
||||
// let bounding_box = self.piece.bounding_box;
|
||||
// let origin_x = bounding_box.min.x;
|
||||
// let origin_y = bounding_box.min.y;
|
||||
// let origin_z = bounding_box.min.z;
|
||||
|
||||
// let offset = |x, y, z| Vector3::new(origin_x + x, origin_y + y, origin_z + z);
|
||||
|
||||
// let fill_rel = |min_x, min_y, min_z, max_x, max_y, max_z, block, c: &mut ProtoChunk| {
|
||||
// fill(
|
||||
// origin_x + min_x,
|
||||
// origin_y + min_y,
|
||||
// origin_z + min_z,
|
||||
// origin_x + max_x,
|
||||
// origin_y + max_y,
|
||||
// origin_z + max_z,
|
||||
// block,
|
||||
// c,
|
||||
// )
|
||||
// };
|
||||
|
||||
// let fill_outline_rel =
|
||||
// |min_x, min_y, min_z, max_x, max_y, max_z, outline, inside, c: &mut ProtoChunk| {
|
||||
// fill_with_outline(
|
||||
// origin_x + min_x,
|
||||
// origin_y + min_y,
|
||||
// origin_z + min_z,
|
||||
// origin_x + max_x,
|
||||
// origin_y + max_y,
|
||||
// origin_z + max_z,
|
||||
// outline,
|
||||
// inside,
|
||||
// c,
|
||||
// )
|
||||
// };
|
||||
|
||||
// match self.piece_type {
|
||||
// NetherFortressPieceType::BridgePlatform => {
|
||||
// fill_rel(0, 2, 0, 6, 7, 7, Block::AIR.default_state, chunk);
|
||||
// fill_rel(1, 0, 0, 5, 1, 7, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(1, 2, 1, 5, 2, 7, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(1, 3, 2, 5, 3, 7, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(1, 4, 3, 5, 4, 7, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(1, 2, 0, 1, 4, 2, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(5, 2, 0, 5, 4, 2, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(1, 5, 2, 1, 5, 3, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(5, 5, 2, 5, 5, 3, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(0, 5, 3, 0, 5, 8, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(6, 5, 3, 6, 5, 8, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(1, 5, 8, 5, 5, 8, Block::NETHER_BRICKS.default_state, chunk);
|
||||
|
||||
// let fence = &Block::NETHER_BRICK_FENCE.default_state;
|
||||
|
||||
// chunk.set_block_state(&offset(1, 6, 3), fence);
|
||||
// chunk.set_block_state(&offset(5, 6, 3), fence);
|
||||
// chunk.set_block_state(&offset(0, 6, 3), fence);
|
||||
// chunk.set_block_state(&offset(6, 6, 3), fence);
|
||||
|
||||
// fill_outline_rel(0, 6, 4, 0, 6, 7, fence, fence, chunk);
|
||||
// fill_outline_rel(6, 6, 4, 6, 6, 7, fence, fence, chunk);
|
||||
|
||||
// chunk.set_block_state(&offset(0, 6, 8), fence);
|
||||
// chunk.set_block_state(&offset(6, 6, 8), fence);
|
||||
|
||||
// fill_outline_rel(1, 6, 8, 5, 6, 8, fence, fence, chunk);
|
||||
|
||||
// chunk.set_block_state(&offset(1, 7, 8), fence);
|
||||
// fill_outline_rel(2, 7, 8, 4, 7, 8, fence, fence, chunk);
|
||||
// chunk.set_block_state(&offset(5, 7, 8), fence);
|
||||
|
||||
// chunk.set_block_state(&offset(2, 8, 8), fence);
|
||||
// chunk.set_block_state(&offset(3, 8, 8), fence);
|
||||
// chunk.set_block_state(&offset(4, 8, 8), fence);
|
||||
|
||||
// // Blaze Spawner
|
||||
// chunk.set_block_state(&offset(3, 5, 5), Block::SPAWNER.default_state);
|
||||
|
||||
// // Pillars down
|
||||
// for x in 0..6 {
|
||||
// for z in 0..6 {
|
||||
// fill_downwards(
|
||||
// origin_x + x,
|
||||
// origin_y - 1,
|
||||
// origin_z + z,
|
||||
// Block::NETHER_BRICKS.default_state,
|
||||
// chunk,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// NetherFortressPieceType::SmallCorridor => {
|
||||
// fill_rel(0, 0, 0, 4, 1, 4, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(0, 2, 0, 4, 5, 4, Block::AIR.default_state, chunk);
|
||||
|
||||
// let fence = &Block::NETHER_BRICK_FENCE.default_state;
|
||||
|
||||
// fill_rel(0, 2, 0, 0, 5, 4, Block::NETHER_BRICKS.default_state, chunk);
|
||||
// fill_rel(4, 2, 0, 4, 5, 4, Block::NETHER_BRICKS.default_state, chunk);
|
||||
|
||||
// fill_rel(0, 3, 1, 0, 4, 1, fence, chunk);
|
||||
// fill_rel(0, 3, 3, 0, 4, 3, fence, chunk);
|
||||
// fill_rel(4, 3, 1, 4, 4, 1, fence, chunk);
|
||||
// fill_rel(4, 3, 3, 4, 4, 3, fence, chunk);
|
||||
|
||||
// fill_rel(0, 6, 0, 4, 6, 4, Block::NETHER_BRICKS.default_state, chunk);
|
||||
|
||||
// for i in 0..=4 {
|
||||
// for j in 0..=4 {
|
||||
// fill_downwards(
|
||||
// origin_x + i,
|
||||
// origin_y - 1,
|
||||
// origin_z + j,
|
||||
// Block::NETHER_BRICKS.default_state,
|
||||
// chunk,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn get_structure_piece(&self) -> &super::StructurePiece {
|
||||
// &self.piece
|
||||
// }
|
||||
|
||||
// fn get_structure_piece_mut(&mut self) -> &mut super::StructurePiece {
|
||||
// &mut self.piece
|
||||
// }
|
||||
// }
|
||||
@ -0,0 +1,155 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{
|
||||
BlockDirection,
|
||||
math::block_box::BlockBox,
|
||||
random::{RandomGenerator, RandomImpl},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Straight exterior bridge segment (5 × 10 × 19).
|
||||
#[derive(Clone)]
|
||||
pub struct BridgePiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl BridgePiece {
|
||||
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 bbox = BlockBox::rotated(x, y, z, -1, -3, 0, 5, 10, 19, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece =
|
||||
NetherFortressPiece::new(StructurePieceType::NetherFortressBridge, chain_length, bbox);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for BridgePiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last_piece: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last_piece,
|
||||
1,
|
||||
3,
|
||||
false,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 0, 4, 4, 18, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 5, 0, 3, 7, 18, air, air);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 0, 0, 5, 18, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 5, 0, 4, 5, 18, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 4, 2, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 13, 4, 2, 18, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 0, 4, 1, 3, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 15, 4, 1, 18, nb, nb);
|
||||
|
||||
for i in 0..=4i32 {
|
||||
for j in 0..=2i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
p.fill_downwards(chunk, nb, i, -1, 18 - j, &bb);
|
||||
}
|
||||
}
|
||||
|
||||
// North-South fence (connects along X axis on left/right walls)
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.north = true;
|
||||
props.south = true;
|
||||
let _fence_ns =
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE));
|
||||
|
||||
// fence_ns + east (left wall)
|
||||
props.east = true;
|
||||
props.north = true;
|
||||
props.south = true;
|
||||
let fence_east =
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE));
|
||||
|
||||
// fence_ns + west (right wall)
|
||||
props.east = false;
|
||||
props.west = true;
|
||||
let fence_west =
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE));
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 1, 1, 0, 4, 1, fence_east, fence_east);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 4, 0, 4, 4, fence_east, fence_east);
|
||||
p.fill_with_outline(
|
||||
chunk, &bb, false, 0, 3, 14, 0, 4, 14, fence_east, fence_east,
|
||||
);
|
||||
p.fill_with_outline(
|
||||
chunk, &bb, false, 0, 1, 17, 0, 4, 17, fence_east, fence_east,
|
||||
);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 1, 1, 4, 4, 1, fence_west, fence_west);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 3, 4, 4, 4, 4, fence_west, fence_west);
|
||||
p.fill_with_outline(
|
||||
chunk, &bb, false, 4, 3, 14, 4, 4, 14, fence_west, fence_west,
|
||||
);
|
||||
p.fill_with_outline(
|
||||
chunk, &bb, false, 4, 1, 17, 4, 4, 17, fence_west, fence_west,
|
||||
);
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,189 @@
|
||||
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,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// 4-way exterior bridge crossing (19 × 10 × 19).
|
||||
/// Also serves as the generation start piece.
|
||||
#[derive(Clone)]
|
||||
pub struct BridgeCrossingPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl BridgeCrossingPiece {
|
||||
/// Create as the very first (start) piece at a fixed y=64.
|
||||
pub fn new_start(random: &mut impl RandomImpl, x: i32, z: i32) -> Self {
|
||||
let orientation = BlockDirection::get_random_horizontal_direction(random);
|
||||
let bbox = BlockBox::create_box(x, 64, z, orientation.get_axis(), 19, 10, 19);
|
||||
let mut piece =
|
||||
NetherFortressPiece::new(StructurePieceType::NetherFortressBridgeCrossing, 0, bbox);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Self { piece }
|
||||
}
|
||||
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
let bbox = BlockBox::rotated(x, y, z, -8, -3, 0, 19, 10, 19, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressBridgeCrossing,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
|
||||
pub fn fill_openings(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut impl RandomImpl,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last_piece: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last_piece,
|
||||
8,
|
||||
3,
|
||||
false,
|
||||
pieces_to_process,
|
||||
);
|
||||
self.piece.fill_nw_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last_piece,
|
||||
3,
|
||||
8,
|
||||
false,
|
||||
pieces_to_process,
|
||||
);
|
||||
self.piece.fill_se_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last_piece,
|
||||
3,
|
||||
8,
|
||||
false,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for BridgeCrossingPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
self.fill_openings(
|
||||
start,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
collector,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 3, 0, 11, 4, 18, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 7, 18, 4, 11, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 8, 5, 0, 10, 7, 18, air, air);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 8, 18, 7, 10, air, air);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 5, 0, 7, 5, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 5, 11, 7, 5, 18, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 11, 5, 0, 11, 5, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 11, 5, 11, 11, 5, 18, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 7, 7, 5, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 11, 5, 7, 18, 5, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 11, 7, 5, 11, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 11, 5, 11, 18, 5, 11, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 2, 0, 11, 2, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 2, 13, 11, 2, 18, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 0, 0, 11, 1, 3, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 0, 15, 11, 1, 18, nb, nb);
|
||||
|
||||
for i in 7..=11i32 {
|
||||
for j in 0..=2i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
p.fill_downwards(chunk, nb, i, -1, 18 - j, &bb);
|
||||
}
|
||||
}
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 7, 5, 2, 11, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 13, 2, 7, 18, 2, 11, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 7, 3, 1, 11, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 15, 0, 7, 18, 1, 11, nb, nb);
|
||||
|
||||
for i in 0..=2i32 {
|
||||
for j in 7..=11i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
p.fill_downwards(chunk, nb, i, -1, 18 - j, &bb); // Note: Java uses `18 - i` but iterates j; faithful copy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
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,
|
||||
nether_fortress::{NetherFortressPiece, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Dead-end / terminator piece for the exterior bridge (5 × 10 × 8).
|
||||
/// Generated randomly on each side and used as a fallback when no valid piece
|
||||
/// can be placed.
|
||||
#[derive(Clone)]
|
||||
pub struct BridgeEndPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
/// Seed used so the crumbling geometry is deterministic per world seed.
|
||||
pub seed: u32,
|
||||
}
|
||||
|
||||
impl BridgeEndPiece {
|
||||
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 bbox = BlockBox::rotated(x, y, z, -1, -3, 0, 5, 10, 8, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let seed = random.next_i32() as u32;
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressBridgeEnd,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece, seed }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for BridgeEndPiece {
|
||||
fn get_structure_piece(&self) -> &StructurePiece {
|
||||
&self.piece.piece
|
||||
}
|
||||
|
||||
fn get_structure_piece_mut(&mut self) -> &mut StructurePiece {
|
||||
&mut self.piece.piece
|
||||
}
|
||||
|
||||
// BridgeEnd is a terminal piece – it never spawns children.
|
||||
fn fill_openings_nether(
|
||||
&self,
|
||||
_start: &StructurePiece,
|
||||
_random: &mut RandomGenerator,
|
||||
_bridge_pieces: &mut Vec<PieceWeight>,
|
||||
_corridor_pieces: &mut Vec<PieceWeight>,
|
||||
_collector: &mut StructurePiecesCollector,
|
||||
_pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
|
||||
// Use a seeded local random so geometry is deterministic.
|
||||
let mut rng = pumpkin_util::random::xoroshiro128::Xoroshiro::from_seed(self.seed as u64);
|
||||
|
||||
for i in 0..=4i32 {
|
||||
for j in 3..=4i32 {
|
||||
let k = rng.next_bounded_i32(8);
|
||||
p.fill_with_outline(chunk, &bb, false, i, j, 0, i, j, k, nb, nb);
|
||||
}
|
||||
}
|
||||
|
||||
let k0 = rng.next_bounded_i32(8);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 0, 0, 5, k0, nb, nb);
|
||||
|
||||
let k1 = rng.next_bounded_i32(8);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 5, 0, 4, 5, k1, nb, nb);
|
||||
|
||||
for i in 0..=4i32 {
|
||||
let j = rng.next_bounded_i32(5);
|
||||
p.fill_with_outline(chunk, &bb, false, i, 2, 0, i, 2, j, nb, nb);
|
||||
}
|
||||
|
||||
for i in 0..=4i32 {
|
||||
for j in 0..=1i32 {
|
||||
let k = rng.next_bounded_i32(3);
|
||||
p.fill_with_outline(chunk, &bb, false, i, j, 0, i, j, k, nb, nb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,157 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{BlockDirection, math::block_box::BlockBox, random::RandomGenerator};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Exterior platform with a Blaze mob-spawner (7 × 8 × 9).
|
||||
#[derive(Clone)]
|
||||
pub struct BridgePlatformPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
pub has_blaze_spawner: bool,
|
||||
}
|
||||
|
||||
impl BridgePlatformPiece {
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
chain_length: u32,
|
||||
orientation: BlockDirection,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
let bbox = BlockBox::rotated(x, y, z, -2, 0, 0, 7, 8, 9, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressBridgePlatform,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self {
|
||||
piece,
|
||||
has_blaze_spawner: false,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for BridgePlatformPiece {
|
||||
fn get_structure_piece(&self) -> &StructurePiece {
|
||||
&self.piece.piece
|
||||
}
|
||||
|
||||
fn get_structure_piece_mut(&mut self) -> &mut StructurePiece {
|
||||
&mut self.piece.piece
|
||||
}
|
||||
|
||||
// Terminal piece – no children.
|
||||
fn fill_openings_nether(
|
||||
&self,
|
||||
_start: &StructurePiece,
|
||||
_random: &mut RandomGenerator,
|
||||
_bridge_pieces: &mut Vec<PieceWeight>,
|
||||
_corridor_pieces: &mut Vec<PieceWeight>,
|
||||
_collector: &mut StructurePiecesCollector,
|
||||
_pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 6, 7, 7, air, air);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 0, 0, 5, 1, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 2, 1, 5, 2, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 3, 2, 5, 3, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 4, 3, 5, 4, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 2, 0, 1, 4, 2, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 2, 0, 5, 4, 2, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 5, 2, 1, 5, 3, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 5, 2, 5, 5, 3, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 3, 0, 5, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 5, 3, 6, 5, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 5, 8, 5, 5, 8, nb, nb);
|
||||
|
||||
// Fence helpers
|
||||
let fence = |west: bool, east: bool, north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.west = west;
|
||||
props.east = east;
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
|
||||
let f_ew = fence(true, true, false, false);
|
||||
let f_ns = fence(false, false, true, true);
|
||||
|
||||
p.add_block(chunk, fence(true, false, false, false), 1, 6, 3, &bb);
|
||||
p.add_block(chunk, fence(false, true, false, false), 5, 6, 3, &bb);
|
||||
p.add_block(chunk, fence(false, true, true, false), 0, 6, 3, &bb);
|
||||
p.add_block(chunk, fence(true, false, true, false), 6, 6, 3, &bb);
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 6, 4, 0, 6, 7, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 6, 4, 6, 6, 7, f_ns, f_ns);
|
||||
|
||||
p.add_block(chunk, fence(false, true, false, true), 0, 6, 8, &bb);
|
||||
p.add_block(chunk, fence(true, false, false, true), 6, 6, 8, &bb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 6, 8, 5, 6, 8, f_ew, f_ew);
|
||||
|
||||
p.add_block(chunk, fence(false, true, false, false), 1, 7, 8, &bb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 7, 8, 4, 7, 8, f_ew, f_ew);
|
||||
p.add_block(chunk, fence(true, false, false, false), 5, 7, 8, &bb);
|
||||
|
||||
p.add_block(chunk, fence(false, true, false, false), 2, 8, 8, &bb);
|
||||
p.add_block(chunk, f_ew, 3, 8, 8, &bb);
|
||||
p.add_block(chunk, fence(true, false, false, false), 4, 8, 8, &bb);
|
||||
|
||||
// Blaze spawner (placed once)
|
||||
if !self.has_blaze_spawner {
|
||||
let spawner_pos = p.offset_pos(3, 5, 5);
|
||||
if bb.contains_pos(&spawner_pos) {
|
||||
self.has_blaze_spawner = true;
|
||||
chunk.set_block_state(
|
||||
spawner_pos.x,
|
||||
spawner_pos.y,
|
||||
spawner_pos.z,
|
||||
Block::SPAWNER.default_state,
|
||||
);
|
||||
// TODO: set spawner entity type to Blaze via block entity data
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..=6i32 {
|
||||
for j in 0..=6i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,163 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{BlockDirection, math::block_box::BlockBox, random::RandomGenerator};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Small 3-way crossing for the exterior bridge network (7 × 9 × 7).
|
||||
#[derive(Clone)]
|
||||
pub struct BridgeSmallCrossingPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl BridgeSmallCrossingPiece {
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
let bbox = BlockBox::rotated(x, y, z, -2, 0, 0, 7, 9, 7, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressBridgeSmallCrossing,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for BridgeSmallCrossingPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
2,
|
||||
0,
|
||||
false,
|
||||
pieces_to_process,
|
||||
);
|
||||
self.piece.fill_nw_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
0,
|
||||
2,
|
||||
false,
|
||||
pieces_to_process,
|
||||
);
|
||||
self.piece.fill_se_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
0,
|
||||
2,
|
||||
false,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 0, 6, 1, 6, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 6, 7, 6, air, air);
|
||||
|
||||
// Walls
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 1, 6, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 6, 1, 6, 6, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 2, 0, 6, 6, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 2, 6, 6, 6, 6, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 0, 6, 1, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 5, 0, 6, 6, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 2, 0, 6, 6, 1, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 2, 5, 6, 6, 6, nb, nb);
|
||||
|
||||
// Fence helpers
|
||||
let fence = |west: bool, east: bool, north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.west = west;
|
||||
props.east = east;
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ew = fence(true, true, false, false);
|
||||
let f_ns = fence(false, false, true, true);
|
||||
|
||||
// Battlements: top of the four open sides
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 6, 0, 4, 6, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 0, 4, 5, 0, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 6, 6, 4, 6, 6, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 6, 4, 5, 6, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 6, 2, 0, 6, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 2, 0, 5, 4, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 6, 2, 6, 6, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 5, 2, 6, 5, 4, f_ns, f_ns);
|
||||
|
||||
for i in 0..=6i32 {
|
||||
for j in 0..=6i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{BlockDirection, math::block_box::BlockBox, random::RandomGenerator};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Stairway that transitions from bridge level to interior level (7 × 11 × 7).
|
||||
#[derive(Clone)]
|
||||
pub struct BridgeStairsPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl BridgeStairsPiece {
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
chain_length: u32,
|
||||
orientation: BlockDirection,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
let bbox = BlockBox::rotated(x, y, z, -2, 0, 0, 7, 11, 7, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressBridgeStairs,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for BridgeStairsPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
// SE opening connects into the corridor network (inside = true)
|
||||
self.piece.fill_se_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
6,
|
||||
2,
|
||||
false,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 0, 6, 1, 6, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 6, 10, 6, air, air);
|
||||
|
||||
// Walls
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 1, 8, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 2, 0, 6, 8, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 1, 0, 8, 6, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 2, 1, 6, 8, 6, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 2, 6, 5, 8, 6, nb, nb);
|
||||
|
||||
// Fence helpers
|
||||
let fence = |west: bool, east: bool, north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.west = west;
|
||||
props.east = east;
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ew = fence(true, true, false, false);
|
||||
let f_ns = fence(false, false, true, true);
|
||||
|
||||
// Fence railings
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 2, 0, 5, 4, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 3, 2, 6, 5, 2, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 3, 4, 6, 5, 4, f_ns, f_ns);
|
||||
|
||||
// Stair steps (bottom to top, going from z=5 → z=1)
|
||||
p.add_block(chunk, nb, 5, 2, 5, &bb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 2, 5, 4, 3, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 3, 2, 5, 3, 4, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 2, 5, 2, 5, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 2, 5, 1, 6, 5, nb, nb);
|
||||
|
||||
// Upper floor platform
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 7, 1, 5, 7, 4, nb, nb);
|
||||
|
||||
// Open the SE exit gap
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 8, 2, 6, 8, 4, air, air);
|
||||
|
||||
// Battlement above forward opening
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 6, 0, 4, 8, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 0, 4, 5, 0, f_ew, f_ew);
|
||||
|
||||
for i in 0..=6i32 {
|
||||
for j in 0..=6i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,171 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{
|
||||
BlockDirection,
|
||||
math::block_box::BlockBox,
|
||||
random::{RandomGenerator, RandomImpl},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Interior corridor piece with a balcony overlook (9 × 7 × 9).
|
||||
#[derive(Clone)]
|
||||
pub struct CorridorBalconyPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl CorridorBalconyPiece {
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
let bbox = BlockBox::rotated(x, y, z, -3, 0, 0, 9, 7, 9, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressCorridorBalcony,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for CorridorBalconyPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
|
||||
// In Java: `i` is 1 for EAST/SOUTH facing, 5 for WEST/NORTH.
|
||||
let i = match self.piece.piece.facing {
|
||||
Some(BlockDirection::West) | Some(BlockDirection::North) => 5,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
let nw_blocked = random.next_bounded_i32(8) > 0;
|
||||
let se_blocked = random.next_bounded_i32(8) > 0;
|
||||
|
||||
self.piece.fill_nw_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
0,
|
||||
i,
|
||||
nw_blocked,
|
||||
pieces_to_process,
|
||||
);
|
||||
self.piece.fill_se_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
0,
|
||||
i,
|
||||
se_blocked,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
let fence = |west: bool, east: bool, north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.west = west;
|
||||
props.east = east;
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ns = fence(false, false, true, true);
|
||||
let f_ew = fence(true, true, false, false);
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 0, 8, 1, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 8, 5, 8, air, air);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 6, 0, 8, 6, 5, nb, nb);
|
||||
|
||||
// Front wall (z=0) openings
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 2, 5, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 2, 0, 8, 5, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 3, 0, 1, 4, 0, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 3, 0, 7, 4, 0, f_ew, f_ew);
|
||||
|
||||
// Back floor and openings
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 4, 8, 2, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 1, 4, 2, 2, 4, air, air);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 1, 4, 7, 2, 4, air, air);
|
||||
|
||||
// Back fence railing
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 3, 8, 7, 3, 8, f_ew, f_ew);
|
||||
p.add_block(chunk, fence(false, true, false, true), 0, 3, 8, &bb);
|
||||
p.add_block(chunk, fence(true, false, false, true), 8, 3, 8, &bb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 6, 0, 3, 7, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 8, 3, 6, 8, 3, 7, f_ns, f_ns);
|
||||
|
||||
// Side wall pillars and fences
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 4, 0, 5, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 8, 3, 4, 8, 5, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 3, 5, 2, 5, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 3, 5, 7, 5, 5, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 4, 5, 1, 5, 5, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 4, 5, 7, 5, 5, f_ew, f_ew);
|
||||
|
||||
for i in 0..=5i32 {
|
||||
for j in 0..=8i32 {
|
||||
p.fill_downwards(chunk, nb, j, -1, i, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_util::{BlockDirection, math::block_box::BlockBox, random::RandomGenerator};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// 4-way interior corridor crossing (5 × 7 × 5).
|
||||
#[derive(Clone)]
|
||||
pub struct CorridorCrossingPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl CorridorCrossingPiece {
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
let bbox = BlockBox::rotated(x, y, z, -1, 0, 0, 5, 7, 5, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressCorridorCrossing,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for CorridorCrossingPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
1,
|
||||
0,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
self.piece.fill_nw_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
0,
|
||||
1,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
self.piece.fill_se_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
0,
|
||||
1,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 0, 4, 1, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 4, 5, 4, air, air);
|
||||
|
||||
// Four corner pillars
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 0, 5, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 2, 0, 4, 5, 0, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 4, 0, 5, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 2, 4, 4, 5, 4, nb, nb);
|
||||
|
||||
// Ceiling
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 6, 0, 4, 6, 4, nb, nb);
|
||||
|
||||
for i in 0..=4i32 {
|
||||
for j in 0..=4i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,236 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{
|
||||
BlockDirection,
|
||||
math::block_box::BlockBox,
|
||||
random::{RandomGenerator, RandomImpl},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Large entrance tower connecting the bridge network to the interior (13 × 14 × 13).
|
||||
#[derive(Clone)]
|
||||
pub struct CorridorExitPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl CorridorExitPiece {
|
||||
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 bbox = BlockBox::rotated(x, y, z, -5, -3, 0, 13, 14, 13, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressCorridorExit,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for CorridorExitPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
5,
|
||||
3,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
let fence = |west: bool, east: bool, north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.west = west;
|
||||
props.east = east;
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ew = fence(true, true, false, false);
|
||||
let f_ns = fence(false, false, true, true);
|
||||
|
||||
// Main shell
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 0, 12, 4, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 0, 12, 13, 12, air, air);
|
||||
|
||||
// Outer walls
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 0, 1, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 11, 5, 0, 12, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 11, 4, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 8, 5, 11, 10, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 9, 11, 7, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 0, 4, 12, 1, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 8, 5, 0, 10, 12, 1, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 9, 0, 7, 12, 1, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 11, 2, 10, 12, 10, nb, nb);
|
||||
|
||||
// Gate arch fence
|
||||
p.fill_with_outline(
|
||||
chunk,
|
||||
&bb,
|
||||
false,
|
||||
5,
|
||||
8,
|
||||
0,
|
||||
7,
|
||||
8,
|
||||
0,
|
||||
Block::NETHER_BRICK_FENCE.default_state,
|
||||
Block::NETHER_BRICK_FENCE.default_state,
|
||||
);
|
||||
|
||||
// Battlement fences and corner blocks along top
|
||||
let mut i = 1i32;
|
||||
while i <= 11 {
|
||||
p.fill_with_outline(chunk, &bb, false, i, 10, 0, i, 11, 0, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, i, 10, 12, i, 11, 12, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 10, i, 0, 11, i, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 12, 10, i, 12, 11, i, f_ns, f_ns);
|
||||
p.add_block(chunk, nb, i, 13, 0, &bb);
|
||||
p.add_block(chunk, nb, i, 13, 12, &bb);
|
||||
p.add_block(chunk, nb, 0, 13, i, &bb);
|
||||
p.add_block(chunk, nb, 12, 13, i, &bb);
|
||||
if i != 11 {
|
||||
p.add_block(chunk, f_ew, i + 1, 13, 0, &bb);
|
||||
p.add_block(chunk, f_ew, i + 1, 13, 12, &bb);
|
||||
p.add_block(chunk, f_ns, 0, 13, i + 1, &bb);
|
||||
p.add_block(chunk, f_ns, 12, 13, i + 1, &bb);
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
|
||||
// Corner fence pieces
|
||||
p.add_block(chunk, fence(false, true, true, false), 0, 13, 0, &bb);
|
||||
p.add_block(chunk, fence(false, true, false, true), 0, 13, 12, &bb);
|
||||
p.add_block(chunk, fence(true, false, false, true), 12, 13, 12, &bb);
|
||||
p.add_block(chunk, fence(true, false, true, false), 12, 13, 0, &bb);
|
||||
|
||||
// Interior buttress fences
|
||||
let mut i = 3i32;
|
||||
while i <= 9 {
|
||||
p.fill_with_outline(
|
||||
chunk,
|
||||
&bb,
|
||||
false,
|
||||
1,
|
||||
7,
|
||||
i,
|
||||
1,
|
||||
8,
|
||||
i,
|
||||
fence(false, false, true, true), // + west connection
|
||||
fence(false, false, true, true),
|
||||
);
|
||||
p.fill_with_outline(
|
||||
chunk,
|
||||
&bb,
|
||||
false,
|
||||
11,
|
||||
7,
|
||||
i,
|
||||
11,
|
||||
8,
|
||||
i,
|
||||
fence(false, false, true, true), // + east connection
|
||||
fence(false, false, true, true),
|
||||
);
|
||||
i += 2;
|
||||
}
|
||||
|
||||
// Exterior bridge supports
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 2, 0, 8, 2, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 4, 12, 2, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 0, 0, 8, 1, 3, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 0, 9, 8, 1, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 4, 3, 1, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 9, 0, 4, 12, 1, 8, nb, nb);
|
||||
|
||||
for i in 4..=8i32 {
|
||||
for j in 0..=2i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
p.fill_downwards(chunk, nb, i, -1, 12 - j, &bb);
|
||||
}
|
||||
}
|
||||
for i in 0..=2i32 {
|
||||
for j in 4..=8i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
p.fill_downwards(chunk, nb, 12 - i, -1, j, &bb);
|
||||
}
|
||||
}
|
||||
|
||||
// Central lava well
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 5, 5, 7, 5, 7, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 6, 1, 6, 6, 4, 6, air, air);
|
||||
p.add_block(chunk, nb, 6, 0, 6, &bb);
|
||||
p.add_block(chunk, Block::LAVA.default_state, 6, 5, 6, &bb);
|
||||
|
||||
// Schedule lava fluid tick
|
||||
// TODO
|
||||
// let lava_pos = p.offset_pos(6, 5, 6);
|
||||
// if bb.contains_pos(&lava_pos) {
|
||||
// chunk.schedule_fluid_tick(&lava_pos, 0);
|
||||
// }
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{
|
||||
BlockDirection,
|
||||
math::block_box::BlockBox,
|
||||
random::{RandomGenerator, RandomImpl},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Interior corridor that turns left (NW), optionally containing a chest (5 × 7 × 5).
|
||||
#[derive(Clone)]
|
||||
pub struct CorridorLeftTurnPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
pub contains_chest: bool,
|
||||
}
|
||||
|
||||
impl CorridorLeftTurnPiece {
|
||||
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 bbox = BlockBox::rotated(x, y, z, -1, 0, 0, 5, 7, 5, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let contains_chest = random.next_bounded_i32(3) == 0;
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressCorridorLeftTurn,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self {
|
||||
piece,
|
||||
contains_chest,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for CorridorLeftTurnPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_nw_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
0,
|
||||
1,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
let fence = |west: bool, east: bool, north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.west = west;
|
||||
props.east = east;
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ew = fence(true, true, false, false);
|
||||
let f_ns = fence(false, false, true, true);
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 0, 4, 1, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 4, 5, 4, air, air);
|
||||
|
||||
// Right wall (closed)
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 2, 0, 4, 5, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 3, 1, 4, 4, 1, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 3, 3, 4, 4, 3, f_ns, f_ns);
|
||||
|
||||
// Front wall (closed)
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 0, 5, 0, nb, nb);
|
||||
|
||||
// Back wall
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 4, 3, 5, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 3, 4, 1, 4, 4, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, 3, 3, 4, 3, 4, 4, f_ew, f_ew);
|
||||
|
||||
// Optional chest
|
||||
// TODO
|
||||
// if self.contains_chest {
|
||||
// let chest_pos = p.offset_pos(3, 2, 3);
|
||||
// if bb.contains_pos(&chest_pos) {
|
||||
// self.contains_chest = false;
|
||||
// p.add_chest(chunk, &bb, random, 3, 2, 3, "nether_bridge");
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ceiling
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 6, 0, 4, 6, 4, nb, nb);
|
||||
|
||||
for i in 0..=4i32 {
|
||||
for j in 0..=4i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,281 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{
|
||||
BlockProperties, HorizontalFacing, OakFenceLikeProperties, OakStairsLikeProperties,
|
||||
},
|
||||
};
|
||||
use pumpkin_util::{BlockDirection, math::block_box::BlockBox, random::RandomGenerator};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Large interior room with nether wart crops (13 × 14 × 13).
|
||||
#[derive(Clone)]
|
||||
pub struct CorridorNetherWartsRoomPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl CorridorNetherWartsRoomPiece {
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
let bbox = BlockBox::rotated(x, y, z, -5, -3, 0, 13, 14, 13, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressCorridorNetherWartsRoom,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for CorridorNetherWartsRoomPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
// Two forward exits (one at the back, one even further)
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
5,
|
||||
3,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
5,
|
||||
11,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
let fence = |west: bool, east: bool, north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.west = west;
|
||||
props.east = east;
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ew = fence(true, true, false, false);
|
||||
let f_ns = fence(false, false, true, true);
|
||||
let f_ns_west = fence(true, false, true, true);
|
||||
let f_ns_east = fence(false, true, true, true);
|
||||
|
||||
// Shell (identical to CorridorExit outer shape)
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 0, 12, 4, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 0, 12, 13, 12, air, air);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 5, 0, 1, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 11, 5, 0, 12, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 11, 4, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 8, 5, 11, 10, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 9, 11, 7, 12, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 0, 4, 12, 1, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 8, 5, 0, 10, 12, 1, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 9, 0, 7, 12, 1, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 11, 2, 10, 12, 10, nb, nb);
|
||||
|
||||
// Battlements
|
||||
let mut i = 1i32;
|
||||
while i <= 11 {
|
||||
p.fill_with_outline(chunk, &bb, false, i, 10, 0, i, 11, 0, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, i, 10, 12, i, 11, 12, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 10, i, 0, 11, i, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 12, 10, i, 12, 11, i, f_ns, f_ns);
|
||||
p.add_block(chunk, nb, i, 13, 0, &bb);
|
||||
p.add_block(chunk, nb, i, 13, 12, &bb);
|
||||
p.add_block(chunk, nb, 0, 13, i, &bb);
|
||||
p.add_block(chunk, nb, 12, 13, i, &bb);
|
||||
if i != 11 {
|
||||
p.add_block(chunk, f_ew, i + 1, 13, 0, &bb);
|
||||
p.add_block(chunk, f_ew, i + 1, 13, 12, &bb);
|
||||
p.add_block(chunk, f_ns, 0, 13, i + 1, &bb);
|
||||
p.add_block(chunk, f_ns, 12, 13, i + 1, &bb);
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
p.add_block(chunk, fence(false, true, true, false), 0, 13, 0, &bb);
|
||||
p.add_block(chunk, fence(false, true, false, true), 0, 13, 12, &bb);
|
||||
p.add_block(chunk, fence(true, false, false, true), 12, 13, 12, &bb);
|
||||
p.add_block(chunk, fence(true, false, true, false), 12, 13, 0, &bb);
|
||||
|
||||
// Interior buttress fences
|
||||
let mut i = 3i32;
|
||||
while i <= 9 {
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 7, i, 1, 8, i, f_ns_west, f_ns_west);
|
||||
p.fill_with_outline(chunk, &bb, false, 11, 7, i, 11, 8, i, f_ns_east, f_ns_east);
|
||||
i += 2;
|
||||
}
|
||||
|
||||
// Staircase going up (north-facing stairs, going from z=4 up to z=10)
|
||||
let mut stair_props = OakStairsLikeProperties::default(&Block::NETHER_BRICK_STAIRS);
|
||||
stair_props.facing = HorizontalFacing::North;
|
||||
let stair_n =
|
||||
pumpkin_data::BlockState::from_id(stair_props.to_state_id(&Block::NETHER_BRICK_STAIRS));
|
||||
|
||||
stair_props.facing = HorizontalFacing::East;
|
||||
let stair_e =
|
||||
pumpkin_data::BlockState::from_id(stair_props.to_state_id(&Block::NETHER_BRICK_STAIRS));
|
||||
|
||||
stair_props.facing = HorizontalFacing::West;
|
||||
let stair_w =
|
||||
pumpkin_data::BlockState::from_id(stair_props.to_state_id(&Block::NETHER_BRICK_STAIRS));
|
||||
|
||||
for j in 0..=6i32 {
|
||||
let k = j + 4;
|
||||
for l in 5..=7i32 {
|
||||
p.add_block(chunk, stair_n, l, 5 + j, k, &bb);
|
||||
}
|
||||
if (5..=8).contains(&k) {
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 5, k, 7, j + 4, k, nb, nb);
|
||||
} else if (9..=10).contains(&k) {
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 8, k, 7, j + 4, k, nb, nb);
|
||||
}
|
||||
if j >= 1 {
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 6 + j, k, 7, 9 + j, k, air, air);
|
||||
}
|
||||
}
|
||||
for l in 5..=7i32 {
|
||||
p.add_block(chunk, stair_n, l, 12, 11, &bb);
|
||||
}
|
||||
|
||||
// Stair balcony fences
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 6, 7, 5, 7, 7, f_ns_east, f_ns_east);
|
||||
p.fill_with_outline(chunk, &bb, false, 7, 6, 7, 7, 7, 7, f_ns_west, f_ns_west);
|
||||
|
||||
// Clear the arch above the top stair exit
|
||||
p.fill_with_outline(chunk, &bb, false, 5, 13, 12, 7, 13, 12, air, air);
|
||||
|
||||
// Wart beds (raised platforms of soul sand with nether wart on top)
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 2, 3, 5, 3, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 9, 3, 5, 10, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 2, 5, 4, 2, 5, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 9, 5, 2, 10, 5, 3, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 9, 5, 9, 10, 5, 10, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 10, 5, 4, 10, 5, 8, nb, nb);
|
||||
|
||||
// Stair edgings for the wart beds
|
||||
p.add_block(chunk, stair_w, 4, 5, 2, &bb);
|
||||
p.add_block(chunk, stair_w, 4, 5, 3, &bb);
|
||||
p.add_block(chunk, stair_w, 4, 5, 9, &bb);
|
||||
p.add_block(chunk, stair_w, 4, 5, 10, &bb);
|
||||
p.add_block(chunk, stair_e, 8, 5, 2, &bb);
|
||||
p.add_block(chunk, stair_e, 8, 5, 3, &bb);
|
||||
p.add_block(chunk, stair_e, 8, 5, 9, &bb);
|
||||
p.add_block(chunk, stair_e, 8, 5, 10, &bb);
|
||||
|
||||
let soul_sand = Block::SOUL_SAND.default_state;
|
||||
let nether_wart = Block::NETHER_WART.default_state;
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 3, 4, 4, 4, 4, 8, soul_sand, soul_sand);
|
||||
p.fill_with_outline(chunk, &bb, false, 8, 4, 4, 9, 4, 8, soul_sand, soul_sand);
|
||||
p.fill_with_outline(
|
||||
chunk,
|
||||
&bb,
|
||||
false,
|
||||
3,
|
||||
5,
|
||||
4,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
nether_wart,
|
||||
nether_wart,
|
||||
);
|
||||
p.fill_with_outline(
|
||||
chunk,
|
||||
&bb,
|
||||
false,
|
||||
8,
|
||||
5,
|
||||
4,
|
||||
9,
|
||||
5,
|
||||
8,
|
||||
nether_wart,
|
||||
nether_wart,
|
||||
);
|
||||
|
||||
// Bridge support legs
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 2, 0, 8, 2, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 4, 12, 2, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 0, 0, 8, 1, 3, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 0, 9, 8, 1, 12, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 4, 3, 1, 8, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 9, 0, 4, 12, 1, 8, nb, nb);
|
||||
|
||||
for l in 4..=8i32 {
|
||||
for m in 0..=2i32 {
|
||||
p.fill_downwards(chunk, nb, l, -1, m, &bb);
|
||||
p.fill_downwards(chunk, nb, l, -1, 12 - m, &bb);
|
||||
}
|
||||
}
|
||||
for l in 0..=2i32 {
|
||||
for m in 4..=8i32 {
|
||||
p.fill_downwards(chunk, nb, l, -1, m, &bb);
|
||||
p.fill_downwards(chunk, nb, 12 - l, -1, m, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{
|
||||
BlockDirection,
|
||||
math::block_box::BlockBox,
|
||||
random::{RandomGenerator, RandomImpl},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Interior corridor that turns right (SE), optionally containing a chest (5 × 7 × 5).
|
||||
#[derive(Clone)]
|
||||
pub struct CorridorRightTurnPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
pub contains_chest: bool,
|
||||
}
|
||||
|
||||
impl CorridorRightTurnPiece {
|
||||
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 bbox = BlockBox::rotated(x, y, z, -1, 0, 0, 5, 7, 5, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let contains_chest = random.next_bounded_i32(3) == 0;
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressCorridorRightTurn,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self {
|
||||
piece,
|
||||
contains_chest,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for CorridorRightTurnPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_se_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
0,
|
||||
1,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
let fence = |west: bool, east: bool, north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.west = west;
|
||||
props.east = east;
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ew = fence(true, true, false, false);
|
||||
let f_ns = fence(false, false, true, true);
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 0, 4, 1, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 4, 5, 4, air, air);
|
||||
|
||||
// Left wall (closed)
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 0, 5, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 1, 0, 4, 1, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 3, 0, 4, 3, f_ns, f_ns);
|
||||
|
||||
// Front wall (closed)
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 2, 0, 4, 5, 0, nb, nb);
|
||||
|
||||
// Back wall (SE opening side)
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 2, 4, 4, 5, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 1, 3, 4, 1, 4, 4, f_ew, f_ew);
|
||||
p.fill_with_outline(chunk, &bb, false, 3, 3, 4, 3, 4, 4, f_ew, f_ew);
|
||||
|
||||
// Optional chest
|
||||
// TODO
|
||||
// if self.contains_chest {
|
||||
// let chest_pos = p.offset_pos(1, 2, 3);
|
||||
// if bb.contains_pos(&chest_pos) {
|
||||
// self.contains_chest = false;
|
||||
// p.add_chest(chunk, &bb, random, 1, 2, 3, "nether_bridge");
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ceiling
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 6, 0, 4, 6, 4, nb, nb);
|
||||
|
||||
for i in 0..=4i32 {
|
||||
for j in 0..=4i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,152 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{
|
||||
BlockProperties, HorizontalFacing, OakFenceLikeProperties, OakStairsLikeProperties,
|
||||
},
|
||||
};
|
||||
use pumpkin_util::{BlockDirection, math::block_box::BlockBox, random::RandomGenerator};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Descending interior corridor staircase (5 × 14 × 10).
|
||||
#[derive(Clone)]
|
||||
pub struct CorridorStairsPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl CorridorStairsPiece {
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
// Offset: -1 left/right, -7 height (deep stairs), 14 tall, 10 long
|
||||
let bbox = BlockBox::rotated(x, y, z, -1, -7, 0, 5, 14, 10, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressCorridorStairs,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for CorridorStairsPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
1,
|
||||
0,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
// Stair block facing south (going deeper into the structure)
|
||||
let mut stair_props = OakStairsLikeProperties::default(&Block::NETHER_BRICK_STAIRS);
|
||||
stair_props.facing = HorizontalFacing::South;
|
||||
let stair =
|
||||
pumpkin_data::BlockState::from_id(stair_props.to_state_id(&Block::NETHER_BRICK_STAIRS));
|
||||
|
||||
let fence = |north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ns = fence(true, true);
|
||||
|
||||
for i in 0..=9i32 {
|
||||
let j = 1.max(7 - i);
|
||||
let k = (j + 5).min(14 - i).min(13);
|
||||
let l = i;
|
||||
|
||||
// Solid base
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, i, 4, j, i, nb, nb);
|
||||
|
||||
// Air interior
|
||||
p.fill_with_outline(chunk, &bb, false, 1, j + 1, i, 3, k - 1, i, air, air);
|
||||
|
||||
// Stair treads (only for the descending section)
|
||||
if i <= 6 {
|
||||
p.add_block(chunk, stair, 1, j + 1, i, &bb);
|
||||
p.add_block(chunk, stair, 2, j + 1, i, &bb);
|
||||
p.add_block(chunk, stair, 3, j + 1, i, &bb);
|
||||
}
|
||||
|
||||
// Ceiling row
|
||||
p.fill_with_outline(chunk, &bb, false, 0, k, i, 4, k, i, nb, nb);
|
||||
|
||||
// Side walls
|
||||
p.fill_with_outline(chunk, &bb, false, 0, j + 1, i, 0, k - 1, i, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, j + 1, i, 4, k - 1, i, nb, nb);
|
||||
|
||||
// Fence railings every 2 slices
|
||||
if (i & 1) == 0 {
|
||||
p.fill_with_outline(chunk, &bb, false, 0, j + 2, i, 0, j + 3, i, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, j + 2, i, 4, j + 3, i, f_ns, f_ns);
|
||||
}
|
||||
|
||||
// Fill downwards beneath each slice
|
||||
for m in 0..=4i32 {
|
||||
p.fill_downwards(chunk, nb, m, -1, l, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,624 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use pumpkin_util::{
|
||||
BlockDirection,
|
||||
math::{block_box::BlockBox, position::BlockPos},
|
||||
random::RandomImpl,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::generation::{
|
||||
section_coords,
|
||||
structure::structures::{
|
||||
StructureGenerator, StructureGeneratorContext, StructurePiece, StructurePiecesCollector,
|
||||
StructurePosition, nether_fortress::bridge_crossing::BridgeCrossingPiece,
|
||||
},
|
||||
};
|
||||
|
||||
pub mod bridge;
|
||||
pub mod bridge_crossing;
|
||||
pub mod bridge_end;
|
||||
pub mod bridge_platform;
|
||||
pub mod bridge_small_crossing;
|
||||
pub mod bridge_stairs;
|
||||
pub mod corridor_balcony;
|
||||
pub mod corridor_crossing;
|
||||
pub mod corridor_exit;
|
||||
pub mod corridor_left_turn;
|
||||
pub mod corridor_nether_warts_room;
|
||||
pub mod corridor_right_turn;
|
||||
pub mod corridor_stairs;
|
||||
pub mod small_corridor;
|
||||
|
||||
/// Great reference: <https://minecraft.wiki/w/Nether_fortress>
|
||||
#[derive(Deserialize)]
|
||||
pub struct NetherFortressGenerator;
|
||||
|
||||
impl StructureGenerator for NetherFortressGenerator {
|
||||
fn get_structure_position(
|
||||
&self,
|
||||
context: StructureGeneratorContext,
|
||||
) -> Option<StructurePosition> {
|
||||
let mut collector = StructurePiecesCollector::default();
|
||||
let mut random = context.random;
|
||||
|
||||
let start_x = section_coords::section_to_block(context.chunk_x) + 2;
|
||||
let start_z = section_coords::section_to_block(context.chunk_z) + 2;
|
||||
|
||||
let start_piece = BridgeCrossingPiece::new_start(&mut random, start_x, start_z);
|
||||
let start_box: Box<dyn crate::generation::structure::structures::StructurePieceBase> =
|
||||
Box::new(start_piece.clone());
|
||||
|
||||
let mut pieces_to_process: Vec<
|
||||
Box<dyn crate::generation::structure::structures::StructurePieceBase>,
|
||||
> = Vec::new();
|
||||
|
||||
let mut bridge_pieces = get_bridge_piece_weights();
|
||||
let mut corridor_pieces = get_corridor_piece_weights();
|
||||
|
||||
collector.add_piece(start_box);
|
||||
|
||||
start_piece.fill_openings(
|
||||
&start_piece.piece.piece,
|
||||
&mut random,
|
||||
&mut bridge_pieces,
|
||||
&mut corridor_pieces,
|
||||
&mut collector,
|
||||
&mut pieces_to_process,
|
||||
);
|
||||
|
||||
while !pieces_to_process.is_empty() {
|
||||
let idx = random.next_bounded_i32(pieces_to_process.len() as i32) as usize;
|
||||
let piece = pieces_to_process.remove(idx);
|
||||
piece.fill_openings_nether(
|
||||
&start_piece.piece.piece,
|
||||
&mut random,
|
||||
&mut bridge_pieces,
|
||||
&mut corridor_pieces,
|
||||
&mut collector,
|
||||
&mut pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
Some(StructurePosition {
|
||||
start_pos: BlockPos::new(
|
||||
section_coords::section_to_block(context.chunk_x),
|
||||
64,
|
||||
section_coords::section_to_block(context.chunk_z),
|
||||
),
|
||||
collector: Arc::new(Mutex::new(collector)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Weights for the bridge (exterior) pieces.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PieceWeight {
|
||||
pub piece_type: NetherFortressPieceType,
|
||||
pub weight: i32,
|
||||
pub limit: u32,
|
||||
pub generated_count: u32,
|
||||
pub repeatable: bool,
|
||||
}
|
||||
|
||||
impl PieceWeight {
|
||||
const fn new(
|
||||
piece_type: NetherFortressPieceType,
|
||||
weight: i32,
|
||||
limit: u32,
|
||||
repeatable: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
piece_type,
|
||||
weight,
|
||||
limit,
|
||||
generated_count: 0,
|
||||
repeatable,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn can_generate(&self) -> bool {
|
||||
self.limit == 0 || self.generated_count < self.limit
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum NetherFortressPieceType {
|
||||
// Bridge pieces
|
||||
Bridge,
|
||||
BridgeCrossing,
|
||||
BridgeSmallCrossing,
|
||||
BridgeStairs,
|
||||
BridgePlatform,
|
||||
CorridorExit,
|
||||
// Corridor pieces
|
||||
SmallCorridor,
|
||||
CorridorCrossing,
|
||||
CorridorRightTurn,
|
||||
CorridorLeftTurn,
|
||||
CorridorStairs,
|
||||
CorridorBalcony,
|
||||
CorridorNetherWartsRoom,
|
||||
}
|
||||
|
||||
pub fn get_bridge_piece_weights() -> Vec<PieceWeight> {
|
||||
vec![
|
||||
PieceWeight::new(NetherFortressPieceType::Bridge, 30, 0, true),
|
||||
PieceWeight::new(NetherFortressPieceType::BridgeCrossing, 10, 4, false),
|
||||
PieceWeight::new(NetherFortressPieceType::BridgeSmallCrossing, 10, 4, false),
|
||||
PieceWeight::new(NetherFortressPieceType::BridgeStairs, 10, 3, false),
|
||||
PieceWeight::new(NetherFortressPieceType::BridgePlatform, 5, 2, false),
|
||||
PieceWeight::new(NetherFortressPieceType::CorridorExit, 5, 1, false),
|
||||
]
|
||||
}
|
||||
|
||||
pub fn get_corridor_piece_weights() -> Vec<PieceWeight> {
|
||||
vec![
|
||||
PieceWeight::new(NetherFortressPieceType::SmallCorridor, 25, 0, true),
|
||||
PieceWeight::new(NetherFortressPieceType::CorridorCrossing, 15, 5, false),
|
||||
PieceWeight::new(NetherFortressPieceType::CorridorRightTurn, 5, 10, false),
|
||||
PieceWeight::new(NetherFortressPieceType::CorridorLeftTurn, 5, 10, false),
|
||||
PieceWeight::new(NetherFortressPieceType::CorridorStairs, 10, 3, true),
|
||||
PieceWeight::new(NetherFortressPieceType::CorridorBalcony, 7, 2, false),
|
||||
PieceWeight::new(
|
||||
NetherFortressPieceType::CorridorNetherWartsRoom,
|
||||
5,
|
||||
2,
|
||||
false,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// The shared base state for every nether fortress piece.
|
||||
#[derive(Clone)]
|
||||
pub struct NetherFortressPiece {
|
||||
pub piece: StructurePiece,
|
||||
}
|
||||
|
||||
impl NetherFortressPiece {
|
||||
#[must_use]
|
||||
pub const fn new(
|
||||
r#type: crate::generation::structure::piece::StructurePieceType,
|
||||
chain_length: u32,
|
||||
bbox: BlockBox,
|
||||
) -> Self {
|
||||
Self {
|
||||
piece: StructurePiece::new(r#type, bbox, chain_length),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn is_in_bounds(bb: &BlockBox) -> bool {
|
||||
bb.min.y > 10
|
||||
}
|
||||
|
||||
/// Attempt to pick a random piece from `weights` up to 5 times.
|
||||
/// Falls back to `BridgeEnd` if nothing succeeds.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn pick_piece(
|
||||
weights: &mut Vec<PieceWeight>,
|
||||
last_piece: &mut Option<NetherFortressPieceType>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
random: &mut impl RandomImpl,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn crate::generation::structure::structures::StructurePieceBase>> {
|
||||
let total_weight = Self::check_remaining_pieces(weights);
|
||||
if total_weight < 0 {
|
||||
return bridge_end::BridgeEndPiece::create(
|
||||
collector,
|
||||
random,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
);
|
||||
}
|
||||
|
||||
let mut attempt = 0;
|
||||
while attempt < 5 {
|
||||
attempt += 1;
|
||||
let mut k = random.next_bounded_i32(total_weight);
|
||||
|
||||
for i in 0..weights.len() {
|
||||
k -= weights[i].weight;
|
||||
if k < 0 {
|
||||
let same_as_last =
|
||||
Some(weights[i].piece_type) == *last_piece && !weights[i].repeatable;
|
||||
if !weights[i].can_generate() || same_as_last {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(p) = Self::create_piece(
|
||||
weights[i].piece_type,
|
||||
collector,
|
||||
random,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
) {
|
||||
weights[i].generated_count += 1;
|
||||
*last_piece = Some(weights[i].piece_type);
|
||||
|
||||
if !weights[i].can_generate() {
|
||||
weights.remove(i);
|
||||
}
|
||||
|
||||
return Some(p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bridge_end::BridgeEndPiece::create(collector, random, x, y, z, orientation, chain_length)
|
||||
}
|
||||
|
||||
fn check_remaining_pieces(weights: &[PieceWeight]) -> i32 {
|
||||
let mut has_limited = false;
|
||||
let mut total = 0i32;
|
||||
for w in weights {
|
||||
if w.limit > 0 && w.generated_count < w.limit {
|
||||
has_limited = true;
|
||||
}
|
||||
total += w.weight;
|
||||
}
|
||||
if has_limited { total } else { -1 }
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_piece(
|
||||
piece_type: NetherFortressPieceType,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
random: &mut impl RandomImpl,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn crate::generation::structure::structures::StructurePieceBase>> {
|
||||
match piece_type {
|
||||
NetherFortressPieceType::Bridge => {
|
||||
bridge::BridgePiece::create(collector, random, x, y, z, orientation, chain_length)
|
||||
}
|
||||
NetherFortressPieceType::BridgeCrossing => {
|
||||
bridge_crossing::BridgeCrossingPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
)
|
||||
}
|
||||
NetherFortressPieceType::BridgeSmallCrossing => {
|
||||
bridge_small_crossing::BridgeSmallCrossingPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
)
|
||||
}
|
||||
NetherFortressPieceType::BridgeStairs => bridge_stairs::BridgeStairsPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
chain_length,
|
||||
orientation,
|
||||
),
|
||||
NetherFortressPieceType::BridgePlatform => {
|
||||
bridge_platform::BridgePlatformPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
chain_length,
|
||||
orientation,
|
||||
)
|
||||
}
|
||||
NetherFortressPieceType::CorridorExit => corridor_exit::CorridorExitPiece::create(
|
||||
collector,
|
||||
random,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
),
|
||||
NetherFortressPieceType::SmallCorridor => small_corridor::SmallCorridorPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
),
|
||||
NetherFortressPieceType::CorridorCrossing => {
|
||||
corridor_crossing::CorridorCrossingPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
)
|
||||
}
|
||||
NetherFortressPieceType::CorridorRightTurn => {
|
||||
corridor_right_turn::CorridorRightTurnPiece::create(
|
||||
collector,
|
||||
random,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
)
|
||||
}
|
||||
NetherFortressPieceType::CorridorLeftTurn => {
|
||||
corridor_left_turn::CorridorLeftTurnPiece::create(
|
||||
collector,
|
||||
random,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
)
|
||||
}
|
||||
NetherFortressPieceType::CorridorStairs => {
|
||||
corridor_stairs::CorridorStairsPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
)
|
||||
}
|
||||
NetherFortressPieceType::CorridorBalcony => {
|
||||
corridor_balcony::CorridorBalconyPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
)
|
||||
}
|
||||
NetherFortressPieceType::CorridorNetherWartsRoom => {
|
||||
corridor_nether_warts_room::CorridorNetherWartsRoomPiece::create(
|
||||
collector,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
chain_length,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- opening helpers --------------------------------------------------
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn fill_forward_opening(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
random: &mut impl RandomImpl,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
last_piece: &mut Option<NetherFortressPieceType>,
|
||||
left_right_offset: i32,
|
||||
height_offset: i32,
|
||||
inside: bool,
|
||||
pieces_to_process: &mut Vec<
|
||||
Box<dyn crate::generation::structure::structures::StructurePieceBase>,
|
||||
>,
|
||||
) {
|
||||
if let Some(facing) = self.piece.facing {
|
||||
let bb = self.piece.bounding_box;
|
||||
let (nx, ny, nz) = match facing {
|
||||
BlockDirection::North => (
|
||||
bb.min.x + left_right_offset,
|
||||
bb.min.y + height_offset,
|
||||
bb.min.z - 1,
|
||||
),
|
||||
BlockDirection::South => (
|
||||
bb.min.x + left_right_offset,
|
||||
bb.min.y + height_offset,
|
||||
bb.max.z + 1,
|
||||
),
|
||||
BlockDirection::West => (
|
||||
bb.min.x - 1,
|
||||
bb.min.y + height_offset,
|
||||
bb.min.z + left_right_offset,
|
||||
),
|
||||
BlockDirection::East => (
|
||||
bb.max.x + 1,
|
||||
bb.min.y + height_offset,
|
||||
bb.min.z + left_right_offset,
|
||||
),
|
||||
_ => return,
|
||||
};
|
||||
self.piece_generator(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
last_piece,
|
||||
nx,
|
||||
ny,
|
||||
nz,
|
||||
facing,
|
||||
inside,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn fill_nw_opening(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
random: &mut impl RandomImpl,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
last_piece: &mut Option<NetherFortressPieceType>,
|
||||
height_offset: i32,
|
||||
left_right_offset: i32,
|
||||
inside: bool,
|
||||
pieces_to_process: &mut Vec<
|
||||
Box<dyn crate::generation::structure::structures::StructurePieceBase>,
|
||||
>,
|
||||
) {
|
||||
if let Some(facing) = self.piece.facing {
|
||||
let bb = self.piece.bounding_box;
|
||||
let (nx, ny, nz, next_facing) = match facing {
|
||||
BlockDirection::North | BlockDirection::South => (
|
||||
bb.min.x - 1,
|
||||
bb.min.y + height_offset,
|
||||
bb.min.z + left_right_offset,
|
||||
BlockDirection::West,
|
||||
),
|
||||
BlockDirection::West | BlockDirection::East => (
|
||||
bb.min.x + left_right_offset,
|
||||
bb.min.y + height_offset,
|
||||
bb.min.z - 1,
|
||||
BlockDirection::North,
|
||||
),
|
||||
_ => return,
|
||||
};
|
||||
self.piece_generator(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
last_piece,
|
||||
nx,
|
||||
ny,
|
||||
nz,
|
||||
next_facing,
|
||||
inside,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn fill_se_opening(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
random: &mut impl RandomImpl,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
last_piece: &mut Option<NetherFortressPieceType>,
|
||||
height_offset: i32,
|
||||
left_right_offset: i32,
|
||||
inside: bool,
|
||||
pieces_to_process: &mut Vec<
|
||||
Box<dyn crate::generation::structure::structures::StructurePieceBase>,
|
||||
>,
|
||||
) {
|
||||
if let Some(facing) = self.piece.facing {
|
||||
let bb = self.piece.bounding_box;
|
||||
let (nx, ny, nz, next_facing) = match facing {
|
||||
BlockDirection::North | BlockDirection::South => (
|
||||
bb.max.x + 1,
|
||||
bb.min.y + height_offset,
|
||||
bb.min.z + left_right_offset,
|
||||
BlockDirection::East,
|
||||
),
|
||||
BlockDirection::West | BlockDirection::East => (
|
||||
bb.min.x + left_right_offset,
|
||||
bb.min.y + height_offset,
|
||||
bb.max.z + 1,
|
||||
BlockDirection::South,
|
||||
),
|
||||
_ => return,
|
||||
};
|
||||
self.piece_generator(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
last_piece,
|
||||
nx,
|
||||
ny,
|
||||
nz,
|
||||
next_facing,
|
||||
inside,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn piece_generator(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
random: &mut impl RandomImpl,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
last_piece: &mut Option<NetherFortressPieceType>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
inside: bool,
|
||||
pieces_to_process: &mut Vec<
|
||||
Box<dyn crate::generation::structure::structures::StructurePieceBase>,
|
||||
>,
|
||||
) {
|
||||
let start_box = start.bounding_box;
|
||||
if (x - start_box.min.x).abs() > 112 || (z - start_box.min.z).abs() > 112 {
|
||||
if let Some(p) = bridge_end::BridgeEndPiece::create(
|
||||
collector,
|
||||
random,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
self.piece.chain_length,
|
||||
) {
|
||||
collector.add_piece(p)
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let weights = if inside {
|
||||
corridor_pieces
|
||||
} else {
|
||||
bridge_pieces
|
||||
};
|
||||
|
||||
if let Some(p) = Self::pick_piece(
|
||||
weights,
|
||||
last_piece,
|
||||
collector,
|
||||
random,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
orientation,
|
||||
self.piece.chain_length + 1,
|
||||
) {
|
||||
collector.add_piece(p.clone_box());
|
||||
pieces_to_process.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, OakFenceLikeProperties},
|
||||
};
|
||||
use pumpkin_util::{BlockDirection, math::block_box::BlockBox, random::RandomGenerator};
|
||||
|
||||
use crate::{
|
||||
ProtoChunk,
|
||||
generation::structure::{
|
||||
piece::StructurePieceType,
|
||||
structures::{
|
||||
StructurePiece, StructurePieceBase, StructurePiecesCollector,
|
||||
nether_fortress::{NetherFortressPiece, NetherFortressPieceType, PieceWeight},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/// Straight interior corridor segment (5 × 7 × 5).
|
||||
/// This is also the fallback piece returned by the generation logic.
|
||||
#[derive(Clone)]
|
||||
pub struct SmallCorridorPiece {
|
||||
pub piece: NetherFortressPiece,
|
||||
}
|
||||
|
||||
impl SmallCorridorPiece {
|
||||
pub fn create(
|
||||
collector: &mut StructurePiecesCollector,
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
orientation: BlockDirection,
|
||||
chain_length: u32,
|
||||
) -> Option<Box<dyn StructurePieceBase>> {
|
||||
let bbox = BlockBox::rotated(x, y, z, -1, 0, 0, 5, 7, 5, &orientation);
|
||||
if !NetherFortressPiece::is_in_bounds(&bbox) || collector.get_intersecting(&bbox).is_some()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut piece = NetherFortressPiece::new(
|
||||
StructurePieceType::NetherFortressSmallCorridor,
|
||||
chain_length,
|
||||
bbox,
|
||||
);
|
||||
piece.piece.set_facing(Some(orientation));
|
||||
Some(Box::new(Self { piece }))
|
||||
}
|
||||
}
|
||||
|
||||
impl StructurePieceBase for SmallCorridorPiece {
|
||||
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_nether(
|
||||
&self,
|
||||
start: &StructurePiece,
|
||||
random: &mut RandomGenerator,
|
||||
bridge_pieces: &mut Vec<PieceWeight>,
|
||||
corridor_pieces: &mut Vec<PieceWeight>,
|
||||
collector: &mut StructurePiecesCollector,
|
||||
pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
||||
) {
|
||||
let mut last: Option<NetherFortressPieceType> = None;
|
||||
self.piece.fill_forward_opening(
|
||||
start,
|
||||
collector,
|
||||
random,
|
||||
bridge_pieces,
|
||||
corridor_pieces,
|
||||
&mut last,
|
||||
1,
|
||||
0,
|
||||
true,
|
||||
pieces_to_process,
|
||||
);
|
||||
}
|
||||
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let bb = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
let nb = Block::NETHER_BRICKS.default_state;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
let fence = |north: bool, south: bool| {
|
||||
let mut props = OakFenceLikeProperties::default(&Block::NETHER_BRICK_FENCE);
|
||||
props.north = north;
|
||||
props.south = south;
|
||||
pumpkin_data::BlockState::from_id(props.to_state_id(&Block::NETHER_BRICK_FENCE))
|
||||
};
|
||||
let f_ns = fence(true, true);
|
||||
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 0, 0, 4, 1, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 4, 5, 4, air, air);
|
||||
|
||||
// Side walls
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 2, 0, 0, 5, 4, nb, nb);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 2, 0, 4, 5, 4, nb, nb);
|
||||
|
||||
// Fence railings on side walls
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 1, 0, 4, 1, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 3, 3, 0, 4, 3, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 3, 1, 4, 4, 1, f_ns, f_ns);
|
||||
p.fill_with_outline(chunk, &bb, false, 4, 3, 3, 4, 4, 3, f_ns, f_ns);
|
||||
|
||||
// Ceiling
|
||||
p.fill_with_outline(chunk, &bb, false, 0, 6, 0, 4, 6, 4, nb, nb);
|
||||
|
||||
for i in 0..=4i32 {
|
||||
for j in 0..=4i32 {
|
||||
p.fill_downwards(chunk, nb, i, -1, j, &bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_box(&self) -> Box<dyn StructurePieceBase> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@ use std::sync::Arc;
|
||||
|
||||
use pumpkin_data::{Block, BlockDirection, BlockState};
|
||||
use pumpkin_util::{
|
||||
math::{position::BlockPos, vector3::Vector3},
|
||||
math::{block_box::BlockBox, position::BlockPos, vector3::Vector3},
|
||||
random::{RandomDeriverImpl, RandomGenerator, RandomImpl},
|
||||
};
|
||||
use tracing::debug;
|
||||
@ -166,7 +166,13 @@ impl StructurePieceBase for NetherFossilPiece {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, _random: &mut RandomGenerator, seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
seed: i64,
|
||||
_chunk_box: &BlockBox,
|
||||
) {
|
||||
// Vanilla column scan: find air above soul sand or solid block
|
||||
let Some(placement_y) = self.find_placement_y(chunk) else {
|
||||
debug!(
|
||||
|
||||
@ -91,9 +91,15 @@ impl StructurePieceBase for ChestCorridorPiece {
|
||||
);
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
|
||||
|
||||
@ -119,9 +119,15 @@ impl StructurePieceBase for CorridorPiece {
|
||||
}
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
let air = Block::AIR.default_state;
|
||||
@ -246,8 +252,14 @@ impl StructurePieceBase for SmallCorridorPiece {
|
||||
&mut self.piece.piece
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, _random: &mut RandomGenerator, _seed: i64) {
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece.piece;
|
||||
|
||||
let stone = Block::STONE_BRICKS.default_state;
|
||||
|
||||
@ -159,9 +159,15 @@ impl StructurePieceBase for FiveWayCrossingPiece {
|
||||
}
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
@ -101,9 +101,15 @@ impl StructurePieceBase for LeftTurnPiece {
|
||||
}
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
@ -71,9 +71,15 @@ impl StructurePieceBase for LibraryPiece {
|
||||
&mut self.piece.piece
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
|
||||
|
||||
@ -87,9 +87,15 @@ impl StructurePieceBase for PortalRoomPiece {
|
||||
*has_portal_room = true;
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
|
||||
|
||||
@ -92,9 +92,15 @@ impl StructurePieceBase for PrisonHallPiece {
|
||||
);
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
@ -102,9 +102,15 @@ impl StructurePieceBase for RightTurnPiece {
|
||||
}
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ impl Clone for SpiralStaircasePiece {
|
||||
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 = StructurePiece::get_random_horizontal_direction(random);
|
||||
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));
|
||||
@ -138,9 +138,15 @@ impl StructurePieceBase for SpiralStaircasePiece {
|
||||
);
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
|
||||
let p = &self.piece;
|
||||
|
||||
|
||||
@ -123,9 +123,15 @@ impl StructurePieceBase for SquareRoomPiece {
|
||||
);
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
let air = Block::AIR.default_state;
|
||||
|
||||
@ -90,9 +90,15 @@ impl StructurePieceBase for StairsPiece {
|
||||
);
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
let randomizer = StoneBrickRandomizer;
|
||||
let box_limit = self.piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.piece;
|
||||
let inner = &p.piece;
|
||||
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_util::{math::position::BlockPos, random::RandomGenerator};
|
||||
use pumpkin_util::{
|
||||
BlockDirection,
|
||||
math::{block_box::BlockBox, position::BlockPos},
|
||||
random::RandomGenerator,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
@ -12,7 +16,7 @@ use crate::{
|
||||
piece::StructurePieceType,
|
||||
shiftable_piece::ShiftableStructurePiece,
|
||||
structures::{
|
||||
StructureGenerator, StructureGeneratorContext, StructurePiece, StructurePieceBase,
|
||||
StructureGenerator, StructureGeneratorContext, StructurePieceBase,
|
||||
StructurePiecesCollector, StructurePosition,
|
||||
},
|
||||
},
|
||||
@ -40,7 +44,7 @@ impl StructureGenerator for SwampHutGenerator {
|
||||
7,
|
||||
7,
|
||||
9,
|
||||
StructurePiece::get_random_horizontal_direction(&mut context.random).get_axis(),
|
||||
BlockDirection::get_random_horizontal_direction(&mut context.random).get_axis(),
|
||||
),
|
||||
}));
|
||||
|
||||
@ -61,7 +65,13 @@ impl StructurePieceBase for SwampHutPiece {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, _random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
chunk_box: &BlockBox,
|
||||
) {
|
||||
if !self
|
||||
.shiftable_structure_piece
|
||||
.adjust_to_average_height(chunk)
|
||||
@ -69,7 +79,7 @@ impl StructurePieceBase for SwampHutPiece {
|
||||
return;
|
||||
}
|
||||
|
||||
let box_limit = self.shiftable_structure_piece.piece.bounding_box;
|
||||
let box_limit = *chunk_box;
|
||||
let p = &self.shiftable_structure_piece.piece;
|
||||
|
||||
let spruce_planks = Block::SPRUCE_PLANKS.default_state;
|
||||
|
||||
@ -163,7 +163,13 @@ impl StructurePieceBase for TemplatePiece {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn place(&mut self, chunk: &mut ProtoChunk, _random: &mut RandomGenerator, _seed: i64) {
|
||||
fn place(
|
||||
&mut self,
|
||||
chunk: &mut ProtoChunk,
|
||||
_random: &mut RandomGenerator,
|
||||
_seed: i64,
|
||||
_chunk_box: &BlockBox,
|
||||
) {
|
||||
self.place_blocks(chunk);
|
||||
|
||||
// TODO: Spawn entities from template
|
||||
|
||||
Loading…
Reference in New Issue
Block a user