Skip to main content

steel_core/behavior/items/
copper_chest_events.rs

1use std::sync::Arc;
2
3use steel_registry::blocks::block_state_ext::BlockStateExt;
4use steel_registry::blocks::properties::{BlockStateProperties, ChestType};
5use steel_registry::vanilla_game_events;
6use steel_utils::{BlockPos, BlockStateId};
7
8use crate::{
9    entity::Entity,
10    player::Player,
11    world::{World, game_event::GameEventContext},
12};
13
14/// Emits the extra vanilla block-change notification for the other half of a double copper chest.
15pub(super) fn emit_connected_chest_block_change(
16    world: &Arc<World>,
17    pos: BlockPos,
18    old_state: BlockStateId,
19    player: &Player,
20    level_event: Option<i32>,
21) {
22    let Some(neighbor_pos) = connected_chest_pos(pos, old_state) else {
23        return;
24    };
25
26    let neighbor_state = world.get_block_state(neighbor_pos);
27    world.game_event(
28        &vanilla_game_events::BLOCK_CHANGE,
29        neighbor_pos,
30        &GameEventContext::new(Some(player), Some(neighbor_state)),
31    );
32
33    if let Some(event) = level_event {
34        world.level_event(event, neighbor_pos, 0, Some(player.id()));
35    }
36}
37
38fn connected_chest_pos(pos: BlockPos, state: BlockStateId) -> Option<BlockPos> {
39    let chest_type = state.try_get_value(&BlockStateProperties::CHEST_TYPE)?;
40    if chest_type == ChestType::Single {
41        return None;
42    }
43
44    let facing = state.try_get_value(&BlockStateProperties::FACING)?;
45    let connected_direction = if chest_type == ChestType::Left {
46        facing.rotate_y_clockwise()
47    } else {
48        facing.rotate_y_counter_clockwise()
49    };
50
51    Some(pos.relative(connected_direction))
52}
53
54#[cfg(test)]
55mod tests {
56    use steel_registry::blocks::block_state_ext::BlockStateExt;
57    use steel_registry::blocks::properties::{BlockStateProperties, ChestType, Direction};
58    use steel_registry::init_vanilla_registry;
59    use steel_registry::vanilla_blocks;
60    use steel_utils::BlockPos;
61
62    use crate::behavior::items::copper_chest_events::connected_chest_pos;
63
64    #[test]
65    fn connected_chest_pos_matches_vanilla_left_and_right_offsets() {
66        init_vanilla_registry();
67
68        let pos = BlockPos::new(10, 64, 10);
69        let north_left = vanilla_blocks::COPPER_CHEST
70            .default_state()
71            .set_value(&BlockStateProperties::FACING, Direction::North)
72            .set_value(&BlockStateProperties::CHEST_TYPE, ChestType::Left);
73        let north_right = vanilla_blocks::COPPER_CHEST
74            .default_state()
75            .set_value(&BlockStateProperties::FACING, Direction::North)
76            .set_value(&BlockStateProperties::CHEST_TYPE, ChestType::Right);
77
78        assert_eq!(connected_chest_pos(pos, north_left), Some(pos.east()));
79        assert_eq!(connected_chest_pos(pos, north_right), Some(pos.west()));
80    }
81
82    #[test]
83    fn connected_chest_pos_ignores_single_chests() {
84        init_vanilla_registry();
85
86        let pos = BlockPos::new(10, 64, 10);
87        let single = vanilla_blocks::COPPER_CHEST
88            .default_state()
89            .set_value(&BlockStateProperties::CHEST_TYPE, ChestType::Single);
90
91        assert_eq!(connected_chest_pos(pos, single), None);
92    }
93}