Skip to main content

steel_core/behavior/blocks/vegetation/
lily_pad_block.rs

1use std::sync::Arc;
2
3use steel_macros::block_behavior;
4use steel_registry::blocks::block_state_ext::BlockStateExt;
5use steel_registry::vanilla_block_tags::BlockTag;
6use steel_registry::vanilla_fluid_tags::FluidTag;
7use steel_utils::{BlockPos, BlockStateId, Direction};
8
9use crate::behavior::block::BlockBehavior;
10use crate::behavior::blocks::vegetation::vegetation_block::survival_update_shape;
11use crate::behavior::context::BlockPlaceContext;
12use crate::entity::{Entity, InsideBlockEffectCollector};
13use crate::fluid::get_fluid_state_from_block;
14use crate::world::{LevelReader, ScheduledTickAccess, World};
15
16use super::BlockRef;
17
18/// Vanilla `LilyPadBlock` survival.
19#[block_behavior]
20pub struct LilyPadBlock {
21    block: BlockRef,
22}
23
24impl LilyPadBlock {
25    /// Creates a new lily-pad block behavior.
26    #[must_use]
27    pub const fn new(block: BlockRef) -> Self {
28        Self { block }
29    }
30
31    fn may_place_on(world: &dyn LevelReader, pos: BlockPos) -> bool {
32        let below = world.get_block_state(pos);
33        let below_fluid = get_fluid_state_from_block(below);
34        let above_fluid = get_fluid_state_from_block(world.get_block_state(pos.above()));
35
36        (below_fluid.fluid_id.has_tag(&FluidTag::SUPPORTS_LILY_PAD)
37            || below.get_block().has_tag(&BlockTag::SUPPORTS_LILY_PAD))
38            && above_fluid.is_empty()
39    }
40}
41
42impl BlockBehavior for LilyPadBlock {
43    fn entity_inside(
44        &self,
45        _state: BlockStateId,
46        world: &Arc<World>,
47        pos: BlockPos,
48        entity: &dyn Entity,
49        _effect_collector: &mut InsideBlockEffectCollector,
50        _is_precise: bool,
51    ) {
52        if entity.entity_type().is_abstract_boat {
53            world.destroy_block_by_entity(pos, true, entity);
54        }
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        survival_update_shape(self, state, world, pos)
67    }
68
69    fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
70        let below = pos.below();
71        Self::may_place_on(world, below)
72    }
73
74    fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
75        Some(self.block.default_state())
76    }
77}