Pumpkin/pumpkin/src/block/blocks/redstone/buttons.rs
Alexander Medvedev 1edbfa7289 Implement Piston 1/2
Not fully done
2025-05-12 19:42:55 +02:00

192 lines
5.6 KiB
Rust

use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_data::Block;
use pumpkin_data::BlockState;
use pumpkin_data::block_properties::BlockFace;
use pumpkin_data::block_properties::BlockProperties;
use pumpkin_data::item::Item;
use pumpkin_data::tag::RegistryKey;
use pumpkin_data::tag::get_tag_values;
use pumpkin_protocol::server::play::SUseItemOn;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use pumpkin_world::chunk::TickPriority;
use pumpkin_world::world::BlockFlags;
type ButtonLikeProperties = pumpkin_data::block_properties::LeverLikeProperties;
use crate::block::BlockIsReplacing;
use crate::block::blocks::redstone::lever::LeverLikePropertiesExt;
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
use crate::block::registry::BlockActionResult;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
async fn click_button(world: &Arc<World>, block_pos: &BlockPos) {
let (block, state) = world.get_block_and_block_state(block_pos).await.unwrap();
let mut button_props = ButtonLikeProperties::from_state_id(state.id, &block);
if !button_props.powered {
button_props.powered = true;
world
.set_block_state(
block_pos,
button_props.to_state_id(&block),
BlockFlags::NOTIFY_ALL,
)
.await;
let delay = if block == Block::STONE_BUTTON { 20 } else { 30 };
world
.schedule_block_tick(&block, *block_pos, delay, TickPriority::Normal)
.await;
ButtonBlock::update_neighbors(world, block_pos, &button_props).await;
}
}
pub struct ButtonBlock;
impl BlockMetadata for ButtonBlock {
fn namespace(&self) -> &'static str {
"minecraft"
}
fn ids(&self) -> &'static [&'static str] {
get_tag_values(RegistryKey::Block, "minecraft:buttons").unwrap()
}
}
#[async_trait]
impl PumpkinBlock for ButtonBlock {
async fn on_place(
&self,
_server: &Server,
_world: &World,
player: &Player,
block: &Block,
_block_pos: &BlockPos,
face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut props = ButtonLikeProperties::default(block);
match face {
BlockDirection::Up => props.face = BlockFace::Ceiling,
BlockDirection::Down => props.face = BlockFace::Floor,
_ => props.face = BlockFace::Wall,
}
if face == BlockDirection::Up || face == BlockDirection::Down {
props.facing = player.living_entity.entity.get_horizontal_facing();
} else {
props.facing = face.opposite().to_cardinal_direction();
}
props.to_state_id(block)
}
async fn normal_use(
&self,
_block: &Block,
_player: &Player,
location: BlockPos,
_server: &Server,
world: &Arc<World>,
) {
click_button(world, &location).await;
}
async fn use_with_item(
&self,
_block: &Block,
_player: &Player,
location: BlockPos,
_item: &Item,
_server: &Server,
world: &Arc<World>,
) -> BlockActionResult {
click_button(world, &location).await;
BlockActionResult::Consume
}
async fn on_scheduled_tick(&self, world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
let state = world.get_block_state(block_pos).await.unwrap();
let mut props = ButtonLikeProperties::from_state_id(state.id, block);
props.powered = false;
world
.set_block_state(block_pos, props.to_state_id(block), BlockFlags::NOTIFY_ALL)
.await;
Self::update_neighbors(world, block_pos, &props).await;
}
async fn emits_redstone_power(
&self,
_block: &Block,
_state: &BlockState,
_direction: BlockDirection,
) -> bool {
true
}
async fn get_weak_redstone_power(
&self,
block: &Block,
_world: &World,
_block_pos: &BlockPos,
state: &BlockState,
_direction: BlockDirection,
) -> u8 {
let button_props = ButtonLikeProperties::from_state_id(state.id, block);
if button_props.powered { 15 } else { 0 }
}
async fn get_strong_redstone_power(
&self,
block: &Block,
_world: &World,
_block_pos: &BlockPos,
state: &BlockState,
direction: BlockDirection,
) -> u8 {
let button_props = ButtonLikeProperties::from_state_id(state.id, block);
if button_props.powered && button_props.get_direction() == direction {
15
} else {
0
}
}
async fn on_state_replaced(
&self,
world: &Arc<World>,
block: &Block,
location: BlockPos,
old_state_id: BlockStateId,
moved: bool,
) {
if !moved {
let button_props = ButtonLikeProperties::from_state_id(old_state_id, block);
if button_props.powered {
Self::update_neighbors(world, &location, &button_props).await;
}
}
}
}
impl ButtonBlock {
async fn update_neighbors(
world: &Arc<World>,
block_pos: &BlockPos,
props: &ButtonLikeProperties,
) {
let direction = props.get_direction().opposite();
world.update_neighbors(block_pos, None).await;
world
.update_neighbors(&block_pos.offset(direction.to_offset()), None)
.await;
}
}