Skip to main content

steel_core/worldgen/structure/piece_placer/
jungle_temple.rs

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}