steel_core/behavior/blocks/vegetation/
vegetation_block.rs1use steel_registry::{
2 blocks::{
3 block_state_ext::BlockStateExt,
4 properties::{BlockStateProperties, DoubleBlockHalf},
5 },
6 vanilla_block_tags::BlockTag,
7 vanilla_blocks,
8};
9use steel_utils::{BlockPos, BlockStateId, Direction, axis::Axis};
10
11use crate::{
12 behavior::BlockBehavior,
13 world::{LevelReader, ScheduledTickAccess},
14};
15
16pub trait Vegetation {
18 fn may_place_on(&self, state: BlockStateId, _world: &dyn LevelReader, _pos: BlockPos) -> bool {
20 state.get_block().has_tag(&BlockTag::SUPPORTS_VEGETATION)
21 }
22}
23
24pub fn vegetation_can_survive<H: Vegetation>(
26 hooks: &H,
27 _state: BlockStateId,
28 world: &dyn LevelReader,
29 pos: BlockPos,
30) -> bool {
31 let state_below = world.get_block_state(pos.below());
32 hooks.may_place_on(state_below, world, pos.below())
33}
34
35pub fn survival_update_shape<B: BlockBehavior>(
40 block: &B,
41 state: BlockStateId,
42 world: &dyn ScheduledTickAccess,
43 pos: BlockPos,
44) -> BlockStateId {
45 if block.can_survive(state, world, pos) {
46 state
47 } else {
48 vanilla_blocks::AIR.default_state()
49 }
50}
51
52pub fn double_plant_can_survive<H: Vegetation>(
54 hooks: &H,
55 state: BlockStateId,
56 world: &dyn LevelReader,
57 pos: BlockPos,
58) -> bool {
59 if state.get_value(&BlockStateProperties::DOUBLE_BLOCK_HALF) == DoubleBlockHalf::Upper {
60 let state_below = world.get_block_state(pos.below());
61 state_below.get_block() == state.get_block()
62 && state_below.get_value(&BlockStateProperties::DOUBLE_BLOCK_HALF)
63 == DoubleBlockHalf::Lower
64 } else {
65 vegetation_can_survive(hooks, state, world, pos)
66 }
67}
68
69pub fn double_plant_update_shape<B: BlockBehavior>(
73 block: &B,
74 state: BlockStateId,
75 world: &dyn ScheduledTickAccess,
76 pos: BlockPos,
77 direction: Direction,
78 neighbor_state: BlockStateId,
79) -> BlockStateId {
80 let half = state.get_value(&BlockStateProperties::DOUBLE_BLOCK_HALF);
81
82 if direction.axis() != Axis::Y
83 || ((half == DoubleBlockHalf::Lower) != (direction == Direction::Up))
84 || (neighbor_state.get_block() == state.get_block()
85 && neighbor_state.get_value(&BlockStateProperties::DOUBLE_BLOCK_HALF) != half)
86 {
87 if half == DoubleBlockHalf::Lower
88 && direction == Direction::Down
89 && !block.can_survive(state, world, pos)
90 {
91 return vanilla_blocks::AIR.default_state();
92 }
93
94 survival_update_shape(block, state, world, pos)
95 } else {
96 vanilla_blocks::AIR.default_state()
97 }
98}