142 lines
4.7 KiB
Rust
142 lines
4.7 KiB
Rust
use std::sync::Arc;
|
|
|
|
use crate::block::{
|
|
BlockFuture, EmitsRedstonePowerArgs, GetRedstonePowerArgs, GetStateForNeighborUpdateArgs,
|
|
OnPlaceArgs, OnScheduledTickArgs, OnStateReplacedArgs,
|
|
};
|
|
use pumpkin_data::{
|
|
Block, FacingExt,
|
|
block_properties::{BlockProperties, ObserverLikeProperties},
|
|
};
|
|
use pumpkin_macros::pumpkin_block;
|
|
use pumpkin_util::math::position::BlockPos;
|
|
use pumpkin_world::{BlockStateId, tick::TickPriority, world::BlockFlags};
|
|
|
|
use crate::{block::BlockBehaviour, world::World};
|
|
|
|
#[pumpkin_block("minecraft:observer")]
|
|
pub struct ObserverBlock;
|
|
|
|
impl BlockBehaviour for ObserverBlock {
|
|
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
|
|
Box::pin(async move {
|
|
let mut props = ObserverLikeProperties::default(args.block);
|
|
props.facing = args.player.living_entity.entity.get_facing();
|
|
props.to_state_id(args.block)
|
|
})
|
|
}
|
|
|
|
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
let state = args.world.get_block_state(args.position);
|
|
let mut props = ObserverLikeProperties::from_state_id(state.id, args.block);
|
|
|
|
if props.powered {
|
|
props.powered = false;
|
|
args.world
|
|
.set_block_state(
|
|
args.position,
|
|
props.to_state_id(args.block),
|
|
BlockFlags::NOTIFY_LISTENERS,
|
|
)
|
|
.await;
|
|
} else {
|
|
props.powered = true;
|
|
args.world
|
|
.set_block_state(
|
|
args.position,
|
|
props.to_state_id(args.block),
|
|
BlockFlags::NOTIFY_LISTENERS,
|
|
)
|
|
.await;
|
|
args.world
|
|
.schedule_block_tick(args.block, *args.position, 2, TickPriority::Normal);
|
|
}
|
|
|
|
Self::update_neighbors(args.world, args.block, args.position, &props).await;
|
|
})
|
|
}
|
|
|
|
fn get_state_for_neighbor_update<'a>(
|
|
&'a self,
|
|
args: GetStateForNeighborUpdateArgs<'a>,
|
|
) -> BlockFuture<'a, BlockStateId> {
|
|
Box::pin(async move {
|
|
let props = ObserverLikeProperties::from_state_id(args.state_id, args.block);
|
|
|
|
if props.facing.to_block_direction() == args.direction && !props.powered {
|
|
Self::schedule_tick(args.world, args.position);
|
|
}
|
|
|
|
args.state_id
|
|
})
|
|
}
|
|
|
|
fn emits_redstone_power<'a>(
|
|
&'a self,
|
|
args: EmitsRedstonePowerArgs<'a>,
|
|
) -> BlockFuture<'a, bool> {
|
|
Box::pin(async move {
|
|
let props = ObserverLikeProperties::from_state_id(args.state.id, args.block);
|
|
props.facing.to_block_direction() == args.direction
|
|
})
|
|
}
|
|
|
|
fn get_weak_redstone_power<'a>(
|
|
&'a self,
|
|
args: GetRedstonePowerArgs<'a>,
|
|
) -> BlockFuture<'a, u8> {
|
|
Box::pin(async move {
|
|
let props = ObserverLikeProperties::from_state_id(args.state.id, args.block);
|
|
if props.facing.to_block_direction() == args.direction && props.powered {
|
|
15
|
|
} else {
|
|
0
|
|
}
|
|
})
|
|
}
|
|
|
|
fn get_strong_redstone_power<'a>(
|
|
&'a self,
|
|
args: GetRedstonePowerArgs<'a>,
|
|
) -> BlockFuture<'a, u8> {
|
|
Box::pin(async move { self.get_weak_redstone_power(args).await })
|
|
}
|
|
|
|
fn on_state_replaced<'a>(&'a self, args: OnStateReplacedArgs<'a>) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
if !args.moved {
|
|
let props = ObserverLikeProperties::from_state_id(args.old_state_id, args.block);
|
|
if props.powered
|
|
&& args
|
|
.world
|
|
.is_block_tick_scheduled(args.position, &Block::OBSERVER)
|
|
{
|
|
Self::update_neighbors(args.world, args.block, args.position, &props).await;
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ObserverBlock {
|
|
async fn update_neighbors(
|
|
world: &Arc<World>,
|
|
block: &Block,
|
|
block_pos: &BlockPos,
|
|
props: &ObserverLikeProperties,
|
|
) {
|
|
let facing = props.facing;
|
|
let opposite_facing_pos =
|
|
block_pos.offset(facing.to_block_direction().opposite().to_offset());
|
|
world.update_neighbor(&opposite_facing_pos, block).await;
|
|
world
|
|
.update_neighbors(&opposite_facing_pos, Some(facing.to_block_direction()))
|
|
.await;
|
|
}
|
|
|
|
fn schedule_tick(world: &World, block_pos: &BlockPos) {
|
|
world.schedule_block_tick(&Block::OBSERVER, *block_pos, 2, TickPriority::Normal);
|
|
}
|
|
}
|