chore: less awaits more fun

This commit is contained in:
Alexander Medvedev 2026-05-14 12:28:43 +02:00
parent c8633b78d7
commit 92abb1e44e
350 changed files with 3888 additions and 4927 deletions

4
Cargo.lock generated
View File

@ -886,9 +886,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]] [[package]]
name = "crossfire" name = "crossfire"
version = "3.1.10" version = "3.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebed7d0a3a92ebc771f880516a5eecef5942a0fc67855dc4f30e719b04c77ac5" checksum = "72bdfcf389b100bb85fcf39ad434f67b617813cf0608095c905b79f6b2194aea"
dependencies = [ dependencies = [
"crossbeam-utils", "crossbeam-utils",
"futures-core", "futures-core",

View File

@ -120,7 +120,7 @@ console-subscriber = { version = "0.5.0", default-features = false }
crc-fast = "1.10.0" crc-fast = "1.10.0"
criterion = { version = "0.8", default-features = false } criterion = { version = "0.8", default-features = false }
crossbeam-utils = "0.8.21" crossbeam-utils = "0.8.21"
crossfire = { version = "3.1.10", features = ["compat"] } crossfire = { version = "3.1.12", features = ["compat"] }
crypto-bigint = "0.7.3" crypto-bigint = "0.7.3"
dashmap = "6.1" dashmap = "6.1"
ecdsa = "0.16.9" ecdsa = "0.16.9"

View File

@ -15,8 +15,6 @@ use pumpkin_nbt::compound::NbtCompound;
use pumpkin_util::HeightMap; use pumpkin_util::HeightMap;
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
use std::future::Future;
use std::pin::Pin;
use tracing::debug; use tracing::debug;
pub struct Cache { pub struct Cache {
@ -45,35 +43,21 @@ impl HeightLimitView for Cache {
} }
impl BlockAccessor for Cache { impl BlockAccessor for Cache {
fn get_block<'a>( fn get_block(&self, position: &BlockPos) -> &'static Block {
&'a self, GenerationCache::get_block_state(self, &position.0).to_block()
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = &'static Block> + Send + 'a>> {
Box::pin(async move { GenerationCache::get_block_state(self, &position.0).to_block() })
} }
fn get_block_state<'a>( fn get_block_state(&self, position: &BlockPos) -> &'static BlockState {
&'a self, GenerationCache::get_block_state(self, &position.0).to_state()
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = &'static BlockState> + Send + 'a>> {
Box::pin(async move { GenerationCache::get_block_state(self, &position.0).to_state() })
} }
fn get_block_state_id<'a>( fn get_block_state_id(&self, position: &BlockPos) -> BlockStateId {
&'a self, GenerationCache::get_block_state(self, &position.0).0
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = BlockStateId> + Send + 'a>> {
Box::pin(async move { GenerationCache::get_block_state(self, &position.0).0 })
} }
fn get_block_and_state<'a>( fn get_block_and_state(&self, position: &BlockPos) -> (&'static Block, &'static BlockState) {
&'a self, let state = GenerationCache::get_block_state(self, &position.0);
position: &'a BlockPos, (state.to_block(), state.to_state())
) -> Pin<Box<dyn Future<Output = (&'static Block, &'static BlockState)> + Send + 'a>> {
Box::pin(async move {
let id = GenerationCache::get_block_state(self, &position.0);
(id.to_block(), id.to_state())
})
} }
} }

View File

@ -1,4 +1,3 @@
use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use pumpkin_data::block_properties::is_air; use pumpkin_data::block_properties::is_air;
@ -1362,34 +1361,20 @@ impl ProtoChunk {
} }
impl BlockAccessor for ProtoChunk { impl BlockAccessor for ProtoChunk {
fn get_block<'a>( fn get_block(&self, position: &BlockPos) -> &'static Block {
&'a self, self.get_block_state(&position.0).to_block()
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = &'static Block> + Send + 'a>> {
Box::pin(async move { self.get_block_state(&position.0).to_block() })
} }
fn get_block_state<'a>( fn get_block_state(&self, position: &BlockPos) -> &'static BlockState {
&'a self, self.get_block_state(&position.0).to_state()
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = &'static BlockState> + Send + 'a>> {
Box::pin(async move { self.get_block_state(&position.0).to_state() })
} }
fn get_block_state_id<'a>( fn get_block_state_id(&self, position: &BlockPos) -> BlockStateId {
&'a self, self.get_block_state(&position.0).0
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = BlockStateId> + Send + 'a>> {
Box::pin(async move { self.get_block_state(&position.0).0 })
} }
fn get_block_and_state<'a>( fn get_block_and_state(&self, position: &BlockPos) -> (&'static Block, &'static BlockState) {
&'a self, let id = self.get_block_state(&position.0);
position: &'a BlockPos, BlockState::from_id_with_block(id.0)
) -> Pin<Box<dyn Future<Output = (&'static Block, &'static BlockState)> + Send + 'a>> {
Box::pin(async move {
let id = self.get_block_state(&position.0);
BlockState::from_id_with_block(id.0)
})
} }
} }

View File

