Skip to main content

steel_core/behavior/blocks/building/
amethyst_cluster.rs

1use crate::{
2    behavior::{
3        BlockBehavior, BlockPlaceContext, block::schedule_water_tick_if_waterlogged,
4        blocks::AmethystBlock,
5    },
6    entity::projectile::Projectile,
7    world::{ClipHitResult, LevelReader, ScheduledTickAccess, World},
8};
9use std::sync::Arc;
10use steel_macros::block_behavior;
11use steel_registry::{
12    blocks::{
13        BlockRef,
14        block_state_ext::BlockStateExt,
15        properties::{BlockStateProperties, BoolProperty, EnumProperty},
16    },
17    vanilla_blocks,
18};
19use steel_utils::{BlockPos, BlockStateId, Direction};
20
21/// Behavior for vanilla amethyst clusters blocks.
22#[block_behavior]
23pub struct AmethystClusterBlock {
24    block: BlockRef,
25}
26
27const FACING: &EnumProperty<Direction> = &BlockStateProperties::FACING;
28const WATERLOGGED: &BoolProperty = &BlockStateProperties::WATERLOGGED;
29
30impl AmethystClusterBlock {
31    /// Creates a new cluster block behavior.
32    #[must_use]
33    pub const fn new(block: BlockRef) -> Self {
34        Self { block }
35    }
36}
37
38impl BlockBehavior for AmethystClusterBlock {
39    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
40        let state = self
41            .block
42            .default_state()
43            .set_value(WATERLOGGED, context.is_water_source())
44            .set_value(FACING, context.clicked_face());
45        self.can_survive(state, context.world, context.place_pos())
46            .then_some(state)
47    }
48
49    fn update_shape(
50        &self,
51        state: BlockStateId,
52        world: &dyn ScheduledTickAccess,
53        pos: BlockPos,
54        direction: Direction,
55        _neighbor_pos: BlockPos,
56        _neighbor_state: BlockStateId,
57    ) -> BlockStateId {
58        schedule_water_tick_if_waterlogged(state, world, pos);
59
60        if direction == state.get_value(FACING).opposite() && !self.can_survive(state, world, pos) {
61            vanilla_blocks::AIR.default_state()
62        } else {
63            state
64        }
65    }
66
67    fn can_survive(&self, state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
68        let direction = state.get_value(FACING);
69        let adjacent = pos.relative(direction.opposite());
70        world.is_face_sturdy(world.get_block_state(adjacent), adjacent, direction)
71    }
72
73    fn on_projectile_hit(
74        &self,
75        _state: BlockStateId,
76        world: &Arc<World>,
77        hit: &ClipHitResult,
78        _projectile: &dyn Projectile,
79    ) {
80        AmethystBlock::play_projectile_hit_sound(world, hit.block_pos);
81    }
82}