1use std::sync::Arc;
2
3use glam::DVec3;
4use steel_registry::blocks::block_state_ext::BlockStateExt as _;
5use steel_registry::blocks::properties::{BlockStateProperties, StairsShape};
6use steel_registry::entity_type::EntityTypeRef;
7use steel_registry::{Registry, vanilla_blocks, vanilla_entities};
8use steel_utils::random::worldgen_random::WorldgenRandom;
9use steel_utils::{BlockStateId, BoundingBox, Direction};
10
11use crate::entity::{entities::RawEntity, next_entity_id};
12use crate::worldgen::region::WorldGenRegion;
13use steel_worldgen::structure::swamp_hut::SwampHutPieceData;
14
15use super::StructurePiecePlacer;
16use super::scattered_feature::ScatteredFeaturePlacer;
17
18impl StructurePiecePlacer {
19 pub(super) fn place_swamp_hut_piece(
20 region: &mut WorldGenRegion<'_>,
21 registry: &Registry,
22 bounding_box: &mut BoundingBox,
23 orientation: Option<Direction>,
24 data: &mut SwampHutPieceData,
25 clip: BoundingBox,
26 _random: &mut WorldgenRandom,
27 ) -> bool {
28 let mut placer =
29 ScatteredFeaturePlacer::new(region, registry, bounding_box, orientation, clip);
30 if !placer.update_average_ground_height(&mut data.height_position, 0) {
31 return false;
32 }
33
34 place_swamp_hut(&mut placer, data);
35 true
36 }
37}
38
39fn place_swamp_hut(placer: &mut ScatteredFeaturePlacer<'_, '_>, data: &mut SwampHutPieceData) {
40 let spruce_planks = vanilla_blocks::SPRUCE_PLANKS.default_state();
41 let oak_log = vanilla_blocks::OAK_LOG.default_state();
42 let oak_fence = vanilla_blocks::OAK_FENCE.default_state();
43 let air = vanilla_blocks::AIR.default_state();
44
45 placer.generate_box(1, 1, 1, 5, 1, 7, spruce_planks, spruce_planks, false);
46 placer.generate_box(1, 4, 2, 5, 4, 7, spruce_planks, spruce_planks, false);
47 placer.generate_box(2, 1, 0, 4, 1, 0, spruce_planks, spruce_planks, false);
48 placer.generate_box(2, 2, 2, 3, 3, 2, spruce_planks, spruce_planks, false);
49 placer.generate_box(1, 2, 3, 1, 3, 6, spruce_planks, spruce_planks, false);
50 placer.generate_box(5, 2, 3, 5, 3, 6, spruce_planks, spruce_planks, false);
51 placer.generate_box(2, 2, 7, 4, 3, 7, spruce_planks, spruce_planks, false);
52 placer.generate_box(1, 0, 2, 1, 3, 2, oak_log, oak_log, false);
53 placer.generate_box(5, 0, 2, 5, 3, 2, oak_log, oak_log, false);
54 placer.generate_box(1, 0, 7, 1, 3, 7, oak_log, oak_log, false);
55 placer.generate_box(5, 0, 7, 5, 3, 7, oak_log, oak_log, false);
56 placer.place_block(oak_fence, 2, 3, 2);
57 placer.place_block(oak_fence, 3, 3, 7);
58 placer.place_block(air, 1, 3, 4);
59 placer.place_block(air, 5, 3, 4);
60 placer.place_block(air, 5, 3, 5);
61 placer.place_block(vanilla_blocks::POTTED_RED_MUSHROOM.default_state(), 1, 3, 5);
62 placer.place_block(vanilla_blocks::CRAFTING_TABLE.default_state(), 3, 2, 6);
63 placer.place_block(vanilla_blocks::CAULDRON.default_state(), 4, 2, 6);
64 placer.place_block(oak_fence, 1, 2, 1);
65 placer.place_block(oak_fence, 5, 2, 1);
66
67 let north_stairs = stairs(Direction::North);
68 let east_stairs = stairs(Direction::East);
69 let west_stairs = stairs(Direction::West);
70 let south_stairs = stairs(Direction::South);
71 placer.generate_box(0, 4, 1, 6, 4, 1, north_stairs, north_stairs, false);
72 placer.generate_box(0, 4, 2, 0, 4, 7, east_stairs, east_stairs, false);
73 placer.generate_box(6, 4, 2, 6, 4, 7, west_stairs, west_stairs, false);
74 placer.generate_box(0, 4, 8, 6, 4, 8, south_stairs, south_stairs, false);
75 placer.place_block(stairs_shape(north_stairs, StairsShape::OuterRight), 0, 4, 1);
76 placer.place_block(stairs_shape(north_stairs, StairsShape::OuterLeft), 6, 4, 1);
77 placer.place_block(stairs_shape(south_stairs, StairsShape::OuterLeft), 0, 4, 8);
78 placer.place_block(stairs_shape(south_stairs, StairsShape::OuterRight), 6, 4, 8);
79
80 for z in [2, 7] {
81 for x in [1, 5] {
82 placer.fill_column_down(oak_log, x, -1, z);
83 }
84 }
85
86 spawn_swamp_hut_mob(placer, &mut data.spawned_witch, &vanilla_entities::WITCH);
87 spawn_swamp_hut_mob(placer, &mut data.spawned_cat, &vanilla_entities::CAT);
88}
89
90fn spawn_swamp_hut_mob(
91 placer: &mut ScatteredFeaturePlacer<'_, '_>,
92 spawned: &mut bool,
93 entity_type: EntityTypeRef,
94) {
95 if *spawned {
96 return;
97 }
98
99 let pos = placer.world_pos(2, 2, 5);
100 if !placer.clip().contains_blockpos(pos) {
101 return;
102 }
103
104 *spawned = true;
105 let entity = Arc::new(RawEntity::new(
106 next_entity_id(),
107 DVec3::new(
108 f64::from(pos.x()) + 0.5,
109 f64::from(pos.y()),
110 f64::from(pos.z()) + 0.5,
111 ),
112 placer.weak_world(),
113 entity_type,
114 ));
115 entity.set_persistence_required();
116 entity.snap_to(
117 DVec3::new(
118 f64::from(pos.x()) + 0.5,
119 f64::from(pos.y()),
120 f64::from(pos.z()) + 0.5,
121 ),
122 0.0,
123 0.0,
124 );
125 let _ = placer.add_fresh_entity(entity);
126}
127
128fn stairs(facing: Direction) -> BlockStateId {
129 vanilla_blocks::SPRUCE_STAIRS
130 .default_state()
131 .set_value(&BlockStateProperties::FACING, facing)
132}
133
134fn stairs_shape(state: BlockStateId, shape: StairsShape) -> BlockStateId {
135 state.set_value(&BlockStateProperties::STAIRS_SHAPE, shape)
136}