Pumpkin/pumpkin/src/block/blocks/redstone/lever.rs
2026-01-13 23:36:49 +01:00

163 lines
5.0 KiB
Rust

use std::sync::Arc;
use crate::block::{
BlockFuture, CanPlaceAtArgs, EmitsRedstonePowerArgs, GetRedstonePowerArgs,
GetStateForNeighborUpdateArgs, OnPlaceArgs, OnStateReplacedArgs,
blocks::abstract_wall_mounting::WallMountedBlock,
};
use pumpkin_data::{
Block, BlockDirection, HorizontalFacingExt,
block_properties::{BlockFace, BlockProperties, LeverLikeProperties},
};
use pumpkin_macros::pumpkin_block;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::{BlockStateId, world::BlockFlags};
use crate::{
block::{
registry::BlockActionResult,
{BlockBehaviour, NormalUseArgs},
},
world::World,
};
async fn toggle_lever(world: &Arc<World>, block_pos: &BlockPos) {
let (block, state) = world.get_block_and_state_id(block_pos).await;
let mut lever_props = LeverLikeProperties::from_state_id(state, block);
lever_props.powered = !lever_props.powered;
world
.set_block_state(
block_pos,
lever_props.to_state_id(block),
BlockFlags::NOTIFY_ALL,
)
.await;
LeverBlock::update_neighbors(world, block_pos, &lever_props).await;
}
#[pumpkin_block("minecraft:lever")]
pub struct LeverBlock;
impl BlockBehaviour for LeverBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move {
toggle_lever(args.world, args.position).await;
BlockActionResult::Success
})
}
fn emits_redstone_power<'a>(
&'a self,
_args: EmitsRedstonePowerArgs<'a>,
) -> BlockFuture<'a, bool> {
Box::pin(async move { true })
}
fn get_weak_redstone_power<'a>(
&'a self,
args: GetRedstonePowerArgs<'a>,
) -> BlockFuture<'a, u8> {
Box::pin(async move {
let lever_props = LeverLikeProperties::from_state_id(args.state.id, args.block);
if lever_props.powered { 15 } else { 0 }
})
}
fn get_strong_redstone_power<'a>(
&'a self,
args: GetRedstonePowerArgs<'a>,
) -> BlockFuture<'a, u8> {
Box::pin(async move {
let lever_props = LeverLikeProperties::from_state_id(args.state.id, args.block);
if lever_props.powered && lever_props.get_direction() == args.direction {
15
} else {
0
}
})
}
fn on_state_replaced<'a>(&'a self, args: OnStateReplacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
if !args.moved {
let lever_props = LeverLikeProperties::from_state_id(args.old_state_id, args.block);
if lever_props.powered {
Self::update_neighbors(args.world, args.position, &lever_props).await;
}
}
})
}
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move {
let mut props =
LeverLikeProperties::from_state_id(args.block.default_state.id, args.block);
(props.face, props.facing) =
WallMountedBlock::get_placement_face(self, args.player, args.direction);
props.to_state_id(args.block)
})
}
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> {
Box::pin(async move {
WallMountedBlock::can_place_at(
self,
args.block_accessor,
args.position,
self.get_direction(args.state.id, args.block),
)
.await
})
}
fn get_state_for_neighbor_update<'a>(
&'a self,
args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { WallMountedBlock::get_state_for_neighbor_update(self, args).await })
}
}
impl WallMountedBlock for LeverBlock {
fn get_direction(&self, state_id: BlockStateId, block: &Block) -> BlockDirection {
let props = LeverLikeProperties::from_state_id(state_id, block);
match props.face {
BlockFace::Floor => BlockDirection::Up,
BlockFace::Ceiling => BlockDirection::Down,
BlockFace::Wall => props.facing.to_block_direction(),
}
}
}
impl LeverBlock {
async fn update_neighbors(
world: &Arc<World>,
block_pos: &BlockPos,
lever_props: &LeverLikeProperties,
) {
let direction = lever_props.get_direction().opposite();
world.update_neighbors(block_pos, None).await;
world
.update_neighbors(&block_pos.offset(direction.to_offset()), None)
.await;
}
}
pub trait LeverLikePropertiesExt {
fn get_direction(&self) -> BlockDirection;
}
impl LeverLikePropertiesExt for LeverLikeProperties {
fn get_direction(&self) -> BlockDirection {
match self.face {
BlockFace::Ceiling => BlockDirection::Down,
BlockFace::Floor => BlockDirection::Up,
BlockFace::Wall => self.facing.to_block_direction(),
}
}
}