steel_core/worldgen/structure/piece_placer/
buried_treasure.rs1use simdnbt::owned::NbtCompound;
2use steel_registry::blocks::block_state_ext::BlockStateExt as _;
3use steel_registry::{vanilla_block_entity_types, vanilla_blocks};
4use steel_utils::random::Random;
5use steel_utils::random::worldgen_random::WorldgenRandom;
6use steel_utils::{BlockPos, BlockStateId, BoundingBox, Direction, types::UpdateFlags};
7
8use super::StructurePiecePlacer;
9use crate::chunk::heightmap::HeightmapType;
10use crate::worldgen::region::WorldGenRegion;
11
12const BURIED_TREASURE_LOOT: &str = "minecraft:chests/buried_treasure";
13const VANILLA_DIRECTION_VALUES: [Direction; 6] = [
14 Direction::Down,
15 Direction::Up,
16 Direction::North,
17 Direction::South,
18 Direction::West,
19 Direction::East,
20];
21
22impl StructurePiecePlacer {
23 pub(super) fn place_buried_treasure_piece(
24 region: &mut WorldGenRegion<'_>,
25 bounding_box: &mut BoundingBox,
26 clip: BoundingBox,
27 random: &mut WorldgenRandom,
28 ) -> bool {
29 let x = bounding_box.min_x();
30 let z = bounding_box.min_z();
31 let mut y = region.height_at(HeightmapType::OceanFloorWg, x, z);
32
33 while y > region.min_y() {
34 let pos = BlockPos::new(x, y, z);
35 let current_state = region.block_state(pos);
36 let below_state = region.block_state(pos.below());
37
38 if Self::is_buried_treasure_base(below_state) {
39 let soft_state =
40 if !current_state.is_air() && !Self::is_buried_treasure_liquid(current_state) {
41 current_state
42 } else {
43 vanilla_blocks::SAND.default_state()
44 };
45
46 for direction in VANILLA_DIRECTION_VALUES {
47 let relative_pos = pos.relative(direction);
48 let relative_state = region.block_state(relative_pos);
49 if !relative_state.is_air() && !Self::is_buried_treasure_liquid(relative_state)
50 {
51 continue;
52 }
53
54 let below_relative_pos = relative_pos.below();
55 let below_relative_state = region.block_state(below_relative_pos);
56 let place_state = if direction != Direction::Up
57 && (below_relative_state.is_air()
58 || Self::is_buried_treasure_liquid(below_relative_state))
59 {
60 below_state
61 } else {
62 soft_state
63 };
64 let _ =
65 region.set_block_state(relative_pos, place_state, UpdateFlags::UPDATE_ALL);
66 }
67
68 *bounding_box = BoundingBox::from_corners(pos, pos);
69 let _ = Self::create_buried_treasure_chest(region, clip, random, pos);
70 return true;
71 }
72
73 y -= 1;
74 }
75
76 true
77 }
78
79 fn is_buried_treasure_base(state: BlockStateId) -> bool {
80 let block = state.get_block();
81 block == &vanilla_blocks::SANDSTONE
82 || block == &vanilla_blocks::STONE
83 || block == &vanilla_blocks::ANDESITE
84 || block == &vanilla_blocks::GRANITE
85 || block == &vanilla_blocks::DIORITE
86 }
87
88 fn is_buried_treasure_liquid(state: BlockStateId) -> bool {
89 let block = state.get_block();
90 block == &vanilla_blocks::WATER || block == &vanilla_blocks::LAVA
91 }
92
93 fn create_buried_treasure_chest(
94 region: &mut WorldGenRegion<'_>,
95 clip: BoundingBox,
96 random: &mut WorldgenRandom,
97 pos: BlockPos,
98 ) -> bool {
99 if !clip.contains_blockpos(pos)
100 || region.block_state(pos).get_block() == &vanilla_blocks::CHEST
101 {
102 return false;
103 }
104
105 let state = Self::reorient_chest(region, pos, vanilla_blocks::CHEST.default_state());
106 if !region.set_block_state(pos, state, UpdateFlags::UPDATE_CLIENTS) {
107 return false;
108 }
109
110 let mut nbt = NbtCompound::new();
111 nbt.insert("LootTable", BURIED_TREASURE_LOOT);
112 nbt.insert("LootTableSeed", random.next_i64());
113 region.set_block_entity_data(pos, &vanilla_block_entity_types::CHEST, state, nbt)
114 }
115}