@ -711,20 +711,6 @@ impl Level {
RawBlockState(id.unwrap_or(Block::VOID_AIR.default_state.id)) RawBlockState(id.unwrap_or(Block::VOID_AIR.default_state.id))
} }
pub async fn get_rough_biome(self: &Arc<Self>, position: &BlockPos) -> &'static Biome {
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
let id = self
.get_or_fetch_chunk(chunk_coordinate, |chunk| {
chunk.section.get_rough_biome_absolute_y(
relative.x as usize,
relative.y,
relative.z as usize,
)
})
.await;
Biome::from_id(id.unwrap_or(0)).unwrap_or(&Biome::THE_VOID)
}
pub async fn set_block_state( pub async fn set_block_state(
self: &Arc<Self>, self: &Arc<Self>,
position: &BlockPos, position: &BlockPos,
@ -798,6 +784,18 @@ impl Level {
self.loaded_chunks.get(coordinates).map(|x| f(x.value())) self.loaded_chunks.get(coordinates).map(|x| f(x.value()))
} }
pub fn get_rough_biome(&self, position: &BlockPos) -> &'static Biome {
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
let id = self.read_chunk_sync(&chunk_coordinate, |chunk| {
chunk.section.get_rough_biome_absolute_y(
relative.x as usize,
relative.y,
relative.z as usize,
)
});
Biome::from_id(id.flatten().unwrap_or(0)).unwrap_or(&Biome::THE_VOID)
}
pub fn read_entity_chunk_sync<R, F: Fn(&SyncEntityChunk) -> R>( pub fn read_entity_chunk_sync<R, F: Fn(&SyncEntityChunk) -> R>(
&self, &self,
coordinates: &Vector2<i32>, coordinates: &Vector2<i32>,
@ -808,6 +806,12 @@ impl Level {
.map(|x| f(x.value())) .map(|x| f(x.value()))
} }
pub fn get_entity_chunk_sync(&self, pos: &Vector2<i32>) -> Option<SyncEntityChunk> {
self.loaded_entity_chunks
.get(pos)
.map(|x| x.value().clone())
}
pub async fn get_or_fetch_entity_chunk<R, F: Fn(&SyncEntityChunk) -> R>( pub async fn get_or_fetch_entity_chunk<R, F: Fn(&SyncEntityChunk) -> R>(
self: &Arc<Self>, self: &Arc<Self>,
pos: Vector2<i32>, pos: Vector2<i32>,

View File

@ -445,6 +445,50 @@ impl DynamicLightEngine {
} }
} }
pub fn get_block_light_level_sync(&self, level: &Level, position: &BlockPos) -> Option<u8> {
let (chunk_pos, relative) = position.chunk_and_chunk_relative_position();
level.read_chunk_sync(&chunk_pos, |chunk| {
let section_idx = (relative.y - chunk.section.min_y) as usize / 16;
let light_engine = chunk.light_engine.lock().ok()?;
light_engine
.block_light
.get(section_idx)?
.get(
relative.x as usize,
(relative.y - chunk.section.min_y) as usize % 16,
relative.z as usize,
)
.into()
})?
}
pub fn get_sky_light_level_sync(&self, level: &Level, position: &BlockPos) -> u8 {
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
level
.read_chunk_sync(&chunk_coordinate, |chunk| {
let section_index =
(relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE;
let light_engine = chunk
.light_engine
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
// Bounds check for section index (lock the light engine)
if section_index >= light_engine.sky_light.len() {
return 15;
}
light_engine.sky_light[section_index].get(
relative.x as usize,
(relative.y - chunk.section.min_y) as usize % BlockPalette::SIZE,
relative.z as usize,
)
})
.unwrap_or(0)
}
pub async fn get_block_light_level( pub async fn get_block_light_level(
&self, &self,
level: &Arc<Level>, level: &Arc<Level>,

View File

@ -74,23 +74,11 @@ pub trait WorldPortalExt: Send + Sync {
} }
pub trait BlockAccessor: Send + Sync { pub trait BlockAccessor: Send + Sync {
fn get_block<'a>( fn get_block(&self, position: &BlockPos) -> &'static Block;
&'a self,
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = &'static Block> + Send + 'a>>;
fn get_block_state<'a>( fn get_block_state(&self, position: &BlockPos) -> &'static BlockState;
&'a self,
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = &'static BlockState> + Send + 'a>>;
fn get_block_state_id<'a>( fn get_block_state_id(&self, position: &BlockPos) -> BlockStateId;
&'a self,
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = BlockStateId> + Send + 'a>>;
fn get_block_and_state<'a>( fn get_block_and_state(&self, position: &BlockPos) -> (&'static Block, &'static BlockState);
&'a self,
position: &'a BlockPos,
) -> Pin<Box<dyn Future<Output = (&'static Block, &'static BlockState)> + Send + 'a>>;
} }

View File

@ -53,12 +53,10 @@ pub trait WallMountedBlock: Send + Sync {
world: &'a dyn BlockAccessor, world: &'a dyn BlockAccessor,
pos: &'a BlockPos, pos: &'a BlockPos,
direction: BlockDirection, direction: BlockDirection,
) -> BlockFuture<'a, bool> { ) -> bool {
Box::pin(async move { let block_pos = pos.offset(direction.to_offset());
let block_pos = pos.offset(direction.to_offset()); let block_state = world.get_block_state(&block_pos);
let block_state = world.get_block_state(&block_pos).await; block_state.is_side_solid(direction.opposite())
block_state.is_side_solid(direction.opposite())
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -67,9 +65,7 @@ pub trait WallMountedBlock: Send + Sync {
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if self.get_direction(args.state_id, args.block).opposite() == args.direction if self.get_direction(args.state_id, args.block).opposite() == args.direction
&& !self && !self.can_place_at(args.world, args.position, args.direction)
.can_place_at(args.world, args.position, args.direction)
.await
{ {
Block::AIR.default_state.id Block::AIR.default_state.id
} else { } else {

View File

@ -21,13 +21,13 @@ impl BlockBehaviour for BannerBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: crate::block::CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: crate::block::CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -40,7 +40,7 @@ impl BlockBehaviour for BannerBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -50,7 +50,7 @@ impl BlockBehaviour for BannerBlock {
} }
} }
async fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool { fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool {
let state = world.get_block_state(&position.down()).await; let state = world.get_block_state(&position.down());
state.is_solid() state.is_solid()
} }

View File

@ -60,7 +60,7 @@ impl BlockBehaviour for BarrelBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(inventory) = block_entity.get_inventory() && let Some(inventory) = block_entity.get_inventory()
{ {
args.player args.player

View File

@ -51,7 +51,7 @@ pub struct BeaconBlock;
impl BlockBehaviour for BeaconBlock { impl BlockBehaviour for BeaconBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let block_entity = args.world.get_block_entity(args.position).await; let block_entity = args.world.get_block_entity(args.position);
// Extract the inventory from the entity // Extract the inventory from the entity
let Some(inventory) = block_entity.and_then(BlockEntity::get_inventory) else { let Some(inventory) = block_entity.and_then(BlockEntity::get_inventory) else {

View File

@ -70,23 +70,19 @@ const NO_SLEEP_IDS: &[u16] = &[
pub struct BedBlock; pub struct BedBlock;
impl BlockBehaviour for BedBlock { impl BlockBehaviour for BedBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { if let Some(player) = args.player {
if let Some(player) = args.player { let facing = player.living_entity.entity.get_horizontal_facing();
let facing = player.living_entity.entity.get_horizontal_facing(); return args
return args .block_accessor
.get_block_state(args.position)
.replaceable()
&& args
.block_accessor .block_accessor
.get_block_state(args.position) .get_block_state(&args.position.offset(facing.to_offset()))
.await .replaceable();
.replaceable() }
&& args false
.block_accessor
.get_block_state(&args.position.offset(facing.to_offset()))
.await
.replaceable();
}
false
})
} }
fn on_landed_upon<'a>(&'a self, args: OnLandedUponArgs<'a>) -> BlockFuture<'a, ()> { fn on_landed_upon<'a>(&'a self, args: OnLandedUponArgs<'a>) -> BlockFuture<'a, ()> {
@ -150,7 +146,7 @@ impl BlockBehaviour for BedBlock {
args.position.offset(bed_props.facing.to_offset()) args.position.offset(bed_props.facing.to_offset())
}; };
let neighbor_block_id = args.world.get_block_state_id(&other_half_pos).await; let neighbor_block_id = args.world.get_block_state_id(&other_half_pos);
if neighbor_block_id != args.block.id { if neighbor_block_id != args.block.id {
args.world.update_neighbors(&other_half_pos, None).await; args.world.update_neighbors(&other_half_pos, None).await;
return; return;
@ -180,7 +176,7 @@ impl BlockBehaviour for BedBlock {
// If the block is being replaced with air (i.e., broken), the `broken` callback // If the block is being replaced with air (i.e., broken), the `broken` callback
// will handle breaking the other half with the correct drop flags. Only handle it here // will handle breaking the other half with the correct drop flags. Only handle it here
// if the block is being replaced with something else (e.g., piston movement). // if the block is being replaced with something else (e.g., piston movement).
let new_state_id = args.world.get_block_state_id(args.position).await; let new_state_id = args.world.get_block_state_id(args.position);
let new_block = Block::from_state_id(new_state_id); let new_block = Block::from_state_id(new_state_id);
if new_block == &Block::AIR { if new_block == &Block::AIR {
return; return;
@ -194,7 +190,7 @@ impl BlockBehaviour for BedBlock {
args.position.offset(bed_props.facing.to_offset()) args.position.offset(bed_props.facing.to_offset())
}; };
let (other_block, other_state) = args.world.get_block_and_state(&other_half_pos).await; let (other_block, other_state) = args.world.get_block_and_state(&other_half_pos);
if other_block == args.block { if other_block == args.block {
let other_props = BedProperties::from_state_id(other_state.id, other_block); let other_props = BedProperties::from_state_id(other_state.id, other_block);
if other_props.part != bed_props.part { if other_props.part != bed_props.part {
@ -213,7 +209,7 @@ impl BlockBehaviour for BedBlock {
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let bed_props = BedProperties::from_state_id(state_id, args.block); let bed_props = BedProperties::from_state_id(state_id, args.block);
let (bed_head_pos, bed_foot_pos) = if bed_props.part == BedPart::Head { let (bed_head_pos, bed_foot_pos) = if bed_props.part == BedPart::Head {
@ -246,16 +242,8 @@ impl BlockBehaviour for BedBlock {
} }
// Make sure the bed is not obstructed // Make sure the bed is not obstructed
if args if args.world.get_block_state(&bed_head_pos.up()).is_solid()
.world || args.world.get_block_state(&bed_foot_pos.up()).is_solid()
.get_block_state(&bed_head_pos.up())
.await
.is_solid()
|| args
.world
.get_block_state(&bed_foot_pos.up())
.await
.is_solid()
{ {
args.player args.player
.send_system_message_raw( .send_system_message_raw(
@ -370,7 +358,7 @@ impl BlockBehaviour for BedBlock {
} }
} }
args.player.sleep(bed_head_pos).await; args.player.sleep(bed_head_pos);
Self::set_occupied(true, args.world, args.block, args.position, state_id).await; Self::set_occupied(true, args.world, args.block, args.position, state_id).await;
BlockActionResult::SuccessServer BlockActionResult::SuccessServer

View File

@ -86,7 +86,7 @@ pub struct BlastFurnaceBlock;
impl BlockBehaviour for BlastFurnaceBlock { impl BlockBehaviour for BlastFurnaceBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(inventory) = block_entity.clone().get_inventory() && let Some(inventory) = block_entity.clone().get_inventory()
&& let Some(property_delegate) = block_entity.clone().to_property_delegate() && let Some(property_delegate) = block_entity.clone().to_property_delegate()
&& let Some(experience_container) = block_entity.to_experience_container() && let Some(experience_container) = block_entity.to_experience_container()
@ -130,7 +130,7 @@ impl BlockBehaviour for BlastFurnaceBlock {
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
// Extract and drop accumulated XP as orbs before removing the block entity // Extract and drop accumulated XP as orbs before removing the block entity
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(experience_container) = block_entity.to_experience_container() && let Some(experience_container) = block_entity.to_experience_container()
{ {
let xp = experience_container.extract_experience(); let xp = experience_container.extract_experience();

View File

@ -52,7 +52,7 @@ pub struct BrewingStandBlock;
impl BlockBehaviour for BrewingStandBlock { impl BlockBehaviour for BrewingStandBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(inventory) = block_entity.clone().get_inventory() && let Some(inventory) = block_entity.clone().get_inventory()
&& let Some(pd) = block_entity.clone().to_property_delegate() && let Some(pd) = block_entity.clone().to_property_delegate()
{ {

View File

@ -84,15 +84,15 @@ impl CakeBlock {
impl BlockBehaviour for CakeBlock { impl BlockBehaviour for CakeBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
Block::CAKE.default_state.id Block::CAKE.default_state.id
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
fn use_with_item<'a>( fn use_with_item<'a>(
@ -100,7 +100,7 @@ impl BlockBehaviour for CakeBlock {
args: UseWithItemArgs<'a>, args: UseWithItemArgs<'a>,
) -> BlockFuture<'a, BlockActionResult> { ) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let properties = CakeLikeProperties::from_state_id(state_id, args.block); let properties = CakeLikeProperties::from_state_id(state_id, args.block);
let item_lock = args.item_stack.lock().await; let item_lock = args.item_stack.lock().await;
let item = item_lock.item; let item = item_lock.item;
@ -159,7 +159,7 @@ impl BlockBehaviour for CakeBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
Self::consume_if_hungry(args.world, args.player, args.block, args.position, state_id) Self::consume_if_hungry(args.world, args.player, args.block, args.position, state_id)
.await .await
}) })
@ -167,7 +167,7 @@ impl BlockBehaviour for CakeBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -180,7 +180,7 @@ impl BlockBehaviour for CakeBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -190,7 +190,7 @@ impl BlockBehaviour for CakeBlock {
} }
} }
async fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool { fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool {
let state = world.get_block_state(&position.down()).await; let state = world.get_block_state(&position.down());
state.is_solid() state.is_solid()
} }

View File

@ -66,7 +66,7 @@ impl BlockBehaviour for CampfireBlock {
CampfireLikeProperties::from_state_id(args.block.default_state.id, args.block); CampfireLikeProperties::from_state_id(args.block.default_state.id, args.block);
props.waterlogged = is_replacing_water; props.waterlogged = is_replacing_water;
props.signal_fire = props.signal_fire =
is_signal_fire_base_block(args.world.get_block(&args.position.down()).await); is_signal_fire_base_block(args.world.get_block(&args.position.down()));
props.lit = !is_replacing_water; props.lit = !is_replacing_water;
props.facing = args.player.get_entity().get_horizontal_facing(); props.facing = args.player.get_entity().get_horizontal_facing();
props.to_state_id(args.block) props.to_state_id(args.block)
@ -93,7 +93,7 @@ impl BlockBehaviour for CampfireBlock {
if args.direction == BlockDirection::Down { if args.direction == BlockDirection::Down {
props.signal_fire = props.signal_fire =
is_signal_fire_base_block(args.world.get_block(args.neighbor_position).await); is_signal_fire_base_block(args.world.get_block(args.neighbor_position));
} }
props.to_state_id(args.block) props.to_state_id(args.block)

View File

@ -92,7 +92,7 @@ impl CandleCakeBlock {
) )
.await; .await;
let (block, state) = world.get_block_and_state_id(location).await; let (block, state) = world.get_block_and_state_id(location);
CakeBlock::consume_if_hungry(world, player, block, location, state).await CakeBlock::consume_if_hungry(world, player, block, location, state).await
} }
@ -122,7 +122,7 @@ impl BlockBehaviour for CandleCakeBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -135,7 +135,7 @@ impl BlockBehaviour for CandleCakeBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -145,7 +145,7 @@ impl BlockBehaviour for CandleCakeBlock {
} }
} }
async fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool { fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool {
let state = world.get_block_state(&position.down()).await; let state = world.get_block_state(&position.down());
state.is_solid() state.is_solid()
} }

View File

@ -50,7 +50,7 @@ impl BlockBehaviour for CandleBlock {
args: UseWithItemArgs<'a>, args: UseWithItemArgs<'a>,
) -> BlockFuture<'a, BlockActionResult> { ) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
let mut properties = CandleLikeProperties::from_state_id(state.id, args.block); let mut properties = CandleLikeProperties::from_state_id(state.id, args.block);
let item_lock = args.item_stack.lock().await; let item_lock = args.item_stack.lock().await;
@ -102,7 +102,7 @@ impl BlockBehaviour for CandleBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let mut properties = CandleLikeProperties::from_state_id(state_id, args.block); let mut properties = CandleLikeProperties::from_state_id(state_id, args.block);
if properties.lit { if properties.lit {
@ -121,22 +121,20 @@ impl BlockBehaviour for CandleBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
fn can_update_at<'a>(&'a self, args: CanUpdateAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_update_at(&self, args: CanUpdateAtArgs<'_>) -> bool {
Box::pin(async move { let b = BlockAccessor::get_block(args.world, args.position);
let b = args.world.get_block(args.position).await; args.player.get_entity().pose.load() != EntityPose::Crouching
args.player.get_entity().pose.load() != EntityPose::Crouching && CandleLikeProperties::from_state_id(args.state_id, args.block).candles != 4
&& CandleLikeProperties::from_state_id(args.state_id, args.block).candles != 4 && args.block.id == b.id
&& args.block.id == b.id
})
} }
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -149,7 +147,7 @@ impl BlockBehaviour for CandleBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -159,7 +157,7 @@ impl BlockBehaviour for CandleBlock {
} }
} }
async fn can_place_at(block_accessor: &dyn BlockAccessor, position: &BlockPos) -> bool { fn can_place_at(block_accessor: &dyn BlockAccessor, position: &BlockPos) -> bool {
let (support_block, state) = block_accessor.get_block_and_state(&position.down()).await; let (support_block, state) = block_accessor.get_block_and_state(&position.down());
!support_block.is_waterlogged(state.id) && state.is_center_solid(BlockDirection::Up) !support_block.is_waterlogged(state.id) && state.is_center_solid(BlockDirection::Up)
} }

View File

@ -12,8 +12,8 @@ use pumpkin_world::world::{BlockAccessor, BlockFlags};
pub struct CarpetBlock; pub struct CarpetBlock;
impl BlockBehaviour for CarpetBlock { impl BlockBehaviour for CarpetBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -21,7 +21,7 @@ impl BlockBehaviour for CarpetBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -32,7 +32,7 @@ impl BlockBehaviour for CarpetBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -45,8 +45,8 @@ impl BlockBehaviour for CarpetBlock {
pub struct MossCarpetBlock; pub struct MossCarpetBlock;
impl BlockBehaviour for MossCarpetBlock { impl BlockBehaviour for MossCarpetBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -54,7 +54,7 @@ impl BlockBehaviour for MossCarpetBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -65,7 +65,7 @@ impl BlockBehaviour for MossCarpetBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -78,8 +78,8 @@ impl BlockBehaviour for MossCarpetBlock {
pub struct PaleMossCarpetBlock; pub struct PaleMossCarpetBlock;
impl BlockBehaviour for PaleMossCarpetBlock { impl BlockBehaviour for PaleMossCarpetBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -87,7 +87,7 @@ impl BlockBehaviour for PaleMossCarpetBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -98,7 +98,7 @@ impl BlockBehaviour for PaleMossCarpetBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -107,6 +107,6 @@ impl BlockBehaviour for PaleMossCarpetBlock {
} }
} }
async fn can_place_at(block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
!is_air(block_accessor.get_block_state_id(&block_pos.down()).await) !is_air(block_accessor.get_block_state_id(&block_pos.down()))
} }

View File

@ -40,8 +40,8 @@ impl BlockBehaviour for CarvedPumpkinBlock {
// Mojang uses some BlockPattern magic, way too complex tbh // Mojang uses some BlockPattern magic, way too complex tbh
Box::pin(async { Box::pin(async {
let down_pos = args.position.down(); let down_pos = args.position.down();
let upper = args.world.get_block(&down_pos).await; let upper = args.world.get_block(&down_pos);
let lower = args.world.get_block(&down_pos.down()).await; let lower = args.world.get_block(&down_pos.down());
if upper == &Block::SNOW_BLOCK && lower == &Block::SNOW_BLOCK { if upper == &Block::SNOW_BLOCK && lower == &Block::SNOW_BLOCK {
for i in 0..3 { for i in 0..3 {
let pos = args.position.down_height(i); let pos = args.position.down_height(i);
@ -52,20 +52,18 @@ impl BlockBehaviour for CarvedPumpkinBlock {
BlockFlags::NOTIFY_LISTENERS, BlockFlags::NOTIFY_LISTENERS,
) )
.await; .await;
args.world args.world.sync_world_event(
.sync_world_event( WorldEvent::ParticlesDestroyBlock,
WorldEvent::ParticlesDestroyBlock, pos,
pos, Block::SNOW_BLOCK.default_state.id.into(),
Block::SNOW_BLOCK.default_state.id.into(), );
)
.await;
} }
let entity = Entity::new( let entity = Entity::new(
args.world.clone(), args.world.clone(),
down_pos.down().to_centered_f64(), down_pos.down().to_centered_f64(),
&EntityType::SNOW_GOLEM, &EntityType::SNOW_GOLEM,
); );
let golem = SnowGolemEntity::new(entity).await; let golem = SnowGolemEntity::new(entity);
args.world.spawn_entity(golem).await; args.world.spawn_entity(golem).await;
return; return;
} }
@ -76,8 +74,8 @@ impl BlockBehaviour for CarvedPumpkinBlock {
let arm1 = down_pos.offset(dir.to_offset()); let arm1 = down_pos.offset(dir.to_offset());
let arm2 = down_pos.offset(opposite.to_offset()); let arm2 = down_pos.offset(opposite.to_offset());
if args.world.get_block(&arm1).await == &Block::IRON_BLOCK if args.world.get_block(&arm1) == &Block::IRON_BLOCK
&& args.world.get_block(&arm2).await == &Block::IRON_BLOCK && args.world.get_block(&arm2) == &Block::IRON_BLOCK
{ {
let pattern = [*args.position, down_pos, down_pos.down(), arm1, arm2]; let pattern = [*args.position, down_pos, down_pos.down(), arm1, arm2];
@ -89,13 +87,11 @@ impl BlockBehaviour for CarvedPumpkinBlock {
BlockFlags::NOTIFY_LISTENERS, BlockFlags::NOTIFY_LISTENERS,
) )
.await; .await;
args.world args.world.sync_world_event(
.sync_world_event( WorldEvent::ParticlesDestroyBlock,
WorldEvent::ParticlesDestroyBlock, p,
p, Block::IRON_BLOCK.default_state.id.into(),
Block::IRON_BLOCK.default_state.id.into(), );
)
.await;
} }
let entity = Entity::new( let entity = Entity::new(
@ -103,7 +99,7 @@ impl BlockBehaviour for CarvedPumpkinBlock {
down_pos.down().to_centered_f64(), down_pos.down().to_centered_f64(),
&EntityType::IRON_GOLEM, &EntityType::IRON_GOLEM,
); );
let golem = IronGolemEntity::new(entity).await; let golem = IronGolemEntity::new(entity);
args.world.spawn_entity(golem).await; args.world.spawn_entity(golem).await;
return; return;
} }

View File

@ -2,7 +2,6 @@ use std::sync::Arc;
use crate::block::entities::BlockEntity; use crate::block::entities::BlockEntity;
use crate::block::entities::chest::ChestBlockEntity; use crate::block::entities::chest::ChestBlockEntity;
use futures::future::join;
use pumpkin_data::block_properties::{ use pumpkin_data::block_properties::{
BlockProperties, ChestLikeProperties, ChestType, HorizontalFacing, BlockProperties, ChestLikeProperties, ChestType, HorizontalFacing,
}; };
@ -75,7 +74,7 @@ impl ScreenHandlerFactory for ChestScreenFactory {
// Shared chest behavior implementations // Shared chest behavior implementations
const LID_ANIMATION_EVENT_TYPE: u8 = 1; const LID_ANIMATION_EVENT_TYPE: u8 = 1;
async fn on_place_chest_impl(args: OnPlaceArgs<'_>) -> BlockStateId { fn on_place_chest_impl(args: &OnPlaceArgs<'_>) -> BlockStateId {
let mut chest_props = ChestLikeProperties::default(args.block); let mut chest_props = ChestLikeProperties::default(args.block);
chest_props.waterlogged = args.replacing.water_source(); chest_props.waterlogged = args.replacing.water_source();
@ -85,8 +84,7 @@ async fn on_place_chest_impl(args: OnPlaceArgs<'_>) -> BlockStateId {
args.block, args.block,
args.position, args.position,
args.direction, args.direction,
) );
.await;
chest_props.facing = facing; chest_props.facing = facing;
chest_props.r#type = r#type; chest_props.r#type = r#type;
@ -114,9 +112,7 @@ async fn placed_chest_impl<E: BlockEntity + 'static>(
chest_props.facing, chest_props.facing,
connected_towards, connected_towards,
ChestType::Single, ChestType::Single,
) ) {
.await
{
neighbor_props.r#type = chest_props.r#type.opposite(); neighbor_props.r#type = chest_props.r#type.opposite();
args.world args.world
@ -130,11 +126,8 @@ async fn placed_chest_impl<E: BlockEntity + 'static>(
} }
async fn normal_use_chest_impl(args: NormalUseArgs<'_>) -> BlockActionResult { async fn normal_use_chest_impl(args: NormalUseArgs<'_>) -> BlockActionResult {
let (state, first_chest) = join( let state = args.world.get_block_state_id(args.position);
args.world.get_block_state_id(args.position), let first_chest = args.world.get_block_entity(args.position);
args.world.get_block_entity(args.position),
)
.await;
let Some(first_inventory) = first_chest.and_then(BlockEntity::get_inventory) else { let Some(first_inventory) = first_chest.and_then(BlockEntity::get_inventory) else {
return BlockActionResult::Fail; return BlockActionResult::Fail;
@ -147,13 +140,13 @@ async fn normal_use_chest_impl(args: NormalUseArgs<'_>) -> BlockActionResult {
ChestType::Right => Some(chest_props.facing.rotate_counter_clockwise()), ChestType::Right => Some(chest_props.facing.rotate_counter_clockwise()),
}; };
if is_chest_blocked(args.world, args.position).await { if is_chest_blocked(args.world, args.position) {
return BlockActionResult::Success; return BlockActionResult::Success;
} }
if let Some(direction) = connected_towards { if let Some(direction) = connected_towards {
let neighbor_pos = args.position.offset(direction.to_offset()); let neighbor_pos = args.position.offset(direction.to_offset());
if is_chest_blocked(args.world, &neighbor_pos).await { if is_chest_blocked(args.world, &neighbor_pos) {
return BlockActionResult::Success; return BlockActionResult::Success;
} }
} }
@ -162,7 +155,6 @@ async fn normal_use_chest_impl(args: NormalUseArgs<'_>) -> BlockActionResult {
&& let Some(second_inventory) = args && let Some(second_inventory) = args
.world .world
.get_block_entity(&args.position.offset(direction.to_offset())) .get_block_entity(&args.position.offset(direction.to_offset()))
.await
.and_then(BlockEntity::get_inventory) .and_then(BlockEntity::get_inventory)
{ {
// Vanilla: chestType == ChestType.RIGHT ? DoubleBlockProperties.Type.FIRST : DoubleBlockProperties.Type.SECOND; // Vanilla: chestType == ChestType.RIGHT ? DoubleBlockProperties.Type.FIRST : DoubleBlockProperties.Type.SECOND;
@ -197,9 +189,7 @@ async fn broken_chest_impl(args: BrokenArgs<'_>) {
chest_props.facing, chest_props.facing,
connected_towards, connected_towards,
chest_props.r#type.opposite(), chest_props.r#type.opposite(),
) ) {
.await
{
neighbor_props.r#type = ChestType::Single; neighbor_props.r#type = ChestType::Single;
args.world args.world
@ -217,7 +207,7 @@ pub struct ChestBlock;
impl BlockBehaviour for ChestBlock { impl BlockBehaviour for ChestBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(on_place_chest_impl(args)) Box::pin(async move { on_place_chest_impl(&args) })
} }
fn on_synced_block_event<'a>( fn on_synced_block_event<'a>(
@ -246,7 +236,7 @@ pub struct CopperChestBlock;
impl BlockBehaviour for CopperChestBlock { impl BlockBehaviour for CopperChestBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(on_place_chest_impl(args)) Box::pin(async move { on_place_chest_impl(&args) })
} }
fn on_synced_block_event<'a>( fn on_synced_block_event<'a>(
@ -270,7 +260,7 @@ impl BlockBehaviour for CopperChestBlock {
fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> { fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let current_state_id = args.world.get_block_state_id(args.position).await; let current_state_id = args.world.get_block_state_id(args.position);
let chest_props = ChestLikeProperties::from_state_id(current_state_id, args.block); let chest_props = ChestLikeProperties::from_state_id(current_state_id, args.block);
// Only oxidize LEFT or SINGLE chests (not RIGHT) to prevent double oxidation // Only oxidize LEFT or SINGLE chests (not RIGHT) to prevent double oxidation
@ -279,7 +269,7 @@ impl BlockBehaviour for CopperChestBlock {
} }
// Only oxidize if no players are viewing the chest // Only oxidize if no players are viewing the chest
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(chest_entity) = block_entity.as_any().downcast_ref::<ChestBlockEntity>() && let Some(chest_entity) = block_entity.as_any().downcast_ref::<ChestBlockEntity>()
&& chest_entity.get_viewer_count() > 0 && chest_entity.get_viewer_count() > 0
{ {
@ -355,7 +345,7 @@ async fn try_oxidize_copper_chest(
// Scan neighbors in 4-block Manhattan distance to calculate oxidation chance // Scan neighbors in 4-block Manhattan distance to calculate oxidation chance
let (same_level_count, higher_level_count) = let (same_level_count, higher_level_count) =
count_neighbor_oxidation_levels(world, position, current_level).await; count_neighbor_oxidation_levels(world, position, current_level);
// If we found any neighbors at a LOWER level, oxidation is blocked // If we found any neighbors at a LOWER level, oxidation is blocked
// (This is handled in count_neighbor_oxidation_levels by returning early) // (This is handled in count_neighbor_oxidation_levels by returning early)
@ -380,7 +370,7 @@ async fn try_oxidize_copper_chest(
/// Count copper blocks at same and higher oxidation levels within 4-block Manhattan distance. /// Count copper blocks at same and higher oxidation levels within 4-block Manhattan distance.
/// Returns (same, higher) counts, or (0, 0) if a lower-level neighbor was found (blocking oxidation). /// Returns (same, higher) counts, or (0, 0) if a lower-level neighbor was found (blocking oxidation).
async fn count_neighbor_oxidation_levels( fn count_neighbor_oxidation_levels(
world: &Arc<World>, world: &Arc<World>,
center: &BlockPos, center: &BlockPos,
current_level: u8, current_level: u8,
@ -405,7 +395,7 @@ async fn count_neighbor_oxidation_levels(
center.0.z + dz, center.0.z + dz,
)); ));
let neighbor_block = world.get_block(&neighbor_pos).await; let neighbor_block = world.get_block(&neighbor_pos);
if let Some(neighbor_level) = get_oxidation_level(neighbor_block) { if let Some(neighbor_level) = get_oxidation_level(neighbor_block) {
match neighbor_level.cmp(&current_level) { match neighbor_level.cmp(&current_level) {
@ -434,7 +424,7 @@ pub struct TrappedChestBlock;
impl BlockBehaviour for TrappedChestBlock { impl BlockBehaviour for TrappedChestBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(on_place_chest_impl(args)) Box::pin(async move { on_place_chest_impl(&args) })
} }
fn on_synced_block_event<'a>( fn on_synced_block_event<'a>(
@ -473,7 +463,7 @@ impl BlockBehaviour for TrappedChestBlock {
// Get viewer count from this chest // Get viewer count from this chest
let viewer_count = if let Some(block_entity) = let viewer_count = if let Some(block_entity) =
args.world.get_block_entity(args.position).await args.world.get_block_entity(args.position)
&& let Some(trapped_chest) = block_entity && let Some(trapped_chest) = block_entity
.as_any() .as_any()
.downcast_ref::<TrappedChestBlockEntity>() .downcast_ref::<TrappedChestBlockEntity>()
@ -503,7 +493,7 @@ impl BlockBehaviour for TrappedChestBlock {
} }
} }
async fn compute_chest_props( fn compute_chest_props(
world: &World, world: &World,
player: &Player, player: &Player,
block: &Block, block: &Block,
@ -518,9 +508,8 @@ async fn compute_chest_props(
return (ChestType::Single, chest_facing); return (ChestType::Single, chest_facing);
}; };
let (clicked_block, clicked_block_state) = world let (clicked_block, clicked_block_state) =
.get_block_and_state_id(&block_pos.offset(face.to_offset())) world.get_block_and_state_id(&block_pos.offset(face.to_offset()));
.await;
if clicked_block == block { if clicked_block == block {
let clicked_props = let clicked_props =
@ -548,7 +537,6 @@ async fn compute_chest_props(
chest_facing.rotate_clockwise(), chest_facing.rotate_clockwise(),
ChestType::Single, ChestType::Single,
) )
.await
.is_some() .is_some()
{ {
(ChestType::Left, chest_facing) (ChestType::Left, chest_facing)
@ -560,7 +548,6 @@ async fn compute_chest_props(
chest_facing.rotate_counter_clockwise(), chest_facing.rotate_counter_clockwise(),
ChestType::Single, ChestType::Single,
) )
.await
.is_some() .is_some()
{ {
(ChestType::Right, chest_facing) (ChestType::Right, chest_facing)
@ -569,7 +556,7 @@ async fn compute_chest_props(
} }
} }
async fn get_chest_properties_if_can_connect( fn get_chest_properties_if_can_connect(
world: &World, world: &World,
block: &Block, block: &Block,
block_pos: &BlockPos, block_pos: &BlockPos,
@ -577,9 +564,8 @@ async fn get_chest_properties_if_can_connect(
direction: HorizontalFacing, direction: HorizontalFacing,
wanted_type: ChestType, wanted_type: ChestType,
) -> Option<ChestLikeProperties> { ) -> Option<ChestLikeProperties> {
let (neighbor_block, neighbor_block_state) = world let (neighbor_block, neighbor_block_state) =
.get_block_and_state_id(&block_pos.offset(direction.to_offset())) world.get_block_and_state_id(&block_pos.offset(direction.to_offset()));
.await;
if neighbor_block != block { if neighbor_block != block {
return None; return None;
@ -593,13 +579,13 @@ async fn get_chest_properties_if_can_connect(
None None
} }
async fn is_chest_blocked(world: &World, block_pos: &BlockPos) -> bool { fn is_chest_blocked(world: &World, block_pos: &BlockPos) -> bool {
// TODO: Block opening when a cat is sitting on top. // TODO: Block opening when a cat is sitting on top.
has_block_on_top(world, block_pos).await has_block_on_top(world, block_pos)
} }
async fn has_block_on_top(world: &World, block_pos: &BlockPos) -> bool { fn has_block_on_top(world: &World, block_pos: &BlockPos) -> bool {
let above_pos = block_pos.up(); let above_pos = block_pos.up();
let above_state = world.get_block_state(&above_pos).await; let above_state = world.get_block_state(&above_pos);
above_state.is_solid_block() above_state.is_solid_block()
} }

View File

@ -41,12 +41,12 @@ impl BlockBehaviour for ChiseledBookshelfBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
let properties = ChiseledBookshelfLikeProperties::from_state_id(state.id, args.block); let properties = ChiseledBookshelfLikeProperties::from_state_id(state.id, args.block);
if let Some(slot) = Self::get_slot_for_hit(args.hit, properties.facing) { if let Some(slot) = Self::get_slot_for_hit(args.hit, properties.facing) {
if Self::is_slot_used(properties, slot) { if Self::is_slot_used(properties, slot) {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(block_entity) = block_entity && let Some(block_entity) = block_entity
.as_any() .as_any()
.downcast_ref::<ChiseledBookshelfBlockEntity>() .downcast_ref::<ChiseledBookshelfBlockEntity>()
@ -75,7 +75,7 @@ impl BlockBehaviour for ChiseledBookshelfBlock {
args: UseWithItemArgs<'a>, args: UseWithItemArgs<'a>,
) -> BlockFuture<'a, BlockActionResult> { ) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
let properties = ChiseledBookshelfLikeProperties::from_state_id(state.id, args.block); let properties = ChiseledBookshelfLikeProperties::from_state_id(state.id, args.block);
if !args if !args
@ -90,7 +90,7 @@ impl BlockBehaviour for ChiseledBookshelfBlock {
if let Some(slot) = Self::get_slot_for_hit(args.hit, properties.facing) { if let Some(slot) = Self::get_slot_for_hit(args.hit, properties.facing) {
if Self::is_slot_used(properties, slot) { if Self::is_slot_used(properties, slot) {
return BlockActionResult::PassToDefaultBlockAction; return BlockActionResult::PassToDefaultBlockAction;
} else if let Some(block_entity) = args.world.get_block_entity(args.position).await } else if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(block_entity) = block_entity && let Some(block_entity) = block_entity
.as_any() .as_any()
.downcast_ref::<ChiseledBookshelfBlockEntity>() .downcast_ref::<ChiseledBookshelfBlockEntity>()
@ -125,7 +125,7 @@ impl BlockBehaviour for ChiseledBookshelfBlock {
args: GetComparatorOutputArgs<'a>, args: GetComparatorOutputArgs<'a>,
) -> BlockFuture<'a, Option<u8>> { ) -> BlockFuture<'a, Option<u8>> {
Box::pin(async move { Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(block_entity) = block_entity && let Some(block_entity) = block_entity
.as_any() .as_any()
.downcast_ref::<ChiseledBookshelfBlockEntity>() .downcast_ref::<ChiseledBookshelfBlockEntity>()
@ -164,9 +164,7 @@ impl ChiseledBookshelfBlock {
.await; .await;
entity.update_state(properties, world.clone(), slot).await; entity.update_state(properties, world.clone(), slot).await;
world world.play_sound(sound, SoundCategory::Blocks, &position.to_centered_f64());
.play_sound(sound, SoundCategory::Blocks, &position.to_centered_f64())
.await;
} }
async fn try_remove_book( async fn try_remove_book(
@ -195,9 +193,7 @@ impl ChiseledBookshelfBlock {
} }
entity.update_state(properties, world.clone(), slot).await; entity.update_state(properties, world.clone(), slot).await;
world world.play_sound(sound, SoundCategory::Blocks, &position.to_centered_f64());
.play_sound(sound, SoundCategory::Blocks, &position.to_centered_f64())
.await;
} }
fn get_slot_for_hit(hit: &BlockHitResult<'_>, facing: HorizontalFacing) -> Option<i8> { fn get_slot_for_hit(hit: &BlockHitResult<'_>, facing: HorizontalFacing) -> Option<i8> {

View File

@ -23,13 +23,13 @@ use tracing::warn;
pub struct CommandBlock; pub struct CommandBlock;
impl CommandBlock { impl CommandBlock {
async fn get_relative_facing( fn get_relative_facing(
world: &World, world: &World,
pos: &BlockPos, pos: &BlockPos,
dir: Facing, dir: Facing,
) -> Option<(BlockPos, CommandBlockLikeProperties)> { ) -> Option<(BlockPos, CommandBlockLikeProperties)> {
let target_pos = pos.offset(dir.to_block_direction().to_offset()); let target_pos = pos.offset(dir.to_block_direction().to_offset());
let block = world.get_block(&target_pos).await; let block = world.get_block(&target_pos);
let allowed_blocks = [ let allowed_blocks = [
Block::COMMAND_BLOCK.name, Block::COMMAND_BLOCK.name,
@ -40,24 +40,24 @@ impl CommandBlock {
return None; return None;
} }
let state_id = world.get_block_state_id(&target_pos).await; let state_id = world.get_block_state_id(&target_pos);
let props = CommandBlockLikeProperties::from_state_id(state_id, block); let props = CommandBlockLikeProperties::from_state_id(state_id, block);
Some((target_pos, props)) Some((target_pos, props))
} }
async fn conditions_met(world: &Arc<World>, pos: &BlockPos, facing: Facing) -> bool { fn conditions_met(world: &Arc<World>, pos: &BlockPos, facing: Facing) -> bool {
let (block, state_id) = world.get_block_and_state_id(pos).await; let (block, state_id) = world.get_block_and_state_id(pos);
let props = CommandBlockLikeProperties::from_state_id(state_id, block); let props = CommandBlockLikeProperties::from_state_id(state_id, block);
if !props.conditional { if !props.conditional {
return true; return true;
} }
let Some(before) = Self::get_relative_facing(world, pos, facing.opposite()).await else { let Some(before) = Self::get_relative_facing(world, pos, facing.opposite()) else {
return false; return false;
}; };
let Some(before_entity) = world.get_block_entity(&before.0).await else { let Some(before_entity) = world.get_block_entity(&before.0) else {
warn!("Command block has no matching entity"); warn!("Command block has no matching entity");
return false; return false;
}; };
@ -83,7 +83,7 @@ impl CommandBlock {
return; return;
} }
let state_id = world.get_block_state_id(pos).await; let state_id = world.get_block_state_id(pos);
let props = CommandBlockLikeProperties::from_state_id(state_id, block); let props = CommandBlockLikeProperties::from_state_id(state_id, block);
if !props.conditional { if !props.conditional {
@ -93,11 +93,10 @@ impl CommandBlock {
return; return;
} }
let Some(behind) = Self::get_relative_facing(world, pos, props.facing.opposite()).await let Some(behind) = Self::get_relative_facing(world, pos, props.facing.opposite()) else {
else {
return; return;
}; };
let Some(behind_entity) = world.get_block_entity(&behind.0).await else { let Some(behind_entity) = world.get_block_entity(&behind.0) else {
warn!( warn!(
"Command Block exists at {} with no matching block entity!", "Command Block exists at {} with no matching block entity!",
behind.0 behind.0
@ -159,12 +158,12 @@ impl CommandBlock {
if !command_blocks_work { if !command_blocks_work {
return; return;
} }
let block = world.get_block(&pos).await; let block = world.get_block(&pos);
if block.id != Block::CHAIN_COMMAND_BLOCK.id { if block.id != Block::CHAIN_COMMAND_BLOCK.id {
break; break;
} }
let Some(block_entity) = world.get_block_entity(&pos).await else { let Some(block_entity) = world.get_block_entity(&pos) else {
warn!("Missing command block entity"); warn!("Missing command block entity");
break; break;
}; };
@ -172,14 +171,14 @@ impl CommandBlock {
let command_entity: &CommandBlockEntity = block_entity.as_any().downcast_ref().unwrap(); let command_entity: &CommandBlockEntity = block_entity.as_any().downcast_ref().unwrap();
let powered = command_entity.powered.load(Ordering::Relaxed); let powered = command_entity.powered.load(Ordering::Relaxed);
let auto = command_entity.auto.load(Ordering::Relaxed); let auto = command_entity.auto.load(Ordering::Relaxed);
let state_id = world.get_block_state_id(&pos).await; let state_id = world.get_block_state_id(&pos);
let props = CommandBlockLikeProperties::from_state_id(state_id, block); let props = CommandBlockLikeProperties::from_state_id(state_id, block);
if powered || auto { if powered || auto {
let conditions_met = Self::conditions_met(&world, &pos, direction).await; let conditions_met = Self::conditions_met(&world, &pos, direction);
if conditions_met { if conditions_met {
let command = command_entity.command.lock().await; let command = command_entity.command.lock().await;
let entity = world.get_block_entity(&pos).await.unwrap(); let entity = world.get_block_entity(&pos).unwrap();
Self::execute(server, world.clone(), entity, &command).await; Self::execute(server, world.clone(), entity, &command).await;
} else if props.conditional { } else if props.conditional {
command_entity.success_count.store(0, Ordering::Release); command_entity.success_count.store(0, Ordering::Release);
@ -224,7 +223,7 @@ impl BlockBehaviour for CommandBlock {
if args.player.permission_lvl.load() < PermissionLvl::Two { if args.player.permission_lvl.load() < PermissionLvl::Two {
return BlockActionResult::Pass; return BlockActionResult::Pass;
} }
let Some(block_entity) = args.world.get_block_entity(args.position).await else { let Some(block_entity) = args.world.get_block_entity(args.position) else {
return BlockActionResult::Pass; return BlockActionResult::Pass;
}; };
args.world.update_block_entity(&block_entity).await; args.world.update_block_entity(&block_entity).await;
@ -239,7 +238,7 @@ impl BlockBehaviour for CommandBlock {
if !command_blocks_work { if !command_blocks_work {
return; return;
} }
if let Some(block_entity) = args.world.get_block_entity(args.position).await { if let Some(block_entity) = args.world.get_block_entity(args.position) {
if block_entity.resource_location() != CommandBlockEntity::ID { if block_entity.resource_location() != CommandBlockEntity::ID {
return; return;
} }
@ -267,7 +266,7 @@ impl BlockBehaviour for CommandBlock {
if !command_blocks_work { if !command_blocks_work {
return; return;
} }
let Some(block_entity) = args.world.get_block_entity(args.position).await else { let Some(block_entity) = args.world.get_block_entity(args.position) else {
return; return;
}; };
if block_entity.resource_location() != CommandBlockEntity::ID { if block_entity.resource_location() != CommandBlockEntity::ID {
@ -279,7 +278,7 @@ impl BlockBehaviour for CommandBlock {
return; return;
}; };
let props = CommandBlockLikeProperties::from_state_id( let props = CommandBlockLikeProperties::from_state_id(
args.world.get_block_state_id(args.position).await, args.world.get_block_state_id(args.position),
args.block, args.block,
); );
@ -300,7 +299,7 @@ impl BlockBehaviour for CommandBlock {
) )
.await; .await;
let block = args.world.get_block(args.position).await; let block = args.world.get_block(args.position);
let is_auto = command_entity.auto.load(Ordering::Relaxed); let is_auto = command_entity.auto.load(Ordering::Relaxed);
let can_run = command_entity.powered.load(Ordering::Relaxed) || is_auto; let can_run = command_entity.powered.load(Ordering::Relaxed) || is_auto;
if block == &Block::REPEATING_COMMAND_BLOCK && can_run { if block == &Block::REPEATING_COMMAND_BLOCK && can_run {
@ -311,16 +310,14 @@ impl BlockBehaviour for CommandBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { if let Some(player) = args.player
if let Some(player) = args.player && player.gamemode.load() == GameMode::Creative
&& player.gamemode.load() == GameMode::Creative {
{ return true;
return true; }
}
false false
})
} }
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
@ -344,7 +341,7 @@ impl BlockBehaviour for CommandBlock {
args: crate::block::GetComparatorOutputArgs<'a>, args: crate::block::GetComparatorOutputArgs<'a>,
) -> BlockFuture<'a, Option<u8>> { ) -> BlockFuture<'a, Option<u8>> {
Box::pin(async { Box::pin(async {
let entity = args.world.get_block_entity(args.position).await; let entity = args.world.get_block_entity(args.position);
entity.map_or_else( entity.map_or_else(
|| { || {

View File

@ -29,7 +29,7 @@ pub struct ComposterBlock;
impl BlockBehaviour for ComposterBlock { impl BlockBehaviour for ComposterBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let props = ComposterLikeProperties::from_state_id(state_id, args.block); let props = ComposterLikeProperties::from_state_id(state_id, args.block);
if props.level == 8 { if props.level == 8 {
self.clear_composter(args.world, args.position, state_id, args.block) self.clear_composter(args.world, args.position, state_id, args.block)
@ -45,7 +45,7 @@ impl BlockBehaviour for ComposterBlock {
args: UseWithItemArgs<'a>, args: UseWithItemArgs<'a>,
) -> BlockFuture<'a, BlockActionResult> { ) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let props = ComposterLikeProperties::from_state_id(state_id, args.block); let props = ComposterLikeProperties::from_state_id(state_id, args.block);
let level = props.level; let level = props.level;
@ -80,8 +80,7 @@ impl BlockBehaviour for ComposterBlock {
) )
.await; .await;
args.world args.world
.sync_world_event(WorldEvent::ComposterFill, *args.position, 1) .sync_world_event(WorldEvent::ComposterFill, *args.position, 1);
.await;
} }
// Consume the item // Consume the item
@ -91,7 +90,7 @@ impl BlockBehaviour for ComposterBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let props = ComposterLikeProperties::from_state_id(state_id, args.block); let props = ComposterLikeProperties::from_state_id(state_id, args.block);
let level = props.level; let level = props.level;
if level == 7 { if level == 7 {
@ -161,8 +160,7 @@ impl ComposterBlock {
let item_entity = ItemEntity::new( let item_entity = ItemEntity::new(
Entity::new(world.clone(), item_position, &EntityType::ITEM), Entity::new(world.clone(), item_position, &EntityType::ITEM),
ItemStack::new(1, &Item::BONE_MEAL), ItemStack::new(1, &Item::BONE_MEAL),
) );
.await;
world.spawn_entity(Arc::new(item_entity)).await; world.spawn_entity(Arc::new(item_entity)).await;
} }

View File

@ -32,7 +32,7 @@ impl BlockBehaviour for DirtPathBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
return Block::DIRT.default_state.id; return Block::DIRT.default_state.id;
} }
@ -45,9 +45,7 @@ impl BlockBehaviour for DirtPathBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if args.direction == BlockDirection::Up if args.direction == BlockDirection::Up && !can_place_at(args.world, args.position) {
&& !can_place_at(args.world, args.position).await
{
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -56,12 +54,12 @@ impl BlockBehaviour for DirtPathBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
} }
async fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
let state = world.get_block_state(&block_pos.up()).await; let state = world.get_block_state(&block_pos.up());
!state.is_solid() // TODO: add fence gate block !state.is_solid() // TODO: add fence gate block
} }

View File

@ -37,7 +37,7 @@ use pumpkin_util::GameMode;
type DoorProperties = pumpkin_data::block_properties::OakDoorLikeProperties; type DoorProperties = pumpkin_data::block_properties::OakDoorLikeProperties;
async fn toggle_door(player: &Player, world: &Arc<World>, block_pos: &BlockPos) { async fn toggle_door(player: &Player, world: &Arc<World>, block_pos: &BlockPos) {
let (block, block_state) = world.get_block_and_state_id(block_pos).await; let (block, block_state) = world.get_block_and_state_id(block_pos);
let mut door_props = DoorProperties::from_state_id(block_state, block); let mut door_props = DoorProperties::from_state_id(block_state, block);
door_props.open = !door_props.open; door_props.open = !door_props.open;
@ -47,18 +47,16 @@ async fn toggle_door(player: &Player, world: &Arc<World>, block_pos: &BlockPos)
}; };
let other_pos = block_pos.offset(other_half.to_offset()); let other_pos = block_pos.offset(other_half.to_offset());
let (other_block, other_state_id) = world.get_block_and_state_id(&other_pos).await; let (other_block, other_state_id) = world.get_block_and_state_id(&other_pos);
let mut other_door_props = DoorProperties::from_state_id(other_state_id, other_block); let mut other_door_props = DoorProperties::from_state_id(other_state_id, other_block);
other_door_props.open = door_props.open; other_door_props.open = door_props.open;
world world.play_block_sound_expect(
.play_block_sound_expect( player,
player, get_sound(block, door_props.open),
get_sound(block, door_props.open), SoundCategory::Blocks,
SoundCategory::Blocks, *block_pos,
*block_pos, );
)
.await;
world world
.set_block_state( .set_block_state(
@ -114,24 +112,22 @@ async fn get_hinge(
let top_pos = pos.up(); let top_pos = pos.up();
let left_dir = facing.rotate_counter_clockwise(); let left_dir = facing.rotate_counter_clockwise();
let left_pos = pos.offset(left_dir.to_block_direction().to_offset()); let left_pos = pos.offset(left_dir.to_block_direction().to_offset());
let (left_block, left_state) = world.get_block_and_state(&left_pos).await; let (left_block, left_state) = world.get_block_and_state(&left_pos);
let top_facing = top_pos.offset(facing.to_block_direction().to_offset()); let top_facing = top_pos.offset(facing.to_block_direction().to_offset());
let top_state = world.get_block_state(&top_facing).await; let top_state = world.get_block_state(&top_facing);
let right_dir = facing.rotate_clockwise(); let right_dir = facing.rotate_clockwise();
let right_pos = pos.offset(right_dir.to_block_direction().to_offset()); let right_pos = pos.offset(right_dir.to_block_direction().to_offset());
let (right_block, right_state) = world.get_block_and_state(&right_pos).await; let (right_block, right_state) = world.get_block_and_state(&right_pos);
let top_right = top_pos.offset(facing.to_block_direction().to_offset()); let top_right = top_pos.offset(facing.to_block_direction().to_offset());
let top_right_state = world.get_block_state(&top_right).await; let top_right_state = world.get_block_state(&top_right);
let has_left_door = world let has_left_door = world
.get_block(&left_pos) .get_block(&left_pos)
.await
.has_tag(&tag::Block::MINECRAFT_DOORS) .has_tag(&tag::Block::MINECRAFT_DOORS)
&& DoorProperties::from_state_id(left_state.id, left_block).half == DoubleBlockHalf::Lower; && DoorProperties::from_state_id(left_state.id, left_block).half == DoubleBlockHalf::Lower;
let has_right_door = world let has_right_door = world
.get_block(&right_pos) .get_block(&right_pos)
.await
.has_tag(&tag::Block::MINECRAFT_DOORS) .has_tag(&tag::Block::MINECRAFT_DOORS)
&& DoorProperties::from_state_id(right_state.id, right_block).half && DoorProperties::from_state_id(right_state.id, right_block).half
== DoubleBlockHalf::Lower; == DoubleBlockHalf::Lower;
@ -184,8 +180,8 @@ impl BlockBehaviour for DoorBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
@ -223,7 +219,7 @@ impl BlockBehaviour for DoorBlock {
DoubleBlockHalf::Lower => args.position.up(), DoubleBlockHalf::Lower => args.position.up(),
}; };
let neighbor_block_id = args.world.get_block_state_id(&other_half_pos).await; let neighbor_block_id = args.world.get_block_state_id(&other_half_pos);
if neighbor_block_id != args.block.id { if neighbor_block_id != args.block.id {
args.world.update_neighbors(&other_half_pos, None).await; args.world.update_neighbors(&other_half_pos, None).await;
return; // Neighbor is already gone or is a different block return; // Neighbor is already gone or is a different block
@ -244,7 +240,7 @@ impl BlockBehaviour for DoorBlock {
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> { fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let block_state = args.world.get_block_state(args.position).await; let block_state = args.world.get_block_state(args.position);
let mut door_props = DoorProperties::from_state_id(block_state.id, args.block); let mut door_props = DoorProperties::from_state_id(block_state.id, args.block);
let other_half = match door_props.half { let other_half = match door_props.half {
@ -252,7 +248,7 @@ impl BlockBehaviour for DoorBlock {
DoubleBlockHalf::Lower => BlockDirection::Up, DoubleBlockHalf::Lower => BlockDirection::Up,
}; };
let other_pos = args.position.offset(other_half.to_offset()); let other_pos = args.position.offset(other_half.to_offset());
let (other_block, other_state_id) = args.world.get_block_and_state_id(&other_pos).await; let (other_block, other_state_id) = args.world.get_block_and_state_id(&other_pos);
if other_block.id != args.block.id { if other_block.id != args.block.id {
return; return;
@ -271,13 +267,11 @@ impl BlockBehaviour for DoorBlock {
door_props.open = door_props.powered; door_props.open = door_props.powered;
other_door_props.open = other_door_props.powered; other_door_props.open = other_door_props.powered;
args.world args.world.play_block_sound(
.play_block_sound( get_sound(args.block, powered),
get_sound(args.block, powered), SoundCategory::Blocks,
SoundCategory::Blocks, *args.position,
*args.position, );
)
.await;
} }
args.world args.world
@ -309,7 +303,7 @@ impl BlockBehaviour for DoorBlock {
{ {
if lv == DoubleBlockHalf::Lower if lv == DoubleBlockHalf::Lower
&& args.direction == BlockDirection::Down && args.direction == BlockDirection::Down
&& !can_place_at(args.world, args.position).await && !can_place_at(args.world, args.position)
{ {
return 0; return 0;
} }
@ -333,7 +327,7 @@ impl BlockBehaviour for DoorBlock {
return; return;
} }
let new_state_id = args.world.get_block_state_id(args.position).await; let new_state_id = args.world.get_block_state_id(args.position);
let new_block = Block::from_state_id(new_state_id); let new_block = Block::from_state_id(new_state_id);
if new_block == &Block::AIR { if new_block == &Block::AIR {
return; return;
@ -356,10 +350,9 @@ impl BlockBehaviour for DoorBlock {
} }
} }
async fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
world.get_block_state(&block_pos.up()).await.replaceable() world.get_block_state(&block_pos.up()).replaceable()
&& world && world
.get_block_state(&block_pos.down()) .get_block_state(&block_pos.down())
.await
.is_side_solid(BlockDirection::Up) .is_side_solid(BlockDirection::Up)
} }

View File

@ -19,11 +19,11 @@ impl DragonEggBlock {
let z = pos.0.z + rng().random_range(-16..16); let z = pos.0.z + rng().random_range(-16..16);
let test_pos = BlockPos::new(x, y, z); let test_pos = BlockPos::new(x, y, z);
let state = world.get_block_state(&test_pos).await; let state = world.get_block_state(&test_pos);
let below_state = world.get_block_state(&test_pos.down()).await; let below_state = world.get_block_state(&test_pos.down());
if state.is_air() && !below_state.is_air() { if state.is_air() && !below_state.is_air() {
let current_state = world.get_block_state(pos).await; let current_state = world.get_block_state(pos);
world world
.set_block_state( .set_block_state(
&test_pos, &test_pos,

View File

@ -28,16 +28,13 @@ impl BlockMetadata for DripstoneBlock {
} }
impl BlockBehaviour for DripstoneBlock { impl BlockBehaviour for DripstoneBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at_pos(
can_place_at_pos( args.block_accessor,
args.block_accessor, args.position,
args.position, args.direction,
args.direction, args.player,
args.player, )
)
.await
})
} }
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
@ -48,9 +45,7 @@ impl BlockBehaviour for DripstoneBlock {
args.position, args.position,
Some(args.direction), Some(args.direction),
Some(args.player), Some(args.player),
) ) else {
.await
else {
//this shouldn't happen //this shouldn't happen
return Block::AIR.id; return Block::AIR.id;
}; };
@ -65,8 +60,7 @@ impl BlockBehaviour for DripstoneBlock {
args.world, args.world,
args.position, args.position,
args.state_id, args.state_id,
) );
.await;
match vertical_dir { match vertical_dir {
VerticalDirection::Up => { VerticalDirection::Up => {
update_stalagmite(args.world, len, args.position).await; update_stalagmite(args.world, len, args.position).await;
@ -90,8 +84,7 @@ impl BlockBehaviour for DripstoneBlock {
args.world, args.world,
&new_tip_pos, &new_tip_pos,
args.state.id, args.state.id,
) );
.await;
match vertical_dir { match vertical_dir {
VerticalDirection::Up => { VerticalDirection::Up => {
update_stalagmite(args.world, len, &new_tip_pos).await; update_stalagmite(args.world, len, &new_tip_pos).await;
@ -107,7 +100,7 @@ impl BlockBehaviour for DripstoneBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at_pos(args.world, args.position, None, None).await { if !can_place_at_pos(args.world, args.position, None, None) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
let mut dripstone_props = let mut dripstone_props =
@ -117,14 +110,14 @@ impl BlockBehaviour for DripstoneBlock {
} }
match dripstone_props.vertical_direction { match dripstone_props.vertical_direction {
VerticalDirection::Up => { VerticalDirection::Up => {
let block_above = args.world.get_block(&args.position.up()).await; let block_above = args.world.get_block(&args.position.up());
if block_above != &Block::POINTED_DRIPSTONE { if block_above != &Block::POINTED_DRIPSTONE {
dripstone_props.thickness = DripstoneThickness::Tip; dripstone_props.thickness = DripstoneThickness::Tip;
return dripstone_props.to_state_id(args.block); return dripstone_props.to_state_id(args.block);
} }
} }
VerticalDirection::Down => { VerticalDirection::Down => {
let block_below = args.world.get_block(&args.position.down()).await; let block_below = args.world.get_block(&args.position.down());
if block_below != &Block::POINTED_DRIPSTONE { if block_below != &Block::POINTED_DRIPSTONE {
dripstone_props.thickness = DripstoneThickness::Tip; dripstone_props.thickness = DripstoneThickness::Tip;
return dripstone_props.to_state_id(args.block); return dripstone_props.to_state_id(args.block);
@ -136,7 +129,7 @@ impl BlockBehaviour for DripstoneBlock {
} }
} }
async fn update_stalagmite(world: &Arc<World>, stalagmite_len: u8, tip_pos: &BlockPos) { async fn update_stalagmite(world: &Arc<World>, stalagmite_len: u8, tip_pos: &BlockPos) {
let block_above = world.get_block(&tip_pos.up()).await; let block_above = world.get_block(&tip_pos.up());
if block_above == &Block::POINTED_DRIPSTONE { if block_above == &Block::POINTED_DRIPSTONE {
modify_dripstone_thickness_to(world, tip_pos, DripstoneThickness::TipMerge).await; modify_dripstone_thickness_to(world, tip_pos, DripstoneThickness::TipMerge).await;
modify_dripstone_thickness_to(world, &tip_pos.up(), DripstoneThickness::TipMerge).await; modify_dripstone_thickness_to(world, &tip_pos.up(), DripstoneThickness::TipMerge).await;
@ -203,7 +196,7 @@ async fn update_stalagmite(world: &Arc<World>, stalagmite_len: u8, tip_pos: &Blo
} }
async fn update_stalactite(world: &Arc<World>, stalagmite_len: u8, tip_pos: &BlockPos) { async fn update_stalactite(world: &Arc<World>, stalagmite_len: u8, tip_pos: &BlockPos) {
let block_below = world.get_block(&tip_pos.down()).await; let block_below = world.get_block(&tip_pos.down());
if block_below == &Block::POINTED_DRIPSTONE { if block_below == &Block::POINTED_DRIPSTONE {
modify_dripstone_thickness_to(world, tip_pos, DripstoneThickness::TipMerge).await; modify_dripstone_thickness_to(world, tip_pos, DripstoneThickness::TipMerge).await;
modify_dripstone_thickness_to(world, &tip_pos.down(), DripstoneThickness::TipMerge).await; modify_dripstone_thickness_to(world, &tip_pos.down(), DripstoneThickness::TipMerge).await;
@ -256,7 +249,7 @@ async fn update_stalactite(world: &Arc<World>, stalagmite_len: u8, tip_pos: &Blo
_ => {} _ => {}
} }
} }
async fn get_stalagmite_or_stalactice_len_and_dir_from_tip_pos( fn get_stalagmite_or_stalactice_len_and_dir_from_tip_pos(
world: &Arc<World>, world: &Arc<World>,
position: &BlockPos, position: &BlockPos,
block_state_id: BlockStateId, block_state_id: BlockStateId,
@ -268,7 +261,7 @@ async fn get_stalagmite_or_stalactice_len_and_dir_from_tip_pos(
let mut next_dripstone_pos = offset_pos_by_vertical_dir(position, props.vertical_direction); let mut next_dripstone_pos = offset_pos_by_vertical_dir(position, props.vertical_direction);
//We dont care if it's longer than 5 blocks because of how thickness system works. //We dont care if it's longer than 5 blocks because of how thickness system works.
while dripstone_len < 5 { while dripstone_len < 5 {
if world.get_block(&next_dripstone_pos).await != &Block::POINTED_DRIPSTONE { if world.get_block(&next_dripstone_pos) != &Block::POINTED_DRIPSTONE {
break; break;
} }
next_dripstone_pos = next_dripstone_pos =
@ -277,7 +270,7 @@ async fn get_stalagmite_or_stalactice_len_and_dir_from_tip_pos(
} }
(dripstone_len, props.vertical_direction) (dripstone_len, props.vertical_direction)
} }
async fn can_place_at_pos( fn can_place_at_pos(
block_accessor: &dyn BlockAccessor, block_accessor: &dyn BlockAccessor,
position: &BlockPos, position: &BlockPos,
placing_direction: Option<BlockDirection>, placing_direction: Option<BlockDirection>,
@ -289,22 +282,21 @@ async fn can_place_at_pos(
position, position,
placing_direction, placing_direction,
player_option, player_option,
) ) else {
.await
else {
return false; return false;
}; };
let support_pos = match support_block_vertical_direction { let support_pos = match support_block_vertical_direction {
VerticalDirection::Up => position.up(), VerticalDirection::Up => position.up(),
VerticalDirection::Down => position.down(), VerticalDirection::Down => position.down(),
}; };
let support_block = block_accessor.get_block(&support_pos).await; let support_block = block_accessor.get_block(&support_pos);
if can_support_dripstone(support_block) { if can_support_dripstone(support_block) {
return true; return true;
} }
false false
} }
async fn get_support_block_vertical_direction(
fn get_support_block_vertical_direction(
block_accessor: &dyn BlockAccessor, block_accessor: &dyn BlockAccessor,
position: &BlockPos, position: &BlockPos,
placing_direction_wrapper: Option<BlockDirection>, placing_direction_wrapper: Option<BlockDirection>,
@ -312,7 +304,7 @@ async fn get_support_block_vertical_direction(
) -> Option<VerticalDirection> { ) -> Option<VerticalDirection> {
let Some(placing_direction) = placing_direction_wrapper else { let Some(placing_direction) = placing_direction_wrapper else {
//then this is basically called by a neighbor update check //then this is basically called by a neighbor update check
let (block, state) = block_accessor.get_block_and_state(position).await; let (block, state) = block_accessor.get_block_and_state(position);
if block != &Block::POINTED_DRIPSTONE { if block != &Block::POINTED_DRIPSTONE {
return None; return None;
} }
@ -322,8 +314,8 @@ async fn get_support_block_vertical_direction(
match block_direction_to_vertical_direction(placing_direction) { match block_direction_to_vertical_direction(placing_direction) {
Some(ver_dir) => match ver_dir { Some(ver_dir) => match ver_dir {
VerticalDirection::Up => { VerticalDirection::Up => {
let block_above = block_accessor.get_block(&position.up()).await; let block_above = block_accessor.get_block(&position.up());
let block_below = block_accessor.get_block(&position.down()).await; let block_below = block_accessor.get_block(&position.down());
if can_support_dripstone(block_above) { if can_support_dripstone(block_above) {
return Some(VerticalDirection::Up); return Some(VerticalDirection::Up);
} else if can_support_dripstone(block_below) { } else if can_support_dripstone(block_below) {
@ -332,8 +324,8 @@ async fn get_support_block_vertical_direction(
None None
} }
VerticalDirection::Down => { VerticalDirection::Down => {
let block_above = block_accessor.get_block(&position.up()).await; let block_above = block_accessor.get_block(&position.up());
let block_below = block_accessor.get_block(&position.down()).await; let block_below = block_accessor.get_block(&position.down());
if can_support_dripstone(block_below) { if can_support_dripstone(block_below) {
return Some(VerticalDirection::Down); return Some(VerticalDirection::Down);
} else if can_support_dripstone(block_above) { } else if can_support_dripstone(block_above) {
@ -342,32 +334,29 @@ async fn get_support_block_vertical_direction(
None None
} }
}, },
None => match player_option { None => player_option.map_or(Some(VerticalDirection::Up), |player| {
Some(player) => { let (_, pitch) = player.rotation();
let (_, pitch) = player.rotation(); let (can_place_above, can_place_below) = {
let (can_place_above, can_place_below) = { let block_above = block_accessor.get_block(&position.up());
let block_above = block_accessor.get_block(&position.up()).await; let block_below = block_accessor.get_block(&position.down());
let block_below = block_accessor.get_block(&position.down()).await; (
( can_support_dripstone(block_above),
can_support_dripstone(block_above), can_support_dripstone(block_below),
can_support_dripstone(block_below), )
) };
}; match (can_place_above, can_place_below) {
match (can_place_above, can_place_below) { (true, true) => {
(true, true) => { if pitch > 0.0 {
if pitch > 0.0 { Some(VerticalDirection::Down)
Some(VerticalDirection::Down) } else {
} else { Some(VerticalDirection::Up)
Some(VerticalDirection::Up)
}
} }
(false, false) => None,
(true, false) => Some(VerticalDirection::Up),
(false, true) => Some(VerticalDirection::Down),
} }
(false, false) => None,
(true, false) => Some(VerticalDirection::Up),
(false, true) => Some(VerticalDirection::Down),
} }
None => Some(VerticalDirection::Up), }),
},
} }
} }
fn can_support_dripstone(support_block: &Block) -> bool { fn can_support_dripstone(support_block: &Block) -> bool {
@ -384,7 +373,7 @@ async fn modify_dripstone_thickness_to(
pos: &BlockPos, pos: &BlockPos,
new_thickness: DripstoneThickness, new_thickness: DripstoneThickness,
) { ) {
let (block, support_block_state_id) = world.get_block_and_state_id(pos).await; let (block, support_block_state_id) = world.get_block_and_state_id(pos);
if block != &Block::POINTED_DRIPSTONE { if block != &Block::POINTED_DRIPSTONE {
//this shouldn't happen //this shouldn't happen

View File

@ -2,7 +2,7 @@ use std::sync::Arc;
use crate::block::registry::BlockActionResult; use crate::block::registry::BlockActionResult;
use crate::block::{BlockBehaviour, BlockFuture, NormalUseArgs}; use crate::block::{BlockBehaviour, BlockFuture, NormalUseArgs};
use pumpkin_data::translation; use pumpkin_data::{Block, translation};
use pumpkin_inventory::enchanting::enchanting_screen_handler::EnchantingTableScreenHandler; use pumpkin_inventory::enchanting::enchanting_screen_handler::EnchantingTableScreenHandler;
use pumpkin_inventory::player::player_inventory::PlayerInventory; use pumpkin_inventory::player::player_inventory::PlayerInventory;
use pumpkin_inventory::screen_handler::{ use pumpkin_inventory::screen_handler::{
@ -25,37 +25,28 @@ impl BlockBehaviour for EnchantingTableBlock {
for off_z in -1..=1 { for off_z in -1..=1 {
for off_x in -1..=1 { for off_x in -1..=1 {
if (off_z != 0 || off_x != 0) if (off_z != 0 || off_x != 0)
&& args.world.get_block_state(&args.position.add(off_x, 0, off_z)).await.id == 0 // Air && args.world.get_block_state(&args.position.add(off_x, 0, off_z)).id == 0 // Air
&& args.world.get_block_state(&args.position.add(off_x, 1, off_z)).await.id == 0 && args.world.get_block_state(&args.position.add(off_x, 1, off_z)).id == 0
// Air // Air
{ {
for off_y in 0..=1 { for off_y in 0..=1 {
if self if Self::is_bookshelf(
.is_bookshelf( args.world,
args.world, &args.position.add(off_x * 2, off_y, off_z * 2),
&args.position.add(off_x * 2, off_y, off_z * 2), ) {
)
.await
{
bookshelf_count += 1; bookshelf_count += 1;
} }
if off_x != 0 && off_z != 0 { if off_x != 0 && off_z != 0 {
if self if Self::is_bookshelf(
.is_bookshelf( args.world,
args.world, &args.position.add(off_x * 2, off_y, off_z),
&args.position.add(off_x * 2, off_y, off_z), ) {
)
.await
{
bookshelf_count += 1; bookshelf_count += 1;
} }
if self if Self::is_bookshelf(
.is_bookshelf( args.world,
args.world, &args.position.add(off_x, off_y, off_z * 2),
&args.position.add(off_x, off_y, off_z * 2), ) {
)
.await
{
bookshelf_count += 1; bookshelf_count += 1;
} }
} }
@ -80,10 +71,10 @@ impl BlockBehaviour for EnchantingTableBlock {
} }
impl EnchantingTableBlock { impl EnchantingTableBlock {
async fn is_bookshelf(&self, world: &Arc<crate::world::World>, pos: &BlockPos) -> bool { fn is_bookshelf(world: &Arc<crate::world::World>, pos: &BlockPos) -> bool {
let state = world.get_block_state(pos).await; let state = world.get_block_state(pos);
let block = pumpkin_data::Block::from_state_id(state.id); let block = pumpkin_data::Block::from_state_id(state.id);
block.name == "bookshelf" block == &Block::BOOKSHELF
} }
} }

View File

@ -16,8 +16,7 @@ impl BlockBehaviour for EndRodBlock {
let blockstate = args let blockstate = args
.world .world
.get_block_state_id(&args.position.offset(args.direction.to_offset())) .get_block_state_id(&args.position.offset(args.direction.to_offset()));
.await;
if Block::from_state_id(blockstate).eq(args.block) if Block::from_state_id(blockstate).eq(args.block)
&& EndRodLikeProperties::from_state_id(blockstate, args.block).facing && EndRodLikeProperties::from_state_id(blockstate, args.block).facing

View File

@ -74,11 +74,11 @@ impl BlockBehaviour for EnderChestBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
if is_chest_blocked(args.world, args.position).await { if is_chest_blocked(args.world, args.position) {
return BlockActionResult::Success; return BlockActionResult::Success;
} }
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(block_entity) = block_entity && let Some(block_entity) = block_entity
.as_any() .as_any()
.downcast_ref::<EnderChestBlockEntity>() .downcast_ref::<EnderChestBlockEntity>()
@ -108,13 +108,13 @@ impl BlockBehaviour for EnderChestBlock {
} }
} }
async fn is_chest_blocked(world: &World, block_pos: &BlockPos) -> bool { fn is_chest_blocked(world: &World, block_pos: &BlockPos) -> bool {
// TODO: Block opening when a cat is sitting on top. // TODO: Block opening when a cat is sitting on top.
has_block_on_top(world, block_pos).await has_block_on_top(world, block_pos)
} }
async fn has_block_on_top(world: &World, block_pos: &BlockPos) -> bool { fn has_block_on_top(world: &World, block_pos: &BlockPos) -> bool {
let above_pos = block_pos.up(); let above_pos = block_pos.up();
let above_state = world.get_block_state(&above_pos).await; let above_state = world.get_block_state(&above_pos);
above_state.is_solid_block() above_state.is_solid_block()
} }
impl EnderChestBlock { impl EnderChestBlock {

View File

@ -52,11 +52,11 @@ impl BlockBehaviour for FallingBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let (block, state) = args.world.get_block_and_state(&args.position.down()).await; let (block, state) = args.world.get_block_and_state(&args.position.down());
if !Self::can_fall_through(state, block) || args.position.0.y < args.world.min_y { if !Self::can_fall_through(state, block) || args.position.0.y < args.world.min_y {
return; return;
} }
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
FallingEntity::replace_spawn(args.world, *args.position, state.id).await; FallingEntity::replace_spawn(args.world, *args.position, state.id).await;
}) })
} }

View File

@ -43,7 +43,7 @@ impl BlockBehaviour for FarmlandBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
return Block::DIRT.default_state.id; return Block::DIRT.default_state.id;
} }
args.block.default_state.id args.block.default_state.id
@ -55,9 +55,7 @@ impl BlockBehaviour for FarmlandBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if args.direction == BlockDirection::Up if args.direction == BlockDirection::Up && !can_place_at(args.world, args.position) {
&& !can_place_at(args.world, args.position).await
{
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -66,14 +64,14 @@ impl BlockBehaviour for FarmlandBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> { fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
// TODO: add rain check. Remember to check which one is most optimized. // TODO: add rain check. Remember to check which one is most optimized.
if is_water_nearby(args.world, args.position).await { if is_water_nearby(args.world, args.position) {
let mut props = FarmlandProperties::default(args.block); let mut props = FarmlandProperties::default(args.block);
props.moisture = 7; props.moisture = 7;
args.world args.world
@ -84,13 +82,12 @@ impl BlockBehaviour for FarmlandBlock {
) )
.await; .await;
} else { } else {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let mut props = FarmlandProperties::from_state_id(state_id, args.block); let mut props = FarmlandProperties::from_state_id(state_id, args.block);
if props.moisture == 0 { if props.moisture == 0 {
if !args if !args
.world .world
.get_block(&args.position.up()) .get_block(&args.position.up())
.await
.has_tag(&tag::Block::MINECRAFT_MAINTAINS_FARMLAND) .has_tag(&tag::Block::MINECRAFT_MAINTAINS_FARMLAND)
{ {
//TODO push entities up //TODO push entities up
@ -117,12 +114,12 @@ impl BlockBehaviour for FarmlandBlock {
} }
} }
async fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
let state = world.get_block_state(&block_pos.up()).await; let state = world.get_block_state(&block_pos.up());
!state.is_solid() // TODO: add fence gate block !state.is_solid() // TODO: add fence gate block
} }
async fn is_water_nearby(world: &Arc<World>, block_pos: &BlockPos) -> bool { fn is_water_nearby(world: &Arc<World>, block_pos: &BlockPos) -> bool {
for dx in -4..=4 { for dx in -4..=4 {
for dy in 0..=1 { for dy in 0..=1 {
for dz in -4..=4 { for dz in -4..=4 {
@ -132,7 +129,7 @@ async fn is_water_nearby(world: &Arc<World>, block_pos: &BlockPos) -> bool {
z: dz, z: dz,
}); });
//TODO this should use tag water. It does not seem to work rn. //TODO this should use tag water. It does not seem to work rn.
if world.get_block(&check_pos).await == &Block::WATER { if world.get_block(&check_pos) == &Block::WATER {
return true; return true;
} }
} }

View File

@ -42,7 +42,7 @@ pub async fn toggle_fence_gate(
block_pos: &BlockPos, block_pos: &BlockPos,
player: &Player, player: &Player,
) -> BlockStateId { ) -> BlockStateId {
let (block, state) = world.get_block_and_state_id(block_pos).await; let (block, state) = world.get_block_and_state_id(block_pos);
let mut fence_gate_props = FenceGateProperties::from_state_id(state, block); let mut fence_gate_props = FenceGateProperties::from_state_id(state, block);
if fence_gate_props.open { if fence_gate_props.open {
@ -60,14 +60,12 @@ pub async fn toggle_fence_gate(
fence_gate_props.open = true; fence_gate_props.open = true;
} }
world world.play_block_sound_expect(
.play_block_sound_expect( player,
player, get_sound(block, fence_gate_props.open),
get_sound(block, fence_gate_props.open), SoundCategory::Blocks,
SoundCategory::Blocks, *block_pos,
*block_pos, );
)
.await;
world world
.set_block_state( .set_block_state(
@ -101,7 +99,7 @@ impl BlockBehaviour for FenceGateBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
let fence_props = is_in_wall(&args).await; let fence_props = is_in_wall(&args);
fence_props.to_state_id(args.block) fence_props.to_state_id(args.block)
}) })
} }
@ -116,7 +114,7 @@ impl BlockBehaviour for FenceGateBlock {
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> { fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let block_state = args.world.get_block_state(args.position).await; let block_state = args.world.get_block_state(args.position);
let mut fence_gate_props = let mut fence_gate_props =
FenceGateProperties::from_state_id(block_state.id, args.block); FenceGateProperties::from_state_id(block_state.id, args.block);
let powered = block_receives_redstone_power(args.world, args.position).await; let powered = block_receives_redstone_power(args.world, args.position).await;
@ -130,13 +128,11 @@ impl BlockBehaviour for FenceGateBlock {
if powered != fence_gate_props.open { if powered != fence_gate_props.open {
fence_gate_props.open = powered; fence_gate_props.open = powered;
args.world args.world.play_block_sound(
.play_block_sound( get_sound(args.block, powered),
get_sound(args.block, powered), SoundCategory::Blocks,
SoundCategory::Blocks, *args.position,
*args.position, );
)
.await;
} }
args.world args.world
@ -150,7 +146,7 @@ impl BlockBehaviour for FenceGateBlock {
} }
} }
async fn is_in_wall(args: &GetStateForNeighborUpdateArgs<'_>) -> FenceGateProperties { fn is_in_wall(args: &GetStateForNeighborUpdateArgs<'_>) -> FenceGateProperties {
let mut fence_props = FenceGateProperties::from_state_id(args.state_id, args.block); let mut fence_props = FenceGateProperties::from_state_id(args.state_id, args.block);
let side_offset_left = args let side_offset_left = args
@ -165,8 +161,8 @@ async fn is_in_wall(args: &GetStateForNeighborUpdateArgs<'_>) -> FenceGateProper
args.neighbor_position == &side_offset_left || args.neighbor_position == &side_offset_right; args.neighbor_position == &side_offset_left || args.neighbor_position == &side_offset_right;
if neighbor_on_side { if neighbor_on_side {
let neighbor_right = args.world.get_block(&side_offset_right).await; let neighbor_right = args.world.get_block(&side_offset_right);
let neighbor_left = args.world.get_block(&side_offset_left).await; let neighbor_left = args.world.get_block(&side_offset_left);
fence_props.in_wall = neighbor_left.has_tag(&tag::Block::MINECRAFT_WALLS) fence_props.in_wall = neighbor_left.has_tag(&tag::Block::MINECRAFT_WALLS)
|| neighbor_right.has_tag(&tag::Block::MINECRAFT_WALLS); || neighbor_right.has_tag(&tag::Block::MINECRAFT_WALLS);

View File

@ -28,7 +28,7 @@ impl BlockBehaviour for FenceBlock {
let mut fence_props = FenceProperties::default(args.block); let mut fence_props = FenceProperties::default(args.block);
fence_props.waterlogged = args.replacing.water_source(); fence_props.waterlogged = args.replacing.water_source();
compute_fence_state(fence_props, args.world, args.block, args.position).await compute_fence_state(fence_props, args.world, args.block, args.position)
}) })
} }
@ -38,12 +38,12 @@ impl BlockBehaviour for FenceBlock {
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
let fence_props = FenceProperties::from_state_id(args.state_id, args.block); let fence_props = FenceProperties::from_state_id(args.state_id, args.block);
compute_fence_state(fence_props, args.world, args.block, args.position).await compute_fence_state(fence_props, args.world, args.block, args.position)
}) })
} }
} }
pub async fn compute_fence_state( pub fn compute_fence_state(
mut fence_props: FenceProperties, mut fence_props: FenceProperties,
world: &World, world: &World,
block: &Block, block: &Block,
@ -51,7 +51,7 @@ pub async fn compute_fence_state(
) -> u16 { ) -> u16 {
for direction in BlockDirection::horizontal() { for direction in BlockDirection::horizontal() {
let other_block_pos = block_pos.offset(direction.to_offset()); let other_block_pos = block_pos.offset(direction.to_offset());
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos).await; let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
let connected = connects_to(block, other_block, other_block_state, direction); let connected = connects_to(block, other_block, other_block_state, direction);
match direction { match direction {

View File

@ -54,14 +54,10 @@ impl FireBlock {
.is_some_and(|f| f.burn_chance > 0) .is_some_and(|f| f.burn_chance > 0)
} }
async fn are_blocks_around_flammable( fn are_blocks_around_flammable(block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
&self,
block_accessor: &dyn BlockAccessor,
pos: &BlockPos,
) -> bool {
for direction in BlockDirection::all() { for direction in BlockDirection::all() {
let neighbor_pos = pos.offset(direction.to_offset()); let neighbor_pos = pos.offset(direction.to_offset());
let block_state = block_accessor.get_block_state(&neighbor_pos).await; let block_state = block_accessor.get_block_state(&neighbor_pos);
if Self::is_flammable(block_state) { if Self::is_flammable(block_state) {
return true; return true;
} }
@ -69,21 +65,21 @@ impl FireBlock {
false false
} }
pub async fn get_state_for_position( pub fn get_state_for_position(
&self, &self,
world: &World, world: &World,
block: &Block, block: &Block,
pos: &BlockPos, pos: &BlockPos,
) -> BlockStateId { ) -> BlockStateId {
let down_pos = pos.down(); let down_pos = pos.down();
let down_state = world.get_block_state(&down_pos).await; let down_state = world.get_block_state(&down_pos);
if Self::is_flammable(down_state) || down_state.is_side_solid(BlockDirection::Up) { if Self::is_flammable(down_state) || down_state.is_side_solid(BlockDirection::Up) {
return block.default_state.id; return block.default_state.id;
} }
let mut fire_props = FireProperties::from_state_id(block.default_state.id, block); let mut fire_props = FireProperties::from_state_id(block.default_state.id, block);
for direction in BlockDirection::all() { for direction in BlockDirection::all() {
let neighbor_pos = pos.offset(direction.to_offset()); let neighbor_pos = pos.offset(direction.to_offset());
let neighbor_state = world.get_block_state(&neighbor_pos).await; let neighbor_state = world.get_block_state(&neighbor_pos);
if Self::is_flammable(neighbor_state) { if Self::is_flammable(neighbor_state) {
match direction { match direction {
BlockDirection::North => fire_props.north = true, BlockDirection::North => fire_props.north = true,
@ -99,16 +95,16 @@ impl FireBlock {
} }
// Used for spreading fire // Used for spreading fire
pub async fn get_burn_chance(&self, world: &Arc<World>, pos: &BlockPos) -> i32 { pub fn get_burn_chance(&self, world: &Arc<World>, pos: &BlockPos) -> i32 {
let block_state = world.get_block_state(pos).await; let block_state = world.get_block_state(pos);
if !block_state.is_air() { if !block_state.is_air() {
return 0; return 0;
} }
let mut total_burn_chance = 0; let mut total_burn_chance = 0;
for dir in BlockDirection::all() { for dir in BlockDirection::all() {
let neighbor_block = world.get_block(&pos.offset(dir.to_offset())).await; let neighbor_block = world.get_block(&pos.offset(dir.to_offset()));
if world.get_fluid(&pos.offset(dir.to_offset())).await.name != Fluid::EMPTY.name { if world.get_fluid(&pos.offset(dir.to_offset())).name != Fluid::EMPTY.name {
continue; // Skip if there is a fluid continue; // Skip if there is a fluid
} }
if let Some(flammable) = &neighbor_block.flammable { if let Some(flammable) = &neighbor_block.flammable {
@ -130,7 +126,7 @@ impl FireBlock {
block.flammable.as_ref().map_or(0, |f| f.burn_chance.into()) block.flammable.as_ref().map_or(0, |f| f.burn_chance.into())
} }
async fn is_increased_burnout_biome(world: &World, pos: &BlockPos) -> bool { fn is_increased_burnout_biome(world: &World, pos: &BlockPos) -> bool {
// Fire burnout increases in the Nether // Fire burnout increases in the Nether
if world.dimension == Dimension::THE_NETHER { if world.dimension == Dimension::THE_NETHER {
return true; return true;
@ -138,7 +134,7 @@ impl FireBlock {
// Fire burnout increases in specific biomes // Fire burnout increases in specific biomes
// TODO: Use proper tag or bool for this when available // TODO: Use proper tag or bool for this when available
let biome_id = world.level.get_rough_biome(pos).await.id; let biome_id = world.level.get_rough_biome(pos).id;
matches!( matches!(
biome_id, biome_id,
id if id == Biome::BAMBOO_JUNGLE.id id if id == Biome::BAMBOO_JUNGLE.id
@ -153,7 +149,7 @@ impl FireBlock {
} }
async fn try_spreading_fire(&self, world: &Arc<World>, pos: &BlockPos, chance: i32, age: u8) { async fn try_spreading_fire(&self, world: &Arc<World>, pos: &BlockPos, chance: i32, age: u8) {
let block = world.get_block(pos).await; let block = world.get_block(pos);
let odds = Self::get_burn_odds(block); let odds = Self::get_burn_odds(block);
if rand::rng().random_range(0..chance) < odds { if rand::rng().random_range(0..chance) < odds {
let old_block = block; let old_block = block;
@ -161,9 +157,7 @@ impl FireBlock {
&& !Self::is_near_rain(world.as_ref(), pos) && !Self::is_near_rain(world.as_ref(), pos)
{ {
let new_age = (age + (rand::rng().random_range(0..5) / 4)).min(15) as u8; let new_age = (age + (rand::rng().random_range(0..5) / 4)).min(15) as u8;
let state_id = self let state_id = self.get_state_for_position(world.as_ref(), &Block::FIRE, pos);
.get_state_for_position(world.as_ref(), &Block::FIRE, pos)
.await;
let mut fire_props = FireProperties::from_state_id(state_id, &Block::FIRE); let mut fire_props = FireProperties::from_state_id(state_id, &Block::FIRE);
fire_props.age = new_age; fire_props.age = new_age;
let new_state_id = fire_props.to_state_id(&Block::FIRE); let new_state_id = fire_props.to_state_id(&Block::FIRE);
@ -199,7 +193,7 @@ impl BlockBehaviour for FireBlock {
// First lets check if we are in OverWorld or Nether, its not possible to place an Nether portal in other dimensions in Vanilla // First lets check if we are in OverWorld or Nether, its not possible to place an Nether portal in other dimensions in Vanilla
if (dimension == &Dimension::OVERWORLD || dimension == &Dimension::THE_NETHER) if (dimension == &Dimension::OVERWORLD || dimension == &Dimension::THE_NETHER)
&& let Some(portal) = && let Some(portal) =
NetherPortal::get_new_portal(args.world, args.position, HorizontalAxis::X).await NetherPortal::get_new_portal(args.world, args.position, HorizontalAxis::X)
{ {
portal.create(args.world).await; portal.create(args.world).await;
return; return;
@ -225,24 +219,20 @@ impl BlockBehaviour for FireBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if self if self.can_place_at(CanPlaceAtArgs {
.can_place_at(CanPlaceAtArgs { server: None,
server: None, world: Some(args.world),
world: Some(args.world), block_accessor: args.world,
block_accessor: args.world, block: &Block::FIRE,
block: &Block::FIRE, state: Block::FIRE.default_state,
state: Block::FIRE.default_state, position: args.position,
position: args.position, direction: None,
direction: None, player: None,
player: None, use_item_on: None,
use_item_on: None, }) {
})
.await
{
let old_fire_props = FireProperties::from_state_id(args.state_id, &Block::FIRE); let old_fire_props = FireProperties::from_state_id(args.state_id, &Block::FIRE);
let fire_state_id = self let fire_state_id =
.get_state_for_position(args.world, &Block::FIRE, args.position) self.get_state_for_position(args.world, &Block::FIRE, args.position);
.await;
let mut fire_props = FireProperties::from_state_id(fire_state_id, &Block::FIRE); let mut fire_props = FireProperties::from_state_id(fire_state_id, &Block::FIRE);
fire_props.age = old_fire_props.age; fire_props.age = old_fire_props.age;
return fire_props.to_state_id(&Block::FIRE); return fire_props.to_state_id(&Block::FIRE);
@ -251,18 +241,12 @@ impl BlockBehaviour for FireBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { let state = args.block_accessor.get_block_state(&args.position.down());
let state = args if state.is_side_solid(BlockDirection::Up) {
.block_accessor return true;
.get_block_state(&args.position.down()) }
.await; Self::are_blocks_around_flammable(args.block_accessor, args.position)
if state.is_side_solid(BlockDirection::Up) {
return true;
}
self.are_blocks_around_flammable(args.block_accessor, args.position)
.await
})
} }
#[expect(clippy::too_many_lines)] #[expect(clippy::too_many_lines)]
@ -281,20 +265,17 @@ impl BlockBehaviour for FireBlock {
.await; .await;
// Check if fire can survive // Check if fire can survive
if !Self if !self.can_place_at(CanPlaceAtArgs {
.can_place_at(CanPlaceAtArgs { server: None,
server: None, world: Some(world),
world: Some(world), block_accessor: world.as_ref(),
block_accessor: world.as_ref(), block,
block, state: block.default_state,
state: block.default_state, position: pos,
position: pos, direction: None,
direction: None, player: None,
player: None, use_item_on: None,
use_item_on: None, }) {
})
.await
{
world world
.set_block_state( .set_block_state(
pos, pos,
@ -305,8 +286,8 @@ impl BlockBehaviour for FireBlock {
return; return;
} }
let block_state = world.get_block_state(pos).await; let block_state = world.get_block_state(pos);
let block_below = world.get_block(&pos.down()).await; let block_below = world.get_block(&pos.down());
// Check for infiniburn blocks (depending on dimension) // Check for infiniburn blocks (depending on dimension)
let infiniburn = match world.dimension.id { let infiniburn = match world.dimension.id {
@ -353,8 +334,8 @@ impl BlockBehaviour for FireBlock {
if !infiniburn { if !infiniburn {
// Check if fire should extinguish due to lack of fuel // Check if fire should extinguish due to lack of fuel
if !self.are_blocks_around_flammable(world.as_ref(), pos).await { if !Self::are_blocks_around_flammable(world.as_ref(), pos) {
let block_below_state = world.get_block_state(&pos.down()).await; let block_below_state = world.get_block_state(&pos.down());
if !block_below_state.is_side_solid(BlockDirection::Up) || new_age > 3 { if !block_below_state.is_side_solid(BlockDirection::Up) || new_age > 3 {
world world
.set_block_state( .set_block_state(
@ -370,7 +351,7 @@ impl BlockBehaviour for FireBlock {
// At max age, fire has a chance to extinguish if not on flammable block // At max age, fire has a chance to extinguish if not on flammable block
if new_age == 15 if new_age == 15
&& rand::rng().random_range(0..4) == 0 && rand::rng().random_range(0..4) == 0
&& !Self::is_flammable(world.get_block_state(&pos.down()).await) && !Self::is_flammable(world.get_block_state(&pos.down()))
{ {
world world
.set_block_state( .set_block_state(
@ -384,7 +365,7 @@ impl BlockBehaviour for FireBlock {
} }
// Burn adjacent blocks // Burn adjacent blocks
let extra = if Self::is_increased_burnout_biome(world, pos).await { let extra = if Self::is_increased_burnout_biome(world, pos) {
-50 // Increases chance of block being destroyed -50 // Increases chance of block being destroyed
} else { } else {
0 0
@ -448,7 +429,7 @@ impl BlockBehaviour for FireBlock {
for yy in -1..=4 { for yy in -1..=4 {
if xx != 0 || yy != 0 || zz != 0 { if xx != 0 || yy != 0 || zz != 0 {
let offset_pos = pos.offset(Vector3::new(xx, yy, zz)); let offset_pos = pos.offset(Vector3::new(xx, yy, zz));
let ignite_odds = self.get_burn_chance(world, &offset_pos).await; let ignite_odds = self.get_burn_chance(world, &offset_pos);
if ignite_odds > 0 { if ignite_odds > 0 {
// Skip if spreding is disabled or if there are no players nearby // Skip if spreding is disabled or if there are no players nearby
@ -473,7 +454,7 @@ impl BlockBehaviour for FireBlock {
(ignite_odds + 40 + difficulty * 7) / (new_age as i32 + 30); (ignite_odds + 40 + difficulty * 7) / (new_age as i32 + 30);
// Reduce spread odds in certain biomes // Reduce spread odds in certain biomes
if Self::is_increased_burnout_biome(world, &offset_pos).await { if Self::is_increased_burnout_biome(world, &offset_pos) {
odds /= 2; // Fire spreads 50% slower odds /= 2; // Fire spreads 50% slower
} }
@ -484,9 +465,11 @@ impl BlockBehaviour for FireBlock {
let spread_age = (new_age + rand::rng().random_range(0..5) / 4) let spread_age = (new_age + rand::rng().random_range(0..5) / 4)
.min(15) .min(15)
as u8; as u8;
let fire_state_id = self let fire_state_id = self.get_state_for_position(
.get_state_for_position(world.as_ref(), block, &offset_pos) world.as_ref(),
.await; block,
&offset_pos,
);
let mut new_fire_props = let mut new_fire_props =
FireProperties::from_state_id(fire_state_id, &Block::FIRE); FireProperties::from_state_id(fire_state_id, &Block::FIRE);
new_fire_props.age = spread_age; new_fire_props.age = spread_age;
@ -509,7 +492,7 @@ impl BlockBehaviour for FireBlock {
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
FireBlockBase::broken(args.world, *args.position).await; FireBlockBase::broken(args.world, *args.position);
}) })
} }
} }

View File

@ -26,8 +26,8 @@ pub mod soul_fire;
pub struct FireBlockBase; pub struct FireBlockBase;
impl FireBlockBase { impl FireBlockBase {
pub async fn get_fire_type(world: &World, pos: &BlockPos) -> Block { pub fn get_fire_type(world: &World, pos: &BlockPos) -> Block {
let block = world.get_block(&pos.down()).await; let block = world.get_block(&pos.down());
if SoulFireBlock::is_soul_base(block) { if SoulFireBlock::is_soul_base(block) {
return Block::SOUL_FIRE; return Block::SOUL_FIRE;
} }
@ -43,49 +43,44 @@ impl FireBlockBase {
&& block != &Block::LAVA && block != &Block::LAVA
} }
pub async fn is_soul_fire(world: &Arc<World>, block_pos: &BlockPos) -> bool { pub fn is_soul_fire(world: &Arc<World>, block_pos: &BlockPos) -> bool {
let block = world.get_block(&block_pos.down()).await; let block = world.get_block(&block_pos.down());
block.has_tag(&tag::Block::MINECRAFT_SOUL_FIRE_BASE_BLOCKS) block.has_tag(&tag::Block::MINECRAFT_SOUL_FIRE_BASE_BLOCKS)
} }
pub async fn can_place_at(world: &Arc<World>, block_pos: &BlockPos) -> bool { pub fn can_place_at(world: &Arc<World>, block_pos: &BlockPos) -> bool {
let block_state = world.get_block_state(block_pos).await; let block_state = world.get_block_state(block_pos);
if !block_state.is_air() { if !block_state.is_air() {
return false; return false;
} }
if Self::is_soul_fire(world, block_pos).await { if Self::is_soul_fire(world, block_pos) {
SoulFireBlock SoulFireBlock.can_place_at(CanPlaceAtArgs {
.can_place_at(CanPlaceAtArgs { server: None,
server: None, world: Some(world),
world: Some(world), block_accessor: world.as_ref(),
block_accessor: world.as_ref(), block: &Block::SOUL_FIRE,
block: &Block::SOUL_FIRE, state: Block::SOUL_FIRE.default_state,
state: Block::SOUL_FIRE.default_state, position: block_pos,
position: block_pos, direction: None,
direction: None, player: None,
player: None, use_item_on: None,
use_item_on: None, })
})
.await
} else { } else {
FireBlock FireBlock.can_place_at(CanPlaceAtArgs {
.can_place_at(CanPlaceAtArgs { server: None,
server: None, world: Some(world),
world: Some(world), block_accessor: world.as_ref(),
block_accessor: world.as_ref(), block: &Block::FIRE,
block: &Block::FIRE, state: Block::FIRE.default_state,
state: Block::FIRE.default_state, position: block_pos,
position: block_pos, direction: None,
direction: None, player: None,
player: None, use_item_on: None,
use_item_on: None, }) || Self::should_light_portal_at(world, block_pos, BlockDirection::Up)
})
.await
|| Self::should_light_portal_at(world, block_pos, BlockDirection::Up).await
} }
} }
pub async fn should_light_portal_at( pub fn should_light_portal_at(
world: &Arc<World>, world: &Arc<World>,
block_pos: &BlockPos, block_pos: &BlockPos,
direction: BlockDirection, direction: BlockDirection,
@ -97,7 +92,7 @@ impl FireBlockBase {
let mut found = false; let mut found = false;
for dir in BlockDirection::all() { for dir in BlockDirection::all() {
if world.get_block(&block_pos.offset(dir.to_offset())).await == &Block::OBSIDIAN { if world.get_block(&block_pos.offset(dir.to_offset())) == &Block::OBSIDIAN {
found = true; found = true;
break; break;
} }
@ -114,9 +109,7 @@ impl FireBlockBase {
Xoroshiro::from_seed(rand::rng().random()), Xoroshiro::from_seed(rand::rng().random()),
)) ))
}; };
return NetherPortal::get_new_portal(world, block_pos, dir.to_horizontal_axis().unwrap()) NetherPortal::get_new_portal(world, block_pos, dir.to_horizontal_axis().unwrap()).is_some()
.await
.is_some();
} }
/// Shared fire collision behavior used by `fire` and `soul_fire`. /// Shared fire collision behavior used by `fire` and `soul_fire`.
@ -162,9 +155,7 @@ impl FireBlockBase {
}) })
} }
async fn broken(world: &World, block_pos: BlockPos) { fn broken(world: &World, block_pos: BlockPos) {
world world.sync_world_event(WorldEvent::SoundExtinguishFire, block_pos, 0);
.sync_world_event(WorldEvent::SoundExtinguishFire, block_pos, 0)
.await;
} }
} }

View File

@ -30,7 +30,7 @@ impl BlockBehaviour for SoulFireBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !Self::is_soul_base(args.world.get_block(&args.position.down()).await) { if !Self::is_soul_base(args.world.get_block(&args.position.down())) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
@ -38,15 +38,13 @@ impl BlockBehaviour for SoulFireBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { Self::is_soul_base(args.block_accessor.get_block(&args.position.down()))
Self::is_soul_base(args.block_accessor.get_block(&args.position.down()).await)
})
} }
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
FireBlockBase::broken(args.world, *args.position).await; FireBlockBase::broken(args.world, *args.position);
}) })
} }
} }

View File

@ -85,7 +85,7 @@ pub struct FurnaceBlock;
impl BlockBehaviour for FurnaceBlock { impl BlockBehaviour for FurnaceBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(inventory) = block_entity.clone().get_inventory() && let Some(inventory) = block_entity.clone().get_inventory()
&& let Some(property_delegate) = block_entity.clone().to_property_delegate() && let Some(property_delegate) = block_entity.clone().to_property_delegate()
&& let Some(experience_container) = block_entity.to_experience_container() && let Some(experience_container) = block_entity.to_experience_container()
@ -126,7 +126,7 @@ impl BlockBehaviour for FurnaceBlock {
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
// Extract and drop accumulated XP as orbs before removing the block entity // Extract and drop accumulated XP as orbs before removing the block entity
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(experience_container) = block_entity.to_experience_container() && let Some(experience_container) = block_entity.to_experience_container()
{ {
let xp = experience_container.extract_experience(); let xp = experience_container.extract_experience();

View File

@ -26,7 +26,7 @@ impl BlockBehaviour for GlassPaneBlock {
let mut pane_props = GlassPaneProperties::default(args.block); let mut pane_props = GlassPaneProperties::default(args.block);
pane_props.waterlogged = args.replacing.water_source(); pane_props.waterlogged = args.replacing.water_source();
compute_pane_state(pane_props, args.world, args.block, args.position).await compute_pane_state(pane_props, args.world, args.block, args.position)
}) })
} }
@ -36,12 +36,12 @@ impl BlockBehaviour for GlassPaneBlock {
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
let pane_props = GlassPaneProperties::from_state_id(args.state_id, args.block); let pane_props = GlassPaneProperties::from_state_id(args.state_id, args.block);
compute_pane_state(pane_props, args.world, args.block, args.position).await compute_pane_state(pane_props, args.world, args.block, args.position)
}) })
} }
} }
pub async fn compute_pane_state( pub fn compute_pane_state(
mut pane_props: GlassPaneProperties, mut pane_props: GlassPaneProperties,
world: &World, world: &World,
block: &Block, block: &Block,
@ -49,7 +49,7 @@ pub async fn compute_pane_state(
) -> u16 { ) -> u16 {
for direction in BlockDirection::horizontal() { for direction in BlockDirection::horizontal() {
let other_block_pos = block_pos.offset(direction.to_offset()); let other_block_pos = block_pos.offset(direction.to_offset());
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos).await; let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
let connected = other_block == block let connected = other_block == block
|| other_block_state.is_side_solid(direction.opposite()) || other_block_state.is_side_solid(direction.opposite())

View File

@ -27,16 +27,13 @@ impl BlockBehaviour for GrindstoneBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { // Use the provided direction, or fallback to the current state's direction if missing
// Use the provided direction, or fallback to the current state's direction if missing let direction = args
let direction = args .direction
.direction .unwrap_or_else(|| self.get_direction(args.state.id, args.block));
.unwrap_or_else(|| self.get_direction(args.state.id, args.block));
WallMountedBlock::can_place_at(self, args.block_accessor, args.position, direction) WallMountedBlock::can_place_at(self, args.block_accessor, args.position, direction)
.await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -53,8 +50,8 @@ impl WallMountedBlock for GrindstoneBlock {
_world: &'a dyn BlockAccessor, _world: &'a dyn BlockAccessor,
_pos: &'a BlockPos, _pos: &'a BlockPos,
_direction: BlockDirection, _direction: BlockDirection,
) -> BlockFuture<'a, bool> { ) -> bool {
Box::pin(async move { true }) true
} }
fn get_direction(&self, state_id: BlockStateId, block: &Block) -> BlockDirection { fn get_direction(&self, state_id: BlockStateId, block: &Block) -> BlockDirection {

View File

@ -59,7 +59,7 @@ type HopperLikeProperties = pumpkin_data::block_properties::HopperLikeProperties
impl BlockBehaviour for HopperBlock { impl BlockBehaviour for HopperBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(inventory) = block_entity.get_inventory() && let Some(inventory) = block_entity.get_inventory()
{ {
args.player args.player
@ -104,7 +104,7 @@ impl BlockBehaviour for HopperBlock {
check_powered_state( check_powered_state(
args.world, args.world,
args.position, args.position,
args.world.get_block_state_id(args.position).await, args.world.get_block_state_id(args.position),
args.block, args.block,
) )
.await; .await;

View File

@ -23,7 +23,7 @@ impl BlockBehaviour for IronBarsBlock {
let mut bars_props = IronBarsProperties::default(args.block); let mut bars_props = IronBarsProperties::default(args.block);
bars_props.waterlogged = args.replacing.water_source(); bars_props.waterlogged = args.replacing.water_source();
compute_bars_state(bars_props, args.world, args.block, args.position).await compute_bars_state(bars_props, args.world, args.block, args.position)
}) })
} }
@ -33,12 +33,12 @@ impl BlockBehaviour for IronBarsBlock {
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
let bars_props = IronBarsProperties::from_state_id(args.state_id, args.block); let bars_props = IronBarsProperties::from_state_id(args.state_id, args.block);
compute_bars_state(bars_props, args.world, args.block, args.position).await compute_bars_state(bars_props, args.world, args.block, args.position)
}) })
} }
} }
pub async fn compute_bars_state( pub fn compute_bars_state(
mut bars_props: IronBarsProperties, mut bars_props: IronBarsProperties,
world: &World, world: &World,
block: &Block, block: &Block,
@ -46,7 +46,7 @@ pub async fn compute_bars_state(
) -> u16 { ) -> u16 {
for direction in BlockDirection::horizontal() { for direction in BlockDirection::horizontal() {
let other_block_pos = block_pos.offset(direction.to_offset()); let other_block_pos = block_pos.offset(direction.to_offset());
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos).await; let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
let connected = other_block == block let connected = other_block == block
|| other_block_state.is_side_solid(direction.opposite()) || other_block_state.is_side_solid(direction.opposite())

View File

@ -52,7 +52,7 @@ impl JukeboxBlock {
/// Drops the record from the jukebox - matches vanilla's `JukeboxBlockEntity.dropRecord()` /// Drops the record from the jukebox - matches vanilla's `JukeboxBlockEntity.dropRecord()`
/// Spawns item at (pos + 0.5, pos + 1.01, pos + 0.5) with horizontal random offset /// Spawns item at (pos + 0.5, pos + 1.01, pos + 0.5) with horizontal random offset
async fn drop_record(position: &BlockPos, world: &Arc<World>) { async fn drop_record(position: &BlockPos, world: &Arc<World>) {
if let Some(block_entity) = world.get_block_entity(position).await if let Some(block_entity) = world.get_block_entity(position)
&& let Some(jukebox_entity) = block_entity.as_any().downcast_ref::<JukeboxBlockEntity>() && let Some(jukebox_entity) = block_entity.as_any().downcast_ref::<JukeboxBlockEntity>()
{ {
let record = jukebox_entity.clear_record().await; let record = jukebox_entity.clear_record().await;
@ -67,7 +67,7 @@ impl JukeboxBlock {
let entity = Entity::new(world.clone(), spawn_pos, &EntityType::ITEM); let entity = Entity::new(world.clone(), spawn_pos, &EntityType::ITEM);
// Vanilla: setToDefaultPickupDelay() = 10 ticks // Vanilla: setToDefaultPickupDelay() = 10 ticks
let item_entity = Arc::new(ItemEntity::new(entity, record).await); let item_entity = Arc::new(ItemEntity::new(entity, record));
world.spawn_entity(item_entity).await; world.spawn_entity(item_entity).await;
} }
} }
@ -76,16 +76,12 @@ impl JukeboxBlock {
/// Stops the music and updates block state /// Stops the music and updates block state
async fn stop_playing(block: &Block, position: &BlockPos, world: &Arc<World>) { async fn stop_playing(block: &Block, position: &BlockPos, world: &Arc<World>) {
Self::set_record_state(false, block, position, world).await; Self::set_record_state(false, block, position, world).await;
world world.sync_world_event(WorldEvent::SoundStopJukeboxSong, *position, 0);
.sync_world_event(WorldEvent::SoundStopJukeboxSong, *position, 0)
.await;
} }
/// Starts playing music /// Starts playing music
async fn start_playing(position: &BlockPos, world: &Arc<World>, song_id: u32) { fn start_playing(position: &BlockPos, world: &Arc<World>, song_id: u32) {
world world.sync_world_event(WorldEvent::SoundPlayJukeboxSong, *position, song_id as i32);
.sync_world_event(WorldEvent::SoundPlayJukeboxSong, *position, song_id as i32)
.await;
} }
} }
@ -102,7 +98,7 @@ impl BlockBehaviour for JukeboxBlock {
/// Vanilla: `JukeboxBlock.onUse()` - drops record if present /// Vanilla: `JukeboxBlock.onUse()` - drops record if present
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state(args.position).await.id; let state_id = args.world.get_block_state(args.position).id;
// Vanilla: if (state.get(HAS_RECORD) && world.getBlockEntity(pos) instanceof JukeboxBlockEntity lv) // Vanilla: if (state.get(HAS_RECORD) && world.getBlockEntity(pos) instanceof JukeboxBlockEntity lv)
if Self::has_record_state(args.block, state_id) { if Self::has_record_state(args.block, state_id) {
@ -125,7 +121,7 @@ impl BlockBehaviour for JukeboxBlock {
) -> BlockFuture<'a, BlockActionResult> { ) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let world = args.world; let world = args.world;
let state_id = world.get_block_state(args.position).await.id; let state_id = world.get_block_state(args.position).id;
// Vanilla: if (state.get(HAS_RECORD)) return PASS_TO_DEFAULT_BLOCK_ACTION // Vanilla: if (state.get(HAS_RECORD)) return PASS_TO_DEFAULT_BLOCK_ACTION
if Self::has_record_state(args.block, state_id) { if Self::has_record_state(args.block, state_id) {
@ -157,7 +153,7 @@ impl BlockBehaviour for JukeboxBlock {
let record = item_stack.split_unless_creative(args.player.gamemode.load(), 1); let record = item_stack.split_unless_creative(args.player.gamemode.load(), 1);
// Vanilla: lv4.setStack(lv3) // Vanilla: lv4.setStack(lv3)
if let Some(block_entity) = world.get_block_entity(args.position).await if let Some(block_entity) = world.get_block_entity(args.position)
&& let Some(jukebox_entity) = && let Some(jukebox_entity) =
block_entity.as_any().downcast_ref::<JukeboxBlockEntity>() block_entity.as_any().downcast_ref::<JukeboxBlockEntity>()
{ {
@ -170,7 +166,7 @@ impl BlockBehaviour for JukeboxBlock {
Self::set_record_state(true, args.block, args.position, world).await; Self::set_record_state(true, args.block, args.position, world).await;
// Start playing the music (client-side audio) // Start playing the music (client-side audio)
Self::start_playing(args.position, world, jukebox_song.get_id()).await; Self::start_playing(args.position, world, jukebox_song.get_id());
// TODO: world.emitGameEvent(GameEvent.BLOCK_CHANGE, pos, ...) // TODO: world.emitGameEvent(GameEvent.BLOCK_CHANGE, pos, ...)
// TODO: player.incrementStat(Stats.PLAY_RECORD) // TODO: player.incrementStat(Stats.PLAY_RECORD)
@ -186,8 +182,7 @@ impl BlockBehaviour for JukeboxBlock {
Self::drop_record(args.position, args.world).await; Self::drop_record(args.position, args.world).await;
// Stop the music // Stop the music
args.world args.world
.sync_world_event(WorldEvent::SoundStopJukeboxSong, *args.position, 0) .sync_world_event(WorldEvent::SoundStopJukeboxSong, *args.position, 0);
.await;
}) })
} }
@ -214,7 +209,7 @@ impl BlockBehaviour for JukeboxBlock {
) -> BlockFuture<'a, u8> { ) -> BlockFuture<'a, u8> {
Box::pin(async move { Box::pin(async move {
// Vanilla: return world.getBlockEntity(pos) instanceof JukeboxBlockEntity lv && lv.getManager().isPlaying() ? 15 : 0 // Vanilla: return world.getBlockEntity(pos) instanceof JukeboxBlockEntity lv && lv.getManager().isPlaying() ? 15 : 0
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(jukebox_entity) = && let Some(jukebox_entity) =
block_entity.as_any().downcast_ref::<JukeboxBlockEntity>() block_entity.as_any().downcast_ref::<JukeboxBlockEntity>()
&& jukebox_entity.is_playing() && jukebox_entity.is_playing()
@ -233,7 +228,7 @@ impl BlockBehaviour for JukeboxBlock {
) -> BlockFuture<'a, Option<u8>> { ) -> BlockFuture<'a, Option<u8>> {
Box::pin(async move { Box::pin(async move {
// Vanilla: return world.getBlockEntity(pos) instanceof JukeboxBlockEntity lv ? lv.getComparatorOutput() : 0 // Vanilla: return world.getBlockEntity(pos) instanceof JukeboxBlockEntity lv ? lv.getComparatorOutput() : 0
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(jukebox_entity) = && let Some(jukebox_entity) =
block_entity.as_any().downcast_ref::<JukeboxBlockEntity>() block_entity.as_any().downcast_ref::<JukeboxBlockEntity>()
{ {

View File

@ -20,7 +20,7 @@ impl BlockBehaviour for LadderBlock {
Box::pin(async move { Box::pin(async move {
let clicked_pos = args.use_item_on.position; let clicked_pos = args.use_item_on.position;
let (clicked_block, clicked_block_state_id) = let (clicked_block, clicked_block_state_id) =
args.world.get_block_and_state_id(&clicked_pos).await; args.world.get_block_and_state_id(&clicked_pos);
if clicked_block == &Block::LADDER { if clicked_block == &Block::LADDER {
//you can't click on a ladder and place a ladder //you can't click on a ladder and place a ladder
let props = let props =
@ -38,7 +38,7 @@ impl BlockBehaviour for LadderBlock {
if dir == Facing::Up || dir == Facing::Down { if dir == Facing::Up || dir == Facing::Down {
continue; continue;
} }
if !can_place_ladder_at(args.world, args.position, dir.to_block_direction()).await { if !can_place_ladder_at(args.world, args.position, dir.to_block_direction()) {
continue; continue;
} }
props.facing = dir props.facing = dir
@ -51,19 +51,17 @@ impl BlockBehaviour for LadderBlock {
Block::AIR.default_state.id Block::AIR.default_state.id
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { for dir in BlockDirection::horizontal() {
for dir in BlockDirection::horizontal() { let Some(world) = args.world else {
let Some(world) = args.world else { //this won't happen
//this won't happen return false;
return false; };
}; if can_place_ladder_at(world, args.position, dir) {
if can_place_ladder_at(world, args.position, dir).await { return true;
return true;
}
} }
false }
}) false
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -77,7 +75,6 @@ impl BlockBehaviour for LadderBlock {
args.position, args.position,
props.facing.to_block_direction().opposite(), props.facing.to_block_direction().opposite(),
) )
.await
{ {
return 0; return 0;
} }
@ -87,7 +84,7 @@ impl BlockBehaviour for LadderBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
if Block::from_state_id(state_id) != &Block::LADDER { if Block::from_state_id(state_id) != &Block::LADDER {
return; return;
} }
@ -96,9 +93,7 @@ impl BlockBehaviour for LadderBlock {
args.world, args.world,
args.position, args.position,
props.facing.to_block_direction().opposite(), props.facing.to_block_direction().opposite(),
) ) {
.await
{
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -116,9 +111,8 @@ pub const fn horizontal_facing_from_offset(offset: Vector3<i32>) -> Option<Block
_ => None, _ => None,
} }
} }
async fn can_place_ladder_at(world: &World, block_pos: &BlockPos, facing: BlockDirection) -> bool { fn can_place_ladder_at(world: &World, block_pos: &BlockPos, facing: BlockDirection) -> bool {
world world
.get_block_state(&block_pos.offset(facing.to_offset())) .get_block_state(&block_pos.offset(facing.to_offset()))
.await
.is_side_solid(facing.opposite()) .is_side_solid(facing.opposite())
} }

View File

@ -38,7 +38,7 @@ impl BlockBehaviour for LanternBlock {
pumpkin_data::block_properties::LanternLikeProperties::default(args.block); pumpkin_data::block_properties::LanternLikeProperties::default(args.block);
props.r#waterlogged = args.replacing.water_source(); props.r#waterlogged = args.replacing.water_source();
let block_up_state = args.world.get_block_state(&args.position.up()).await; let block_up_state = args.world.get_block_state(&args.position.up());
if block_up_state.is_center_solid(BlockDirection::Down) { if block_up_state.is_center_solid(BlockDirection::Down) {
props.r#hanging = true; props.r#hanging = true;
} }
@ -47,8 +47,8 @@ impl BlockBehaviour for LanternBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.world.unwrap(), args.position).await }) can_place_at(args.world.unwrap(), args.position)
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -56,7 +56,7 @@ impl BlockBehaviour for LanternBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -67,7 +67,7 @@ impl BlockBehaviour for LanternBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -76,25 +76,24 @@ impl BlockBehaviour for LanternBlock {
} }
} }
async fn can_place_at(world: &World, position: &BlockPos) -> bool { fn can_place_at(world: &World, position: &BlockPos) -> bool {
//idk why this don't update with .is_center_solid so this is a 'temporary patch' //idk why this don't update with .is_center_solid so this is a 'temporary patch'
if world if world
.get_block(&position.down()) .get_block(&position.down())
.await
.has_tag(&tag::Block::C_FENCE_GATES) .has_tag(&tag::Block::C_FENCE_GATES)
{ {
let fence_gate_props = let fence_gate_props =
pumpkin_data::block_properties::OakFenceGateLikeProperties::from_state_id( pumpkin_data::block_properties::OakFenceGateLikeProperties::from_state_id(
world.get_block_state_id(&position.down()).await, world.get_block_state_id(&position.down()),
world.get_block(&position.down()).await, world.get_block(&position.down()),
); );
if fence_gate_props.open { if fence_gate_props.open {
return false; return false;
} }
} }
let (block_down, block_down_state) = world.get_block_and_state(&position.down()).await; let (block_down, block_down_state) = world.get_block_and_state(&position.down());
let block_up_state = world.get_block_state(&position.up()).await; let block_up_state = world.get_block_state(&position.up());
block_down_state.is_center_solid(BlockDirection::Up) block_down_state.is_center_solid(BlockDirection::Up)
|| block_up_state.is_center_solid(BlockDirection::Down) || block_up_state.is_center_solid(BlockDirection::Down)
|| block_down.has_tag(&tag::Block::MINECRAFT_UNSTABLE_BOTTOM_CENTER) || block_down.has_tag(&tag::Block::MINECRAFT_UNSTABLE_BOTTOM_CENTER)

View File

@ -60,7 +60,7 @@ impl BlockBehaviour for LecternBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(lectern_entity) = && let Some(lectern_entity) =
block_entity.as_any().downcast_ref::<LecternBlockEntity>() block_entity.as_any().downcast_ref::<LecternBlockEntity>()
{ {
@ -70,7 +70,7 @@ impl BlockBehaviour for LecternBlock {
// Need to find a proper way to give items to player. For now skip. // Need to find a proper way to give items to player. For now skip.
let mut props = LecternLikeProperties::from_state_id( let mut props = LecternLikeProperties::from_state_id(
args.world.get_block_state(args.position).await.id, args.world.get_block_state(args.position).id,
args.block, args.block,
); );
Self::update_lectern_state( Self::update_lectern_state(
@ -97,7 +97,7 @@ impl BlockBehaviour for LecternBlock {
// Check if it's a book // Check if it's a book
if item_stack.item.registry_key.contains("book") if item_stack.item.registry_key.contains("book")
&& let Some(block_entity) = args.world.get_block_entity(args.position).await && let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(lectern_entity) = && let Some(lectern_entity) =
block_entity.as_any().downcast_ref::<LecternBlockEntity>() block_entity.as_any().downcast_ref::<LecternBlockEntity>()
&& lectern_entity.book.lock().await.is_empty() && lectern_entity.book.lock().await.is_empty()
@ -106,7 +106,7 @@ impl BlockBehaviour for LecternBlock {
lectern_entity.set_stack(0, book).await; lectern_entity.set_stack(0, book).await;
let mut props = LecternLikeProperties::from_state_id( let mut props = LecternLikeProperties::from_state_id(
args.world.get_block_state(args.position).await.id, args.world.get_block_state(args.position).id,
args.block, args.block,
); );
Self::update_lectern_state(true, args.block, args.position, args.world, &mut props) Self::update_lectern_state(true, args.block, args.position, args.world, &mut props)
@ -119,7 +119,7 @@ impl BlockBehaviour for LecternBlock {
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position).await if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(lectern_entity) = && let Some(lectern_entity) =
block_entity.as_any().downcast_ref::<LecternBlockEntity>() block_entity.as_any().downcast_ref::<LecternBlockEntity>()
{ {
@ -135,7 +135,7 @@ impl BlockBehaviour for LecternBlock {
), ),
&EntityType::ITEM, &EntityType::ITEM,
); );
let item_entity = ItemEntity::new(entity, book).await; let item_entity = ItemEntity::new(entity, book);
args.world.spawn_entity(Arc::new(item_entity)).await; args.world.spawn_entity(Arc::new(item_entity)).await;
} }
} }

View File

@ -60,7 +60,6 @@ impl BlockBehaviour for NetherPortalBlock {
if is_horizontal_and_different if is_horizontal_and_different
|| args.neighbor_state_id == args.state_id || args.neighbor_state_id == args.state_id
|| NetherPortal::get_on_axis(args.world, args.position, state_axis) || NetherPortal::get_on_axis(args.world, args.position, state_axis)
.await
.is_some_and(|e| e.was_already_valid()) .is_some_and(|e| e.was_already_valid())
{ {
return args.state_id; return args.state_id;

View File

@ -26,7 +26,7 @@ pub struct NoteBlock;
impl NoteBlock { impl NoteBlock {
pub async fn play_note(props: &NoteBlockLikeProperties, world: &World, pos: &BlockPos) { pub async fn play_note(props: &NoteBlockLikeProperties, world: &World, pos: &BlockPos) {
if !is_base_block(props.instrument) || world.get_block_state(&pos.up()).await.is_air() { if !is_base_block(props.instrument) || world.get_block_state(&pos.up()).is_air() {
world.add_synced_block_event(*pos, 0, 0).await; world.add_synced_block_event(*pos, 0, 0).await;
} }
} }
@ -34,20 +34,20 @@ impl NoteBlock {
((f32::from(note) - 12.0) / 12.0).exp2() ((f32::from(note) - 12.0) / 12.0).exp2()
} }
async fn get_state_with_instrument( fn get_state_with_instrument(
world: &World, world: &World,
pos: &BlockPos, pos: &BlockPos,
state: BlockStateId, state: BlockStateId,
block: &Block, block: &Block,
) -> BlockStateId { ) -> BlockStateId {
let upper_instrument = world.get_block_state(&pos.up()).await.instrument; let upper_instrument = world.get_block_state(&pos.up()).instrument;
let mut note_props = NoteBlockLikeProperties::from_state_id(state, block); let mut note_props = NoteBlockLikeProperties::from_state_id(state, block);
if !is_base_block(upper_instrument) { if !is_base_block(upper_instrument) {
note_props.instrument = upper_instrument; note_props.instrument = upper_instrument;
return note_props.to_state_id(block); return note_props.to_state_id(block);
} }
let below_instrument = world.get_block_state(&pos.down()).await.instrument; let below_instrument = world.get_block_state(&pos.down()).instrument;
let below_instrument = if is_base_block(below_instrument) { let below_instrument = if is_base_block(below_instrument) {
below_instrument below_instrument
} else { } else {
@ -61,7 +61,7 @@ impl NoteBlock {
impl BlockBehaviour for NoteBlock { impl BlockBehaviour for NoteBlock {
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> { fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let block_state = args.world.get_block_state(args.position).await; let block_state = args.world.get_block_state(args.position);
let mut note_props = NoteBlockLikeProperties::from_state_id(block_state.id, args.block); let mut note_props = NoteBlockLikeProperties::from_state_id(block_state.id, args.block);
let powered = block_receives_redstone_power(args.world, args.position).await; let powered = block_receives_redstone_power(args.world, args.position).await;
// check if powered state changed // check if powered state changed
@ -83,7 +83,7 @@ impl BlockBehaviour for NoteBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let block_state = args.world.get_block_state(args.position).await; let block_state = args.world.get_block_state(args.position);
let mut note_props = NoteBlockLikeProperties::from_state_id(block_state.id, args.block); let mut note_props = NoteBlockLikeProperties::from_state_id(block_state.id, args.block);
note_props.note = (note_props.note + 1) % 25; note_props.note = (note_props.note + 1) % 25;
args.world args.world
@ -114,7 +114,7 @@ impl BlockBehaviour for NoteBlock {
args: OnSyncedBlockEventArgs<'a>, args: OnSyncedBlockEventArgs<'a>,
) -> BlockFuture<'a, bool> { ) -> BlockFuture<'a, bool> {
Box::pin(async move { Box::pin(async move {
let block_state = args.world.get_block_state(args.position).await; let block_state = args.world.get_block_state(args.position);
let note_props = NoteBlockLikeProperties::from_state_id(block_state.id, args.block); let note_props = NoteBlockLikeProperties::from_state_id(block_state.id, args.block);
let instrument = note_props.instrument; let instrument = note_props.instrument;
let pitch = if is_base_block(instrument) { let pitch = if is_base_block(instrument) {
@ -124,15 +124,13 @@ impl BlockBehaviour for NoteBlock {
1.0 // default pitch 1.0 // default pitch
}; };
// check hasCustomSound // check hasCustomSound
args.world args.world.play_sound_raw(
.play_sound_raw( convert_instrument_to_sound(instrument) as u16,
convert_instrument_to_sound(instrument) as u16, SoundCategory::Records,
SoundCategory::Records, &args.position.to_f64(),
&args.position.to_f64(), 3.0,
3.0, pitch,
pitch, );
)
.await;
true true
}) })
} }
@ -145,7 +143,6 @@ impl BlockBehaviour for NoteBlock {
Block::NOTE_BLOCK.default_state.id, Block::NOTE_BLOCK.default_state.id,
args.block, args.block,
) )
.await
}) })
} }
@ -160,8 +157,7 @@ impl BlockBehaviour for NoteBlock {
args.position, args.position,
args.state_id, args.state_id,
args.block, args.block,
) );
.await;
} }
args.state_id args.state_id
}) })

View File

@ -49,7 +49,7 @@ impl<'a> PistonHandler<'a> {
pub async fn calculate_push(&mut self) -> bool { pub async fn calculate_push(&mut self) -> bool {
self.moved_blocks.clear(); self.moved_blocks.clear();
self.broken_blocks.clear(); self.broken_blocks.clear();
let (block, block_state) = self.world.get_block_and_state(&self.pos_to).await; let (block, block_state) = self.world.get_block_and_state(&self.pos_to);
if !PistonBlock::is_movable( if !PistonBlock::is_movable(
block, block,
@ -69,7 +69,7 @@ impl<'a> PistonHandler<'a> {
} }
for i in 0..self.moved_blocks.len() { for i in 0..self.moved_blocks.len() {
let block_pos = self.moved_blocks[i]; let block_pos = self.moved_blocks[i];
let block = self.world.get_block(&block_pos).await; let block = self.world.get_block(&block_pos);
if Self::is_block_sticky(block) if Self::is_block_sticky(block)
&& !self.try_move_adjacent_block(block, &block_pos).await && !self.try_move_adjacent_block(block, &block_pos).await
{ {
@ -94,7 +94,7 @@ impl<'a> PistonHandler<'a> {
} }
async fn try_move(&mut self, pos: BlockPos, dir: BlockDirection) -> bool { async fn try_move(&mut self, pos: BlockPos, dir: BlockDirection) -> bool {
let (block, block_state) = self.world.get_block_and_state(&pos).await; let (block, block_state) = self.world.get_block_and_state(&pos);
if block_state.is_air() { if block_state.is_air() {
return true; return true;
} }
@ -114,7 +114,7 @@ impl<'a> PistonHandler<'a> {
while Self::is_block_sticky(block) { while Self::is_block_sticky(block) {
let block_pos = pos.offset_dir(self.motion_direction.opposite().to_offset(), i as i32); let block_pos = pos.offset_dir(self.motion_direction.opposite().to_offset(), i as i32);
let block2 = block; let block2 = block;
let (block, block_state) = self.world.get_block_and_state(&block_pos).await; let (block, block_state) = self.world.get_block_and_state(&block_pos);
if block_state.is_air() if block_state.is_air()
|| !Self::is_adjacent_block_stuck(block2, block) || !Self::is_adjacent_block_stuck(block2, block)
|| !PistonBlock::is_movable( || !PistonBlock::is_movable(
@ -146,7 +146,7 @@ impl<'a> PistonHandler<'a> {
self.set_moved_blocks(j, l); self.set_moved_blocks(j, l);
for m in 0..=(l + j) { for m in 0..=(l + j) {
let block_pos3 = self.moved_blocks[m]; let block_pos3 = self.moved_blocks[m];
let block = self.world.get_block(&block_pos3).await; let block = self.world.get_block(&block_pos3);
if Self::is_block_sticky(block) if Self::is_block_sticky(block)
&& !Box::pin(self.try_move_adjacent_block(block, &block_pos3)).await && !Box::pin(self.try_move_adjacent_block(block, &block_pos3)).await
{ {
@ -155,7 +155,7 @@ impl<'a> PistonHandler<'a> {
} }
return true; return true;
} }
let (block, block_state) = self.world.get_block_and_state(&block_pos2).await; let (block, block_state) = self.world.get_block_and_state(&block_pos2);
if block_state.is_air() { if block_state.is_air() {
return true; return true;
} }
@ -201,7 +201,7 @@ impl<'a> PistonHandler<'a> {
continue; continue;
} }
let block_pos = pos.offset(direction.to_offset()); let block_pos = pos.offset(direction.to_offset());
let block_state2 = self.world.get_block(&block_pos).await; let block_state2 = self.world.get_block(&block_pos);
if Self::is_adjacent_block_stuck(block_state2, block) if Self::is_adjacent_block_stuck(block_state2, block)
&& !self.try_move(block_pos, direction).await && !self.try_move(block_pos, direction).await
{ {

View File

@ -91,8 +91,7 @@ impl BlockBehaviour for PistonBlock {
let pos = args let pos = args
.position .position
.offset(props.facing.to_block_direction().to_offset()); .offset(props.facing.to_block_direction().to_offset());
let (block_to_check, block_to_check_state_id) = let (block_to_check, block_to_check_state_id) = args.world.get_block_and_state_id(&pos);
args.world.get_block_and_state_id(&pos).await;
if &Block::PISTON_HEAD == block_to_check { if &Block::PISTON_HEAD == block_to_check {
let head_props = let head_props =
PistonHeadProperties::from_state_id(block_to_check_state_id, block_to_check); PistonHeadProperties::from_state_id(block_to_check_state_id, block_to_check);
@ -144,7 +143,7 @@ impl BlockBehaviour for PistonBlock {
args.data, args.data,
); );
let state = world.get_block_state(pos).await; let state = world.get_block_state(pos);
let mut props = PistonProps::from_state_id(state.id, block); let mut props = PistonProps::from_state_id(state.id, block);
let dir = props.facing.to_block_direction(); let dir = props.facing.to_block_direction();
@ -180,22 +179,20 @@ impl BlockBehaviour for PistonBlock {
.await; .await;
// Play piston extend sound // Play piston extend sound
let pitch = rand::rng().random_range(0.6f32..0.85); let pitch = rand::rng().random_range(0.6f32..0.85);
world world.play_sound_fine(
.play_sound_fine( Sound::BlockPistonExtend,
Sound::BlockPistonExtend, SoundCategory::Blocks,
SoundCategory::Blocks, &pos.to_centered_f64(),
&pos.to_centered_f64(), 0.5,
0.5, pitch,
pitch, );
)
.await;
return true; return true;
} }
// Reduce Piston // Reduce Piston
let extended_pos = pos.offset(dir.to_offset()); let extended_pos = pos.offset(dir.to_offset());
if let Some(block_entity) = world.get_block_entity(&extended_pos).await if let Some(block_entity) = world.get_block_entity(&extended_pos)
&& let Some(piston) = block_entity.as_any().downcast_ref::<PistonBlockEntity>() && let Some(piston) = block_entity.as_any().downcast_ref::<PistonBlockEntity>()
{ {
piston.finish(world.clone()).await; piston.finish(world.clone()).await;
@ -237,9 +234,9 @@ impl BlockBehaviour for PistonBlock {
world.update_neighbors(pos, None).await; world.update_neighbors(pos, None).await;
if sticky { if sticky {
let pull_pos = pos.offset_dir(dir.to_offset(), 2); let pull_pos = pos.offset_dir(dir.to_offset(), 2);
let (block, state) = world.get_block_and_state(&pull_pos).await; let (block, state) = world.get_block_and_state(&pull_pos);
let piston_piece = if block == &Block::MOVING_PISTON let piston_piece = if block == &Block::MOVING_PISTON
&& let Some(entity) = world.get_block_entity(&pull_pos).await && let Some(entity) = world.get_block_entity(&pull_pos)
&& let Some(piston) = entity.as_any().downcast_ref::<PistonBlockEntity>() && let Some(piston) = entity.as_any().downcast_ref::<PistonBlockEntity>()
&& piston.facing == dir && piston.facing == dir
&& piston.extending && piston.extending
@ -281,15 +278,13 @@ impl BlockBehaviour for PistonBlock {
} }
// Play piston contract sound // Play piston contract sound
let pitch = rand::rng().random_range(0.6f32..0.75); let pitch = rand::rng().random_range(0.6f32..0.75);
world world.play_sound_fine(
.play_sound_fine( Sound::BlockPistonContract,
Sound::BlockPistonContract, SoundCategory::Blocks,
SoundCategory::Blocks, &pos.to_centered_f64(),
&pos.to_centered_f64(), 0.5,
0.5, pitch,
pitch, );
)
.await;
true true
}) })
} }
@ -298,7 +293,7 @@ impl BlockBehaviour for PistonBlock {
async fn should_extend(world: &World, block_pos: &BlockPos, piston_dir: BlockDirection) -> bool { async fn should_extend(world: &World, block_pos: &BlockPos, piston_dir: BlockDirection) -> bool {
for dir in BlockDirection::all() { for dir in BlockDirection::all() {
let neighbor_pos = block_pos.offset(dir.to_offset()); let neighbor_pos = block_pos.offset(dir.to_offset());
let (block, state) = world.get_block_and_state(&neighbor_pos).await; let (block, state) = world.get_block_and_state(&neighbor_pos);
// Pistons can't be powered from the same direction as they are facing // Pistons can't be powered from the same direction as they are facing
if dir == piston_dir if dir == piston_dir
|| !is_emitting_redstone_power(block, state, world, &neighbor_pos, dir).await || !is_emitting_redstone_power(block, state, world, &neighbor_pos, dir).await
@ -308,13 +303,13 @@ async fn should_extend(world: &World, block_pos: &BlockPos, piston_dir: BlockDir
return true; return true;
} }
let neighbor_pos = block_pos.offset(BlockDirection::Down.to_offset()); let neighbor_pos = block_pos.offset(BlockDirection::Down.to_offset());
let (block, state) = world.get_block_and_state(&neighbor_pos).await; let (block, state) = world.get_block_and_state(&neighbor_pos);
if is_emitting_redstone_power(block, state, world, block_pos, BlockDirection::Down).await { 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() {
let neighbor_pos = block_pos.up().offset(dir.to_offset()); let neighbor_pos = block_pos.up().offset(dir.to_offset());
let (block, state) = world.get_block_and_state(&neighbor_pos).await; let (block, state) = world.get_block_and_state(&neighbor_pos);
if dir == BlockDirection::Down if dir == BlockDirection::Down
|| !is_emitting_redstone_power(block, state, world, &neighbor_pos, dir).await || !is_emitting_redstone_power(block, state, world, &neighbor_pos, dir).await
{ {
@ -326,7 +321,7 @@ async fn should_extend(world: &World, block_pos: &BlockPos, piston_dir: BlockDir
} }
pub async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) { pub async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
let state = world.get_block_state(block_pos).await; let state = world.get_block_state(block_pos);
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_pos, dir).await; let should_extent = should_extend(world, block_pos, dir).await;
@ -342,13 +337,13 @@ pub async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
} }
} else if !should_extent && props.extended { } else if !should_extent && props.extended {
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_state_id(&new_pos).await; let (new_block, new_state) = world.get_block_and_state_id(&new_pos);
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 = MovingPistonLikeProperties::from_state_id(new_state, new_block); let new_props = MovingPistonLikeProperties::from_state_id(new_state, new_block);
if new_props.facing == props.facing if new_props.facing == props.facing
&& let Some(entity) = world.get_block_entity(&new_pos).await && let Some(entity) = world.get_block_entity(&new_pos)
{ {
let piston = entity.as_any().downcast_ref::<PistonBlockEntity>().unwrap(); let piston = entity.as_any().downcast_ref::<PistonBlockEntity>().unwrap();
if piston.extending && piston.current_progress.load() < 0.5 if piston.extending && piston.current_progress.load() < 0.5
@ -374,7 +369,7 @@ async fn move_piston(
sticky: bool, sticky: bool,
) -> bool { ) -> bool {
let extended_pos = block_pos.offset(dir.to_offset()); let extended_pos = block_pos.offset(dir.to_offset());
if !extend && world.get_block(&extended_pos).await == &Block::PISTON_HEAD { if !extend && world.get_block(&extended_pos) == &Block::PISTON_HEAD {
world world
.set_block_state( .set_block_state(
&extended_pos, &extended_pos,
@ -394,7 +389,7 @@ async fn move_piston(
let mut moved_block_states: Vec<&BlockState> = Vec::new(); let mut moved_block_states: Vec<&BlockState> = Vec::new();
for &block_pos in &moved_blocks { for &block_pos in &moved_blocks {
let block_state = world.get_block_state(&block_pos).await; let block_state = world.get_block_state(&block_pos);
moved_block_states.push(block_state); moved_block_states.push(block_state);
moved_blocks_map.insert(block_pos, block_state); moved_blocks_map.insert(block_pos, block_state);
} }
@ -405,7 +400,7 @@ async fn move_piston(
let move_direction = if extend { dir } else { dir.opposite() }; let move_direction = if extend { dir } else { dir.opposite() };
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; let block_state = world.get_block_state(&broken_block_pos);
world world
.break_block( .break_block(
&broken_block_pos, &broken_block_pos,
@ -417,7 +412,7 @@ async fn move_piston(
} }
for (index, &moved_block_pos) in moved_blocks.iter().rev().enumerate() { for (index, &moved_block_pos) in moved_blocks.iter().rev().enumerate() {
let block_state = world.get_block_state(&moved_block_pos).await; let block_state = world.get_block_state(&moved_block_pos);
let target_pos = moved_block_pos.offset(move_direction.to_offset()); let target_pos = moved_block_pos.offset(move_direction.to_offset());
moved_blocks_map.remove(&target_pos); moved_blocks_map.remove(&target_pos);

View File

@ -20,7 +20,7 @@ impl BlockBehaviour for PistonExtensionBlock {
let pos = args let pos = args
.position .position
.offset(props.facing.opposite().to_block_direction().to_offset()); .offset(props.facing.opposite().to_block_direction().to_offset());
let (new_block, new_state) = args.world.get_block_and_state_id(&pos).await; let (new_block, new_state) = args.world.get_block_and_state_id(&pos);
if &Block::PISTON == new_block || &Block::STICKY_PISTON == new_block { if &Block::PISTON == new_block || &Block::STICKY_PISTON == new_block {
let props = PistonProps::from_state_id(new_state, new_block); let props = PistonProps::from_state_id(new_state, new_block);
if props.extended { if props.extended {

View File

@ -21,7 +21,7 @@ impl BlockBehaviour for PistonHeadBlock {
let pos = args let pos = args
.position .position
.offset(props.facing.opposite().to_block_direction().to_offset()); .offset(props.facing.opposite().to_block_direction().to_offset());
let (new_block, new_state) = args.world.get_block_and_state_id(&pos).await; let (new_block, new_state) = args.world.get_block_and_state_id(&pos);
if &Block::PISTON == new_block || &Block::STICKY_PISTON == new_block { if &Block::PISTON == new_block || &Block::STICKY_PISTON == new_block {
let props = PistonProps::from_state_id(new_state, new_block); let props = PistonProps::from_state_id(new_state, new_block);
if props.extended { if props.extended {
@ -35,7 +35,7 @@ impl BlockBehaviour for PistonHeadBlock {
} }
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> { fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let head_state_id = args.world.get_block_state_id(args.position).await; let head_state_id = args.world.get_block_state_id(args.position);
let head_props = let head_props =
PistonHeadProperties::from_state_id(head_state_id, &Block::PISTON_HEAD); PistonHeadProperties::from_state_id(head_state_id, &Block::PISTON_HEAD);
if head_props.facing != Facing::Up { if head_props.facing != Facing::Up {
@ -48,12 +48,12 @@ impl BlockBehaviour for PistonHeadBlock {
.to_block_direction() .to_block_direction()
.to_offset(), .to_offset(),
); );
let piston_block = args.world.get_block(&piston_pos).await; let piston_block = args.world.get_block(&piston_pos);
if &Block::PISTON == piston_block || &Block::STICKY_PISTON == piston_block { if &Block::PISTON == piston_block || &Block::STICKY_PISTON == piston_block {
let up_pos = args let up_pos = args
.position .position
.offset(head_props.facing.to_block_direction().to_offset()); .offset(head_props.facing.to_block_direction().to_offset());
let upper_block = args.world.get_block(&up_pos).await; let upper_block = args.world.get_block(&up_pos);
if upper_block != &Block::REDSTONE_BLOCK { if upper_block != &Block::REDSTONE_BLOCK {
//Then somebody probably broke the redstone block, try to check if piston should still be extended. //Then somebody probably broke the redstone block, try to check if piston should still be extended.
try_move(args.world, piston_block, &piston_pos).await; try_move(args.world, piston_block, &piston_pos).await;

View File

@ -27,10 +27,8 @@ pub struct BambooBlock;
impl BlockBehaviour for BambooBlock { impl BlockBehaviour for BambooBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
let (block_below, state_id_below) = args let (block_below, state_id_below) =
.world args.world.get_block_and_state_id(&args.position.down());
.get_block_and_state_id(&args.position.down())
.await;
if block_below.has_tag(&MINECRAFT_SUPPORTS_BAMBOO) { if block_below.has_tag(&MINECRAFT_SUPPORTS_BAMBOO) {
let mut props = BambooLikeProperties::from_state_id( let mut props = BambooLikeProperties::from_state_id(
@ -47,7 +45,7 @@ impl BlockBehaviour for BambooBlock {
} }
} else { } else {
let (block_above, state_id_above) = let (block_above, state_id_above) =
args.world.get_block_and_state_id(&args.position.up()).await; args.world.get_block_and_state_id(&args.position.up());
if block_above == &Block::BAMBOO { if block_above == &Block::BAMBOO {
let props_above = let props_above =
BambooLikeProperties::from_state_id(state_id_above, block_above); BambooLikeProperties::from_state_id(state_id_above, block_above);
@ -76,21 +74,17 @@ impl BlockBehaviour for BambooBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !<Self as PlantBlockBase>::can_place_at(self, args.world.as_ref(), args.position) if !<Self as PlantBlockBase>::can_place_at(self, args.world.as_ref(), args.position) {
.await
{
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
} else if args.world.get_block(&args.position.down()).await == &Block::BAMBOO_SAPLING { } else if args.world.get_block(&args.position.down()) == &Block::BAMBOO_SAPLING {
args.world args.world
.set_block_state( .set_block_state(
&args.position.down(), &args.position.down(),
@ -107,12 +101,12 @@ impl BlockBehaviour for BambooBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !<Self as PlantBlockBase>::can_place_at(self, args.world, args.position).await { if !<Self as PlantBlockBase>::can_place_at(self, args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
} }
let neighbor_block = args.world.get_block(args.neighbor_position).await; let neighbor_block = args.world.get_block(args.neighbor_position);
if args.direction == BlockDirection::Up && neighbor_block == &Block::BAMBOO { if args.direction == BlockDirection::Up && neighbor_block == &Block::BAMBOO {
let neighbor_props = let neighbor_props =
BambooLikeProperties::from_state_id(args.neighbor_state_id, neighbor_block); BambooLikeProperties::from_state_id(args.neighbor_state_id, neighbor_block);
@ -143,8 +137,8 @@ async fn update_leaves_and_grow(world: Arc<World>, position: &BlockPos) {
let below_pos = position.down(); let below_pos = position.down();
let two_below_pos = position.down_height(2); let two_below_pos = position.down_height(2);
let (block, state_id) = world.get_block_and_state_id(position).await; let (block, state_id) = world.get_block_and_state_id(position);
let state_above = world.get_block_state(&above_pos).await; let state_above = world.get_block_state(&above_pos);
if !state_above.is_air() { if !state_above.is_air() {
return; return;
@ -155,12 +149,12 @@ async fn update_leaves_and_grow(world: Arc<World>, position: &BlockPos) {
return; return;
} }
let bamboo_count = count_bamboo_below(world.clone(), position).await; let bamboo_count = count_bamboo_below(&world, position);
if bamboo_count >= 16 { if bamboo_count >= 16 {
return; return;
} }
let (block_below, state_id_below) = world.get_block_and_state_id(&below_pos).await; let (block_below, state_id_below) = world.get_block_and_state_id(&below_pos);
let (block_two_below, state_id_two_below) = world.get_block_and_state_id(&two_below_pos).await; let (block_two_below, state_id_two_below) = world.get_block_and_state_id(&two_below_pos);
let mut props_below = BambooLikeProperties::from_state_id(state_id_below, block_below); let mut props_below = BambooLikeProperties::from_state_id(state_id_below, block_below);
@ -209,13 +203,13 @@ async fn update_leaves_and_grow(world: Arc<World>, position: &BlockPos) {
.await; .await;
} }
async fn count_bamboo_below(world: Arc<World>, pos: &BlockPos) -> usize { fn count_bamboo_below(world: &World, pos: &BlockPos) -> usize {
let mut bamboo_count = 0; let mut bamboo_count = 0;
let mut found_bamboo_below = true; let mut found_bamboo_below = true;
let mut current_position = pos.down(); let mut current_position = pos.down();
while found_bamboo_below && bamboo_count < 16 { while found_bamboo_below && bamboo_count < 16 {
found_bamboo_below = false; found_bamboo_below = false;
if world.get_block(&current_position).await == &Block::BAMBOO { if world.get_block(&current_position) == &Block::BAMBOO {
current_position = current_position.down(); current_position = current_position.down();
bamboo_count += 1; bamboo_count += 1;
found_bamboo_below = true; found_bamboo_below = true;
@ -224,13 +218,13 @@ async fn count_bamboo_below(world: Arc<World>, pos: &BlockPos) -> usize {
bamboo_count bamboo_count
} }
async fn count_bamboo_above(world: Arc<World>, pos: &BlockPos) -> usize { fn count_bamboo_above(world: &World, pos: &BlockPos) -> usize {
let mut bamboo_count = 0; let mut bamboo_count = 0;
let mut found_bamboo_below = true; let mut found_bamboo_below = true;
let mut current_position = pos.up(); let mut current_position = pos.up();
while found_bamboo_below && bamboo_count < 16 { while found_bamboo_below && bamboo_count < 16 {
found_bamboo_below = false; found_bamboo_below = false;
if world.get_block(&current_position).await == &Block::BAMBOO { if world.get_block(&current_position) == &Block::BAMBOO {
current_position = current_position.up(); current_position = current_position.up();
bamboo_count += 1; bamboo_count += 1;
found_bamboo_below = true; found_bamboo_below = true;
@ -240,16 +234,15 @@ async fn count_bamboo_above(world: Arc<World>, pos: &BlockPos) -> usize {
} }
async fn bone_meal(world: Arc<World>, position: &BlockPos) { async fn bone_meal(world: Arc<World>, position: &BlockPos) {
let mut bamboo_above = count_bamboo_above(Arc::clone(&world), position).await; let bamboo_below = count_bamboo_below(&world, position);
let bamboo_below = count_bamboo_below(Arc::clone(&world), position).await;
let growth_amount = rand::rng().random_range(1..=3); let growth_amount = rand::rng().random_range(1..=3);
for _ in 0..growth_amount { for (bamboo_above, _) in (count_bamboo_above(&world, position)..).zip(0..growth_amount) {
let current_total_height = bamboo_above + bamboo_below + 1; let current_total_height = bamboo_above + bamboo_below + 1;
let next_pos = position.up_height(bamboo_above as i32); let next_pos = position.up_height(bamboo_above as i32);
let next_state = world.get_block_state(&next_pos).await; let next_state = world.get_block_state(&next_pos);
if !next_state.is_air() || current_total_height >= 16 { if !next_state.is_air() || current_total_height >= 16 {
return; return;
@ -261,22 +254,20 @@ async fn bone_meal(world: Arc<World>, position: &BlockPos) {
} }
update_leaves_and_grow(Arc::clone(&world), position).await; update_leaves_and_grow(Arc::clone(&world), position).await;
bamboo_above += 1;
} }
} }
impl PlantBlockBase for BambooBlock { impl PlantBlockBase for BambooBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_BAMBOO) block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_BAMBOO)
} }
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await <Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down())
} }
} }

View File

@ -22,11 +22,8 @@ use crate::block::{
pub struct BambooSaplingBlock; pub struct BambooSaplingBlock;
impl BlockBehaviour for BambooSaplingBlock { impl BlockBehaviour for BambooSaplingBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, &args.position.down())
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, &args.position.down())
.await
})
} }
fn use_with_item<'a>( fn use_with_item<'a>(
@ -57,7 +54,7 @@ impl BlockBehaviour for BambooSaplingBlock {
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> { fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if args.block == &Block::BAMBOO_SAPLING if args.block == &Block::BAMBOO_SAPLING
&& args.world.get_block(&args.position.up()).await == &Block::BAMBOO && args.world.get_block(&args.position.up()) == &Block::BAMBOO
{ {
args.world args.world
.set_block_state( .set_block_state(
@ -75,11 +72,11 @@ impl BlockBehaviour for BambooSaplingBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !<Self as PlantBlockBase>::can_place_at(self, args.world, args.position).await { if !<Self as PlantBlockBase>::can_place_at(self, args.world, args.position) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
if args.direction == BlockDirection::Up if args.direction == BlockDirection::Up
&& args.world.get_block(args.neighbor_position).await == &Block::BAMBOO && args.world.get_block(args.neighbor_position) == &Block::BAMBOO
{ {
return Block::BAMBOO.default_state.id; return Block::BAMBOO.default_state.id;
} }
@ -89,7 +86,7 @@ impl BlockBehaviour for BambooSaplingBlock {
fn random_tick<'a>(&'a self, args: crate::block::RandomTickArgs<'a>) -> BlockFuture<'a, ()> { fn random_tick<'a>(&'a self, args: crate::block::RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let state_above = args.world.get_block_state(&args.position.up()).await; let state_above = args.world.get_block_state(&args.position.up());
if !state_above.is_air() || rand::rng().random_range(0..3) > 0 { if !state_above.is_air() || rand::rng().random_range(0..3) > 0 {
return; return;
} }
@ -108,12 +105,12 @@ impl BlockBehaviour for BambooSaplingBlock {
} }
impl PlantBlockBase for BambooSaplingBlock { impl PlantBlockBase for BambooSaplingBlock {
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await <Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down())
} }
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
block.has_tag(&pumpkin_data::tag::Block::MINECRAFT_SUPPORTS_BAMBOO) block.has_tag(&pumpkin_data::tag::Block::MINECRAFT_SUPPORTS_BAMBOO)
} }
} }

View File

@ -50,7 +50,7 @@ impl BlockBehaviour for BigDripleafBlock {
} }
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
if block_receives_redstone_power(args.world, args.position).await { if block_receives_redstone_power(args.world, args.position).await {
reset_tilt(state.id, args.world, args.position).await; reset_tilt(state.id, args.world, args.position).await;
} else { } else {
@ -82,17 +82,13 @@ impl BlockBehaviour for BigDripleafBlock {
}) })
} }
//TODO: onProjectileHit //TODO: onProjectileHit
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
let (support_block, support_block_state_id) = args let (support_block, support_block_state_id) =
.world args.world.get_block_and_state_id(&args.position.down());
.get_block_and_state_id(&args.position.down())
.await;
let facing = if support_block == &Block::BIG_DRIPLEAF { let facing = if support_block == &Block::BIG_DRIPLEAF {
get_dripleaf_facing_dir(support_block_state_id) get_dripleaf_facing_dir(support_block_state_id)
} else { } else {
@ -128,7 +124,7 @@ impl BlockBehaviour for BigDripleafBlock {
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> { fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if block_receives_redstone_power(args.world, args.position).await { if block_receives_redstone_power(args.world, args.position).await {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
reset_tilt(state_id, args.world, args.position).await; reset_tilt(state_id, args.world, args.position).await;
} }
}) })
@ -138,8 +134,7 @@ impl BlockBehaviour for BigDripleafBlock {
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let support_pos = args.position.down(); let support_pos = args.position.down();
let (support_block, support_state_id) = let (support_block, support_state_id) = args.world.get_block_and_state_id(&support_pos);
args.world.get_block_and_state_id(&support_pos).await;
if support_block == &Block::BIG_DRIPLEAF { if support_block == &Block::BIG_DRIPLEAF {
let old_dripleaf_props = BigDripleafLikeProperties::from_state_id( let old_dripleaf_props = BigDripleafLikeProperties::from_state_id(
support_state_id, support_state_id,
@ -175,7 +170,7 @@ async fn set_tilt_and_schedule_tick(
) { ) {
set_tilt(state_id, world, pos, tilt).await; set_tilt(state_id, world, pos, tilt).await;
if let Some(tilt_sound) = sound_wrapper { if let Some(tilt_sound) = sound_wrapper {
play_tilt_sound(world, pos, tilt_sound).await; play_tilt_sound(world, pos, tilt_sound);
} }
let tick_delay = match tilt { let tick_delay = match tilt {
Tilt::None => -1, Tilt::None => -1,
@ -193,19 +188,17 @@ async fn set_tilt_and_schedule_tick(
.await; .await;
} }
} }
async fn play_tilt_sound(world: &Arc<World>, pos: &BlockPos, tilt_sound: Sound) { fn play_tilt_sound(world: &Arc<World>, pos: &BlockPos, tilt_sound: Sound) {
let pitch = rand::rng().random_range(0.8f32..1.2f32); let pitch = rand::rng().random_range(0.8f32..1.2f32);
let v = pos.as_vector3(); let v = pos.as_vector3();
let position = Vector3::new(v.x as f64, v.y as f64, v.z as f64); let position = Vector3::new(v.x as f64, v.y as f64, v.z as f64);
world world.play_sound_fine(tilt_sound, SoundCategory::Blocks, &position, 1f32, pitch);
.play_sound_fine(tilt_sound, SoundCategory::Blocks, &position, 1f32, pitch)
.await;
} }
async fn reset_tilt(state_id: BlockStateId, world: &Arc<World>, pos: &BlockPos) { async fn reset_tilt(state_id: BlockStateId, world: &Arc<World>, pos: &BlockPos) {
set_tilt(state_id, world, pos, Tilt::None).await; set_tilt(state_id, world, pos, Tilt::None).await;
let props = BigDripleafLikeProperties::from_state_id(state_id, &Block::BIG_DRIPLEAF); let props = BigDripleafLikeProperties::from_state_id(state_id, &Block::BIG_DRIPLEAF);
if props.tilt != Tilt::None { if props.tilt != Tilt::None {
play_tilt_sound(world, pos, Sound::BlockBigDripleafTiltUp).await; play_tilt_sound(world, pos, Sound::BlockBigDripleafTiltUp);
} }
} }
async fn set_tilt(state_id: BlockStateId, world: &Arc<World>, pos: &BlockPos, new_tilt: Tilt) { async fn set_tilt(state_id: BlockStateId, world: &Arc<World>, pos: &BlockPos, new_tilt: Tilt) {
@ -234,8 +227,8 @@ fn is_dripleaf_waterlogged(state_id: BlockStateId) -> bool {
dripleaf_props.waterlogged dripleaf_props.waterlogged
} }
impl PlantBlockBase for BigDripleafBlock { impl PlantBlockBase for BigDripleafBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let support_block = block_accessor.get_block(pos).await; let support_block = block_accessor.get_block(pos);
can_plant_dripleaf_on_top(support_block) can_plant_dripleaf_on_top(support_block)
} }
async fn get_state_for_neighbor_update( async fn get_state_for_neighbor_update(
@ -244,7 +237,7 @@ impl PlantBlockBase for BigDripleafBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
if is_dripleaf_waterlogged(block_state) { if is_dripleaf_waterlogged(block_state) {
return Block::WATER.default_state.id; return Block::WATER.default_state.id;
} }

View File

@ -21,10 +21,8 @@ pub struct BigDripleafStemBlock;
pub type BigDripleafStemLikeProperties = LadderLikeProperties; pub type BigDripleafStemLikeProperties = LadderLikeProperties;
impl BlockBehaviour for BigDripleafStemBlock { impl BlockBehaviour for BigDripleafStemBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -46,8 +44,8 @@ impl BlockBehaviour for BigDripleafStemBlock {
} }
} }
impl PlantBlockBase for BigDripleafStemBlock { impl PlantBlockBase for BigDripleafStemBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let support_block = block_accessor.get_block(pos).await; let support_block = block_accessor.get_block(pos);
can_plant_dripleaf_on_top(support_block) can_plant_dripleaf_on_top(support_block)
} }
@ -57,8 +55,8 @@ impl PlantBlockBase for BigDripleafStemBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
let block = block_accessor.get_block(block_pos).await; let block = block_accessor.get_block(block_pos);
let dripleaf_stem_props = let dripleaf_stem_props =
BigDripleafStemLikeProperties::from_state_id(block_state, block); BigDripleafStemLikeProperties::from_state_id(block_state, block);
@ -72,7 +70,7 @@ impl PlantBlockBase for BigDripleafStemBlock {
} }
pub async fn handle_big_dripleaf_breaking(world: &Arc<World>, position: &BlockPos) { pub async fn handle_big_dripleaf_breaking(world: &Arc<World>, position: &BlockPos) {
let support_pos = position.down(); let support_pos = position.down();
let (support_block, support_state_id) = world.get_block_and_state_id(&support_pos).await; let (support_block, support_state_id) = world.get_block_and_state_id(&support_pos);
if support_block == &Block::BIG_DRIPLEAF_STEM { if support_block == &Block::BIG_DRIPLEAF_STEM {
let dripleaf_stem_props = let dripleaf_stem_props =
BigDripleafStemLikeProperties::from_state_id(support_state_id, support_block); BigDripleafStemLikeProperties::from_state_id(support_state_id, support_block);

View File

@ -15,10 +15,8 @@ impl BlockMetadata for BushBlock {
} }
impl BlockBehaviour for BushBlock { impl BlockBehaviour for BushBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -20,7 +20,7 @@ pub struct CactusBlock;
impl BlockBehaviour for CactusBlock { impl BlockBehaviour for CactusBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -31,19 +31,19 @@ impl BlockBehaviour for CactusBlock {
fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> { fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let block_up = args.position.up(); let block_up = args.position.up();
if args.world.get_block_state(&block_up).await.is_air() { if args.world.get_block_state(&block_up).is_air() {
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
let mut props = CactusLikeProperties::from_state_id(state.id, args.block); let mut props = CactusLikeProperties::from_state_id(state.id, args.block);
let age = props.age; let age = props.age;
let mut i = 1; let mut i = 1;
while args.world.get_block(&args.position.down_height(i)).await == &Block::CACTUS { while args.world.get_block(&args.position.down_height(i)) == &Block::CACTUS {
i += 1; i += 1;
if 1 == 3 && age == 15 { if 1 == 3 && age == 15 {
return; return;
} }
} }
if age == 8 && can_place_at(args.world.as_ref(), &block_up).await { if age == 8 && can_place_at(args.world.as_ref(), &block_up) {
let d = if i >= 3 { 0.25 } else { 0.1 }; let d = if i >= 3 { 0.25 } else { 0.1 };
if rand::rng().random_range(0.0..1.0) <= d { if rand::rng().random_range(0.0..1.0) <= d {
args.world args.world
@ -102,7 +102,7 @@ impl BlockBehaviour for CactusBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -112,21 +112,19 @@ impl BlockBehaviour for CactusBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
} }
async fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
for direction in BlockDirection::horizontal() { for direction in BlockDirection::horizontal() {
let (block, state) = world let (block, state) = world.get_block_and_state(&block_pos.offset(direction.to_offset()));
.get_block_and_state(&block_pos.offset(direction.to_offset()))
.await;
if state.is_solid() || block == &Block::LAVA { if state.is_solid() || block == &Block::LAVA {
return false; return false;
} }
} }
let block = world.get_block(&block_pos.down()).await; let block = world.get_block(&block_pos.down());
(block == &Block::CACTUS || block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_CACTUS)) (block == &Block::CACTUS || block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_CACTUS))
&& !world.get_block_state(&block_pos.up()).await.is_liquid() && !world.get_block_state(&block_pos.up()).is_liquid()
} }

View File

@ -11,10 +11,8 @@ use pumpkin_world::world::BlockAccessor;
pub struct CactusFlowerBlock; pub struct CactusFlowerBlock;
impl BlockBehaviour for CactusFlowerBlock { impl BlockBehaviour for CactusFlowerBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -33,14 +31,13 @@ impl BlockBehaviour for CactusFlowerBlock {
} }
impl PlantBlockBase for CactusFlowerBlock { impl PlantBlockBase for CactusFlowerBlock {
async fn can_place_at( fn can_place_at(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
let support_pos = pos.down(); let support_pos = pos.down();
let (support_block, support_block_state) = let (support_block, support_block_state) = block_accessor.get_block_and_state(&support_pos);
block_accessor.get_block_and_state(&support_pos).await;
if supports_cactus_flower(support_block, support_block_state) { if supports_cactus_flower(support_block, support_block_state) {
return true; return true;
} }
@ -52,7 +49,7 @@ impl PlantBlockBase for CactusFlowerBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
block_state block_state

View File

@ -18,8 +18,8 @@ use crate::block::{
pub struct ChorusFlowerBlock; pub struct ChorusFlowerBlock;
impl BlockBehaviour for ChorusFlowerBlock { impl BlockBehaviour for ChorusFlowerBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_survive(args.block_accessor, args.position).await }) can_survive(args.block_accessor, args.position)
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -27,8 +27,7 @@ impl BlockBehaviour for ChorusFlowerBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if args.direction != BlockDirection::Up && !can_survive(args.world, args.position).await if args.direction != BlockDirection::Up && !can_survive(args.world, args.position) {
{
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -39,7 +38,7 @@ impl BlockBehaviour for ChorusFlowerBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_survive(args.world.as_ref(), args.position).await { if !can_survive(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -48,8 +47,8 @@ impl BlockBehaviour for ChorusFlowerBlock {
} }
} }
async fn can_survive(block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_survive(block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block_below = block_accessor.get_block(&pos.down()).await; let block_below = block_accessor.get_block(&pos.down());
if block_below == &Block::CHORUS_PLANT if block_below == &Block::CHORUS_PLANT
|| block_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_CHORUS_FLOWER) || block_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_CHORUS_FLOWER)
@ -65,7 +64,7 @@ async fn can_survive(block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool
// Exactly one horizontal neighbor must be a chorus plant stem. // Exactly one horizontal neighbor must be a chorus plant stem.
let mut plant_count = 0u32; let mut plant_count = 0u32;
for dir in BlockDirection::horizontal() { for dir in BlockDirection::horizontal() {
let neighbor = block_accessor.get_block(&pos.offset(dir.to_offset())).await; let neighbor = block_accessor.get_block(&pos.offset(dir.to_offset()));
if neighbor == &Block::CHORUS_PLANT { if neighbor == &Block::CHORUS_PLANT {
plant_count += 1; plant_count += 1;
if plant_count > 1 { if plant_count > 1 {

View File

@ -23,12 +23,12 @@ impl BlockBehaviour for ChorusPlantBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
// Compute all 6 face connections immediately so the placed block visually connects to its neighbors. // Compute all 6 face connections immediately so the placed block visually connects to its neighbors.
get_state_with_connections(args.world, args.block, args.position).await get_state_with_connections(args.world, args.block, args.position)
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_survive(args.block_accessor, args.position).await }) can_survive(args.block_accessor, args.position)
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -36,7 +36,7 @@ impl BlockBehaviour for ChorusPlantBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_survive(args.world, args.position).await { if !can_survive(args.world, args.position) {
// Schedule delayed destruction so the whole plant cascades down. // Schedule delayed destruction so the whole plant cascades down.
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
@ -45,7 +45,7 @@ impl BlockBehaviour for ChorusPlantBlock {
} }
// Update the single face connection for the direction that changed. // Update the single face connection for the direction that changed.
let neighbor_block = args.world.get_block(args.neighbor_position).await; let neighbor_block = args.world.get_block(args.neighbor_position);
let connect = neighbor_block == &Block::CHORUS_PLANT let connect = neighbor_block == &Block::CHORUS_PLANT
|| neighbor_block == &Block::CHORUS_FLOWER || neighbor_block == &Block::CHORUS_FLOWER
|| (args.direction == BlockDirection::Down || (args.direction == BlockDirection::Down
@ -69,7 +69,7 @@ impl BlockBehaviour for ChorusPlantBlock {
Box::pin(async move { Box::pin(async move {
// Destroy if unsupported; breaking propagates neighbor-update callbacks // Destroy if unsupported; breaking propagates neighbor-update callbacks
// to connected chorus blocks, which schedule their own ticks. // to connected chorus blocks, which schedule their own ticks.
if !can_survive(args.world.as_ref(), args.position).await { if !can_survive(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -78,7 +78,7 @@ impl BlockBehaviour for ChorusPlantBlock {
} }
} }
async fn get_state_with_connections( fn get_state_with_connections(
block_accessor: &dyn BlockAccessor, block_accessor: &dyn BlockAccessor,
block: &Block, block: &Block,
pos: &BlockPos, pos: &BlockPos,
@ -89,20 +89,12 @@ async fn get_state_with_connections(
let connects = |b: &Block| b.id == plant_id || b.id == flower_id; let connects = |b: &Block| b.id == plant_id || b.id == flower_id;
let block_down = block_accessor.get_block(&pos.down()).await; let block_down = block_accessor.get_block(&pos.down());
let block_up = block_accessor.get_block(&pos.up()).await; let block_up = block_accessor.get_block(&pos.up());
let block_north = block_accessor let block_north = block_accessor.get_block(&pos.offset(BlockDirection::North.to_offset()));
.get_block(&pos.offset(BlockDirection::North.to_offset())) let block_east = block_accessor.get_block(&pos.offset(BlockDirection::East.to_offset()));
.await; let block_south = block_accessor.get_block(&pos.offset(BlockDirection::South.to_offset()));
let block_east = block_accessor let block_west = block_accessor.get_block(&pos.offset(BlockDirection::West.to_offset()));
.get_block(&pos.offset(BlockDirection::East.to_offset()))
.await;
let block_south = block_accessor
.get_block(&pos.offset(BlockDirection::South.to_offset()))
.await;
let block_west = block_accessor
.get_block(&pos.offset(BlockDirection::West.to_offset()))
.await;
let props = BrownMushroomBlockLikeProperties { let props = BrownMushroomBlockLikeProperties {
down: connects(block_down) || block_down.has_tag(supports), down: connects(block_down) || block_down.has_tag(supports),
@ -115,12 +107,12 @@ async fn get_state_with_connections(
props.to_state_id(block) props.to_state_id(block)
} }
async fn can_survive(block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_survive(block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let below_pos = pos.down(); let below_pos = pos.down();
let above_pos = pos.up(); let above_pos = pos.up();
let (block_below, state_below) = block_accessor.get_block_and_state(&below_pos).await; let (block_below, state_below) = block_accessor.get_block_and_state(&below_pos);
let state_above = block_accessor.get_block_state(&above_pos).await; let state_above = block_accessor.get_block_state(&above_pos);
// A horizontal branch is invalid when both the block immediately above and // A horizontal branch is invalid when both the block immediately above and
// below this one are non-air (enclosed inside something). // below this one are non-air (enclosed inside something).
@ -128,12 +120,12 @@ async fn can_survive(block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool
for dir in BlockDirection::horizontal() { for dir in BlockDirection::horizontal() {
let neighbor_pos = pos.offset(dir.to_offset()); let neighbor_pos = pos.offset(dir.to_offset());
let neighbor_block = block_accessor.get_block(&neighbor_pos).await; let neighbor_block = block_accessor.get_block(&neighbor_pos);
if neighbor_block == &Block::CHORUS_PLANT { if neighbor_block == &Block::CHORUS_PLANT {
if block_above_or_below { if block_above_or_below {
return false; return false;
} }
let neighbor_below = block_accessor.get_block(&neighbor_pos.down()).await; let neighbor_below = block_accessor.get_block(&neighbor_pos.down());
if neighbor_below == &Block::CHORUS_PLANT if neighbor_below == &Block::CHORUS_PLANT
|| neighbor_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_CHORUS_PLANT) || neighbor_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_CHORUS_PLANT)
{ {

View File

@ -16,15 +16,8 @@ type BeetrootProperties = NetherWartLikeProperties;
pub struct BeetrootBlock; pub struct BeetrootBlock;
impl BlockBehaviour for BeetrootBlock { impl BlockBehaviour for BeetrootBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as CropBlockBase>::can_plant_on_top(self, args.block_accessor, &args.position.down())
<Self as CropBlockBase>::can_plant_on_top(
self,
args.block_accessor,
&args.position.down(),
)
.await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -11,15 +11,8 @@ use crate::block::{
pub struct CarrotBlock; pub struct CarrotBlock;
impl BlockBehaviour for CarrotBlock { impl BlockBehaviour for CarrotBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as CropBlockBase>::can_plant_on_top(self, args.block_accessor, &args.position.down())
<Self as CropBlockBase>::can_plant_on_top(
self,
args.block_accessor,
&args.position.down(),
)
.await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -45,10 +45,8 @@ impl AttachedStemBlock {
} }
impl BlockBehaviour for AttachedStemBlock { impl BlockBehaviour for AttachedStemBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -76,8 +74,8 @@ impl BlockBehaviour for AttachedStemBlock {
} }
impl PlantBlockBase for AttachedStemBlock { impl PlantBlockBase for AttachedStemBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
if block == &Block::ATTACHED_PUMPKIN_STEM { if block == &Block::ATTACHED_PUMPKIN_STEM {
block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_PUMPKIN_STEM) block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_PUMPKIN_STEM)
} else { } else {

View File

@ -58,10 +58,8 @@ impl StemBlock {
} }
impl BlockBehaviour for StemBlock { impl BlockBehaviour for StemBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -84,7 +82,7 @@ impl BlockBehaviour for StemBlock {
// TODO add light level check // TODO add light level check
let f: f32 = get_available_moisture(args.world, args.position, args.block).await; let f: f32 = get_available_moisture(args.world, args.position, args.block).await;
if rand::rng().random_range(0..=(25.0 / f).floor() as i32) == 0 { if rand::rng().random_range(0..=(25.0 / f).floor() as i32) == 0 {
let (block, state) = args.world.get_block_and_state_id(args.position).await; let (block, state) = args.world.get_block_and_state_id(args.position);
let props = StemProperties::from_state_id(state, block); let props = StemProperties::from_state_id(state, block);
let age = i32::from(props.age); let age = i32::from(props.age);
if age < 7 { if age < 7 {
@ -100,8 +98,8 @@ impl BlockBehaviour for StemBlock {
Xoroshiro::from_seed(rand::rng().random()), Xoroshiro::from_seed(rand::rng().random()),
)); ));
let plant_block_pos = args.position.offset(dir.to_offset()); let plant_block_pos = args.position.offset(dir.to_offset());
let plant_block_state = args.world.get_block_state(&plant_block_pos).await; let plant_block_state = args.world.get_block_state(&plant_block_pos);
let under_block: &Block = args.world.get_block(&plant_block_pos.down()).await; let under_block: &Block = args.world.get_block(&plant_block_pos.down());
if plant_block_state.is_air() if plant_block_state.is_air()
&& (under_block == &Block::FARMLAND && (under_block == &Block::FARMLAND
|| under_block.has_tag(&tag::Block::MINECRAFT_DIRT)) || under_block.has_tag(&tag::Block::MINECRAFT_DIRT))
@ -130,8 +128,8 @@ impl BlockBehaviour for StemBlock {
} }
impl PlantBlockBase for StemBlock { impl PlantBlockBase for StemBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
if block == &Block::PUMPKIN_STEM { if block == &Block::PUMPKIN_STEM {
block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_PUMPKIN_STEM) block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_PUMPKIN_STEM)
} else { } else {

View File

@ -30,8 +30,8 @@ pub mod torch_flower;
pub mod wheat; pub mod wheat;
trait CropBlockBase: PlantBlockBase { trait CropBlockBase: PlantBlockBase {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
block == &Block::FARMLAND block == &Block::FARMLAND
} }
@ -51,7 +51,7 @@ trait CropBlockBase: PlantBlockBase {
} }
async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) { async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) {
let (block, state) = world.get_block_and_state_id(pos).await; let (block, state) = world.get_block_and_state_id(pos);
let age = self.get_age(state, block); let age = self.get_age(state, block);
if age < self.max_age() { if age < self.max_age() {
let f = get_available_moisture(world, pos, block).await; let f = get_available_moisture(world, pos, block).await;
@ -90,9 +90,8 @@ pub async fn get_available_moisture(world: &Arc<World>, pos: &BlockPos, block: &
for dz in -1..=1 { for dz in -1..=1 {
let mut local_moisture = 0.0; let mut local_moisture = 0.0;
let (block, block_state) = world let (block, block_state) =
.get_block_and_state_id(&down_pos.offset(Vector3 { x: dx, y: 0, z: dz })) world.get_block_and_state_id(&down_pos.offset(Vector3 { x: dx, y: 0, z: dz }));
.await;
if block == &Block::FARMLAND { if block == &Block::FARMLAND {
local_moisture = 1.0; local_moisture = 1.0;
let props = FarmlandProperties::from_state_id(block_state, block); let props = FarmlandProperties::from_state_id(block_state, block);
@ -113,13 +112,13 @@ pub async fn get_available_moisture(world: &Arc<World>, pos: &BlockPos, block: &
let south = pos.offset(South.to_offset()); let south = pos.offset(South.to_offset());
let west = pos.offset(West.to_offset()); let west = pos.offset(West.to_offset());
let east = pos.offset(East.to_offset()); let east = pos.offset(East.to_offset());
let horizontal = world.get_block(&west).await == block || world.get_block(&east).await == block; let horizontal = world.get_block(&west) == block || world.get_block(&east) == block;
let vertical = world.get_block(&north).await == block || world.get_block(&south).await == block; let vertical = world.get_block(&north) == block || world.get_block(&south) == block;
if (horizontal && vertical) if (horizontal && vertical)
|| world.get_block(&west.offset(North.to_offset())).await == block || world.get_block(&west.offset(North.to_offset())) == block
|| world.get_block(&east.offset(North.to_offset())).await == block || world.get_block(&east.offset(North.to_offset())) == block
|| world.get_block(&east.offset(South.to_offset())).await == block || world.get_block(&east.offset(South.to_offset())) == block
|| world.get_block(&west.offset(South.to_offset())).await == block || world.get_block(&west.offset(South.to_offset())) == block
{ {
moisture /= 2.0; moisture /= 2.0;
} }

View File

@ -25,10 +25,8 @@ use crate::{
pub struct NetherWartBlock; pub struct NetherWartBlock;
impl BlockBehaviour for NetherWartBlock { impl BlockBehaviour for NetherWartBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -54,19 +52,19 @@ impl BlockBehaviour for NetherWartBlock {
} }
impl PlantBlockBase for NetherWartBlock { impl PlantBlockBase for NetherWartBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_NETHER_WART) block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_NETHER_WART)
} }
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await <Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down())
} }
} }
impl CropBlockBase for NetherWartBlock { impl CropBlockBase for NetherWartBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, pos).await <Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, pos)
} }
fn max_age(&self) -> i32 { fn max_age(&self) -> i32 {
@ -85,7 +83,7 @@ impl CropBlockBase for NetherWartBlock {
} }
async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) { async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) {
let (block, state) = world.get_block_and_state_id(pos).await; let (block, state) = world.get_block_and_state_id(pos);
let age = self.get_age(state, block); let age = self.get_age(state, block);
if age < self.max_age() && rand::rng().random_range(0..=10) == 0 { if age < self.max_age() && rand::rng().random_range(0..=10) == 0 {
world world

View File

@ -11,15 +11,8 @@ use crate::block::{
pub struct PotatoBlock; pub struct PotatoBlock;
impl BlockBehaviour for PotatoBlock { impl BlockBehaviour for PotatoBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as CropBlockBase>::can_plant_on_top(self, args.block_accessor, &args.position.down())
<Self as CropBlockBase>::can_plant_on_top(
self,
args.block_accessor,
&args.position.down(),
)
.await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -32,7 +32,7 @@ pub struct SweetBerryBushBlock;
impl BlockBehaviour for SweetBerryBushBlock { impl BlockBehaviour for SweetBerryBushBlock {
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let mut props = NetherWartLikeProperties::from_state_id(state_id, args.block); let mut props = NetherWartLikeProperties::from_state_id(state_id, args.block);
match props.age { match props.age {
2 | 3 => { 2 | 3 => {
@ -66,7 +66,7 @@ impl BlockBehaviour for SweetBerryBushBlock {
args: UseWithItemArgs<'a>, args: UseWithItemArgs<'a>,
) -> BlockFuture<'a, BlockActionResult> { ) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let props = NetherWartLikeProperties::from_state_id(state_id, &Block::SWEET_BERRY_BUSH); let props = NetherWartLikeProperties::from_state_id(state_id, &Block::SWEET_BERRY_BUSH);
if props.age != 3 && args.item_stack.lock().await.get_item() == &Item::BONE_MEAL { if props.age != 3 && args.item_stack.lock().await.get_item() == &Item::BONE_MEAL {
BlockActionResult::Pass BlockActionResult::Pass
@ -76,10 +76,8 @@ impl BlockBehaviour for SweetBerryBushBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -119,7 +117,7 @@ impl BlockBehaviour for SweetBerryBushBlock {
entity.last_pos.load() - entity.pos.load() entity.last_pos.load() - entity.pos.load()
}; };
let state_id = args.world.get_block_state_id(args.position).await; let state_id = args.world.get_block_state_id(args.position);
let props = NetherWartLikeProperties::from_state_id(state_id, args.block); let props = NetherWartLikeProperties::from_state_id(state_id, args.block);
if props.age == 0 { if props.age == 0 {
return; return;
@ -153,20 +151,20 @@ impl PlantBlockBase for SweetBerryBushBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
block_state block_state
} }
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await <Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down())
} }
} }
impl CropBlockBase for SweetBerryBushBlock { impl CropBlockBase for SweetBerryBushBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, pos).await <Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, pos)
} }
fn max_age(&self) -> i32 { fn max_age(&self) -> i32 {
@ -185,10 +183,10 @@ impl CropBlockBase for SweetBerryBushBlock {
} }
async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) { async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) {
let (block, state) = world.get_block_and_state_id(pos).await; let (block, state) = world.get_block_and_state_id(pos);
let age = self.get_age(state, block); let age = self.get_age(state, block);
if age < self.max_age() { if age < self.max_age() {
let state_above = world.get_block_state(&pos.up()).await; let state_above = world.get_block_state(&pos.up());
if state_above.is_full_cube() || state_above.is_solid() { if state_above.is_full_cube() || state_above.is_solid() {
return; return;

View File

@ -16,15 +16,8 @@ type TorchFlowerProperties = TorchflowerCropLikeProperties;
pub struct TorchFlowerBlock; pub struct TorchFlowerBlock;
impl BlockBehaviour for TorchFlowerBlock { impl BlockBehaviour for TorchFlowerBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as CropBlockBase>::can_plant_on_top(self, args.block_accessor, &args.position.down())
<Self as CropBlockBase>::can_plant_on_top(
self,
args.block_accessor,
&args.position.down(),
)
.await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -11,15 +11,8 @@ use crate::block::{
pub struct WheatBlock; pub struct WheatBlock;
impl BlockBehaviour for WheatBlock { impl BlockBehaviour for WheatBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as CropBlockBase>::can_plant_on_top(self, args.block_accessor, &args.position.down())
<Self as CropBlockBase>::can_plant_on_top(
self,
args.block_accessor,
&args.position.down(),
)
.await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -22,10 +22,8 @@ impl BlockMetadata for DryVegetationBlock {
} }
impl BlockBehaviour for DryVegetationBlock { impl BlockBehaviour for DryVegetationBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -45,12 +43,8 @@ impl BlockBehaviour for DryVegetationBlock {
} }
impl PlantBlockBase for DryVegetationBlock { impl PlantBlockBase for DryVegetationBlock {
async fn can_plant_on_top( fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
&self, let block_below = block_accessor.get_block(block_pos);
block_accessor: &dyn BlockAccessor,
block_pos: &BlockPos,
) -> bool {
let block_below = block_accessor.get_block(block_pos).await;
block_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_DRY_VEGETATION) block_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_DRY_VEGETATION)
} }
} }

View File

@ -19,10 +19,8 @@ impl BlockMetadata for FlowerBlock {
} }
impl BlockBehaviour for FlowerBlock { impl BlockBehaviour for FlowerBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -22,19 +22,17 @@ impl BlockMetadata for FlowerbedBlock {
} }
impl BlockBehaviour for FlowerbedBlock { impl BlockBehaviour for FlowerbedBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { let block_below = args.block_accessor.get_block(&args.position.down());
let block_below = args.block_accessor.get_block(&args.position.down()).await; block_below.has_tag(&tag::Block::MINECRAFT_DIRT) || block_below == &Block::FARMLAND
block_below.has_tag(&tag::Block::MINECRAFT_DIRT) || block_below == &Block::FARMLAND
})
} }
fn can_update_at<'a>(&'a self, args: CanUpdateAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_update_at(&self, args: CanUpdateAtArgs<'_>) -> bool {
Box::pin(async move { Segmented::can_update_at(self, args).await }) Segmented::can_update_at(self, args)
} }
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Segmented::on_place(self, args).await }) Segmented::on_place(self, args)
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -14,10 +14,8 @@ impl BlockMetadata for FungusBlock {
} }
impl BlockBehaviour for FungusBlock { impl BlockBehaviour for FungusBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -35,19 +33,19 @@ impl BlockBehaviour for FungusBlock {
} }
} }
impl PlantBlockBase for FungusBlock { impl PlantBlockBase for FungusBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
if block == &Block::WARPED_FUNGUS { if block == &Block::WARPED_FUNGUS {
return block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_WARPED_FUNGUS); return block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_WARPED_FUNGUS);
} }
block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_CRIMSON_FUNGUS) block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_CRIMSON_FUNGUS)
} }
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await <Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down())
} }
} }

View File

@ -18,10 +18,8 @@ impl BlockMetadata for KelpBlock {
} }
impl BlockBehaviour for KelpBlock { impl BlockBehaviour for KelpBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -40,7 +38,7 @@ impl BlockBehaviour for KelpBlock {
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let support_pos = args.position.down(); let support_pos = args.position.down();
let support_block = args.world.get_block(&support_pos).await; let support_block = args.world.get_block(&support_pos);
if support_block == &Block::KELP { if support_block == &Block::KELP {
args.world args.world
.set_block_state( .set_block_state(
@ -55,7 +53,7 @@ impl BlockBehaviour for KelpBlock {
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let support_pos = args.position.down(); let support_pos = args.position.down();
let support_block = args.world.get_block(&support_pos).await; let support_block = args.world.get_block(&support_pos);
if support_block == &Block::KELP_PLANT { if support_block == &Block::KELP_PLANT {
args.world args.world
.set_block_state( .set_block_state(
@ -77,7 +75,7 @@ impl BlockBehaviour for KelpBlock {
} }
impl PlantBlockBase for KelpBlock { impl PlantBlockBase for KelpBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
@ -85,9 +83,8 @@ impl PlantBlockBase for KelpBlock {
// Determine support block // Determine support block
let support_pos = pos; let support_pos = pos;
let (replacing_block, replacing_block_state) = let (replacing_block, replacing_block_state) =
block_accessor.get_block_and_state(&pos.up()).await; block_accessor.get_block_and_state(&pos.up());
let (support_block, support_block_state) = let (support_block, support_block_state) = block_accessor.get_block_and_state(support_pos);
block_accessor.get_block_and_state(support_pos).await;
if replacing_block == &Block::WATER { if replacing_block == &Block::WATER {
let water_props = let water_props =
WaterLikeProperties::from_state_id(replacing_block_state.id, replacing_block); WaterLikeProperties::from_state_id(replacing_block_state.id, replacing_block);
@ -122,7 +119,7 @@ impl PlantBlockBase for KelpBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
return Block::WATER.default_state.id; return Block::WATER.default_state.id;
} }
block_state block_state

View File

@ -19,18 +19,13 @@ impl BlockMetadata for LeafLitterBlock {
} }
impl BlockBehaviour for LeafLitterBlock { impl BlockBehaviour for LeafLitterBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { let block_below = args.block_accessor.get_block_state(&args.position.down());
let block_below = args block_below.is_side_solid(BlockDirection::Up)
.block_accessor
.get_block_state(&args.position.down())
.await;
block_below.is_side_solid(BlockDirection::Up)
})
} }
fn can_update_at<'a>(&'a self, args: CanUpdateAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_update_at(&self, args: CanUpdateAtArgs<'_>) -> bool {
Box::pin(async move { Segmented::can_update_at(self, args).await }) Segmented::can_update_at(self, args)
} }
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
@ -43,7 +38,7 @@ impl BlockBehaviour for LeafLitterBlock {
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if args.direction == BlockDirection::Down { if args.direction == BlockDirection::Down {
let block_below_state = args.world.get_block_state(&args.position.down()).await; let block_below_state = args.world.get_block_state(&args.position.down());
if !block_below_state.is_side_solid(BlockDirection::Up) { if !block_below_state.is_side_solid(BlockDirection::Up) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }

View File

@ -31,10 +31,8 @@ impl BlockBehaviour for LilyPadBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -54,10 +52,10 @@ impl BlockBehaviour for LilyPadBlock {
} }
impl PlantBlockBase for LilyPadBlock { impl PlantBlockBase for LilyPadBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
// TODO: get and use fluids not blocks // TODO: get and use fluids not blocks
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
let above_fluid = block_accessor.get_block(&pos.up()).await; let above_fluid = block_accessor.get_block(&pos.up());
(block.has_tag(&tag::Fluid::MINECRAFT_SUPPORTS_LILY_PAD) (block.has_tag(&tag::Fluid::MINECRAFT_SUPPORTS_LILY_PAD)
|| block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_LILY_PAD)) || block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_LILY_PAD))
&& above_fluid.is_air() && above_fluid.is_air()

View File

@ -37,8 +37,8 @@ pub mod weeping_vines;
pub mod wither_rose; pub mod wither_rose;
trait PlantBlockBase { trait PlantBlockBase {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_VEGETATION) block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_VEGETATION)
} }
@ -48,14 +48,13 @@ trait PlantBlockBase {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !self.can_place_at(block_accessor, block_pos).await { if !self.can_place_at(block_accessor, block_pos) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
block_state block_state
} }
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
self.can_plant_on_top(block_accessor, &block_pos.down()) self.can_plant_on_top(block_accessor, &block_pos.down())
.await
} }
} }

View File

@ -17,10 +17,8 @@ impl BlockMetadata for MushroomPlantBlock {
} }
impl BlockBehaviour for MushroomPlantBlock { impl BlockBehaviour for MushroomPlantBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -40,8 +38,8 @@ impl BlockBehaviour for MushroomPlantBlock {
} }
impl PlantBlockBase for MushroomPlantBlock { impl PlantBlockBase for MushroomPlantBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
block.has_tag(&tag::Block::MINECRAFT_OVERRIDES_MUSHROOM_LIGHT_REQUIREMENT) block.has_tag(&tag::Block::MINECRAFT_OVERRIDES_MUSHROOM_LIGHT_REQUIREMENT)
// TODO: Check light level and isOpaqueFullCube // TODO: Check light level and isOpaqueFullCube
} }

View File

@ -7,10 +7,8 @@ use pumpkin_world::BlockStateId;
pub struct NetherSproutsBlock; pub struct NetherSproutsBlock;
impl BlockBehaviour for NetherSproutsBlock { impl BlockBehaviour for NetherSproutsBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -28,12 +26,12 @@ impl BlockBehaviour for NetherSproutsBlock {
} }
} }
impl PlantBlockBase for NetherSproutsBlock { impl PlantBlockBase for NetherSproutsBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
let block = block_accessor.get_block(pos).await; let block = block_accessor.get_block(pos);
block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_NETHER_SPROUTS) block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_NETHER_SPROUTS)
} }
} }

View File

@ -18,10 +18,8 @@ impl BlockMetadata for RootsBlock {
} }
impl BlockBehaviour for RootsBlock { impl BlockBehaviour for RootsBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -41,8 +39,8 @@ impl BlockBehaviour for RootsBlock {
} }
impl PlantBlockBase for RootsBlock { impl PlantBlockBase for RootsBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block_below = block_accessor.get_block(pos).await; let block_below = block_accessor.get_block(pos);
if block_below == &Block::WARPED_ROOTS { if block_below == &Block::WARPED_ROOTS {
block_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_WARPED_ROOTS) block_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_WARPED_ROOTS)
} else { } else {
@ -50,8 +48,7 @@ impl PlantBlockBase for RootsBlock {
} }
} }
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
self.can_plant_on_top(block_accessor, &block_pos.down()) self.can_plant_on_top(block_accessor, &block_pos.down())
.await
} }
} }

View File

@ -18,7 +18,7 @@ pub struct SaplingBlock;
impl SaplingBlock { impl SaplingBlock {
async fn generate(&self, world: &Arc<World>, pos: &BlockPos) { async fn generate(&self, world: &Arc<World>, pos: &BlockPos) {
let (block, state) = world.get_block_and_state_id(pos).await; let (block, state) = world.get_block_and_state_id(pos);
let mut props = SaplingProperties::from_state_id(state, block); let mut props = SaplingProperties::from_state_id(state, block);
if props.stage == 0 { if props.stage == 0 {
props.stage = 1; props.stage = 1;
@ -32,10 +32,8 @@ impl SaplingBlock {
} }
impl BlockBehaviour for SaplingBlock { impl BlockBehaviour for SaplingBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -32,10 +32,9 @@ impl BlockBehaviour for SeaPickleBlock {
|| !args || !args
.world .world
.get_block(&args.position.down()) .get_block(&args.position.down())
.await
.has_tag(&tag::Block::MINECRAFT_CORAL_BLOCKS) .has_tag(&tag::Block::MINECRAFT_CORAL_BLOCKS)
|| !SeaPickleProperties::from_state_id( || !SeaPickleProperties::from_state_id(
args.world.get_block_state_id(args.position).await, args.world.get_block_state_id(args.position),
args.block, args.block,
) )
.waterlogged .waterlogged
@ -62,11 +61,10 @@ impl BlockBehaviour for SeaPickleBlock {
); );
if &lv == args.position if &lv == args.position
|| rand::rng().random_range(0..6) != 0 || rand::rng().random_range(0..6) != 0
|| !args.world.get_block(&lv).await.eq(&Block::WATER) || !args.world.get_block(&lv).eq(&Block::WATER)
|| !args || !args
.world .world
.get_block(&lv.down()) .get_block(&lv.down())
.await
.has_tag(&tag::Block::MINECRAFT_CORAL_BLOCKS) .has_tag(&tag::Block::MINECRAFT_CORAL_BLOCKS)
{ {
continue; continue;
@ -124,21 +122,14 @@ impl BlockBehaviour for SeaPickleBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { let support_block = args.block_accessor.get_block_state(&args.position.down());
let support_block = args support_block.is_center_solid(BlockDirection::Up)
.block_accessor
.get_block_state(&args.position.down())
.await;
support_block.is_center_solid(BlockDirection::Up)
})
} }
fn can_update_at<'a>(&'a self, args: CanUpdateAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_update_at(&self, args: CanUpdateAtArgs<'_>) -> bool {
Box::pin(async move { args.player.get_entity().pose.load() != EntityPose::Crouching
args.player.get_entity().pose.load() != EntityPose::Crouching && SeaPickleProperties::from_state_id(args.state_id, args.block).pickles < 4
&& SeaPickleProperties::from_state_id(args.state_id, args.block).pickles < 4
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -13,10 +13,8 @@ use crate::block::{
#[pumpkin_block("minecraft:seagrass")] #[pumpkin_block("minecraft:seagrass")]
pub struct SeaGrassBlock; pub struct SeaGrassBlock;
impl BlockBehaviour for SeaGrassBlock { impl BlockBehaviour for SeaGrassBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -36,13 +34,13 @@ impl BlockBehaviour for SeaGrassBlock {
} }
impl PlantBlockBase for SeaGrassBlock { impl PlantBlockBase for SeaGrassBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
let (support_block, support_block_state) = block_accessor.get_block_and_state(pos).await; let (support_block, support_block_state) = block_accessor.get_block_and_state(pos);
let replacing_block = block_accessor.get_block(&pos.up()).await; let replacing_block = block_accessor.get_block(&pos.up());
if replacing_block != &Block::WATER && replacing_block != &Block::SEAGRASS { if replacing_block != &Block::WATER && replacing_block != &Block::SEAGRASS {
return false; return false;
} }
@ -57,7 +55,7 @@ impl PlantBlockBase for SeaGrassBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
return Block::WATER.default_state.id; return Block::WATER.default_state.id;
} }
block_state block_state

View File

@ -73,11 +73,9 @@ pub trait Segmented: BlockBehaviour {
} }
} }
fn can_update_at<'a>(&'a self, ctx: CanUpdateAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_update_at(&self, ctx: CanUpdateAtArgs<'_>) -> bool {
Box::pin(async move { let current_props = Self::Properties::from_state_id(ctx.state_id, ctx.block);
let current_props = Self::Properties::from_state_id(ctx.state_id, ctx.block); self.can_add_segment(&current_props)
self.can_add_segment(&current_props)
})
} }
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {

View File

@ -15,10 +15,8 @@ impl BlockMetadata for ShortPlantBlock {
} }
impl BlockBehaviour for ShortPlantBlock { impl BlockBehaviour for ShortPlantBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(

View File

@ -17,10 +17,8 @@ use pumpkin_world::world::{BlockAccessor, BlockFlags};
pub struct SmallDripleafBlock; pub struct SmallDripleafBlock;
impl BlockBehaviour for SmallDripleafBlock { impl BlockBehaviour for SmallDripleafBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> { fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
@ -65,7 +63,7 @@ impl BlockBehaviour for SmallDripleafBlock {
let mut upper_small_dripleaf_props = let mut upper_small_dripleaf_props =
SmallDripleafLikeProperties::default(&Block::SMALL_DRIPLEAF); SmallDripleafLikeProperties::default(&Block::SMALL_DRIPLEAF);
let upper_block = args.world.get_block(&args.position.up()).await; let upper_block = args.world.get_block(&args.position.up());
upper_small_dripleaf_props.facing = lower_small_dripleaf_props.facing; upper_small_dripleaf_props.facing = lower_small_dripleaf_props.facing;
upper_small_dripleaf_props.waterlogged = upper_block == &Block::WATER; upper_small_dripleaf_props.waterlogged = upper_block == &Block::WATER;
upper_small_dripleaf_props.half = DoubleBlockHalf::Upper; upper_small_dripleaf_props.half = DoubleBlockHalf::Upper;
@ -86,13 +84,13 @@ fn is_small_dripleaf_waterlogged(state_id: BlockStateId) -> bool {
dripleaf_props.waterlogged dripleaf_props.waterlogged
} }
impl PlantBlockBase for SmallDripleafBlock { impl PlantBlockBase for SmallDripleafBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool { fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let support_block = block_accessor.get_block(pos).await; let support_block = block_accessor.get_block(pos);
if support_block == &Block::SMALL_DRIPLEAF { if support_block == &Block::SMALL_DRIPLEAF {
return true; return true;
} }
let upper_block = block_accessor.get_block(&pos.up_height(2)).await; let upper_block = block_accessor.get_block(&pos.up_height(2));
if upper_block != &Block::AIR if upper_block != &Block::AIR
&& upper_block != &Block::WATER && upper_block != &Block::WATER
&& upper_block != &Block::SMALL_DRIPLEAF && upper_block != &Block::SMALL_DRIPLEAF
@ -100,7 +98,7 @@ impl PlantBlockBase for SmallDripleafBlock {
return false; return false;
} }
let (replacing_block, replacing_block_state) = let (replacing_block, replacing_block_state) =
block_accessor.get_block_and_state(&pos.up()).await; block_accessor.get_block_and_state(&pos.up());
if replacing_block == &Block::SMALL_DRIPLEAF && replacing_block_state.is_waterlogged() { if replacing_block == &Block::SMALL_DRIPLEAF && replacing_block_state.is_waterlogged() {
//in case of neighbor update check //in case of neighbor update check
supports_small_dripleaf(support_block, true) supports_small_dripleaf(support_block, true)
@ -115,14 +113,14 @@ impl PlantBlockBase for SmallDripleafBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
if is_small_dripleaf_waterlogged(block_state) { if is_small_dripleaf_waterlogged(block_state) {
return Block::WATER.default_state.id; return Block::WATER.default_state.id;
} }
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
let upper_block = block_accessor.get_block(&block_pos.up()).await; let upper_block = block_accessor.get_block(&block_pos.up());
let below_blow = block_accessor.get_block(&block_pos.down()).await; let below_blow = block_accessor.get_block(&block_pos.down());
if upper_block != &Block::SMALL_DRIPLEAF && below_blow != &Block::SMALL_DRIPLEAF { if upper_block != &Block::SMALL_DRIPLEAF && below_blow != &Block::SMALL_DRIPLEAF {
if is_small_dripleaf_waterlogged(block_state) { if is_small_dripleaf_waterlogged(block_state) {
return Block::WATER.default_state.id; return Block::WATER.default_state.id;

View File

@ -11,10 +11,8 @@ use pumpkin_world::world::BlockAccessor;
pub struct SporeBlossomBlock; pub struct SporeBlossomBlock;
impl BlockBehaviour for SporeBlossomBlock { impl BlockBehaviour for SporeBlossomBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -32,15 +30,15 @@ impl BlockBehaviour for SporeBlossomBlock {
} }
} }
impl PlantBlockBase for SporeBlossomBlock { impl PlantBlockBase for SporeBlossomBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
_block_accessor: &dyn pumpkin_world::world::BlockAccessor, _block_accessor: &dyn pumpkin_world::world::BlockAccessor,
_pos: &pumpkin_util::math::position::BlockPos, _pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
false false
} }
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
let ceiling_block = block_accessor.get_block(&block_pos.up()).await; let ceiling_block = block_accessor.get_block(&block_pos.up());
supports_spore_blossom(ceiling_block) supports_spore_blossom(ceiling_block)
} }
} }

View File

@ -22,7 +22,7 @@ pub struct SugarCaneBlock;
impl BlockBehaviour for SugarCaneBlock { impl BlockBehaviour for SugarCaneBlock {
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world.as_ref(), args.position).await { if !can_place_at(args.world.as_ref(), args.position) {
args.world args.world
.break_block(args.position, None, BlockFlags::empty()) .break_block(args.position, None, BlockFlags::empty())
.await; .await;
@ -32,16 +32,11 @@ impl BlockBehaviour for SugarCaneBlock {
fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> { fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
if args if args.world.get_block_state(&args.position.up()).is_air()
.world && !(args.world.get_block(&args.position.down()) == &Block::SUGAR_CANE
.get_block_state(&args.position.up()) && args.world.get_block(&args.position.down().down()) == &Block::SUGAR_CANE)
.await
.is_air()
&& !(args.world.get_block(&args.position.down()).await == &Block::SUGAR_CANE
&& args.world.get_block(&args.position.down().down()).await
== &Block::SUGAR_CANE)
{ {
let state_id = args.world.get_block_state(args.position).await.id; let state_id = args.world.get_block_state(args.position).id;
let age = CactusLikeProperties::from_state_id(state_id, args.block).age; let age = CactusLikeProperties::from_state_id(state_id, args.block).age;
if age == 15 { if age == 15 {
args.world args.world
@ -74,7 +69,7 @@ impl BlockBehaviour for SugarCaneBlock {
args: GetStateForNeighborUpdateArgs<'a>, args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> { ) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move { Box::pin(async move {
if !can_place_at(args.world, args.position).await { if !can_place_at(args.world, args.position) {
args.world args.world
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal) .schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
.await; .await;
@ -83,13 +78,13 @@ impl BlockBehaviour for SugarCaneBlock {
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { can_place_at(args.block_accessor, args.position).await }) can_place_at(args.block_accessor, args.position)
} }
} }
async fn can_place_at(block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool { fn can_place_at(block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
let block_below = block_accessor.get_block(&block_pos.down()).await; let block_below = block_accessor.get_block(&block_pos.down());
if block_below == &Block::SUGAR_CANE { if block_below == &Block::SUGAR_CANE {
return true; return true;
@ -97,9 +92,7 @@ async fn can_place_at(block_accessor: &dyn BlockAccessor, block_pos: &BlockPos)
if block_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_SUGAR_CANE) { if block_below.has_tag(&tag::Block::MINECRAFT_SUPPORTS_SUGAR_CANE) {
for direction in HorizontalFacing::all() { for direction in HorizontalFacing::all() {
let block = block_accessor let block = block_accessor.get_block(&block_pos.down().offset(direction.to_offset()));
.get_block(&block_pos.down().offset(direction.to_offset()))
.await;
// TODO: use fluid // TODO: use fluid
if block.has_tag(&tag::Fluid::MINECRAFT_SUPPORTS_SUGAR_CANE_ADJACENTLY) if block.has_tag(&tag::Fluid::MINECRAFT_SUPPORTS_SUGAR_CANE_ADJACENTLY)
&& block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_SUGAR_CANE_ADJACENTLY) && block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_SUGAR_CANE_ADJACENTLY)

View File

@ -32,32 +32,23 @@ impl BlockMetadata for TallPlantBlock {
} }
impl BlockBehaviour for TallPlantBlock { impl BlockBehaviour for TallPlantBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { let up_pos = args.position.up();
let up_pos = args.position.up();
let upper_state = args.block_accessor.get_block_state(&up_pos).await; let upper_state = args.block_accessor.get_block_state(&up_pos);
let Some(world) = args.world else { let Some(world) = args.world else {
return <Self as PlantBlockBase>::can_place_at(
self,
args.block_accessor,
args.position,
)
.await
&& upper_state.is_air();
};
if up_pos.0.y > world.get_top_y() {
return false;
}
return <Self as PlantBlockBase>::can_place_at( return <Self as PlantBlockBase>::can_place_at(
self, self,
args.block_accessor, args.block_accessor,
args.position, args.position,
) ) && upper_state.is_air();
.await };
&& upper_state.is_air();
}) if up_pos.0.y > world.get_top_y() {
return false;
}
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
&& upper_state.is_air()
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -71,14 +62,11 @@ impl BlockBehaviour for TallPlantBlock {
DoubleBlockHalf::Upper => (args.position.down_height(2), args.position.down()), DoubleBlockHalf::Upper => (args.position.down_height(2), args.position.down()),
DoubleBlockHalf::Lower => (args.position.down(), args.position.up()), DoubleBlockHalf::Lower => (args.position.down(), args.position.up()),
}; };
if !<Self as PlantBlockBase>::can_place_at(self, args.world, &support_block_pos.up()) if !<Self as PlantBlockBase>::can_place_at(self, args.world, &support_block_pos.up()) {
.await
{
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
let (other_block, other_state_id) = let (other_block, other_state_id) = args.world.get_block_and_state_id(&other_block_pos);
args.world.get_block_and_state_id(&other_block_pos).await;
if Self::ids().contains(&other_block.id) { if Self::ids().contains(&other_block.id) {
let other_props = let other_props =
TallSeagrassLikeProperties::from_state_id(other_state_id, other_block); TallSeagrassLikeProperties::from_state_id(other_state_id, other_block);
@ -117,8 +105,7 @@ impl BlockBehaviour for TallPlantBlock {
DoubleBlockHalf::Upper => args.position.down(), DoubleBlockHalf::Upper => args.position.down(),
DoubleBlockHalf::Lower => args.position.up(), DoubleBlockHalf::Lower => args.position.up(),
}; };
let (other_block, other_state_id) = let (other_block, other_state_id) = args.world.get_block_and_state_id(&other_block_pos);
args.world.get_block_and_state_id(&other_block_pos).await;
if Self::ids().contains(&other_block.id) { if Self::ids().contains(&other_block.id) {
let other_props = let other_props =
TallSeagrassLikeProperties::from_state_id(other_state_id, other_block); TallSeagrassLikeProperties::from_state_id(other_state_id, other_block);

View File

@ -10,10 +10,8 @@ use crate::block::{
#[pumpkin_block("minecraft:tall_seagrass")] #[pumpkin_block("minecraft:tall_seagrass")]
pub struct TallSeaGrassBlock; pub struct TallSeaGrassBlock;
impl BlockBehaviour for TallSeaGrassBlock { impl BlockBehaviour for TallSeaGrassBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
@ -33,20 +31,20 @@ impl BlockBehaviour for TallSeaGrassBlock {
} }
impl PlantBlockBase for TallSeaGrassBlock { impl PlantBlockBase for TallSeaGrassBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
let (support_block, support_block_state) = block_accessor.get_block_and_state(pos).await; let (support_block, support_block_state) = block_accessor.get_block_and_state(pos);
let replacing_block = block_accessor.get_block(&pos.up()).await; let replacing_block = block_accessor.get_block(&pos.up());
if replacing_block != &Block::WATER && replacing_block != &Block::TALL_SEAGRASS { if replacing_block != &Block::WATER && replacing_block != &Block::TALL_SEAGRASS {
return false; return false;
} }
if replacing_block == &Block::TALL_SEAGRASS { if replacing_block == &Block::TALL_SEAGRASS {
//only for blockupdate //only for blockupdate
let block_above = block_accessor.get_block(&pos.up_height(2)).await; let block_above = block_accessor.get_block(&pos.up_height(2));
let is_support_seagrass_block = support_block == &Block::TALL_SEAGRASS; let is_support_seagrass_block = support_block == &Block::TALL_SEAGRASS;
let is_above_seagrass_block = block_above == &Block::TALL_SEAGRASS; let is_above_seagrass_block = block_above == &Block::TALL_SEAGRASS;
match (is_support_seagrass_block, is_above_seagrass_block) { match (is_support_seagrass_block, is_above_seagrass_block) {
@ -68,7 +66,7 @@ impl PlantBlockBase for TallSeaGrassBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
return Block::WATER.default_state.id; return Block::WATER.default_state.id;
} }
block_state block_state

View File

@ -16,10 +16,8 @@ impl BlockMetadata for TwistingVinesBlock {
} }
impl BlockBehaviour for TwistingVinesBlock { impl BlockBehaviour for TwistingVinesBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -38,7 +36,7 @@ impl BlockBehaviour for TwistingVinesBlock {
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let support_pos = args.position.down(); let support_pos = args.position.down();
let support_block = args.world.get_block(&support_pos).await; let support_block = args.world.get_block(&support_pos);
if support_block == &Block::TWISTING_VINES { if support_block == &Block::TWISTING_VINES {
args.world args.world
.set_block_state( .set_block_state(
@ -53,7 +51,7 @@ impl BlockBehaviour for TwistingVinesBlock {
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let support_pos = args.position.down(); let support_pos = args.position.down();
let support_block = args.world.get_block(&support_pos).await; let support_block = args.world.get_block(&support_pos);
if support_block == &Block::TWISTING_VINES_PLANT { if support_block == &Block::TWISTING_VINES_PLANT {
args.world args.world
.set_block_state( .set_block_state(
@ -68,15 +66,14 @@ impl BlockBehaviour for TwistingVinesBlock {
} }
impl PlantBlockBase for TwistingVinesBlock { impl PlantBlockBase for TwistingVinesBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
// Determine support block // Determine support block
let support_pos = pos; let support_pos = pos;
let (support_block, support_block_state) = let (support_block, support_block_state) = block_accessor.get_block_and_state(support_pos);
block_accessor.get_block_and_state(support_pos).await;
if support_block == &Block::TWISTING_VINES || support_block == &Block::TWISTING_VINES_PLANT if support_block == &Block::TWISTING_VINES || support_block == &Block::TWISTING_VINES_PLANT
{ {
@ -95,7 +92,7 @@ impl PlantBlockBase for TwistingVinesBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
block_state block_state

View File

@ -16,10 +16,8 @@ impl BlockMetadata for WeepingVinesBlock {
} }
impl BlockBehaviour for WeepingVinesBlock { impl BlockBehaviour for WeepingVinesBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -38,7 +36,7 @@ impl BlockBehaviour for WeepingVinesBlock {
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let support_pos = args.position.up(); let support_pos = args.position.up();
let support_block = args.world.get_block(&support_pos).await; let support_block = args.world.get_block(&support_pos);
if support_block == &Block::WEEPING_VINES { if support_block == &Block::WEEPING_VINES {
args.world args.world
.set_block_state( .set_block_state(
@ -53,7 +51,7 @@ impl BlockBehaviour for WeepingVinesBlock {
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let support_pos = args.position.up(); let support_pos = args.position.up();
let support_block = args.world.get_block(&support_pos).await; let support_block = args.world.get_block(&support_pos);
if support_block == &Block::WEEPING_VINES_PLANT { if support_block == &Block::WEEPING_VINES_PLANT {
args.world args.world
.set_block_state( .set_block_state(
@ -68,15 +66,14 @@ impl BlockBehaviour for WeepingVinesBlock {
} }
impl PlantBlockBase for WeepingVinesBlock { impl PlantBlockBase for WeepingVinesBlock {
async fn can_place_at( fn can_place_at(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
// Determine support block // Determine support block
let support_pos = pos.up(); let support_pos = pos.up();
let (support_block, support_block_state) = let (support_block, support_block_state) = block_accessor.get_block_and_state(&support_pos);
block_accessor.get_block_and_state(&support_pos).await;
if support_block == &Block::WEEPING_VINES || support_block == &Block::WEEPING_VINES_PLANT { if support_block == &Block::WEEPING_VINES || support_block == &Block::WEEPING_VINES_PLANT {
return true; return true;
@ -94,7 +91,7 @@ impl PlantBlockBase for WeepingVinesBlock {
block_pos: &BlockPos, block_pos: &BlockPos,
block_state: BlockStateId, block_state: BlockStateId,
) -> BlockStateId { ) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await { if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos) {
return Block::AIR.default_state.id; return Block::AIR.default_state.id;
} }
block_state block_state

View File

@ -42,10 +42,8 @@ impl BlockBehaviour for WitherRoseBlock {
} }
}) })
} }
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { <Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
} }
fn get_state_for_neighbor_update<'a>( fn get_state_for_neighbor_update<'a>(
&'a self, &'a self,
@ -64,12 +62,12 @@ impl BlockBehaviour for WitherRoseBlock {
} }
impl PlantBlockBase for WitherRoseBlock { impl PlantBlockBase for WitherRoseBlock {
async fn can_plant_on_top( fn can_plant_on_top(
&self, &self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor, block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos, pos: &pumpkin_util::math::position::BlockPos,
) -> bool { ) -> bool {
let support_block = block_accessor.get_block(pos).await; let support_block = block_accessor.get_block(pos);
support_block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_WITHER_ROSE) support_block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_WITHER_ROSE)
} }
} }

View File

@ -96,7 +96,7 @@ impl BlockBehaviour for PowderSnowBlock {
Sound::EntityGenericBigFall Sound::EntityGenericBigFall
}; };
living.entity.play_sound(sound).await; living.entity.play_sound(sound);
} }
}) })
} }

View File

@ -42,8 +42,10 @@ impl crate::block::BlockBehaviour for PumpkinBlock {
args.position.to_f64(), args.position.to_f64(),
&EntityType::ITEM, &EntityType::ITEM,
); );
let item_entity = let item_entity = Arc::new(ItemEntity::new(
Arc::new(ItemEntity::new(entity, ItemStack::new(4, &Item::PUMPKIN_SEEDS)).await); entity,
ItemStack::new(4, &Item::PUMPKIN_SEEDS),
));
args.world.spawn_entity(item_entity).await; args.world.spawn_entity(item_entity).await;
// TODO: Deduct 1 durability from held shears (skip in Creative mode). // TODO: Deduct 1 durability from held shears (skip in Creative mode).
BlockActionResult::Consume BlockActionResult::Consume

View File

@ -32,30 +32,24 @@ pub trait RedstoneGateBlockProperties {
} }
pub trait RedstoneGateBlock<T: Send + Sync + BlockProperties + RedstoneGateBlockProperties> { pub trait RedstoneGateBlock<T: Send + Sync + BlockProperties + RedstoneGateBlockProperties> {
// 💡 Converted async fn to fn returning BlockFuture // 💡 Converted async fn to fn
fn can_place_at<'a>( fn can_place_at(&self, world: &dyn BlockAccessor, pos: BlockPos) -> bool
&'a self,
world: &'a dyn BlockAccessor,
pos: BlockPos,
) -> BlockFuture<'a, bool>
where where
Self: Send + Sync, Self: Send + Sync,
{ {
Box::pin(async move { let under_pos = pos.down();
let under_pos = pos.down(); let under_state = world.get_block_state(&under_pos);
let under_state = world.get_block_state(&under_pos).await; self.can_place_above(world, under_pos, under_state)
self.can_place_above(world, under_pos, under_state).await
})
} }
// 💡 Converted async fn to fn returning BlockFuture // 💡 Converted async fn to fn
fn can_place_above<'a>( fn can_place_above(
&'a self, &self,
_world: &'a dyn BlockAccessor, _world: &dyn BlockAccessor,
_pos: BlockPos, _pos: BlockPos,
state: &'a BlockState, state: &BlockState,
) -> BlockFuture<'a, bool> { ) -> bool {
Box::pin(async { state.is_side_solid(BlockDirection::Up) }) state.is_side_solid(BlockDirection::Up)
} }
fn get_weak_redstone_power<'a>(&'a self, args: GetRedstonePowerArgs<'a>) -> BlockFuture<'a, u8> fn get_weak_redstone_power<'a>(&'a self, args: GetRedstonePowerArgs<'a>) -> BlockFuture<'a, u8>
@ -90,8 +84,8 @@ pub trait RedstoneGateBlock<T: Send + Sync + BlockProperties + RedstoneGateBlock
Self: Send + Sync, Self: Send + Sync,
{ {
Box::pin(async move { Box::pin(async move {
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
if RedstoneGateBlock::can_place_at(self, args.world.as_ref(), *args.position).await { if RedstoneGateBlock::can_place_at(self, args.world.as_ref(), *args.position) {
self.update_powered(args.world, *args.position, state, args.block) self.update_powered(args.world, *args.position, state, args.block)
.await; .await;
return; return;
@ -259,9 +253,8 @@ pub trait RedstoneGateBlock<T: Send + Sync + BlockProperties + RedstoneGateBlock
Box::pin(async move { Box::pin(async move {
let props = T::from_state_id(state.id, block); let props = T::from_state_id(state.id, block);
let facing = props.get_facing().opposite(); let facing = props.get_facing().opposite();
let (target_block, target_state) = world let (target_block, target_state) =
.get_block_and_state(&pos.offset(facing.to_offset())) world.get_block_and_state(&pos.offset(facing.to_offset()));
.await;
if target_block == &Block::COMPARATOR { if target_block == &Block::COMPARATOR {
let props = ComparatorLikeProperties::from_state_id(target_state.id, target_block); let props = ComparatorLikeProperties::from_state_id(target_state.id, target_block);
props.facing != facing props.facing != facing
@ -286,7 +279,7 @@ pub async fn get_power<T: BlockProperties + RedstoneGateBlockProperties + Send>(
let props = T::from_state_id(state_id, block); let props = T::from_state_id(state_id, block);
let facing = props.get_facing(); let facing = props.get_facing();
let source_pos = pos.offset(facing.to_offset()); let source_pos = pos.offset(facing.to_offset());
let (source_block, source_state) = world.get_block_and_state(&source_pos).await; let (source_block, source_state) = world.get_block_and_state(&source_pos);
let source_level = get_redstone_power( let source_level = get_redstone_power(
source_block, source_block,
source_state, source_state,
@ -314,7 +307,7 @@ async fn get_power_on_side(
only_gate: bool, only_gate: bool,
) -> u8 { ) -> u8 {
let side_pos = pos.offset(side.to_block_direction().to_offset()); let side_pos = pos.offset(side.to_block_direction().to_offset());
let (side_block, side_state) = world.get_block_and_state(&side_pos).await; let (side_block, side_state) = world.get_block_and_state(&side_pos);
if !only_gate || is_diode(side_block) { if !only_gate || is_diode(side_block) {
world world
.block_registry .block_registry

View File

@ -21,31 +21,25 @@ use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId; use pumpkin_world::BlockStateId;
use pumpkin_world::world::BlockFlags; use pumpkin_world::world::BlockFlags;
async fn ring_bell( fn ring_bell(position: BlockPos, world: &Arc<World>, hit_direction: Option<HorizontalFacing>) {
position: BlockPos, let (block, state_id) = world.get_block_and_state_id(&position);
world: &Arc<World>,
hit_direction: Option<HorizontalFacing>,
) {
let (block, state_id) = world.get_block_and_state_id(&position).await;
let props = BellLikeProperties::from_state_id(state_id, block); let props = BellLikeProperties::from_state_id(state_id, block);
let direction = hit_direction.map_or(props.facing, |direction3| direction3); let direction = hit_direction.map_or(props.facing, |direction3| direction3);
if let Some(block_entity) = world.get_block_entity(&position).await if let Some(block_entity) = world.get_block_entity(&position)
&& let Some(be) = block_entity.as_any().downcast_ref::<BellBlockEntity>() && let Some(be) = block_entity.as_any().downcast_ref::<BellBlockEntity>()
{ {
be.activate(direction); be.activate(direction);
} }
world world.play_sound_fine(
.play_sound_fine( Sound::BlockBellUse,
Sound::BlockBellUse, SoundCategory::Blocks,
SoundCategory::Blocks, &position.to_centered_f64(),
&position.to_centered_f64(), 1.0,
1.0, 2.0,
2.0, );
)
.await;
//TODO Emit game event: BLOCK_CHANGE -> Send block update Packet //TODO Emit game event: BLOCK_CHANGE -> Send block update Packet
} }
@ -73,10 +67,9 @@ fn is_point_on_bell(
} }
} }
async fn is_single_wall(position: BlockPos, facing: HorizontalFacing, world: &World) -> bool { fn is_single_wall(position: BlockPos, facing: HorizontalFacing, world: &World) -> bool {
!world !world
.get_block(&position.offset(facing.to_offset())) .get_block(&position.offset(facing.to_offset()))
.await
.is_solid() .is_solid()
} }
@ -97,28 +90,26 @@ impl WallMountedBlock for BellBlock {
} }
impl BlockBehaviour for BellBlock { impl BlockBehaviour for BellBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> { fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
Box::pin(async move { if let Some(direction) = args.direction
if let Some(direction) = args.direction && let Some(world) = args.world
&& let Some(world) = args.world {
{ if direction == BlockDirection::Up {
if direction == BlockDirection::Up { let block: &Block = world.get_block(args.position);
let block: &Block = world.get_block(args.position).await;
if block.has_tag(&tag::Block::MINECRAFT_UNSTABLE_BOTTOM_CENTER) { if block.has_tag(&tag::Block::MINECRAFT_UNSTABLE_BOTTOM_CENTER) {
false false
} else {
let block_pos = args.position.offset(direction.to_offset());
let block_state = world.get_block_state(&block_pos).await;
block_state.is_center_solid(direction)
}
} else { } else {
WallMountedBlock::can_place_at(self, world, args.position, direction).await let block_pos = args.position.offset(direction.to_offset());
let block_state = world.get_block_state(&block_pos);
block_state.is_center_solid(direction)
} }
} else { } else {
false WallMountedBlock::can_place_at(self, world, args.position, direction)
} }
}) } else {
false
}
} }
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> { fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
@ -136,7 +127,7 @@ impl BlockBehaviour for BellBlock {
} }
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> { fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move { Box::pin(async move {
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
let props = BellLikeProperties::from_state_id(state.id, args.block); let props = BellLikeProperties::from_state_id(state.id, args.block);
@ -147,8 +138,7 @@ impl BlockBehaviour for BellBlock {
*args.position, *args.position,
args.world, args.world,
args.hit.face.to_horizontal_facing(), args.hit.face.to_horizontal_facing(),
) );
.await;
BlockActionResult::Success BlockActionResult::Success
}) })
@ -170,7 +160,7 @@ impl BlockBehaviour for BellBlock {
props.attachment = match block_face { props.attachment = match block_face {
AttachFace::Wall => { AttachFace::Wall => {
if is_single_wall(*args.position, props.facing.opposite(), args.world).await { if is_single_wall(*args.position, props.facing.opposite(), args.world) {
BellAttachment::SingleWall BellAttachment::SingleWall
} else { } else {
BellAttachment::DoubleWall BellAttachment::DoubleWall
@ -189,7 +179,7 @@ impl BlockBehaviour for BellBlock {
let world: &World = args.world; let world: &World = args.world;
let is_receiving_power = block_receives_redstone_power(world, args.position).await; let is_receiving_power = block_receives_redstone_power(world, args.position).await;
let state = args.world.get_block_state(args.position).await; let state = args.world.get_block_state(args.position);
let mut props = BellLikeProperties::from_state_id(state.id, args.block); let mut props = BellLikeProperties::from_state_id(state.id, args.block);
@ -205,7 +195,7 @@ impl BlockBehaviour for BellBlock {
.await; .await;
if is_receiving_power { if is_receiving_power {
ring_bell(*args.position, args.world, None).await; ring_bell(*args.position, args.world, None);
} }
} }
}) })

Some files were not shown because too many files have changed in this diff Show More