steel_core/behavior/blocks/vegetation/
twisting_vines_block.rs1use crate::behavior::blocks::vegetation::bonemealable::{BonemealAction, Bonemealable};
2use crate::behavior::blocks::vegetation::nether_vines;
3use crate::behavior::context::BlockPlaceContext;
4use crate::behavior::{
5 block::BlockBehavior,
6 blocks::vegetation::growing_plant_head_block::{
7 GrowingPlantHeadBehavior, GrowingPlantHeadBlock,
8 },
9};
10use crate::world::{LevelReader, ScheduledTickAccess, World};
11use rand::Rng;
12use std::sync::Arc;
13use steel_macros::block_behavior;
14use steel_registry::blocks::block_state_ext::BlockStateExt;
15use steel_registry::vanilla_blocks;
16use steel_utils::{BlockPos, BlockStateId, Direction};
17
18use super::BlockRef;
19
20#[block_behavior]
22pub struct TwistingVinesBlock {
23 base: GrowingPlantHeadBlock,
24}
25
26impl TwistingVinesBlock {
27 #[must_use]
29 pub const fn new(block: BlockRef) -> Self {
30 Self {
31 base: GrowingPlantHeadBlock::new(
32 block,
33 Direction::Up,
34 false,
35 0.1,
36 &vanilla_blocks::TWISTING_VINES_PLANT,
37 Some(nether_vines::get_blocks_to_grow_when_bonemealed),
38 Self::can_grow_into,
39 ),
40 }
41 }
42
43 fn can_grow_into(state: BlockStateId) -> bool {
44 state.is_air()
45 }
46}
47
48impl BlockBehavior for TwistingVinesBlock {
49 fn can_survive(&self, state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
50 self.base.can_survive(state, world, pos)
51 }
52
53 fn random_tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
54 self.base.random_tick(state, world, pos);
55 }
56
57 fn update_shape(
58 &self,
59 state: BlockStateId,
60 world: &dyn ScheduledTickAccess,
61 pos: BlockPos,
62 direction: Direction,
63 neighbor_pos: BlockPos,
64 neighbor_state: BlockStateId,
65 ) -> BlockStateId {
66 self.base
67 .update_shape(state, world, pos, direction, neighbor_pos, neighbor_state)
68 }
69
70 fn tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
71 self.base.tick(state, world, pos);
72 }
73
74 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
75 self.base.get_state_for_placement(context)
76 }
77
78 fn as_bonemealable(&self) -> Option<&dyn Bonemealable> {
79 Some(self)
80 }
81
82 fn as_growing_plant_head(&self) -> Option<&dyn GrowingPlantHeadBehavior> {
83 Some(&self.base)
84 }
85}
86impl Bonemealable for TwistingVinesBlock {
87 fn is_valid_bonemeal_target(
88 &self,
89 state: BlockStateId,
90 world: &dyn LevelReader,
91 pos: BlockPos,
92 ) -> bool {
93 self.base.is_valid_bonemeal_target(state, world, pos)
94 }
95
96 fn perform_bonemeal(
97 &self,
98 state: BlockStateId,
99 world: &Arc<World>,
100 rng: &mut dyn Rng,
101 pos: BlockPos,
102 ) {
103 self.base.perform_bonemeal(state, world, rng, pos);
104 }
105
106 fn bonemeal_action_type(&self) -> BonemealAction {
107 BonemealAction::Grower
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use steel_registry::init_vanilla_registry;
114
115 use super::*;
116 use crate::test_support::TestLevel;
117
118 #[test]
119 fn bonemeal_target_requires_open_growth_position() {
120 init_vanilla_registry();
121
122 let behavior = TwistingVinesBlock::new(&vanilla_blocks::TWISTING_VINES);
123 let state = vanilla_blocks::TWISTING_VINES.default_state();
124 let open_level = TestLevel::default();
125 assert!(behavior.is_valid_bonemeal_target(state, &open_level, BlockPos::ZERO));
126
127 let blocked_level = TestLevel::default().with_block(
128 BlockPos::ZERO.above(),
129 vanilla_blocks::NETHERRACK.default_state(),
130 );
131 assert!(!behavior.is_valid_bonemeal_target(state, &blocked_level, BlockPos::ZERO));
132 }
133
134 #[test]
135 fn connected_head_converts_to_body() {
136 init_vanilla_registry();
137
138 let behavior = TwistingVinesBlock::new(&vanilla_blocks::TWISTING_VINES);
139 let state = vanilla_blocks::TWISTING_VINES.default_state();
140 let level = TestLevel::default();
141 let converted = behavior.update_shape(
142 state,
143 &level,
144 BlockPos::ZERO,
145 Direction::Up,
146 BlockPos::ZERO.above(),
147 vanilla_blocks::TWISTING_VINES_PLANT.default_state(),
148 );
149
150 assert_eq!(
151 converted,
152 vanilla_blocks::TWISTING_VINES_PLANT.default_state()
153 );
154 }
155}