326 lines
9.6 KiB
Rust
326 lines
9.6 KiB
Rust
use std::sync::Arc;
|
|
|
|
use pumpkin_data::{
|
|
Block, BlockDirection, BlockState, HorizontalFacingExt,
|
|
block_properties::{
|
|
BlockProperties, ComparatorLikeProperties, HorizontalFacing, RedstoneWireLikeProperties,
|
|
RepeaterLikeProperties,
|
|
},
|
|
};
|
|
use pumpkin_util::math::position::BlockPos;
|
|
use pumpkin_world::{
|
|
BlockStateId,
|
|
tick::TickPriority,
|
|
world::{BlockAccessor, BlockFlags},
|
|
};
|
|
|
|
use crate::{
|
|
block::{
|
|
BlockFuture, GetRedstonePowerArgs, OnNeighborUpdateArgs, OnStateReplacedArgs,
|
|
PlayerPlacedArgs,
|
|
},
|
|
entity::player::Player,
|
|
world::World,
|
|
};
|
|
|
|
use super::{get_redstone_power, is_diode};
|
|
|
|
pub trait RedstoneGateBlockProperties {
|
|
fn is_powered(&self) -> bool;
|
|
fn get_facing(&self) -> HorizontalFacing;
|
|
fn set_facing(&mut self, facing: HorizontalFacing);
|
|
}
|
|
|
|
pub trait RedstoneGateBlock<T: Send + Sync + BlockProperties + RedstoneGateBlockProperties> {
|
|
// 💡 Converted async fn to fn
|
|
fn can_place_at(&self, world: &dyn BlockAccessor, pos: BlockPos) -> bool
|
|
where
|
|
Self: Send + Sync,
|
|
{
|
|
let under_pos = pos.down();
|
|
let under_state = world.get_block_state(&under_pos);
|
|
self.can_place_above(world, under_pos, under_state)
|
|
}
|
|
|
|
// 💡 Converted async fn to fn
|
|
fn can_place_above(
|
|
&self,
|
|
_world: &dyn BlockAccessor,
|
|
_pos: BlockPos,
|
|
state: &BlockState,
|
|
) -> bool {
|
|
state.is_side_solid(BlockDirection::Up)
|
|
}
|
|
|
|
fn get_weak_redstone_power<'a>(&'a self, args: GetRedstonePowerArgs<'a>) -> BlockFuture<'a, u8>
|
|
where
|
|
Self: Send + Sync,
|
|
{
|
|
Box::pin(async move {
|
|
let props = T::from_state_id(args.state.id, args.block);
|
|
if props.is_powered() && props.get_facing().to_block_direction() == args.direction {
|
|
self.get_output_level(args.world, *args.position).await
|
|
} else {
|
|
0
|
|
}
|
|
})
|
|
}
|
|
|
|
fn get_strong_redstone_power<'a>(
|
|
&'a self,
|
|
args: GetRedstonePowerArgs<'a>,
|
|
) -> BlockFuture<'a, u8>
|
|
where
|
|
Self: Send + Sync,
|
|
{
|
|
Box::pin(async move { self.get_weak_redstone_power(args).await })
|
|
}
|
|
|
|
// 💡 Converted async fn to fn returning BlockFuture
|
|
fn get_output_level<'a>(&'a self, world: &'a World, pos: BlockPos) -> BlockFuture<'a, u8>;
|
|
|
|
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()>
|
|
where
|
|
Self: Send + Sync,
|
|
{
|
|
Box::pin(async move {
|
|
let state = args.world.get_block_state(args.position);
|
|
if RedstoneGateBlock::can_place_at(self, args.world.as_ref(), *args.position) {
|
|
self.update_powered(args.world, *args.position, state, args.block)
|
|
.await;
|
|
return;
|
|
}
|
|
args.world
|
|
.set_block_state(
|
|
args.position,
|
|
Block::AIR.default_state.id,
|
|
BlockFlags::NOTIFY_ALL,
|
|
)
|
|
.await;
|
|
for dir in BlockDirection::all() {
|
|
args.world
|
|
.update_neighbor(&args.position.offset(dir.to_offset()), args.source_block)
|
|
.await;
|
|
}
|
|
})
|
|
}
|
|
|
|
// 💡 Converted async fn to fn returning BlockFuture
|
|
fn update_powered<'a>(
|
|
&'a self,
|
|
world: &'a World,
|
|
pos: BlockPos,
|
|
state: &'a BlockState,
|
|
block: &'a Block,
|
|
) -> BlockFuture<'a, ()>;
|
|
|
|
// 💡 Converted async fn to fn returning BlockFuture
|
|
fn has_power<'a>(
|
|
&'a self,
|
|
world: &'a World,
|
|
pos: BlockPos,
|
|
state: &'a BlockState,
|
|
block: &'a Block,
|
|
) -> BlockFuture<'a, bool>
|
|
where
|
|
Self: Send + Sync,
|
|
{
|
|
Box::pin(async move { self.get_power(world, pos, state, block).await > 0 })
|
|
}
|
|
|
|
// 💡 Converted async fn to fn returning BlockFuture
|
|
fn get_power<'a>(
|
|
&'a self,
|
|
world: &'a World,
|
|
pos: BlockPos,
|
|
state: &'a BlockState,
|
|
block: &'a Block,
|
|
) -> BlockFuture<'a, u8>
|
|
where
|
|
Self: Send + Sync,
|
|
{
|
|
Box::pin(async move { get_power::<T>(world, pos, state.id, block).await })
|
|
}
|
|
|
|
// 💡 Converted async fn to fn returning BlockFuture
|
|
fn get_max_input_level_sides<'a>(
|
|
&'a self,
|
|
world: &'a World,
|
|
pos: BlockPos,
|
|
state_id: BlockStateId,
|
|
block: &'a Block,
|
|
only_gate: bool,
|
|
) -> BlockFuture<'a, u8> {
|
|
Box::pin(async move {
|
|
let props = T::from_state_id(state_id, block);
|
|
let facing = props.get_facing();
|
|
|
|
let power_left =
|
|
get_power_on_side(world, &pos, facing.rotate_clockwise(), only_gate).await;
|
|
let power_right =
|
|
get_power_on_side(world, &pos, facing.rotate_counter_clockwise(), only_gate).await;
|
|
|
|
std::cmp::max(power_left, power_right)
|
|
})
|
|
}
|
|
|
|
// 💡 Converted async fn to fn returning BlockFuture
|
|
fn update_target<'a>(
|
|
&'a self,
|
|
world: &'a Arc<World>,
|
|
pos: BlockPos,
|
|
state_id: BlockStateId,
|
|
block: &'a Block,
|
|
) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
let props = T::from_state_id(state_id, block);
|
|
let facing = props.get_facing();
|
|
let front_pos = pos.offset(facing.opposite().to_offset());
|
|
world.update_neighbor(&front_pos, block).await;
|
|
world
|
|
.update_neighbors(&front_pos, Some(facing.to_block_direction()))
|
|
.await;
|
|
})
|
|
}
|
|
|
|
// 💡 Converted async fn to fn returning BlockFuture
|
|
fn on_place<'a>(
|
|
&'a self,
|
|
player: &'a Player,
|
|
block: &'a Block,
|
|
) -> BlockFuture<'a, BlockStateId> {
|
|
Box::pin(async {
|
|
let mut props = T::default(block);
|
|
let dir = player
|
|
.living_entity
|
|
.entity
|
|
.get_horizontal_facing()
|
|
.opposite();
|
|
props.set_facing(dir);
|
|
|
|
props.to_state_id(block)
|
|
})
|
|
}
|
|
|
|
fn player_placed<'a>(&'a self, args: PlayerPlacedArgs<'a>) -> BlockFuture<'a, ()>
|
|
where
|
|
Self: Send + Sync,
|
|
{
|
|
Box::pin(async move {
|
|
if RedstoneGateBlock::has_power(
|
|
self,
|
|
args.world,
|
|
*args.position,
|
|
BlockState::from_id(args.state_id),
|
|
args.block,
|
|
)
|
|
.await
|
|
{
|
|
args.world
|
|
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
|
|
.await;
|
|
}
|
|
})
|
|
}
|
|
|
|
fn on_state_replaced<'a>(&'a self, args: OnStateReplacedArgs<'a>) -> BlockFuture<'a, ()>
|
|
where
|
|
Self: Send + Sync,
|
|
{
|
|
Box::pin(async move {
|
|
if args.moved || Block::from_state_id(args.old_state_id) == args.block {
|
|
return;
|
|
}
|
|
RedstoneGateBlock::update_target(
|
|
self,
|
|
args.world,
|
|
*args.position,
|
|
args.old_state_id,
|
|
args.block,
|
|
)
|
|
.await;
|
|
})
|
|
}
|
|
|
|
// 💡 Converted async fn to fn returning BlockFuture
|
|
fn is_target_not_aligned<'a>(
|
|
&'a self,
|
|
world: &'a dyn BlockAccessor,
|
|
pos: BlockPos,
|
|
state: &'a BlockState,
|
|
block: &'a Block,
|
|
) -> BlockFuture<'a, bool> {
|
|
Box::pin(async move {
|
|
let props = T::from_state_id(state.id, block);
|
|
let facing = props.get_facing().opposite();
|
|
let (target_block, target_state) =
|
|
world.get_block_and_state(&pos.offset(facing.to_offset()));
|
|
if target_block == &Block::COMPARATOR {
|
|
let props = ComparatorLikeProperties::from_state_id(target_state.id, target_block);
|
|
props.facing != facing
|
|
} else if target_block == &Block::REPEATER {
|
|
let props = RepeaterLikeProperties::from_state_id(target_state.id, target_block);
|
|
props.facing != facing
|
|
} else {
|
|
false
|
|
}
|
|
})
|
|
}
|
|
|
|
fn get_update_delay_internal(&self, state_id: BlockStateId, block: &Block) -> u8;
|
|
}
|
|
|
|
pub async fn get_power<T: BlockProperties + RedstoneGateBlockProperties + Send>(
|
|
world: &World,
|
|
pos: BlockPos,
|
|
state_id: BlockStateId,
|
|
block: &Block,
|
|
) -> u8 {
|
|
let props = T::from_state_id(state_id, block);
|
|
let facing = props.get_facing();
|
|
let source_pos = pos.offset(facing.to_offset());
|
|
let (source_block, source_state) = world.get_block_and_state(&source_pos);
|
|
let source_level = get_redstone_power(
|
|
source_block,
|
|
source_state,
|
|
world,
|
|
&source_pos,
|
|
facing.to_block_direction(),
|
|
)
|
|
.await;
|
|
if source_level >= 15 {
|
|
source_level
|
|
} else {
|
|
source_level.max(if source_block == &Block::REDSTONE_WIRE {
|
|
let props = RedstoneWireLikeProperties::from_state_id(source_state.id, source_block);
|
|
props.power
|
|
} else {
|
|
0
|
|
})
|
|
}
|
|
}
|
|
|
|
async fn get_power_on_side(
|
|
world: &World,
|
|
pos: &BlockPos,
|
|
side: HorizontalFacing,
|
|
only_gate: bool,
|
|
) -> u8 {
|
|
let side_pos = pos.offset(side.to_block_direction().to_offset());
|
|
let (side_block, side_state) = world.get_block_and_state(&side_pos);
|
|
if !only_gate || is_diode(side_block) {
|
|
world
|
|
.block_registry
|
|
.get_weak_redstone_power(
|
|
side_block,
|
|
world,
|
|
&side_pos,
|
|
side_state,
|
|
side.to_block_direction(),
|
|
)
|
|
.await
|
|
} else {
|
|
0
|
|
}
|
|
}
|