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 chest::ChestBlockEntity;
|
||||||
use comparator::ComparatorBlockEntity;
|
use comparator::ComparatorBlockEntity;
|
||||||
use piston::PistonBlockEntity;
|
use piston::PistonBlockEntity;
|
||||||
|
use pumpkin_data::{Block, block_properties::BLOCK_ENTITY_TYPES};
|
||||||
use pumpkin_nbt::compound::NbtCompound;
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use sign::SignBlockEntity;
|
use sign::SignBlockEntity;
|
||||||
@ -82,3 +83,7 @@ pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>>
|
|||||||
_ => None,
|
_ => 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> {
|
pub fn to_offset(&self) -> Vector3<i32> {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::Down => (0, -1, 0),
|
BlockDirection::Down => (0, -1, 0),
|
||||||
|
|||||||
@ -26,6 +26,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
generation::{Seed, WorldGenerator, get_world_gen},
|
generation::{Seed, WorldGenerator, get_world_gen},
|
||||||
lock::{LevelLocker, anvil::AnvilLevelLocker},
|
lock::{LevelLocker, anvil::AnvilLevelLocker},
|
||||||
|
world::SimpleWorld,
|
||||||
world_info::{
|
world_info::{
|
||||||
LevelData, WorldInfoError, WorldInfoReader, WorldInfoWriter,
|
LevelData, WorldInfoError, WorldInfoReader, WorldInfoWriter,
|
||||||
anvil::{AnvilLevelInfo, LEVEL_DAT_BACKUP_FILE_NAME, LEVEL_DAT_FILE_NAME},
|
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>) {
|
pub async fn clean_chunk(self: &Arc<Self>, chunk: &Vector2<i32>) {
|
||||||
self.clean_chunks(&[*chunk]).await;
|
self.clean_chunks(&[*chunk]).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ pub struct PistonHandler<'a> {
|
|||||||
motion_direction: BlockDirection,
|
motion_direction: BlockDirection,
|
||||||
pub moved_blocks: Vec<BlockPos>,
|
pub moved_blocks: Vec<BlockPos>,
|
||||||
pub broken_blocks: Vec<BlockPos>,
|
pub broken_blocks: Vec<BlockPos>,
|
||||||
_piston_direction: BlockDirection,
|
piston_direction: BlockDirection,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PistonHandler<'a> {
|
impl<'a> PistonHandler<'a> {
|
||||||
@ -29,7 +29,7 @@ impl<'a> PistonHandler<'a> {
|
|||||||
let motion_direction;
|
let motion_direction;
|
||||||
let pos_to = if retracted {
|
let pos_to = if retracted {
|
||||||
motion_direction = dir;
|
motion_direction = dir;
|
||||||
pos.offset_dir(dir.to_offset(), 1)
|
pos.offset(dir.to_offset())
|
||||||
} else {
|
} else {
|
||||||
motion_direction = dir.opposite();
|
motion_direction = dir.opposite();
|
||||||
pos.offset_dir(dir.to_offset(), 2)
|
pos.offset_dir(dir.to_offset(), 2)
|
||||||
@ -37,7 +37,7 @@ impl<'a> PistonHandler<'a> {
|
|||||||
PistonHandler {
|
PistonHandler {
|
||||||
world,
|
world,
|
||||||
pos_from: pos,
|
pos_from: pos,
|
||||||
_piston_direction: dir,
|
piston_direction: dir,
|
||||||
retracted,
|
retracted,
|
||||||
motion_direction,
|
motion_direction,
|
||||||
pos_to,
|
pos_to,
|
||||||
@ -54,14 +54,19 @@ impl<'a> PistonHandler<'a> {
|
|||||||
.get_block_and_block_state(&self.pos_to)
|
.get_block_and_block_state(&self.pos_to)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
dbg!(PistonBlock::is_movable(
|
||||||
|
&block,
|
||||||
|
&block_state,
|
||||||
|
self.motion_direction,
|
||||||
|
false,
|
||||||
|
self.piston_direction,
|
||||||
|
));
|
||||||
if !PistonBlock::is_movable(
|
if !PistonBlock::is_movable(
|
||||||
&block,
|
&block,
|
||||||
&block_state,
|
&block_state,
|
||||||
// self.world,
|
self.motion_direction,
|
||||||
// self.pos_to,
|
false,
|
||||||
// self.motion_direction,
|
self.piston_direction,
|
||||||
// false,
|
|
||||||
// self.piston_direction,
|
|
||||||
) {
|
) {
|
||||||
if self.retracted && block_state.piston_behavior == PistonBehavior::Destroy {
|
if self.retracted && block_state.piston_behavior == PistonBehavior::Destroy {
|
||||||
self.broken_blocks.push(self.pos_to);
|
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)
|
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) =
|
let (mut block, mut block_state) =
|
||||||
self.world.get_block_and_block_state(&pos).await.unwrap();
|
self.world.get_block_and_block_state(&pos).await.unwrap();
|
||||||
if block_state.is_air() {
|
if block_state.is_air() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if !PistonBlock::is_movable(
|
if !PistonBlock::is_movable(&block, &block_state, self.motion_direction, false, dir) {
|
||||||
&block,
|
|
||||||
&block_state,
|
|
||||||
// self.world,
|
|
||||||
// pos,
|
|
||||||
// self.motion_direction,
|
|
||||||
// false,
|
|
||||||
// dir,
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if pos == self.pos_from {
|
if pos == self.pos_from {
|
||||||
@ -137,11 +134,9 @@ impl<'a> PistonHandler<'a> {
|
|||||||
|| !PistonBlock::is_movable(
|
|| !PistonBlock::is_movable(
|
||||||
&block,
|
&block,
|
||||||
&block_state,
|
&block_state,
|
||||||
// self.world,
|
self.motion_direction,
|
||||||
// block_pos,
|
false,
|
||||||
// self.motion_direction,
|
self.motion_direction.opposite(),
|
||||||
// false,
|
|
||||||
// self.motion_direction.opposite(),
|
|
||||||
)
|
)
|
||||||
|| block_pos == self.pos_from
|
|| block_pos == self.pos_from
|
||||||
{
|
{
|
||||||
@ -185,11 +180,9 @@ impl<'a> PistonHandler<'a> {
|
|||||||
if !PistonBlock::is_movable(
|
if !PistonBlock::is_movable(
|
||||||
&block,
|
&block,
|
||||||
&block_state,
|
&block_state,
|
||||||
// self.world,
|
self.motion_direction,
|
||||||
// block_pos2,
|
true,
|
||||||
// self.motion_direction,
|
self.motion_direction,
|
||||||
// true,
|
|
||||||
// self.motion_direction,
|
|
||||||
) || block_pos2 == self.pos_from
|
) || block_pos2 == self.pos_from
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use pumpkin_data::{
|
|||||||
BlockProperties, MovingPistonLikeProperties, PistonHeadLikeProperties, PistonType,
|
BlockProperties, MovingPistonLikeProperties, PistonHeadLikeProperties, PistonType,
|
||||||
get_block_by_state_id, get_state_by_state_id,
|
get_block_by_state_id, get_state_by_state_id,
|
||||||
},
|
},
|
||||||
|
block_state::PistonBehavior,
|
||||||
};
|
};
|
||||||
use pumpkin_protocol::server::play::SUseItemOn;
|
use pumpkin_protocol::server::play::SUseItemOn;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
@ -14,7 +15,7 @@ use pumpkin_world::{
|
|||||||
BlockStateId,
|
BlockStateId,
|
||||||
block::{
|
block::{
|
||||||
BlockDirection, FacingExt,
|
BlockDirection, FacingExt,
|
||||||
entities::{BlockEntity, piston::PistonBlockEntity},
|
entities::{BlockEntity, has_block_block_entity, piston::PistonBlockEntity},
|
||||||
},
|
},
|
||||||
world::BlockFlags,
|
world::BlockFlags,
|
||||||
};
|
};
|
||||||
@ -30,7 +31,7 @@ use crate::{
|
|||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{PistonHandler, piston_extension::MovingPistonProps};
|
use super::PistonHandler;
|
||||||
|
|
||||||
pub(crate) type PistonProps = pumpkin_data::block_properties::StickyPistonLikeProperties;
|
pub(crate) type PistonProps = pumpkin_data::block_properties::StickyPistonLikeProperties;
|
||||||
|
|
||||||
@ -47,7 +48,13 @@ impl BlockMetadata for PistonBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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
|
// TODO: more checks
|
||||||
if state.is_air() {
|
if state.is_air() {
|
||||||
return true;
|
return true;
|
||||||
@ -60,7 +67,24 @@ impl PistonBlock {
|
|||||||
{
|
{
|
||||||
return false;
|
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;
|
try_move(world, block, block_pos).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(clippy::too_many_lines)]
|
||||||
async fn on_synced_block_event(
|
async fn on_synced_block_event(
|
||||||
&self,
|
&self,
|
||||||
block: &Block,
|
block: &Block,
|
||||||
world: &Arc<World>,
|
world: &Arc<World>,
|
||||||
pos: &BlockPos,
|
pos: &BlockPos,
|
||||||
r#type: u8,
|
r#type: u8,
|
||||||
_data: u8,
|
data: u8,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let state = world.get_block_state(pos).await.unwrap();
|
let state = world.get_block_state(pos).await.unwrap();
|
||||||
let mut props = PistonProps::from_state_id(state.id, block);
|
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 ?
|
// I don't think this is optimal ?
|
||||||
let sticky = block == &Block::STICKY_PISTON;
|
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) {
|
if should_extend && (r#type == 1 || r#type == 2) {
|
||||||
props.extended = true;
|
props.extended = true;
|
||||||
world
|
world
|
||||||
@ -138,6 +163,7 @@ impl PumpkinBlock for PistonBlock {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extend Piston
|
||||||
if r#type == 0 {
|
if r#type == 0 {
|
||||||
if !move_piston(world, dir, pos, true, sticky).await {
|
if !move_piston(world, dir, pos, true, sticky).await {
|
||||||
return false;
|
return false;
|
||||||
@ -152,6 +178,8 @@ impl PumpkinBlock for PistonBlock {
|
|||||||
.await;
|
.await;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// Reduce Piston
|
||||||
|
|
||||||
let extended_pos = pos.offset(dir.to_offset());
|
let extended_pos = pos.offset(dir.to_offset());
|
||||||
|
|
||||||
if let Some((block_entity_nbt, _block_entity)) = world.get_block_entity(&extended_pos).await
|
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
|
PistonType::Normal
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = props.to_state_id(&Block::MOVING_PISTON);
|
|
||||||
|
|
||||||
world
|
world
|
||||||
.set_block_state(pos, state, BlockFlags::FORCE_STATE)
|
.set_block_state(
|
||||||
|
pos,
|
||||||
|
props.to_state_id(&Block::MOVING_PISTON),
|
||||||
|
BlockFlags::FORCE_STATE,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
let mut props = PistonProps::default(block);
|
||||||
|
props.facing = BlockDirection::by_index((data & 7) as usize)
|
||||||
|
.unwrap()
|
||||||
|
.to_facing();
|
||||||
|
|
||||||
world
|
world
|
||||||
.add_block_entity(Arc::new(PistonBlockEntity {
|
.add_block_entity(Arc::new(PistonBlockEntity {
|
||||||
position: *pos,
|
position: *pos,
|
||||||
facing: dir.to_facing().to_block_direction(),
|
facing: dir,
|
||||||
pushed_block_state: get_state_by_state_id(state).unwrap(),
|
pushed_block_state: get_state_by_state_id(props.to_state_id(block)).unwrap(),
|
||||||
current_progress: 0.0.into(),
|
current_progress: 0.0.into(),
|
||||||
last_progress: 0.0.into(),
|
last_progress: 0.0.into(),
|
||||||
extending: false,
|
extending: false,
|
||||||
source: true,
|
source: true,
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
world.update_neighbors(pos, None).await;
|
world.update_neighbors(pos, None).await;
|
||||||
if sticky {
|
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 {
|
} else {
|
||||||
|
// remove
|
||||||
|
world
|
||||||
|
.set_block_state(
|
||||||
|
&extended_pos,
|
||||||
|
Block::AIR.default_state_id,
|
||||||
|
BlockFlags::NOTIFY_ALL,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// remove
|
||||||
world
|
world
|
||||||
.set_block_state(
|
.set_block_state(
|
||||||
&extended_pos,
|
&extended_pos,
|
||||||
@ -201,42 +270,37 @@ impl PumpkinBlock for PistonBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn should_extend(
|
async fn should_extend(world: &World, block_pos: &BlockPos, piston_dir: BlockDirection) -> bool {
|
||||||
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
|
|
||||||
for dir in BlockDirection::all() {
|
for dir in BlockDirection::all() {
|
||||||
if dir == piston_dir
|
let neighbor_pos = block_pos.offset(dir.to_offset());
|
||||||
|| !is_emitting_redstone_power(
|
let (block, state) = world
|
||||||
block,
|
.get_block_and_block_state(&neighbor_pos)
|
||||||
state,
|
|
||||||
world,
|
|
||||||
&block_pos.offset(dir.to_offset()),
|
|
||||||
dir,
|
|
||||||
)
|
|
||||||
.await
|
.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;
|
continue;
|
||||||
}
|
}
|
||||||
return true;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
for dir in BlockDirection::all() {
|
for dir in BlockDirection::all() {
|
||||||
if dir == BlockDirection::Down
|
let neighbor_pos = block_pos.up().offset(dir.to_offset());
|
||||||
|| !is_emitting_redstone_power(
|
let (block, state) = world
|
||||||
block,
|
.get_block_and_block_state(&neighbor_pos)
|
||||||
state,
|
|
||||||
world,
|
|
||||||
&block_pos.up().offset(dir.to_offset()),
|
|
||||||
dir,
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
|
.unwrap();
|
||||||
|
if dir == BlockDirection::Down
|
||||||
|
|| !is_emitting_redstone_power(&block, &state, world, &neighbor_pos, dir).await
|
||||||
{
|
{
|
||||||
continue;
|
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 state = world.get_block_state(block_pos).await.unwrap();
|
||||||
let props = PistonProps::from_state_id(state.id, block);
|
let props = PistonProps::from_state_id(state.id, block);
|
||||||
let dir = props.facing.to_block_direction();
|
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 should_extent && !props.extended {
|
||||||
if PistonHandler::new(world, *block_pos, dir, true)
|
if PistonHandler::new(world, *block_pos, dir, true)
|
||||||
@ -264,13 +328,21 @@ 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_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 (new_block, new_state) = world.get_block_and_block_state(&new_pos).await.unwrap();
|
||||||
let mut r#type = 1;
|
let mut r#type = 1;
|
||||||
|
|
||||||
if new_block == Block::MOVING_PISTON {
|
if new_block == Block::MOVING_PISTON {
|
||||||
let new_props = MovingPistonProps::from_state_id(new_state.id, &new_block);
|
let new_props = MovingPistonLikeProperties::from_state_id(new_state.id, &new_block);
|
||||||
// TODO: check more things
|
|
||||||
if new_props.facing == props.facing {
|
if new_props.facing == props.facing {
|
||||||
|
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;
|
r#type = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
world
|
world
|
||||||
.add_synced_block_event(*block_pos, r#type, dir.to_index())
|
.add_synced_block_event(*block_pos, r#type, dir.to_index())
|
||||||
.await;
|
.await;
|
||||||
@ -308,13 +380,11 @@ async fn move_piston(
|
|||||||
|
|
||||||
for &block_pos in &moved_blocks {
|
for &block_pos in &moved_blocks {
|
||||||
let block_state = world.get_block_state(&block_pos).await.unwrap();
|
let block_state = world.get_block_state(&block_pos).await.unwrap();
|
||||||
dbg!(block_state.id);
|
|
||||||
moved_block_states.push(block_state.clone());
|
moved_block_states.push(block_state.clone());
|
||||||
moved_blocks_map.insert(block_pos, block_state);
|
moved_blocks_map.insert(block_pos, block_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
let broken_blocks: Vec<BlockPos> = handler.broken_blocks;
|
let broken_blocks: Vec<BlockPos> = handler.broken_blocks;
|
||||||
dbg!(&broken_blocks);
|
|
||||||
let mut affected_block_states: Vec<BlockState> =
|
let mut affected_block_states: Vec<BlockState> =
|
||||||
Vec::with_capacity(moved_blocks.len() + broken_blocks.len());
|
Vec::with_capacity(moved_blocks.len() + broken_blocks.len());
|
||||||
let move_direction = if extend { dir } else { dir.opposite() };
|
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() {
|
for &broken_block_pos in broken_blocks.iter().rev() {
|
||||||
let block_state = world.get_block_state(&broken_block_pos).await.unwrap();
|
let block_state = world.get_block_state(&broken_block_pos).await.unwrap();
|
||||||
world
|
world
|
||||||
.break_block(&broken_block_pos, None, BlockFlags::empty())
|
.break_block(
|
||||||
|
&broken_block_pos,
|
||||||
|
None,
|
||||||
|
BlockFlags::NOTIFY_LISTENERS | BlockFlags::FORCE_STATE,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
affected_block_states.push(block_state);
|
affected_block_states.push(block_state);
|
||||||
}
|
}
|
||||||
@ -402,7 +476,6 @@ async fn move_piston(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (pos, state) in &moved_blocks_map {
|
for (pos, state) in &moved_blocks_map {
|
||||||
// state.prepare(world, pos, BlockFlags::NOTIFY_LISTENERS);
|
|
||||||
world
|
world
|
||||||
.block_registry
|
.block_registry
|
||||||
.prepare(
|
.prepare(
|
||||||
@ -451,12 +524,13 @@ async fn move_piston(
|
|||||||
world.update_neighbors(&broken_block_pos, None).await;
|
world.update_neighbors(&broken_block_pos, None).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for &moved_block_pos in moved_blocks.iter().rev() {
|
for &moved_block_pos in moved_blocks.iter().rev() {
|
||||||
world.update_neighbors(&moved_block_pos, None).await;
|
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
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,46 @@
|
|||||||
use async_trait::async_trait;
|
use std::sync::Arc;
|
||||||
use pumpkin_macros::pumpkin_block;
|
|
||||||
|
|
||||||
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")]
|
#[pumpkin_block("minecraft:piston_head")]
|
||||||
pub struct PistonHeadBlock;
|
pub struct PistonHeadBlock;
|
||||||
|
|
||||||
#[async_trait]
|
#[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 buttons;
|
||||||
pub mod lever;
|
pub mod lever;
|
||||||
pub mod observer;
|
pub mod observer;
|
||||||
pub mod piston;
|
|
||||||
pub mod rails;
|
pub mod rails;
|
||||||
pub mod redstone_block;
|
pub mod redstone_block;
|
||||||
pub mod redstone_lamp;
|
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::logs::LogBlock;
|
||||||
use blocks::nether_portal::NetherPortalBlock;
|
use blocks::nether_portal::NetherPortalBlock;
|
||||||
use blocks::note::NoteBlock;
|
use blocks::note::NoteBlock;
|
||||||
|
use blocks::piston::piston::PistonBlock;
|
||||||
use blocks::piston::piston_extension::PistonExtensionBlock;
|
use blocks::piston::piston_extension::PistonExtensionBlock;
|
||||||
|
use blocks::piston::piston_head::PistonHeadBlock;
|
||||||
use blocks::pumpkin::PumpkinBlock;
|
use blocks::pumpkin::PumpkinBlock;
|
||||||
use blocks::redstone::buttons::ButtonBlock;
|
use blocks::redstone::buttons::ButtonBlock;
|
||||||
use blocks::redstone::observer::ObserverBlock;
|
use blocks::redstone::observer::ObserverBlock;
|
||||||
use blocks::redstone::piston::PistonBlock;
|
|
||||||
use blocks::redstone::rails::activator_rail::ActivatorRailBlock;
|
use blocks::redstone::rails::activator_rail::ActivatorRailBlock;
|
||||||
use blocks::redstone::rails::detector_rail::DetectorRailBlock;
|
use blocks::redstone::rails::detector_rail::DetectorRailBlock;
|
||||||
use blocks::redstone::rails::powered_rail::PoweredRailBlock;
|
use blocks::redstone::rails::powered_rail::PoweredRailBlock;
|
||||||
@ -106,6 +107,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
|||||||
// Piston
|
// Piston
|
||||||
manager.register(PistonBlock);
|
manager.register(PistonBlock);
|
||||||
manager.register(PistonExtensionBlock);
|
manager.register(PistonExtensionBlock);
|
||||||
|
manager.register(PistonHeadBlock);
|
||||||
|
|
||||||
manager.register(RedstoneBlock);
|
manager.register(RedstoneBlock);
|
||||||
manager.register(RedstoneLamp);
|
manager.register(RedstoneLamp);
|
||||||
@ -127,6 +129,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
|||||||
Arc::new(manager)
|
Arc::new(manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct BlockEvent {
|
pub struct BlockEvent {
|
||||||
pub pos: BlockPos,
|
pub pos: BlockPos,
|
||||||
pub r#type: u8,
|
pub r#type: u8,
|
||||||
|
|||||||
@ -199,7 +199,12 @@ impl World {
|
|||||||
|
|
||||||
async fn flush_synced_block_events(self: &Arc<Self>) {
|
async fn flush_synced_block_events(self: &Arc<Self>) {
|
||||||
let mut queue = self.synced_block_event_queue.lock().await;
|
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
|
let block = self.get_block(&event.pos).await.unwrap(); // TODO
|
||||||
if !self
|
if !self
|
||||||
.block_registry
|
.block_registry
|
||||||
@ -366,6 +371,8 @@ impl World {
|
|||||||
|
|
||||||
pub async fn tick(self: &Arc<Self>, server: &Server) {
|
pub async fn tick(self: &Arc<Self>, server: &Server) {
|
||||||
self.flush_block_updates().await;
|
self.flush_block_updates().await;
|
||||||
|
// tick block entities
|
||||||
|
self.level.tick_block_entities(self.clone()).await;
|
||||||
self.flush_synced_block_events().await;
|
self.flush_synced_block_events().await;
|
||||||
|
|
||||||
// world ticks
|
// world ticks
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user