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, BoolProperty};
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
23const LIT: &BoolProperty = &BlockStateProperties::LIT;
24
25impl RedstoneLampBlock {
26    /// Creates redstone-lamp behavior for `block`.
27    #[must_use]
28    pub const fn new(block: BlockRef) -> Self {
29        Self { block }
30    }
31}
32
33impl BlockBehavior for RedstoneLampBlock {
34    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
35        Some(
36            self.block
37                .default_state()
38                .set_value(LIT, context.world.has_neighbor_signal(context.place_pos())),
39        )
40    }
41
42    fn handle_neighbor_changed(
43        &self,
44        state: BlockStateId,
45        world: &Arc<World>,
46        pos: BlockPos,
47        _source_block: BlockRef,
48        _moved_by_piston: bool,
49    ) {
50        let lit = state.get_value(LIT);
51        if lit == world.has_neighbor_signal(pos) {
52            return;
53        }
54        if lit {
55            world.schedule_block_tick_default(pos, self.block, TURN_OFF_DELAY);
56        } else {
57            world.set_block(pos, state.set_value(LIT, true), UpdateFlags::UPDATE_CLIENTS);
58        }
59    }
60
61    fn tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
62        if state.get_value(LIT) && !world.has_neighbor_signal(pos) {
63            world.set_block(
64                pos,
65                state.set_value(LIT, false),
66                UpdateFlags::UPDATE_CLIENTS,
67            );
68        }
69    }
70}