steel_core/worldgen/feature/features/
block_entities.rs1use simdnbt::owned::{NbtCompound, NbtList, NbtTag};
2use steel_registry::block_entity_type::BlockEntityTypeRef;
3use steel_registry::vanilla_block_entity_types;
4use steel_registry::vanilla_block_tags::BlockTag;
5use steel_utils::PackedBlockPos;
6
7use super::super::prelude::*;
8use super::super::runner::FeatureDecorationRunner;
9
10impl FeatureDecorationRunner {
11 pub(in crate::worldgen::feature) fn set_loot_table_block_entity(
12 region: &WorldGenRegion<'_>,
13 pos: BlockPos,
14 block_entity_type: BlockEntityTypeRef,
15 state: BlockStateId,
16 loot_table: &'static str,
17 seed: i64,
18 ) {
19 let mut nbt = NbtCompound::new();
20 nbt.insert("LootTable", loot_table);
21 if seed != 0 {
22 nbt.insert("LootTableSeed", seed);
23 }
24 let _ = region.set_block_entity_data(pos, block_entity_type, state, nbt);
25 }
26
27 pub(in crate::worldgen::feature) fn set_empty_block_entity(
28 region: &WorldGenRegion<'_>,
29 pos: BlockPos,
30 block_entity_type: BlockEntityTypeRef,
31 state: BlockStateId,
32 ) {
33 let _ = region.set_block_entity_data(pos, block_entity_type, state, NbtCompound::new());
34 }
35
36 pub(in crate::worldgen::feature) fn set_brushable_loot_table(
37 region: &WorldGenRegion<'_>,
38 pos: BlockPos,
39 state: BlockStateId,
40 loot_table: &'static str,
41 ) {
42 let seed = PackedBlockPos::from(pos).as_raw();
43 Self::set_loot_table_block_entity(
44 region,
45 pos,
46 &vanilla_block_entity_types::BRUSHABLE_BLOCK,
47 state,
48 loot_table,
49 seed,
50 );
51 }
52
53 pub(in crate::worldgen::feature) fn set_spawner_entity(
54 region: &WorldGenRegion<'_>,
55 pos: BlockPos,
56 state: BlockStateId,
57 entity_id: &'static str,
58 ) {
59 let mut entity = NbtCompound::new();
60 entity.insert("id", entity_id);
61
62 let mut spawn_data = NbtCompound::new();
63 spawn_data.insert("entity", NbtTag::Compound(entity));
64
65 let mut nbt = NbtCompound::new();
66 nbt.insert("Delay", 20_i16);
67 nbt.insert("MinSpawnDelay", 200_i16);
68 nbt.insert("MaxSpawnDelay", 800_i16);
69 nbt.insert("SpawnCount", 4_i16);
70 nbt.insert("MaxNearbyEntities", 6_i16);
71 nbt.insert("RequiredPlayerRange", 16_i16);
72 nbt.insert("SpawnRange", 4_i16);
73 nbt.insert("SpawnData", NbtTag::Compound(spawn_data));
74 nbt.insert(
75 "SpawnPotentials",
76 NbtTag::List(NbtList::Compound(Vec::new())),
77 );
78
79 let _ =
80 region.set_block_entity_data(pos, &vanilla_block_entity_types::MOB_SPAWNER, state, nbt);
81 }
82
83 pub(in crate::worldgen::feature) fn set_end_gateway_block_entity(
84 region: &WorldGenRegion<'_>,
85 pos: BlockPos,
86 state: BlockStateId,
87 exit: Option<BlockPos>,
88 exact: bool,
89 ) {
90 let mut nbt = NbtCompound::new();
91 nbt.insert("Age", 0_i64);
92 if let Some(exit) = exit {
93 nbt.insert(
94 "exit_portal",
95 NbtTag::IntArray(vec![exit.x(), exit.y(), exit.z()]),
96 );
97 }
98 if exact {
99 nbt.insert("ExactTeleport", 1_i8);
100 }
101 let _ =
102 region.set_block_entity_data(pos, &vanilla_block_entity_types::END_GATEWAY, state, nbt);
103 }
104
105 pub(in crate::worldgen::feature) fn safe_set_feature_block(
106 region: &WorldGenRegion<'_>,
107 pos: BlockPos,
108 state: BlockStateId,
109 ) -> bool {
110 if Self::feature_can_replace(region.block_state(pos)) {
111 region.set_block_state(pos, state, UpdateFlags::UPDATE_CLIENTS)
112 } else {
113 false
114 }
115 }
116
117 pub(in crate::worldgen::feature) fn feature_can_replace(state: BlockStateId) -> bool {
118 !state
119 .get_block()
120 .has_tag(&BlockTag::FEATURES_CANNOT_REPLACE)
121 }
122}