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