steel_core/behavior/blocks/container/
copper_chest_block.rs1use steel_macros::block_behavior;
13use steel_registry::blocks::BlockRef;
14use steel_registry::blocks::block_state_ext::BlockStateExt as _;
15use steel_registry::blocks::properties::{BlockStateProperties, ChestType};
16use steel_registry::vanilla_block_tags::BlockTag;
17use steel_utils::{BlockPos, BlockStateId, Direction};
18
19use crate::behavior::BlockPlaceContext;
20use crate::behavior::block::{BlockBehavior, schedule_water_tick_if_waterlogged};
21use crate::world::ScheduledTickAccess;
22
23#[block_behavior]
25pub struct CopperChestBlock {
26 block: BlockRef,
27}
28
29impl CopperChestBlock {
30 #[must_use]
32 pub const fn new(block: BlockRef) -> Self {
33 Self { block }
34 }
35}
36
37impl BlockBehavior for CopperChestBlock {
38 fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
39 Some(self.block.default_state())
42 }
43
44 fn update_shape(
45 &self,
46 state: BlockStateId,
47 world: &dyn ScheduledTickAccess,
48 pos: BlockPos,
49 direction: Direction,
50 _neighbor_pos: BlockPos,
51 neighbor_state: BlockStateId,
52 ) -> BlockStateId {
53 schedule_water_tick_if_waterlogged(state, world, pos);
54 update_shape(state, direction, neighbor_state)
55 }
56}
57
58#[block_behavior]
60pub struct WeatheringCopperChestBlock {
61 block: BlockRef,
62}
63
64impl WeatheringCopperChestBlock {
65 #[must_use]
67 pub const fn new(block: BlockRef) -> Self {
68 Self { block }
69 }
70}
71
72impl BlockBehavior for WeatheringCopperChestBlock {
73 fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
76 Some(self.block.default_state())
79 }
80
81 fn update_shape(
82 &self,
83 state: BlockStateId,
84 world: &dyn ScheduledTickAccess,
85 pos: BlockPos,
86 direction: Direction,
87 _neighbor_pos: BlockPos,
88 neighbor_state: BlockStateId,
89 ) -> BlockStateId {
90 schedule_water_tick_if_waterlogged(state, world, pos);
91 update_shape(state, direction, neighbor_state)
92 }
93}
94
95fn update_shape(
96 mut state: BlockStateId,
97 direction: Direction,
98 neighbor_state: BlockStateId,
99) -> BlockStateId {
100 let neighbor_type = neighbor_state
101 .get_block()
102 .has_tag(&BlockTag::COPPER_CHESTS)
103 .then(|| neighbor_state.try_get_value(&BlockStateProperties::CHEST_TYPE))
104 .flatten();
105 if let Some(neighbor_type) = &neighbor_type
106 && direction.is_horizontal()
107 {
108 if state.get_value(&BlockStateProperties::CHEST_TYPE) == ChestType::Single
109 && *neighbor_type != ChestType::Single
110 && state.get_value(&BlockStateProperties::FACING)
111 == neighbor_state.get_value(&BlockStateProperties::FACING)
112 && connected_direction(neighbor_state) == direction.opposite()
113 {
114 let opposite_type = match neighbor_type {
115 ChestType::Left => ChestType::Right,
116 ChestType::Right => ChestType::Left,
117 ChestType::Single => ChestType::Single,
118 };
119 state = state.set_value(&BlockStateProperties::CHEST_TYPE, opposite_type);
120 }
121 } else if connected_direction(state) == direction {
122 state = state.set_value(&BlockStateProperties::CHEST_TYPE, ChestType::Single);
123 }
124
125 if neighbor_type.is_some()
126 && state.get_value(&BlockStateProperties::CHEST_TYPE) != ChestType::Single
127 && connected_direction(state) == direction
128 {
129 return neighbor_state.with_properties_of(state);
130 }
131 state
132}
133
134fn connected_direction(state: BlockStateId) -> Direction {
135 let facing = state.get_value(&BlockStateProperties::FACING);
136 if state.get_value(&BlockStateProperties::CHEST_TYPE) == ChestType::Left {
137 facing.rotate_y_clockwise()
138 } else {
139 facing.rotate_y_counter_clockwise()
140 }
141}