Skip to main content

steel_core/behavior/blocks/building/
amethyst_cluster.rs

1use crate::{
2    behavior::{BlockBehavior, BlockPlaceContext, blocks::AmethystBlock},
3    entity::projectile::Projectile,
4    world::{ClipHitResult, LevelReader, ScheduledTickAccess, World},
5};
6use std::sync::Arc;
7use steel_macros::block_behavior;
8use steel_registry::{
9    blocks::{
10        BlockRef,
11        block_state_ext::BlockStateExt,
12        properties::{BlockStateProperties, BoolProperty, EnumProperty},
13    },
14    vanilla_blocks, vanilla_fluids,
15};
16use steel_utils::{BlockPos, BlockStateId, Direction};
17
18/// Behavior for vanilla amethyst clusters blocks.
19#[block_behavior]
20pub struct AmethystClusterBlock {
21    block: BlockRef,
22}
23
24const FACING: &EnumProperty<Direction> = &BlockStateProperties::FACING;
25const WATERLOGGED: &BoolProperty = &BlockStateProperties::WATERLOGGED;
26
27impl AmethystClusterBlock {
28    /// Creates a new cluster block behavior.
29    #[must_use]
30    pub const fn new(block: BlockRef) -> Self {
31        Self { block }
32    }
33}
34
35impl BlockBehavior for AmethystClusterBlock {
36    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
37        let state = self
38            .block
39            .default_state()
40            .set_value(WATERLOGGED, context.is_water_source())
41            .set_value(FACING, context.clicked_face());
42        self.can_survive(state, context.world, context.place_pos())
43            .then_some(state)
44    }
45
46    fn update_shape(
47        &self,
48        state: BlockStateId,
49        world: &dyn ScheduledTickAccess,
50        pos: BlockPos,
51        direction: Direction,
52        _neighbor_pos: BlockPos,
53        _neighbor_state: BlockStateId,
54    ) -> BlockStateId {
55        if state.get_value(WATERLOGGED) {
56            let delay = world.fluid_tick_delay(&vanilla_fluids::WATER);
57            let _ = world.schedule_fluid_tick_default(pos, &vanilla_fluids::WATER, delay);
58        }
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
83    // TODO: Mirror and Rotate functions
84}