Skip to main content

steel_core/behavior/blocks/vegetation/
coral_fan_block.rs

1use std::sync::Arc;
2
3use steel_macros::block_behavior;
4use steel_registry::blocks::block_state_ext::BlockStateExt;
5use steel_registry::blocks::properties::{BlockStateProperties, BoolProperty, Direction};
6use steel_registry::vanilla_blocks;
7use steel_utils::{BlockPos, BlockStateId, types::UpdateFlags};
8
9use crate::behavior::block::{BlockBehavior, schedule_water_tick_if_waterlogged};
10use crate::behavior::blocks::CoralBlock;
11use crate::behavior::context::BlockPlaceContext;
12use crate::world::{LevelReader, ScheduledTickAccess, World};
13
14use super::BlockRef;
15
16/// Vanilla `CoralFanBlock` survival (live coral fans).
17///
18/// Inherits `canSurvive` from `BaseCoralPlantTypeBlock` via `BaseCoralFanBlock`.
19#[block_behavior]
20pub struct CoralFanBlock {
21    block: BlockRef,
22    #[json_arg(vanilla_blocks, json = "dead_block")]
23    dead_block: BlockRef,
24}
25
26const WATERLOGGED: &BoolProperty = &BlockStateProperties::WATERLOGGED;
27
28impl CoralFanBlock {
29    /// Creates a new live coral fan block behavior.
30    #[must_use]
31    pub const fn new(block: BlockRef, dead_block: BlockRef) -> Self {
32        Self { block, dead_block }
33    }
34
35    fn dead_state(&self) -> BlockStateId {
36        self.dead_block
37            .default_state()
38            .set_value(WATERLOGGED, false)
39    }
40}
41
42impl BlockBehavior for CoralFanBlock {
43    fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
44        CoralBlock::can_survive(world, pos)
45    }
46
47    fn on_place(
48        &self,
49        state: BlockStateId,
50        world: &Arc<World>,
51        pos: BlockPos,
52        _old_state: BlockStateId,
53        _moved_by_piston: bool,
54    ) {
55        CoralBlock::schedule_die_tick(state, world, pos, self.block);
56    }
57
58    fn update_shape(
59        &self,
60        state: BlockStateId,
61        world: &dyn ScheduledTickAccess,
62        pos: BlockPos,
63        direction: Direction,
64        _neighbor_pos: BlockPos,
65        _neighbor_state: BlockStateId,
66    ) -> BlockStateId {
67        if direction == Direction::Down && !self.can_survive(state, world, pos) {
68            return vanilla_blocks::AIR.default_state();
69        }
70
71        CoralBlock::schedule_die_tick(state, world, pos, self.block);
72
73        schedule_water_tick_if_waterlogged(state, world, pos);
74
75        state
76    }
77
78    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
79        let state = self.block.default_state();
80        if !self.can_survive(state, context.world, context.place_pos()) {
81            return None;
82        }
83        Some(state.set_value(WATERLOGGED, context.is_full_water()))
84    }
85
86    fn tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
87        if !CoralBlock::scan_for_water(state, world, pos) {
88            world.set_block(pos, self.dead_state(), UpdateFlags::UPDATE_CLIENTS);
89        }
90    }
91}