1use steel_registry::blocks::block_state_ext::BlockStateExt as _;
2use steel_registry::blocks::properties::{AttachFace, BlockStateProperties, RedstoneSide};
3use steel_registry::{Registry, vanilla_blocks};
4use steel_utils::random::Random;
5use steel_utils::random::worldgen_random::WorldgenRandom;
6use steel_utils::{BlockStateId, BoundingBox, Direction};
7
8use crate::worldgen::region::WorldGenRegion;
9use steel_worldgen::structure::jungle_temple::JungleTemplePieceData;
10
11use super::StructurePiecePlacer;
12use super::scattered_feature::ScatteredFeaturePlacer;
13
14const JUNGLE_TEMPLE_LOOT: &str = "minecraft:chests/jungle_temple";
15const JUNGLE_TEMPLE_DISPENSER_LOOT: &str = "minecraft:chests/jungle_temple_dispenser";
16
17impl StructurePiecePlacer {
18 pub(super) fn place_jungle_temple_piece(
19 region: &mut WorldGenRegion<'_>,
20 registry: &Registry,
21 bounding_box: &mut BoundingBox,
22 orientation: Option<Direction>,
23 data: &mut JungleTemplePieceData,
24 clip: BoundingBox,
25 random: &mut WorldgenRandom,
26 ) -> bool {
27 let mut placer =
28 ScatteredFeaturePlacer::new(region, registry, bounding_box, orientation, clip);
29 if !placer.update_average_ground_height(&mut data.height_position, 0) {
30 return false;
31 }
32
33 place_jungle_temple(&mut placer, data, random);
34 true
35 }
36}
37
38#[expect(
39 clippy::too_many_lines,
40 reason = "jungle temple placement is a direct port of vanilla's linear postProcess"
41)]
42fn place_jungle_temple(
43 placer: &mut ScatteredFeaturePlacer<'_, '_>,
44 data: &mut JungleTemplePieceData,
45 random: &mut WorldgenRandom,
46) {
47 let air = vanilla_blocks::AIR.default_state();
48 let mossy_cobblestone = vanilla_blocks::MOSSY_COBBLESTONE.default_state();
49 let chiseled_stone_bricks = vanilla_blocks::CHISELED_STONE_BRICKS.default_state();
50
51 moss_box(placer, 0, -4, 0, 11, 0, 14, false, random);
52 moss_box(placer, 2, 1, 2, 9, 2, 2, false, random);
53 moss_box(placer, 2, 1, 12, 9, 2, 12, false, random);
54 moss_box(placer, 2, 1, 3, 2, 2, 11, false, random);
55 moss_box(placer, 9, 1, 3, 9, 2, 11, false, random);
56 moss_box(placer, 1, 3, 1, 10, 6, 1, false, random);
57 moss_box(placer, 1, 3, 13, 10, 6, 13, false, random);
58 moss_box(placer, 1, 3, 2, 1, 6, 12, false, random);
59 moss_box(placer, 10, 3, 2, 10, 6, 12, false, random);
60 moss_box(placer, 2, 3, 2, 9, 3, 12, false, random);
61 moss_box(placer, 2, 6, 2, 9, 6, 12, false, random);
62 moss_box(placer, 3, 7, 3, 8, 7, 11, false, random);
63 moss_box(placer, 4, 8, 4, 7, 8, 10, false, random);
64 placer.generate_air_box(3, 1, 3, 8, 2, 11);
65 placer.generate_air_box(4, 3, 6, 7, 3, 9);
66 placer.generate_air_box(2, 4, 2, 9, 5, 12);
67 placer.generate_air_box(4, 6, 5, 7, 6, 9);
68 placer.generate_air_box(5, 7, 6, 6, 7, 8);
69 placer.generate_air_box(5, 1, 2, 6, 2, 2);
70 placer.generate_air_box(5, 2, 12, 6, 2, 12);
71 placer.generate_air_box(5, 5, 1, 6, 5, 1);
72 placer.generate_air_box(5, 5, 13, 6, 5, 13);
73 placer.place_block(air, 1, 5, 5);
74 placer.place_block(air, 10, 5, 5);
75 placer.place_block(air, 1, 5, 9);
76 placer.place_block(air, 10, 5, 9);
77
78 for z in [0, 14] {
79 moss_box(placer, 2, 4, z, 2, 5, z, false, random);
80 moss_box(placer, 4, 4, z, 4, 5, z, false, random);
81 moss_box(placer, 7, 4, z, 7, 5, z, false, random);
82 moss_box(placer, 9, 4, z, 9, 5, z, false, random);
83 }
84
85 moss_box(placer, 5, 6, 0, 6, 6, 0, false, random);
86
87 for x in [0, 11] {
88 for z in (2..=12).step_by(2) {
89 moss_box(placer, x, 4, z, x, 5, z, false, random);
90 }
91 moss_box(placer, x, 6, 5, x, 6, 5, false, random);
92 moss_box(placer, x, 6, 9, x, 6, 9, false, random);
93 }
94
95 moss_box(placer, 2, 7, 2, 2, 9, 2, false, random);
96 moss_box(placer, 9, 7, 2, 9, 9, 2, false, random);
97 moss_box(placer, 2, 7, 12, 2, 9, 12, false, random);
98 moss_box(placer, 9, 7, 12, 9, 9, 12, false, random);
99 moss_box(placer, 4, 9, 4, 4, 9, 4, false, random);
100 moss_box(placer, 7, 9, 4, 7, 9, 4, false, random);
101 moss_box(placer, 4, 9, 10, 4, 9, 10, false, random);
102 moss_box(placer, 7, 9, 10, 7, 9, 10, false, random);
103 moss_box(placer, 5, 9, 7, 6, 9, 7, false, random);
104
105 let east_stairs = stairs(Direction::East);
106 let west_stairs = stairs(Direction::West);
107 let south_stairs = stairs(Direction::South);
108 let north_stairs = stairs(Direction::North);
109 placer.place_block(north_stairs, 5, 9, 6);
110 placer.place_block(north_stairs, 6, 9, 6);
111 placer.place_block(south_stairs, 5, 9, 8);
112 placer.place_block(south_stairs, 6, 9, 8);
113 placer.place_block(north_stairs, 4, 0, 0);
114 placer.place_block(north_stairs, 5, 0, 0);
115 placer.place_block(north_stairs, 6, 0, 0);
116 placer.place_block(north_stairs, 7, 0, 0);
117 placer.place_block(north_stairs, 4, 1, 8);
118 placer.place_block(north_stairs, 4, 2, 9);
119 placer.place_block(north_stairs, 4, 3, 10);
120 placer.place_block(north_stairs, 7, 1, 8);
121 placer.place_block(north_stairs, 7, 2, 9);
122 placer.place_block(north_stairs, 7, 3, 10);
123 moss_box(placer, 4, 1, 9, 4, 1, 9, false, random);
124 moss_box(placer, 7, 1, 9, 7, 1, 9, false, random);
125 moss_box(placer, 4, 1, 10, 7, 2, 10, false, random);
126 moss_box(placer, 5, 4, 5, 6, 4, 5, false, random);
127 placer.place_block(east_stairs, 4, 4, 5);
128 placer.place_block(west_stairs, 7, 4, 5);
129
130 for i in 0..4 {
131 placer.place_block(south_stairs, 5, -i, 6 + i);
132 placer.place_block(south_stairs, 6, -i, 6 + i);
133 placer.generate_air_box(5, -i, 7 + i, 6, -i, 9 + i);
134 }
135
136 placer.generate_air_box(1, -3, 12, 10, -1, 13);
137 placer.generate_air_box(1, -3, 1, 3, -1, 13);
138 placer.generate_air_box(1, -3, 1, 9, -1, 5);
139
140 for z in (1..=13).step_by(2) {
141 moss_box(placer, 1, -3, z, 1, -2, z, false, random);
142 }
143 for z in (2..=12).step_by(2) {
144 moss_box(placer, 1, -1, z, 3, -1, z, false, random);
145 }
146
147 moss_box(placer, 2, -2, 1, 5, -2, 1, false, random);
148 moss_box(placer, 7, -2, 1, 9, -2, 1, false, random);
149 moss_box(placer, 6, -3, 1, 6, -3, 1, false, random);
150 moss_box(placer, 6, -1, 1, 6, -1, 1, false, random);
151 placer.place_block(tripwire_hook(Direction::East), 1, -3, 8);
152 placer.place_block(tripwire_hook(Direction::West), 4, -3, 8);
153 placer.place_block(tripwire_east_west(), 2, -3, 8);
154 placer.place_block(tripwire_east_west(), 3, -3, 8);
155
156 let redstone_wire_ns = redstone_ns();
157 placer.place_block(redstone_wire_ns, 5, -3, 7);
158 placer.place_block(redstone_wire_ns, 5, -3, 6);
159 placer.place_block(redstone_wire_ns, 5, -3, 5);
160 placer.place_block(redstone_wire_ns, 5, -3, 4);
161 placer.place_block(redstone_wire_ns, 5, -3, 3);
162 placer.place_block(redstone_wire_ns, 5, -3, 2);
163 placer.place_block(redstone_nw(), 5, -3, 1);
164 placer.place_block(redstone_ew(), 4, -3, 1);
165 placer.place_block(mossy_cobblestone, 3, -3, 1);
166 if !data.placed_trap1 {
167 data.placed_trap1 = placer.create_dispenser(
168 random,
169 3,
170 -2,
171 1,
172 Direction::North,
173 JUNGLE_TEMPLE_DISPENSER_LOOT,
174 );
175 }
176
177 placer.place_block(vine(Direction::South), 3, -2, 2);
178 placer.place_block(tripwire_hook(Direction::North), 7, -3, 1);
179 placer.place_block(tripwire_hook(Direction::South), 7, -3, 5);
180 placer.place_block(tripwire_north_south(), 7, -3, 2);
181 placer.place_block(tripwire_north_south(), 7, -3, 3);
182 placer.place_block(tripwire_north_south(), 7, -3, 4);
183 placer.place_block(redstone_ew(), 8, -3, 6);
184 placer.place_block(redstone_ws(), 9, -3, 6);
185 placer.place_block(redstone_n_side_s_up(), 9, -3, 5);
186 placer.place_block(mossy_cobblestone, 9, -3, 4);
187 placer.place_block(redstone_wire_ns, 9, -2, 4);
188 if !data.placed_trap2 {
189 data.placed_trap2 = placer.create_dispenser(
190 random,
191 9,
192 -2,
193 3,
194 Direction::West,
195 JUNGLE_TEMPLE_DISPENSER_LOOT,
196 );
197 }
198
199 placer.place_block(vine(Direction::East), 8, -1, 3);
200 placer.place_block(vine(Direction::East), 8, -2, 3);
201 if !data.placed_main_chest {
202 data.placed_main_chest = placer.create_chest(random, 8, -3, 3, JUNGLE_TEMPLE_LOOT);
203 }
204
205 placer.place_block(mossy_cobblestone, 9, -3, 2);
206 placer.place_block(mossy_cobblestone, 8, -3, 1);
207 placer.place_block(mossy_cobblestone, 4, -3, 5);
208 placer.place_block(mossy_cobblestone, 5, -2, 5);
209 placer.place_block(mossy_cobblestone, 5, -1, 5);
210 placer.place_block(mossy_cobblestone, 6, -3, 5);
211 placer.place_block(mossy_cobblestone, 7, -2, 5);
212 placer.place_block(mossy_cobblestone, 7, -1, 5);
213 placer.place_block(mossy_cobblestone, 8, -3, 5);
214 moss_box(placer, 9, -1, 1, 9, -1, 5, false, random);
215 placer.generate_air_box(8, -3, 8, 10, -1, 10);
216 placer.place_block(chiseled_stone_bricks, 8, -2, 11);
217 placer.place_block(chiseled_stone_bricks, 9, -2, 11);
218 placer.place_block(chiseled_stone_bricks, 10, -2, 11);
219 let lever = vanilla_blocks::LEVER
220 .default_state()
221 .set_value(&BlockStateProperties::HORIZONTAL_FACING, Direction::North)
222 .set_value(&BlockStateProperties::ATTACH_FACE, AttachFace::Wall);
223 placer.place_block(lever, 8, -2, 12);
224 placer.place_block(lever, 9, -2, 12);
225 placer.place_block(lever, 10, -2, 12);
226 moss_box(placer, 8, -3, 8, 8, -3, 10, false, random);
227 moss_box(placer, 10, -3, 8, 10, -3, 10, false, random);
228 placer.place_block(mossy_cobblestone, 10, -2, 9);
229 placer.place_block(redstone_wire_ns, 8, -2, 9);
230 placer.place_block(redstone_wire_ns, 8, -2, 10);
231 placer.place_block(redstone_all_sides(), 10, -1, 9);
232 placer.place_block(sticky_piston(Direction::Up), 9, -2, 8);
233 placer.place_block(sticky_piston(Direction::West), 10, -2, 8);
234 placer.place_block(sticky_piston(Direction::West), 10, -1, 8);
235 placer.place_block(repeater(Direction::North), 10, -2, 10);
236 if !data.placed_hidden_chest {
237 data.placed_hidden_chest = placer.create_chest(random, 9, -3, 10, JUNGLE_TEMPLE_LOOT);
238 }
239}
240
241#[expect(
242 clippy::too_many_arguments,
243 reason = "mirrors vanilla StructurePiece.generateBox selector overload"
244)]
245fn moss_box(
246 placer: &mut ScatteredFeaturePlacer<'_, '_>,
247 x0: i32,
248 y0: i32,
249 z0: i32,
250 x1: i32,
251 y1: i32,
252 z1: i32,
253 skip_air: bool,
254 random: &mut WorldgenRandom,
255) {
256 placer.generate_box_with_selector(
257 x0,
258 y0,
259 z0,
260 x1,
261 y1,
262 z1,
263 skip_air,
264 random,
265 |rng, _, _, _, _| {
266 if rng.next_f32() < 0.4 {
267 vanilla_blocks::COBBLESTONE.default_state()
268 } else {
269 vanilla_blocks::MOSSY_COBBLESTONE.default_state()
270 }
271 },
272 );
273}
274
275fn stairs(facing: Direction) -> BlockStateId {
276 vanilla_blocks::COBBLESTONE_STAIRS
277 .default_state()
278 .set_value(&BlockStateProperties::FACING, facing)
279}
280
281fn tripwire_hook(facing: Direction) -> BlockStateId {
282 vanilla_blocks::TRIPWIRE_HOOK
283 .default_state()
284 .set_value(&BlockStateProperties::HORIZONTAL_FACING, facing)
285 .set_value(&BlockStateProperties::ATTACHED, true)
286}
287
288fn tripwire_east_west() -> BlockStateId {
289 vanilla_blocks::TRIPWIRE
290 .default_state()
291 .set_value(&BlockStateProperties::EAST, true)
292 .set_value(&BlockStateProperties::WEST, true)
293 .set_value(&BlockStateProperties::ATTACHED, true)
294}
295
296fn tripwire_north_south() -> BlockStateId {
297 vanilla_blocks::TRIPWIRE
298 .default_state()
299 .set_value(&BlockStateProperties::NORTH, true)
300 .set_value(&BlockStateProperties::SOUTH, true)
301 .set_value(&BlockStateProperties::ATTACHED, true)
302}
303
304fn redstone_ns() -> BlockStateId {
305 vanilla_blocks::REDSTONE_WIRE
306 .default_state()
307 .set_value(&BlockStateProperties::NORTH_REDSTONE, RedstoneSide::Side)
308 .set_value(&BlockStateProperties::SOUTH_REDSTONE, RedstoneSide::Side)
309}
310
311fn redstone_ew() -> BlockStateId {
312 vanilla_blocks::REDSTONE_WIRE
313 .default_state()
314 .set_value(&BlockStateProperties::EAST_REDSTONE, RedstoneSide::Side)
315 .set_value(&BlockStateProperties::WEST_REDSTONE, RedstoneSide::Side)
316}
317
318fn redstone_nw() -> BlockStateId {
319 vanilla_blocks::REDSTONE_WIRE
320 .default_state()
321 .set_value(&BlockStateProperties::NORTH_REDSTONE, RedstoneSide::Side)
322 .set_value(&BlockStateProperties::WEST_REDSTONE, RedstoneSide::Side)
323}
324
325fn redstone_ws() -> BlockStateId {
326 vanilla_blocks::REDSTONE_WIRE
327 .default_state()
328 .set_value(&BlockStateProperties::WEST_REDSTONE, RedstoneSide::Side)
329 .set_value(&BlockStateProperties::SOUTH_REDSTONE, RedstoneSide::Side)
330}
331
332fn redstone_n_side_s_up() -> BlockStateId {
333 vanilla_blocks::REDSTONE_WIRE
334 .default_state()
335 .set_value(&BlockStateProperties::NORTH_REDSTONE, RedstoneSide::Side)
336 .set_value(&BlockStateProperties::SOUTH_REDSTONE, RedstoneSide::Up)
337}
338
339fn redstone_all_sides() -> BlockStateId {
340 vanilla_blocks::REDSTONE_WIRE
341 .default_state()
342 .set_value(&BlockStateProperties::NORTH_REDSTONE, RedstoneSide::Side)
343 .set_value(&BlockStateProperties::SOUTH_REDSTONE, RedstoneSide::Side)
344 .set_value(&BlockStateProperties::EAST_REDSTONE, RedstoneSide::Side)
345 .set_value(&BlockStateProperties::WEST_REDSTONE, RedstoneSide::Side)
346}
347
348fn vine(side: Direction) -> BlockStateId {
349 let vine = vanilla_blocks::VINE.default_state();
350 match side {
351 Direction::North => vine.set_value(&BlockStateProperties::NORTH, true),
352 Direction::East => vine.set_value(&BlockStateProperties::EAST, true),
353 Direction::South => vine.set_value(&BlockStateProperties::SOUTH, true),
354 Direction::West => vine.set_value(&BlockStateProperties::WEST, true),
355 Direction::Up => vine.set_value(&BlockStateProperties::UP, true),
356 Direction::Down => vine,
357 }
358}
359
360fn sticky_piston(facing: Direction) -> BlockStateId {
361 vanilla_blocks::STICKY_PISTON
362 .default_state()
363 .set_value(&BlockStateProperties::FACING, facing)
364}
365
366fn repeater(facing: Direction) -> BlockStateId {
367 vanilla_blocks::REPEATER
368 .default_state()
369 .set_value(&BlockStateProperties::HORIZONTAL_FACING, facing)
370}