steel_core/behavior/blocks/building/
netherrack_block.rs1use std::sync::Arc;
4
5use rand::RngExt;
6use steel_macros::block_behavior;
7use steel_registry::blocks::BlockRef;
8use steel_registry::blocks::block_state_ext::BlockStateExt as _;
9use steel_registry::vanilla_block_tags::BlockTag;
10use steel_registry::vanilla_blocks;
11use steel_utils::{BlockPos, BlockStateId, types::UpdateFlags};
12
13use crate::behavior::blocks::vegetation::bonemealable::{BonemealAction, Bonemealable};
14use crate::behavior::{BlockBehavior, BlockPlaceContext};
15use crate::world::{LevelReader, World};
16
17const WARPED_VS_CRIMSON_CHANCE: f64 = 0.5;
19
20#[block_behavior]
22pub struct NetherrackBlock {
23 block: BlockRef,
24}
25
26impl NetherrackBlock {
27 #[must_use]
29 pub const fn new(block: BlockRef) -> Self {
30 Self { block }
31 }
32}
33
34impl BlockBehavior for NetherrackBlock {
35 fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
36 Some(self.block.default_state())
37 }
38
39 fn as_bonemealable(&self) -> Option<&dyn Bonemealable> {
40 Some(self)
41 }
42}
43
44impl Bonemealable for NetherrackBlock {
45 fn is_valid_bonemeal_target(
46 &self,
47 _state: BlockStateId,
48 world: &dyn LevelReader,
49 pos: BlockPos,
50 ) -> bool {
51 if world.get_block_state(pos.above()).get_light_dampening() != 0 {
52 return false;
53 }
54 for check_pos in BlockPos::between_closed(pos.offset(-1, -1, -1), pos.offset(1, 1, 1)) {
55 if world
56 .get_block_state(check_pos)
57 .get_block()
58 .has_tag(&BlockTag::NYLIUM)
59 {
60 return true;
61 }
62 }
63 false
64 }
65
66 fn perform_bonemeal(
67 &self,
68 _state: BlockStateId,
69 world: &Arc<World>,
70 rng: &mut dyn rand::Rng,
71 pos: BlockPos,
72 ) {
73 let mut found_warped = false;
74 let mut found_crimson = false;
75 for check_pos in BlockPos::between_closed(pos.offset(-1, -1, -1), pos.offset(1, 1, 1)) {
76 let state = world.get_block_state(check_pos);
77 let block = state.get_block();
78 if block == &vanilla_blocks::WARPED_NYLIUM {
79 found_warped = true;
80 }
81 if block == &vanilla_blocks::CRIMSON_NYLIUM {
82 found_crimson = true;
83 }
84 if found_warped && found_crimson {
85 break;
86 }
87 }
88 let new_state = if found_warped && found_crimson {
89 if rng.random_bool(WARPED_VS_CRIMSON_CHANCE) {
90 vanilla_blocks::WARPED_NYLIUM.default_state()
91 } else {
92 vanilla_blocks::CRIMSON_NYLIUM.default_state()
93 }
94 } else if found_warped {
95 vanilla_blocks::WARPED_NYLIUM.default_state()
96 } else if found_crimson {
97 vanilla_blocks::CRIMSON_NYLIUM.default_state()
98 } else {
99 return;
100 };
101 world.set_block(pos, new_state, UpdateFlags::UPDATE_ALL);
102 }
103
104 fn bonemeal_action_type(&self) -> BonemealAction {
105 BonemealAction::NeighborSpreader
106 }
107}