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