Implement Piston 1.5/2
This commit is contained in:
parent
bcf9524334
commit
f79167cece
@ -6,6 +6,7 @@ use bed::BedBlockEntity;
|
||||
use chest::ChestBlockEntity;
|
||||
use comparator::ComparatorBlockEntity;
|
||||
use piston::PistonBlockEntity;
|
||||
use pumpkin_data::{Block, block_properties::BLOCK_ENTITY_TYPES};
|
||||
use pumpkin_nbt::compound::NbtCompound;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use sign::SignBlockEntity;
|
||||
@ -82,3 +83,7 @@ pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>>
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_block_block_entity(block: &Block) -> bool {
|
||||
BLOCK_ENTITY_TYPES.contains(&block.name)
|
||||
}
|
||||
|
||||
@ -67,6 +67,10 @@ impl BlockDirection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn by_index(index: usize) -> Option<Self> {
|
||||
Self::all().get(index % Self::all().len()).cloned()
|
||||
}
|
||||
|
||||
pub fn to_offset(&self) -> Vector3<i32> {
|
||||
match self {
|
||||
BlockDirection::Down => (0, -1, 0),
|
||||
|
||||
@ -26,6 +26,7 @@ use crate::{
|
||||
},
|
||||
generation::{Seed, WorldGenerator, get_world_gen},
|
||||
lock::{LevelLocker, anvil::AnvilLevelLocker},
|
||||
world::SimpleWorld,
|
||||
world_info::{
|
||||
LevelData, WorldInfoError, WorldInfoReader, WorldInfoWriter,
|
||||
anvil::{AnvilLevelInfo, LEVEL_DAT_BACKUP_FILE_NAME, LEVEL_DAT_FILE_NAME},
|
||||
@ -321,6 +322,17 @@ impl Level {
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn tick_block_entities(&self, world: Arc<dyn SimpleWorld>) {
|
||||
for chunk in self.loaded_chunks.iter() {
|
||||
let chunk = chunk.read().await;
|
||||
let cloned_entities = chunk.block_entities.clone();
|
||||
drop(chunk);
|
||||
for block_entity in &cloned_entities {
|
||||
block_entity.1.1.tick(&world).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clean_chunk(self: &Arc<Self>, chunk: &Vector2<i32>) {
|
||||
self.clean_chunks(&[*chunk]).await;
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ pub struct PistonHandler<'a> {
|
||||
motion_direction: BlockDirection,
|
||||
pub moved_blocks: Vec<BlockPos>,
|
||||
pub broken_blocks: Vec<BlockPos>,
|
||||
_piston_direction: BlockDirection,
|
||||
piston_direction: BlockDirection,
|
||||
}
|
||||
|
||||
impl<'a> PistonHandler<'a> {
|
||||
@ -29,7 +29,7 @@ impl<'a> PistonHandler<'a> {
|
||||
let motion_direction;
|
||||
let pos_to = if retracted {
|
||||
motion_direction = dir;
|
||||
pos.offset_dir(dir.to_offset(), 1)
|
||||
pos.offset(dir.to_offset())
|
||||
} else {
|
||||
motion_direction = dir.opposite();
|
||||
pos.offset_dir(dir.to_offset(), 2)
|
||||
@ -37,7 +37,7 @@ impl<'a> PistonHandler<'a> {
|
||||
PistonHandler {
|
||||
world,
|
||||
pos_from: pos,
|
||||
_piston_direction: dir,
|
||||
piston_direction: dir,
|
||||
retracted,
|
||||
motion_direction,
|
||||
pos_to,
|
||||
@ -54,14 +54,19 @@ impl<'a> PistonHandler<'a> {
|
||||
.get_block_and_block_state(&self.pos_to)
|
||||
.await
|
||||
.unwrap();
|
||||
dbg!(PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
self.motion_direction,
|
||||
false,
|
||||
self.piston_direction,
|
||||
));
|
||||
if !PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
// self.world,
|
||||
// self.pos_to,
|
||||
// self.motion_direction,
|
||||
// false,
|
||||
// self.piston_direction,
|
||||
self.motion_direction,
|
||||
false,
|
||||
self.piston_direction,
|
||||
) {
|
||||
if self.retracted && block_state.piston_behavior == PistonBehavior::Destroy {
|
||||
self.broken_blocks.push(self.pos_to);
|
||||
@ -97,21 +102,13 @@ impl<'a> PistonHandler<'a> {
|
||||
Self::is_block_sticky(state) || Self::is_block_sticky(adjacent_state)
|
||||
}
|
||||
|
||||
async fn try_move(&mut self, pos: BlockPos, _dir: BlockDirection) -> bool {
|
||||
async fn try_move(&mut self, pos: BlockPos, dir: BlockDirection) -> bool {
|
||||
let (mut block, mut block_state) =
|
||||
self.world.get_block_and_block_state(&pos).await.unwrap();
|
||||
if block_state.is_air() {
|
||||
return true;
|
||||
}
|
||||
if !PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
// self.world,
|
||||
// pos,
|
||||
// self.motion_direction,
|
||||
// false,
|
||||
// dir,
|
||||
) {
|
||||
if !PistonBlock::is_movable(&block, &block_state, self.motion_direction, false, dir) {
|
||||
return true;
|
||||
}
|
||||
if pos == self.pos_from {
|
||||
@ -137,11 +134,9 @@ impl<'a> PistonHandler<'a> {
|
||||
|| !PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
// self.world,
|
||||
// block_pos,
|
||||
// self.motion_direction,
|
||||
// false,
|
||||
// self.motion_direction.opposite(),
|
||||
self.motion_direction,
|
||||
false,
|
||||
self.motion_direction.opposite(),
|
||||
)
|
||||
|| block_pos == self.pos_from
|
||||
{
|
||||
@ -185,11 +180,9 @@ impl<'a> PistonHandler<'a> {
|
||||
if !PistonBlock::is_movable(
|
||||
&block,
|
||||
&block_state,
|
||||
// self.world,
|
||||
// block_pos2,
|
||||
// self.motion_direction,
|
||||
// true,
|
||||
// self.motion_direction,
|
||||
self.motion_direction,
|
||||
true,
|
||||
self.motion_direction,
|
||||
) || block_pos2 == self.pos_from
|
||||
{
|
||||
return false;
|
||||
|
||||
@ -7,6 +7,7 @@ use pumpkin_data::{
|
||||
BlockProperties, MovingPistonLikeProperties, PistonHeadLikeProperties, PistonType,
|
||||
get_block_by_state_id, get_state_by_state_id,
|
||||
},
|
||||
block_state::PistonBehavior,
|
||||
};
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
@ -14,7 +15,7 @@ use pumpkin_world::{
|
||||
BlockStateId,
|
||||
block::{
|
||||
BlockDirection, FacingExt,
|
||||
entities::{BlockEntity, piston::PistonBlockEntity},
|
||||
entities::{BlockEntity, has_block_block_entity, piston::PistonBlockEntity},
|
||||
},
|
||||
world::BlockFlags,
|
||||
};
|
||||
@ -30,7 +31,7 @@ use crate::{
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::{PistonHandler, piston_extension::MovingPistonProps};
|
||||
use super::PistonHandler;
|
||||
|
||||
pub(crate) type PistonProps = pumpkin_data::block_properties::StickyPistonLikeProperties;
|
||||
|
||||
@ -47,7 +48,13 @@ impl BlockMetadata for PistonBlock {
|
||||
}
|
||||
|
||||
impl PistonBlock {
|
||||
pub fn is_movable(block: &Block, state: &BlockState) -> bool {
|
||||
pub fn is_movable(
|
||||
block: &Block,
|
||||
state: &BlockState,
|
||||
dir: BlockDirection,
|
||||
can_break: bool,
|
||||
piston_dir: BlockDirection,
|
||||
) -> bool {
|
||||
// TODO: more checks
|
||||
if state.is_air() {
|
||||
return true;
|
||||
@ -60,7 +67,24 @@ impl PistonBlock {
|
||||
{
|
||||
return false;
|
||||
}
|
||||
true
|
||||
if block == &Block::PISTON || block == &Block::STICKY_PISTON {
|
||||
let props = PistonProps::from_state_id(state.id, block);
|
||||
if props.extended {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
#[expect(clippy::float_cmp)]
|
||||
if state.hardness == -1.0 {
|
||||
return false;
|
||||
}
|
||||
match state.piston_behavior {
|
||||
pumpkin_data::block_state::PistonBehavior::Destroy => return can_break,
|
||||
pumpkin_data::block_state::PistonBehavior::Block => return false,
|
||||
pumpkin_data::block_state::PistonBehavior::PushOnly => return dir == piston_dir,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
!has_block_block_entity(block)
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,13 +133,14 @@ impl PumpkinBlock for PistonBlock {
|
||||
try_move(world, block, block_pos).await;
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_lines)]
|
||||
async fn on_synced_block_event(
|
||||
&self,
|
||||
block: &Block,
|
||||
world: &Arc<World>,
|
||||
pos: &BlockPos,
|
||||
r#type: u8,
|
||||
_data: u8,
|
||||
data: u8,
|
||||
) -> bool {
|
||||
let state = world.get_block_state(pos).await.unwrap();
|
||||
let mut props = PistonProps::from_state_id(state.id, block);
|
||||
@ -124,7 +149,7 @@ impl PumpkinBlock for PistonBlock {
|
||||
// I don't think this is optimal ?
|
||||
let sticky = block == &Block::STICKY_PISTON;
|
||||
|
||||
let should_extend = should_extend(world, block, &state, pos, dir).await;
|
||||
let should_extend = should_extend(world, pos, dir).await;
|
||||
if should_extend && (r#type == 1 || r#type == 2) {
|
||||
props.extended = true;
|
||||
world
|
||||
@ -138,6 +163,7 @@ impl PumpkinBlock for PistonBlock {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extend Piston
|
||||
if r#type == 0 {
|
||||
if !move_piston(world, dir, pos, true, sticky).await {
|
||||
return false;
|
||||
@ -152,6 +178,8 @@ impl PumpkinBlock for PistonBlock {
|
||||
.await;
|
||||
return true;
|
||||
}
|
||||
// Reduce Piston
|
||||
|
||||
let extended_pos = pos.offset(dir.to_offset());
|
||||
|
||||
if let Some((block_entity_nbt, _block_entity)) = world.get_block_entity(&extended_pos).await
|
||||
@ -169,26 +197,67 @@ impl PumpkinBlock for PistonBlock {
|
||||
PistonType::Normal
|
||||
};
|
||||
|
||||
let state = props.to_state_id(&Block::MOVING_PISTON);
|
||||
|
||||
world
|
||||
.set_block_state(pos, state, BlockFlags::FORCE_STATE)
|
||||
.set_block_state(
|
||||
pos,
|
||||
props.to_state_id(&Block::MOVING_PISTON),
|
||||
BlockFlags::FORCE_STATE,
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut props = PistonProps::default(block);
|
||||
props.facing = BlockDirection::by_index((data & 7) as usize)
|
||||
.unwrap()
|
||||
.to_facing();
|
||||
|
||||
world
|
||||
.add_block_entity(Arc::new(PistonBlockEntity {
|
||||
position: *pos,
|
||||
facing: dir.to_facing().to_block_direction(),
|
||||
pushed_block_state: get_state_by_state_id(state).unwrap(),
|
||||
facing: dir,
|
||||
pushed_block_state: get_state_by_state_id(props.to_state_id(block)).unwrap(),
|
||||
current_progress: 0.0.into(),
|
||||
last_progress: 0.0.into(),
|
||||
extending: false,
|
||||
source: true,
|
||||
}))
|
||||
.await;
|
||||
|
||||
world.update_neighbors(pos, None).await;
|
||||
if sticky {
|
||||
let pos = pos.offset_dir(dir.to_offset(), 2);
|
||||
let (block, state) = world.get_block_and_block_state(&pos).await.unwrap();
|
||||
let mut bl2 = false;
|
||||
if block == Block::MOVING_PISTON {
|
||||
if let Some(entity) = world.get_block_entity(&pos).await {
|
||||
let piston = PistonBlockEntity::from_nbt(&entity.0, pos);
|
||||
if piston.facing == dir && piston.extending {
|
||||
piston.finish(world.clone()).await;
|
||||
bl2 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !bl2 {
|
||||
if r#type == 1
|
||||
&& !state.is_air()
|
||||
&& Self::is_movable(&block, &state, dir, false, dir)
|
||||
&& (state.piston_behavior == PistonBehavior::Normal
|
||||
|| block == Block::PISTON
|
||||
|| block == Block::STICKY_PISTON)
|
||||
{
|
||||
move_piston(world, dir, &pos, false, sticky).await;
|
||||
} else {
|
||||
// remove
|
||||
world
|
||||
.set_block_state(
|
||||
&extended_pos,
|
||||
Block::AIR.default_state_id,
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// remove
|
||||
world
|
||||
.set_block_state(
|
||||
&extended_pos,
|
||||
@ -201,42 +270,37 @@ impl PumpkinBlock for PistonBlock {
|
||||
}
|
||||
}
|
||||
|
||||
async fn should_extend(
|
||||
world: &Arc<World>,
|
||||
block: &Block,
|
||||
state: &BlockState,
|
||||
block_pos: &BlockPos,
|
||||
piston_dir: BlockDirection,
|
||||
) -> bool {
|
||||
// Pistons can't be powered from the same direction as they are facing
|
||||
async fn should_extend(world: &World, block_pos: &BlockPos, piston_dir: BlockDirection) -> bool {
|
||||
for dir in BlockDirection::all() {
|
||||
if dir == piston_dir
|
||||
|| !is_emitting_redstone_power(
|
||||
block,
|
||||
state,
|
||||
world,
|
||||
&block_pos.offset(dir.to_offset()),
|
||||
dir,
|
||||
)
|
||||
let neighbor_pos = block_pos.offset(dir.to_offset());
|
||||
let (block, state) = world
|
||||
.get_block_and_block_state(&neighbor_pos)
|
||||
.await
|
||||
.unwrap();
|
||||
// Pistons can't be powered from the same direction as they are facing
|
||||
if dir == piston_dir
|
||||
|| !is_emitting_redstone_power(&block, &state, world, &neighbor_pos, dir).await
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if is_emitting_redstone_power(block, state, world, block_pos, BlockDirection::Down).await {
|
||||
let neighbor_pos = block_pos.offset(BlockDirection::Down.to_offset());
|
||||
let (block, state) = world
|
||||
.get_block_and_block_state(&neighbor_pos)
|
||||
.await
|
||||
.unwrap();
|
||||
if is_emitting_redstone_power(&block, &state, world, block_pos, BlockDirection::Down).await {
|
||||
return true;
|
||||
}
|
||||
for dir in BlockDirection::all() {
|
||||
if dir == BlockDirection::Down
|
||||
|| !is_emitting_redstone_power(
|
||||
block,
|
||||
state,
|
||||
world,
|
||||
&block_pos.up().offset(dir.to_offset()),
|
||||
dir,
|
||||
)
|
||||
let neighbor_pos = block_pos.up().offset(dir.to_offset());
|
||||
let (block, state) = world
|
||||
.get_block_and_block_state(&neighbor_pos)
|
||||
.await
|
||||
.unwrap();
|
||||
if dir == BlockDirection::Down
|
||||
|| !is_emitting_redstone_power(&block, &state, world, &neighbor_pos, dir).await
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -249,7 +313,7 @@ async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
|
||||
let state = world.get_block_state(block_pos).await.unwrap();
|
||||
let props = PistonProps::from_state_id(state.id, block);
|
||||
let dir = props.facing.to_block_direction();
|
||||
let should_extent = should_extend(world, block, &state, block_pos, dir).await;
|
||||
let should_extent = should_extend(world, block_pos, dir).await;
|
||||
|
||||
if should_extent && !props.extended {
|
||||
if PistonHandler::new(world, *block_pos, dir, true)
|
||||
@ -264,11 +328,19 @@ async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
|
||||
let new_pos = block_pos.offset_dir(dir.to_offset(), 2);
|
||||
let (new_block, new_state) = world.get_block_and_block_state(&new_pos).await.unwrap();
|
||||
let mut r#type = 1;
|
||||
|
||||
if new_block == Block::MOVING_PISTON {
|
||||
let new_props = MovingPistonProps::from_state_id(new_state.id, &new_block);
|
||||
// TODO: check more things
|
||||
let new_props = MovingPistonLikeProperties::from_state_id(new_state.id, &new_block);
|
||||
if new_props.facing == props.facing {
|
||||
r#type = 2;
|
||||
if let Some(entity) = world.get_block_entity(&new_pos).await {
|
||||
let piston = PistonBlockEntity::from_nbt(&entity.0, new_pos);
|
||||
if piston.extending && piston.current_progress.load() < 0.5
|
||||
// TODO: more stuff...
|
||||
{
|
||||
// Piston reduced too quickly, if its a stick piston no blocks will be dragged
|
||||
r#type = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
world
|
||||
@ -308,13 +380,11 @@ async fn move_piston(
|
||||
|
||||
for &block_pos in &moved_blocks {
|
||||
let block_state = world.get_block_state(&block_pos).await.unwrap();
|
||||
dbg!(block_state.id);
|
||||
moved_block_states.push(block_state.clone());
|
||||
moved_blocks_map.insert(block_pos, block_state);
|
||||
}
|
||||
|
||||
let broken_blocks: Vec<BlockPos> = handler.broken_blocks;
|
||||
dbg!(&broken_blocks);
|
||||
let mut affected_block_states: Vec<BlockState> =
|
||||
Vec::with_capacity(moved_blocks.len() + broken_blocks.len());
|
||||
let move_direction = if extend { dir } else { dir.opposite() };
|
||||
@ -322,7 +392,11 @@ async fn move_piston(
|
||||
for &broken_block_pos in broken_blocks.iter().rev() {
|
||||
let block_state = world.get_block_state(&broken_block_pos).await.unwrap();
|
||||
world
|
||||
.break_block(&broken_block_pos, None, BlockFlags::empty())
|
||||
.break_block(
|
||||
&broken_block_pos,
|
||||
None,
|
||||
BlockFlags::NOTIFY_LISTENERS | BlockFlags::FORCE_STATE,
|
||||
)
|
||||
.await;
|
||||
affected_block_states.push(block_state);
|
||||
}
|
||||
@ -402,7 +476,6 @@ async fn move_piston(
|
||||
}
|
||||
|
||||
for (pos, state) in &moved_blocks_map {
|
||||
// state.prepare(world, pos, BlockFlags::NOTIFY_LISTENERS);
|
||||
world
|
||||
.block_registry
|
||||
.prepare(
|
||||
@ -451,12 +524,13 @@ async fn move_piston(
|
||||
world.update_neighbors(&broken_block_pos, None).await;
|
||||
}
|
||||
}
|
||||
|
||||
for &moved_block_pos in moved_blocks.iter().rev() {
|
||||
world.update_neighbors(&moved_block_pos, None).await;
|
||||
}
|
||||
|
||||
// world.update_neighbors(&extended_pos, None).await;
|
||||
if extend {
|
||||
world.update_neighbors(&extended_pos, None).await;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
@ -1,10 +1,46 @@
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::block_properties::BlockProperties;
|
||||
use pumpkin_data::{Block, BlockState};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{block::FacingExt, world::BlockFlags};
|
||||
|
||||
use crate::entity::player::Player;
|
||||
use crate::{
|
||||
block::pumpkin_block::{BlockMetadata, PumpkinBlock},
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::piston::{PistonBlock, PistonProps};
|
||||
use crate::server::Server;
|
||||
|
||||
pub(crate) type PistonHeadProperties = pumpkin_data::block_properties::PistonHeadLikeProperties;
|
||||
|
||||
#[pumpkin_block("minecraft:piston_head")]
|
||||
pub struct PistonHeadBlock;
|
||||
|
||||
#[async_trait]
|
||||
impl PumpkinBlock for PistonHeadBlock {}
|
||||
impl PumpkinBlock for PistonHeadBlock {
|
||||
async fn broken(
|
||||
&self,
|
||||
_block: &Block,
|
||||
_player: &Arc<Player>,
|
||||
location: BlockPos,
|
||||
_server: &Server,
|
||||
world: Arc<World>,
|
||||
state: BlockState,
|
||||
) {
|
||||
let props = PistonHeadProperties::from_state_id(state.id, &Block::PISTON_HEAD);
|
||||
let pos = location.offset(props.facing.opposite().to_block_direction().to_offset());
|
||||
let (new_block, new_state) = world.get_block_and_block_state(&pos).await.unwrap();
|
||||
if PistonBlock::ids(&PistonBlock).contains(&new_block.name) {
|
||||
let props = PistonProps::from_state_id(new_state.id, &new_block);
|
||||
if props.extended {
|
||||
// TODO: use player
|
||||
world.break_block(&pos, None, BlockFlags::SKIP_DROPS).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ use crate::world::World;
|
||||
pub mod buttons;
|
||||
pub mod lever;
|
||||
pub mod observer;
|
||||
pub mod piston;
|
||||
pub mod rails;
|
||||
pub mod redstone_block;
|
||||
pub mod redstone_lamp;
|
||||
|
||||
@ -1,93 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{block::BlockIsReplacing, entity::player::Player};
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::{Block, block_properties::BlockProperties};
|
||||
use pumpkin_protocol::server::play::SUseItemOn;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{BlockStateId, block::BlockDirection, world::BlockFlags};
|
||||
|
||||
use crate::{
|
||||
block::pumpkin_block::{BlockMetadata, PumpkinBlock},
|
||||
server::Server,
|
||||
world::World,
|
||||
};
|
||||
|
||||
use super::block_receives_redstone_power;
|
||||
|
||||
type PistonProps = pumpkin_data::block_properties::StickyPistonLikeProperties;
|
||||
|
||||
pub struct PistonBlock;
|
||||
|
||||
impl BlockMetadata for PistonBlock {
|
||||
fn namespace(&self) -> &'static str {
|
||||
"minecraft"
|
||||
}
|
||||
|
||||
fn ids(&self) -> &'static [&'static str] {
|
||||
&[Block::PISTON.name, Block::STICKY_PISTON.name]
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl PumpkinBlock for PistonBlock {
|
||||
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 = PistonProps::default(block);
|
||||
props.extended = false;
|
||||
props.facing = player.living_entity.entity.get_facing().opposite();
|
||||
props.to_state_id(block)
|
||||
}
|
||||
|
||||
async fn placed(
|
||||
&self,
|
||||
world: &Arc<World>,
|
||||
block: &Block,
|
||||
state_id: BlockStateId,
|
||||
pos: &BlockPos,
|
||||
old_state_id: BlockStateId,
|
||||
_notify: bool,
|
||||
) {
|
||||
if old_state_id == state_id {
|
||||
return;
|
||||
}
|
||||
try_move(world, block, pos).await;
|
||||
}
|
||||
|
||||
async fn on_neighbor_update(
|
||||
&self,
|
||||
world: &Arc<World>,
|
||||
block: &Block,
|
||||
block_pos: &BlockPos,
|
||||
_source_block: &Block,
|
||||
_notify: bool,
|
||||
) {
|
||||
try_move(world, block, block_pos).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
|
||||
let state = world.get_block_state(block_pos).await.unwrap();
|
||||
let mut props = PistonProps::from_state_id(state.id, block);
|
||||
let is_receiving_power = block_receives_redstone_power(world, block_pos).await;
|
||||
|
||||
if is_receiving_power {
|
||||
props.extended = !props.extended;
|
||||
world
|
||||
.set_block_state(
|
||||
block_pos,
|
||||
props.to_state_id(block),
|
||||
BlockFlags::NOTIFY_LISTENERS,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
@ -13,11 +13,12 @@ use blocks::iron_bars::IronBarsBlock;
|
||||
use blocks::logs::LogBlock;
|
||||
use blocks::nether_portal::NetherPortalBlock;
|
||||
use blocks::note::NoteBlock;
|
||||
use blocks::piston::piston::PistonBlock;
|
||||
use blocks::piston::piston_extension::PistonExtensionBlock;
|
||||
use blocks::piston::piston_head::PistonHeadBlock;
|
||||
use blocks::pumpkin::PumpkinBlock;
|
||||
use blocks::redstone::buttons::ButtonBlock;
|
||||
use blocks::redstone::observer::ObserverBlock;
|
||||
use blocks::redstone::piston::PistonBlock;
|
||||
use blocks::redstone::rails::activator_rail::ActivatorRailBlock;
|
||||
use blocks::redstone::rails::detector_rail::DetectorRailBlock;
|
||||
use blocks::redstone::rails::powered_rail::PoweredRailBlock;
|
||||
@ -106,6 +107,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
||||
// Piston
|
||||
manager.register(PistonBlock);
|
||||
manager.register(PistonExtensionBlock);
|
||||
manager.register(PistonHeadBlock);
|
||||
|
||||
manager.register(RedstoneBlock);
|
||||
manager.register(RedstoneLamp);
|
||||
@ -127,6 +129,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
||||
Arc::new(manager)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BlockEvent {
|
||||
pub pos: BlockPos,
|
||||
pub r#type: u8,
|
||||
|
||||
@ -199,7 +199,12 @@ impl World {
|
||||
|
||||
async fn flush_synced_block_events(self: &Arc<Self>) {
|
||||
let mut queue = self.synced_block_event_queue.lock().await;
|
||||
for event in queue.drain(..) {
|
||||
let events: Vec<BlockEvent> = queue.clone();
|
||||
queue.clear();
|
||||
// THIS IS IMPORTANT
|
||||
// it prevents deadlocks and also removes the need to wait for a lock when adding a new synced block
|
||||
drop(queue);
|
||||
for event in events {
|
||||
let block = self.get_block(&event.pos).await.unwrap(); // TODO
|
||||
if !self
|
||||
.block_registry
|
||||
@ -366,6 +371,8 @@ impl World {
|
||||
|
||||
pub async fn tick(self: &Arc<Self>, server: &Server) {
|
||||
self.flush_block_updates().await;
|
||||
// tick block entities
|
||||
self.level.tick_block_entities(self.clone()).await;
|
||||
self.flush_synced_block_events().await;
|
||||
|
||||
// world ticks
|
||||
|
||||
Loading…
Reference in New Issue
Block a user