Skip to main content

steel_core/behavior/blocks/vegetation/
dirt_path_block.rs

1use std::sync::Arc;
2
3use steel_macros::block_behavior;
4use steel_registry::blocks::BlockRef;
5use steel_registry::blocks::block_state_ext::BlockStateExt;
6use steel_registry::vanilla_block_tags::BlockTag;
7use steel_registry::vanilla_blocks;
8use steel_utils::{BlockPos, BlockStateId, Direction};
9
10use crate::behavior::block::{BlockBehavior, push_entities_up};
11use crate::behavior::context::BlockPlaceContext;
12use crate::entity::ai::path::PathComputationType;
13use crate::world::{LevelReader, ScheduledTickAccess, World};
14
15use super::turn_to_dirt;
16
17/// Behavior for dirt path blocks.
18#[block_behavior]
19pub struct DirtPathBlock {
20    block: BlockRef,
21}
22
23impl DirtPathBlock {
24    /// Creates a new dirt path block behavior.
25    #[must_use]
26    pub const fn new(block: BlockRef) -> Self {
27        Self { block }
28    }
29}
30
31impl BlockBehavior for DirtPathBlock {
32    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
33        let path_state = self.block.default_state();
34        let pos = context.place_pos();
35        if self.can_survive(path_state, context.world, pos) {
36            Some(path_state)
37        } else {
38            Some(push_entities_up(
39                path_state,
40                vanilla_blocks::DIRT.default_state(),
41                context.world,
42                pos,
43            ))
44        }
45    }
46
47    fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
48        let above = world.get_block_state(pos.above());
49        !above.is_solid() || above.get_block().has_tag(&BlockTag::FENCE_GATES)
50    }
51
52    fn update_shape(
53        &self,
54        state: BlockStateId,
55        world: &dyn ScheduledTickAccess,
56        pos: BlockPos,
57        direction: Direction,
58        _neighbor_pos: BlockPos,
59        _neighbor_state: BlockStateId,
60    ) -> BlockStateId {
61        if direction == Direction::Up && !self.can_survive(state, world, pos) {
62            let _ = world.schedule_block_tick_default(pos, self.block, 1);
63        }
64        state
65    }
66
67    fn tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
68        turn_to_dirt(state, world, pos, None);
69    }
70
71    fn is_pathfindable(
72        &self,
73        _state: BlockStateId,
74        _computation_type: PathComputationType,
75    ) -> bool {
76        false
77    }
78}