Skip to main content

steel_core/behavior/blocks/decoration/
chain_block.rs

1//! Chain block behavior implementation.
2//!
3//! Chains are oriented blocks with an axis property that determines their direction.
4//! They can also be waterlogged.
5
6use crate::behavior::block::schedule_water_tick_if_waterlogged;
7use crate::behavior::blocks::{WeatherState, WeatheringCopper};
8use crate::behavior::{BlockBehavior, BlockPlaceContext};
9use crate::entity::ai::path::PathComputationType;
10use crate::world::{ScheduledTickAccess, World};
11use std::sync::Arc;
12use steel_macros::block_behavior;
13use steel_registry::blocks::BlockRef;
14use steel_registry::blocks::block_state_ext::BlockStateExt;
15use steel_registry::blocks::properties::{
16    Axis, BlockStateProperties, BoolProperty, Direction, EnumProperty,
17};
18use steel_utils::{BlockPos, BlockStateId};
19
20/// Behavior for chain blocks (iron chain, waxed copper chains).
21///
22/// Chains have an axis property that is set based on which face was clicked
23/// during placement, and can be waterlogged.
24#[block_behavior]
25pub struct ChainBlock {
26    block: BlockRef,
27}
28
29/// Axis property for the chain orientation.
30const AXIS: &EnumProperty<Axis> = &BlockStateProperties::AXIS;
31/// Waterlogged property.
32const WATERLOGGED: &BoolProperty = &BlockStateProperties::WATERLOGGED;
33
34impl ChainBlock {
35    /// Creates a new chain block behavior for the given block.
36    #[must_use]
37    pub const fn new(block: BlockRef) -> Self {
38        Self { block }
39    }
40}
41
42impl BlockBehavior for ChainBlock {
43    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
44        Some(
45            self.block
46                .default_state()
47                .set_value(AXIS, context.clicked_face().get_axis())
48                .set_value(WATERLOGGED, context.is_water_source()),
49        )
50    }
51
52    fn update_shape(
53        &self,
54        state: BlockStateId,
55        world: &dyn ScheduledTickAccess,
56        pos: BlockPos,
57        _direction: Direction,
58        _neighbor_pos: BlockPos,
59        _neighbor_state: BlockStateId,
60    ) -> BlockStateId {
61        schedule_water_tick_if_waterlogged(state, world, pos);
62        state
63    }
64
65    fn is_pathfindable(
66        &self,
67        _state: BlockStateId,
68        _computation_type: PathComputationType,
69    ) -> bool {
70        false
71    }
72}
73/// Behavior for weathering copper chain blocks.
74///
75/// Copper chains have an axis property that is set based on which face was clicked
76/// during placement, can be waterlogged, and will oxidize over time.
77#[block_behavior]
78pub struct WeatheringCopperChainBlock {
79    block: BlockRef,
80    #[json_arg(r#enum = "WeatherState", json = "weather_state")]
81    weathering: WeatheringCopper,
82}
83
84impl WeatheringCopperChainBlock {
85    /// Creates a new weathering copper chain block behavior for the given block.
86    #[must_use]
87    pub const fn new(block: BlockRef, weather_state: WeatherState) -> Self {
88        Self {
89            block,
90            weathering: WeatheringCopper::new(weather_state),
91        }
92    }
93}
94
95impl BlockBehavior for WeatheringCopperChainBlock {
96    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
97        Some(
98            self.block
99                .default_state()
100                .set_value(AXIS, context.clicked_face().get_axis())
101                .set_value(WATERLOGGED, context.is_water_source()),
102        )
103    }
104
105    fn random_tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
106        self.weathering.change_over_time(state, world, pos);
107    }
108
109    fn update_shape(
110        &self,
111        state: BlockStateId,
112        world: &dyn ScheduledTickAccess,
113        pos: BlockPos,
114        _direction: Direction,
115        _neighbor_pos: BlockPos,
116        _neighbor_state: BlockStateId,
117    ) -> BlockStateId {
118        schedule_water_tick_if_waterlogged(state, world, pos);
119        state
120    }
121
122    fn is_pathfindable(
123        &self,
124        _state: BlockStateId,
125        _computation_type: PathComputationType,
126    ) -> bool {
127        false
128    }
129}