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 gamemode::GameMode;
|
||||||
pub use permission::PermissionLvl;
|
pub use permission::PermissionLvl;
|
||||||
|
|
||||||
use crate::math::vector3::Axis;
|
use crate::{math::vector3::Axis, random::RandomImpl};
|
||||||
|
|
||||||
pub mod biome;
|
pub mod biome;
|
||||||
pub mod difficulty;
|
pub mod difficulty;
|
||||||
@ -131,6 +131,15 @@ impl BlockDirection {
|
|||||||
Self::East | Self::West => Axis::X,
|
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.
|
/// 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 dx = chunk_x - self.x;
|
||||||
let dz = chunk_z - self.z;
|
let dz = chunk_z - self.z;
|
||||||
|
|
||||||
(dx >= 0 && dx < self.size && dz >= 0 && dz < self.size)
|
if dx < 0 || dx >= self.size || dz < 0 || dz >= self.size {
|
||||||
.then(|| self.chunks[(dx * self.size + dz) as usize].get_proto_chunk())
|
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> {
|
fn try_get_proto_chunk(&self, chunk_x: i32, chunk_z: i32) -> Option<&ProtoChunk> {
|
||||||
|
|||||||
@ -1022,14 +1022,10 @@ impl ProtoChunk {
|
|||||||
|
|
||||||
match instance {
|
match instance {
|
||||||
StructureInstance::Start(pos) => tasks.push(pos.collector.clone()),
|
StructureInstance::Start(pos) => tasks.push(pos.collector.clone()),
|
||||||
StructureInstance::Reference(origin_block_pos) => {
|
StructureInstance::Reference(collector) => {
|
||||||
let origin_chunk_x = origin_block_pos.0.x >> 4;
|
let collector_arc = collector.clone();
|
||||||
let origin_chunk_z = origin_block_pos.0.z >> 4;
|
if !tasks.iter().any(|t| Arc::ptr_eq(t, &collector_arc)) {
|
||||||
if let Some(neighbor) = cache.get_chunk(origin_chunk_x, origin_chunk_z)
|
tasks.push(collector_arc);
|
||||||
&& let Some(StructureInstance::Start(pos)) =
|
|
||||||
neighbor.structure_starts.get(id)
|
|
||||||
{
|
|
||||||
tasks.push(pos.collector.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1069,29 +1065,10 @@ impl ProtoChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StructureInstance::Reference(origin_block_pos) => {
|
StructureInstance::Reference(collector) => {
|
||||||
let origin_chunk_x = origin_block_pos.0.x >> 4;
|
let collector_arc = collector.clone();
|
||||||
let origin_chunk_z = origin_block_pos.0.z >> 4;
|
if !tasks.iter().any(|t| Arc::ptr_eq(t, &collector_arc)) {
|
||||||
if let Some(origin_neighbor) =
|
tasks.push(collector_arc);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1218,7 +1195,7 @@ impl ProtoChunk {
|
|||||||
.get_bounding_box()
|
.get_bounding_box()
|
||||||
.intersects_raw_xz(start_x, start_z, end_x, end_z)
|
.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::{
|
structure::structures::{
|
||||||
StructureGenerator, StructureGeneratorContext, StructurePosition,
|
StructureGenerator, StructureGeneratorContext, StructurePosition,
|
||||||
buried_treasure::BuriedTreasureGenerator, create_chunk_random, igloo::IglooGenerator,
|
buried_treasure::BuriedTreasureGenerator, create_chunk_random, igloo::IglooGenerator,
|
||||||
nether_fossil::NetherFossilGenerator, stronghold::StrongholdGenerator,
|
nether_fortress::NetherFortressGenerator, nether_fossil::NetherFossilGenerator,
|
||||||
swamp_hut::SwampHutGenerator,
|
stronghold::StrongholdGenerator, swamp_hut::SwampHutGenerator,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -49,6 +49,9 @@ pub fn try_generate_structure(
|
|||||||
StructureKeys::Stronghold => {
|
StructureKeys::Stronghold => {
|
||||||
StrongholdGenerator::get_structure_position(&StrongholdGenerator, context)
|
StrongholdGenerator::get_structure_position(&StrongholdGenerator, context)
|
||||||
}
|
}
|
||||||
|
StructureKeys::Fortress => {
|
||||||
|
NetherFortressGenerator::get_structure_position(&NetherFortressGenerator, context)
|
||||||
|
}
|
||||||
StructureKeys::NetherFossil => {
|
StructureKeys::NetherFossil => {
|
||||||
NetherFossilGenerator::get_structure_position(&NetherFossilGenerator, context)
|
NetherFossilGenerator::get_structure_position(&NetherFossilGenerator, context)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,13 @@ impl StructurePieceBase for BuriedTreasurePiece {
|
|||||||
Box::new((*self).clone())
|
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 boundingbox = self.bounding_box();
|
||||||
let y = chunk.get_top_y(
|
let y = chunk.get_top_y(
|
||||||
&HeightMap::OceanFloorWg,
|
&HeightMap::OceanFloorWg,
|
||||||
|
|||||||
@ -8,7 +8,10 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
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 serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -142,7 +145,13 @@ impl StructurePieceBase for IglooPiece {
|
|||||||
Box::new(self.clone())
|
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;
|
let origin = self.shiftable_structure_piece.piece.bounding_box.min;
|
||||||
|
|
||||||
// Vanilla samples height at the entrance position (3, 0, 5 in template space)
|
// Vanilla samples height at the entrance position (3, 0, 5 in template space)
|
||||||
|
|||||||
@ -10,7 +10,6 @@ use pumpkin_util::{
|
|||||||
};
|
};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::generation::structure::structures::stronghold::PieceWeight;
|
|
||||||
use crate::generation::structure::structures::stronghold::StrongholdPieceType;
|
use crate::generation::structure::structures::stronghold::StrongholdPieceType;
|
||||||
use crate::{
|
use crate::{
|
||||||
ProtoChunk,
|
ProtoChunk,
|
||||||
@ -49,7 +48,13 @@ pub trait StructurePieceBase: Send + Sync {
|
|||||||
fn clone_box(&self) -> Box<dyn StructurePieceBase>;
|
fn clone_box(&self) -> Box<dyn StructurePieceBase>;
|
||||||
|
|
||||||
/// Places the blocks for this piece into the chunk.
|
/// 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)]
|
#[expect(clippy::too_many_arguments)]
|
||||||
fn fill_openings(
|
fn fill_openings(
|
||||||
@ -57,7 +62,7 @@ pub trait StructurePieceBase: Send + Sync {
|
|||||||
_start: &StructurePiece,
|
_start: &StructurePiece,
|
||||||
_random: &mut RandomGenerator,
|
_random: &mut RandomGenerator,
|
||||||
// TODO: this is only for Stronghold and should not be here
|
// 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>,
|
_last_piece_type: &mut Option<StrongholdPieceType>,
|
||||||
_has_portal_room: &mut bool,
|
_has_portal_room: &mut bool,
|
||||||
|
|
||||||
@ -65,6 +70,21 @@ pub trait StructurePieceBase: Send + Sync {
|
|||||||
_pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
|
_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)]
|
#[derive(Clone)]
|
||||||
@ -366,15 +386,6 @@ impl StructurePiece {
|
|||||||
// world.mark_block_for_post_processing(&block_pos);
|
// 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 {
|
impl StructurePieceBase for StructurePiece {
|
||||||
@ -382,7 +393,14 @@ impl StructurePieceBase for StructurePiece {
|
|||||||
Box::new(self.clone())
|
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) {
|
fn translate(&mut self, x: i32, y: i32, z: i32) {
|
||||||
self.bounding_box.move_pos(x, y, z);
|
self.bounding_box.move_pos(x, y, z);
|
||||||
@ -451,7 +469,7 @@ impl StructurePiecesCollector {
|
|||||||
|
|
||||||
for piece in &mut self.pieces {
|
for piece in &mut self.pieces {
|
||||||
if piece.bounding_box().intersects(&chunk_box) {
|
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),
|
Start(StructurePosition),
|
||||||
/// This chunk just contains a piece of a structure starting elsewhere.
|
/// This chunk just contains a piece of a structure starting elsewhere.
|
||||||
/// Stores the `BlockPos` of the 'Start' so you can look it up.
|
/// 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_data::{Block, BlockDirection, BlockState};
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
math::{position::BlockPos, vector3::Vector3},
|
math::{block_box::BlockBox, position::BlockPos, vector3::Vector3},
|
||||||
random::{RandomDeriverImpl, RandomGenerator, RandomImpl},
|
random::{RandomDeriverImpl, RandomGenerator, RandomImpl},
|
||||||
};
|
};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
@ -166,7 +166,13 @@ impl StructurePieceBase for NetherFossilPiece {
|
|||||||
Box::new(self.clone())
|
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
|
// Vanilla column scan: find air above soul sand or solid block
|
||||||
let Some(placement_y) = self.find_placement_y(chunk) else {
|
let Some(placement_y) = self.find_placement_y(chunk) else {
|
||||||
debug!(
|
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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.piece;
|
let inner = &p.piece;
|
||||||
let air = Block::AIR.default_state;
|
let air = Block::AIR.default_state;
|
||||||
@ -246,8 +252,14 @@ impl StructurePieceBase for SmallCorridorPiece {
|
|||||||
&mut self.piece.piece
|
&mut self.piece.piece
|
||||||
}
|
}
|
||||||
|
|
||||||
fn place(&mut self, chunk: &mut ProtoChunk, _random: &mut RandomGenerator, _seed: i64) {
|
fn place(
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
&mut self,
|
||||||
|
chunk: &mut ProtoChunk,
|
||||||
|
_random: &mut RandomGenerator,
|
||||||
|
_seed: i64,
|
||||||
|
chunk_box: &BlockBox,
|
||||||
|
) {
|
||||||
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece.piece;
|
let p = &self.piece.piece;
|
||||||
|
|
||||||
let stone = Block::STONE_BRICKS.default_state;
|
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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.piece;
|
let inner = &p.piece;
|
||||||
let air = Block::AIR.default_state;
|
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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.piece;
|
let inner = &p.piece;
|
||||||
let air = Block::AIR.default_state;
|
let air = Block::AIR.default_state;
|
||||||
|
|||||||
@ -71,9 +71,15 @@ impl StructurePieceBase for LibraryPiece {
|
|||||||
&mut self.piece.piece
|
&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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.piece;
|
let inner = &p.piece;
|
||||||
|
|
||||||
|
|||||||
@ -87,9 +87,15 @@ impl StructurePieceBase for PortalRoomPiece {
|
|||||||
*has_portal_room = true;
|
*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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.piece;
|
let inner = &p.piece;
|
||||||
let air = Block::AIR.default_state;
|
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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.piece;
|
let inner = &p.piece;
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@ impl Clone for SpiralStaircasePiece {
|
|||||||
impl SpiralStaircasePiece {
|
impl SpiralStaircasePiece {
|
||||||
/// Matches Start(Random random, int i, int j)
|
/// Matches Start(Random random, int i, int j)
|
||||||
pub fn new_start(random: &mut impl RandomImpl, x: i32, z: i32) -> Self {
|
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 bounding_box = BlockBox::create_box(x, 64, z, orientation.get_axis(), 5, 11, 5);
|
||||||
let mut piece = StrongholdPiece::new(StructurePieceType::StrongholdStart, 0, bounding_box);
|
let mut piece = StrongholdPiece::new(StructurePieceType::StrongholdStart, 0, bounding_box);
|
||||||
piece.piece.set_facing(Some(orientation));
|
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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
|
|
||||||
let p = &self.piece;
|
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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.piece;
|
let inner = &p.piece;
|
||||||
let air = Block::AIR.default_state;
|
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 randomizer = StoneBrickRandomizer;
|
||||||
let box_limit = self.piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.piece;
|
let p = &self.piece;
|
||||||
let inner = &p.piece;
|
let inner = &p.piece;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use pumpkin_data::Block;
|
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 serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -12,7 +16,7 @@ use crate::{
|
|||||||
piece::StructurePieceType,
|
piece::StructurePieceType,
|
||||||
shiftable_piece::ShiftableStructurePiece,
|
shiftable_piece::ShiftableStructurePiece,
|
||||||
structures::{
|
structures::{
|
||||||
StructureGenerator, StructureGeneratorContext, StructurePiece, StructurePieceBase,
|
StructureGenerator, StructureGeneratorContext, StructurePieceBase,
|
||||||
StructurePiecesCollector, StructurePosition,
|
StructurePiecesCollector, StructurePosition,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -40,7 +44,7 @@ impl StructureGenerator for SwampHutGenerator {
|
|||||||
7,
|
7,
|
||||||
7,
|
7,
|
||||||
9,
|
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())
|
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
|
if !self
|
||||||
.shiftable_structure_piece
|
.shiftable_structure_piece
|
||||||
.adjust_to_average_height(chunk)
|
.adjust_to_average_height(chunk)
|
||||||
@ -69,7 +79,7 @@ impl StructurePieceBase for SwampHutPiece {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let box_limit = self.shiftable_structure_piece.piece.bounding_box;
|
let box_limit = *chunk_box;
|
||||||
let p = &self.shiftable_structure_piece.piece;
|
let p = &self.shiftable_structure_piece.piece;
|
||||||
|
|
||||||
let spruce_planks = Block::SPRUCE_PLANKS.default_state;
|
let spruce_planks = Block::SPRUCE_PLANKS.default_state;
|
||||||
|
|||||||
@ -163,7 +163,13 @@ impl StructurePieceBase for TemplatePiece {
|
|||||||
Box::new(self.clone())
|
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);
|
self.place_blocks(chunk);
|
||||||
|
|
||||||
// TODO: Spawn entities from template
|
// TODO: Spawn entities from template
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user