steel_core/behavior/blocks/building/
amethyst_cluster.rs1use 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#[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 #[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}