Skip to main content

steel_core/worldgen/structure/piece_placer/
buried_treasure.rs

1use 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}