steel_core/behavior/blocks/vegetation/
big_dripleaf_stem_block.rs1use rand::Rng;
2use steel_macros::block_behavior;
3use steel_registry::blocks::block_state_ext::BlockStateExt;
4use steel_registry::blocks::properties::{BlockStateProperties, BoolProperty, EnumProperty};
5use steel_registry::fluid::{FluidState, FluidStateExt};
6use steel_registry::vanilla_block_tags::BlockTag;
7use steel_registry::{vanilla_blocks, vanilla_fluids};
8use steel_utils::types::UpdateFlags;
9use steel_utils::{BlockPos, BlockStateId, Direction};
10
11use crate::behavior::blocks::BigDripleafBlock;
12use crate::behavior::blocks::vegetation::bonemealable::BonemealAction;
13use crate::behavior::blocks::vegetation::get_top_connected_block;
14use crate::behavior::context::BlockPlaceContext;
15use crate::behavior::{block::BlockBehavior, blocks::vegetation::bonemealable::Bonemealable};
16use crate::world::{LevelReader, ScheduledTickAccess, World};
17use std::sync::Arc;
18
19use super::BlockRef;
20
21const WATERLOGGED: BoolProperty = BlockStateProperties::WATERLOGGED;
22const FACING: EnumProperty<Direction> = BlockStateProperties::FACING;
23#[block_behavior]
28pub struct BigDripleafStemBlock {
29 block: BlockRef,
30}
31
32impl BigDripleafStemBlock {
33 #[must_use]
35 pub const fn new(block: BlockRef) -> Self {
36 Self { block }
37 }
38 pub fn place(
40 world: &Arc<World>,
41 pos: BlockPos,
42 fluid_state: FluidState,
43 facing: Direction,
44 ) -> bool {
45 let new_state = vanilla_blocks::BIG_DRIPLEAF_STEM
46 .default_state()
47 .set_value(
48 &WATERLOGGED,
49 fluid_state.is_source() && fluid_state.is_water(),
50 )
51 .set_value(&FACING, facing);
52 world.set_block(pos, new_state, UpdateFlags::UPDATE_ALL)
53 }
54}
55
56impl BlockBehavior for BigDripleafStemBlock {
57 fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
58 let below = world.get_block_state(pos.below());
59 let below_block = below.get_block();
60
61 let above = world.get_block_state(pos.above());
62 let above_block = above.get_block();
63
64 let below_check =
65 below_block == self.block || below_block.has_tag(&BlockTag::SUPPORTS_BIG_DRIPLEAF);
66 let above_check = above_block == self.block || above_block == &vanilla_blocks::BIG_DRIPLEAF;
67
68 below_check && above_check
69 }
70 fn as_bonemealable(&self) -> Option<&dyn Bonemealable> {
71 Some(self)
72 }
73 fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
74 Some(self.block.default_state())
75 }
76
77 fn update_shape(
78 &self,
79 state: BlockStateId,
80 world: &dyn ScheduledTickAccess,
81 pos: BlockPos,
82 direction: Direction,
83 _neighbor_pos: BlockPos,
84 _neighbor_state: BlockStateId,
85 ) -> BlockStateId {
86 if (direction == Direction::Down || direction == Direction::Up)
87 && !self.can_survive(state, world, pos)
88 {
89 world.schedule_block_tick_default(pos, self.block, 1);
90 }
91 if state.get_value(&WATERLOGGED) {
92 world.schedule_fluid_tick_default(
93 pos,
94 &vanilla_fluids::WATER,
95 vanilla_fluids::WATER.tick_delay as i32,
96 );
97 }
98
99 state
100 }
101 fn tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
102 if !self.can_survive(state, world, pos) {
103 world.destroy_block(pos, true);
104 }
105 }
106}
107impl Bonemealable for BigDripleafStemBlock {
108 fn is_valid_bonemeal_target(
109 &self,
110 _state: BlockStateId,
111 world: &dyn LevelReader,
112 pos: BlockPos,
113 ) -> bool {
114 let head_pos = get_top_connected_block(
115 world,
116 pos,
117 self.block,
118 Direction::Up,
119 &vanilla_blocks::BIG_DRIPLEAF,
120 );
121 match head_pos {
122 Some(head_pos) => BigDripleafBlock::can_grow_into(world, head_pos.above()),
123 None => false,
124 }
125 }
126
127 fn perform_bonemeal(
128 &self,
129 state: BlockStateId,
130 world: &Arc<World>,
131 _rng: &mut dyn Rng,
132 pos: BlockPos,
133 ) {
134 let forward_pos = get_top_connected_block(
135 world,
136 pos,
137 self.block,
138 Direction::Up,
139 &vanilla_blocks::BIG_DRIPLEAF,
140 );
141 let Some(head_pos) = forward_pos else {
142 return;
143 };
144 let place_head_pos = head_pos.above();
145 let facing = state.get_value(&FACING);
146 Self::place(
147 world,
148 head_pos,
149 world.get_block_state(head_pos).get_fluid_state(),
150 facing,
151 );
152 BigDripleafBlock::place(
153 world,
154 place_head_pos,
155 world.get_block_state(place_head_pos).get_fluid_state(),
156 facing,
157 );
158 }
159
160 fn bonemeal_action_type(&self) -> BonemealAction {
161 BonemealAction::Grower
162 }
163}