Skip to main content

steel_core/behavior/blocks/redstone/
redstone_lamp_block.rs

1//! Vanilla redstone lamp behavior.
2
3use std::sync::Arc;
4
5use steel_macros::block_behavior;
6use steel_registry::blocks::BlockRef;
7use steel_registry::blocks::block_state_ext::BlockStateExt as _;
8use steel_registry::blocks::properties::BlockStateProperties;
9use steel_utils::types::UpdateFlags;
10use steel_utils::{BlockPos, BlockStateId};
11
12use crate::behavior::{BlockBehavior, BlockPlaceContext};
13use crate::world::{SignalGetter as _, World};
14
15const TURN_OFF_DELAY: i32 = 4;
16
17/// Vanilla `RedstoneLampBlock`, including its delayed turn-off edge.
18#[block_behavior]
19pub struct RedstoneLampBlock {
20    block: BlockRef,
21}
22
23impl RedstoneLampBlock {
24    /// Creates redstone-lamp behavior for `block`.
25    #[must_use]
26    pub const fn new(block: BlockRef) -> Self {
27        Self { block }
28    }
29}
30
31impl BlockBehavior for RedstoneLampBlock {
32    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
33        Some(self.block.default_state().set_value(
34            &BlockStateProperties::LIT,
35            context.world.has_neighbor_signal(context.place_pos()),
36        ))
37    }
38
39    fn handle_neighbor_changed(
40        &self,
41        state: BlockStateId,
42        world: &Arc<World>,
43        pos: BlockPos,
44        _source_block: BlockRef,
45        _moved_by_piston: bool,
46    ) {
47        let lit = state.get_value(&BlockStateProperties::LIT);
48        if lit == world.has_neighbor_signal(pos) {
49            return;
50        }
51        if lit {
52            world.schedule_block_tick_default(pos, self.block, TURN_OFF_DELAY);
53        } else {
54            world.set_block(
55                pos,
56                state.set_value(&BlockStateProperties::LIT, true),
57                UpdateFlags::UPDATE_CLIENTS,
58            );
59        }
60    }
61
62    fn tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
63        if state.get_value(&BlockStateProperties::LIT) && !world.has_neighbor_signal(pos) {
64            world.set_block(
65                pos,
66                state.set_value(&BlockStateProperties::LIT, false),
67                UpdateFlags::UPDATE_CLIENTS,
68            );
69        }
70    }
71}