feat(block): implement decorated pot block logic and fix deadlock

This commit is contained in:
Alexander Medvedev
2026-08-12 20:28:44 +02:00
parent d0cc8a2b51
commit e9958f5d64
5 changed files with 181 additions and 3 deletions

View File

@@ -0,0 +1,131 @@
use std::sync::Arc;
use pumpkin_data::block_properties::{BlockProperties, DecoratedPotLikeProperties};
use pumpkin_data::item::Item;
use pumpkin_data::item_stack::ItemStack;
use pumpkin_data::sound::{Sound, SoundCategory};
use pumpkin_data::BlockStateId;
use pumpkin_macros::pumpkin_block;
use crate::block::entities::decorated_pot::DecoratedPotBlockEntity;
use crate::block::registry::BlockActionResult;
use crate::block::{
BlockBehaviour, BlockFuture, BrokenArgs, GetComparatorOutputArgs, NormalUseArgs, OnPlaceArgs,
PlacedArgs, UseWithItemArgs,
};
#[pumpkin_block("minecraft:decorated_pot")]
pub struct DecoratedPotBlock;
impl BlockBehaviour for DecoratedPotBlock {
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move {
let mut props = DecoratedPotLikeProperties::from_state_id(
args.block.default_state.id,
args.block,
);
props.facing = args
.player
.living_entity
.entity
.get_horizontal_facing()
.opposite();
props.to_state_id(args.block)
})
}
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let entity = DecoratedPotBlockEntity::new(*args.position);
args.world.add_block_entity(Arc::new(entity));
})
}
fn use_with_item<'a>(
&'a self,
args: UseWithItemArgs<'a>,
) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move {
if args.item_stack.item_count == 0 {
return self
.normal_use(NormalUseArgs {
server: args.server,
world: args.world,
block: args.block,
position: args.position,
player: args.player,
hit: args.hit,
})
.await;
}
if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(pot_entity) =
block_entity.as_any().downcast_ref::<DecoratedPotBlockEntity>()
{
if pot_entity.try_insert_item(args.item_stack, 1).await {
args.world.play_sound(
Sound::BlockDecoratedPotInsert,
SoundCategory::Blocks,
&args.position.to_f64(),
);
} else {
args.world.play_sound(
Sound::BlockDecoratedPotInsertFail,
SoundCategory::Blocks,
&args.position.to_f64(),
);
}
return BlockActionResult::Success;
}
BlockActionResult::Pass
})
}
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
Box::pin(async move {
args.world.play_sound(
Sound::BlockDecoratedPotInsertFail,
SoundCategory::Blocks,
&args.position.to_f64(),
);
BlockActionResult::Success
})
}
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(pot_entity) =
block_entity.as_any().downcast_ref::<DecoratedPotBlockEntity>()
&& let Some(contained) = pot_entity.take_item().await
{
args.world.drop_stack(args.position, contained).await;
}
args.world.play_sound(
Sound::BlockDecoratedPotShatter,
SoundCategory::Blocks,
&args.position.to_f64(),
);
args.world.drop_stack(args.position, ItemStack::new(4, &Item::BRICK)).await;
})
}
fn get_comparator_output<'a>(
&'a self,
args: GetComparatorOutputArgs<'a>,
) -> BlockFuture<'a, Option<u8>> {
Box::pin(async move {
if let Some(block_entity) = args.world.get_block_entity(args.position)
&& let Some(pot_entity) =
block_entity.as_any().downcast_ref::<DecoratedPotBlockEntity>()
{
Some(pot_entity.get_comparator_output().await)
} else {
Some(0)
}
})
}
}

View File

@@ -110,5 +110,6 @@ pub mod coral;
pub mod abstract_wall_mounting;
pub mod beacon;
pub mod decorated_pot;
pub mod trial_spawner;
pub mod vault;

View File

@@ -76,6 +76,7 @@ impl BlockEntity for DecoratedPotBlockEntity {
impl DecoratedPotBlockEntity {
pub const ID: &'static str = "minecraft:decorated_pot";
#[must_use]
pub const fn new(position: BlockPos) -> Self {
Self {
@@ -84,4 +85,45 @@ impl DecoratedPotBlockEntity {
item: Mutex::const_new(None),
}
}
pub async fn get_item(&self) -> Option<ItemStack> {
self.item.lock().await.clone()
}
pub async fn take_item(&self) -> Option<ItemStack> {
self.item.lock().await.take()
}
pub async fn try_insert_item(&self, stack: &mut ItemStack, count: u8) -> bool {
let mut item_guard = self.item.lock().await;
if let Some(existing) = item_guard.as_mut() {
if existing.item.id == stack.item.id {
let add = count.min(64 - existing.item_count);
if add > 0 {
existing.item_count += add;
stack.item_count -= add;
return true;
}
}
false
} else {
let insert_count = count.min(stack.item_count);
let mut inserted = stack.clone();
inserted.item_count = insert_count;
*item_guard = Some(inserted);
stack.item_count -= insert_count;
true
}
}
pub async fn get_comparator_output(&self) -> u8 {
self.item.lock().await.as_ref().map_or(0, |item| {
if item.item_count == 0 {
0
} else {
let max_count = 64f32;
1 + ((item.item_count as f32 / max_count) * 14.0).floor() as u8
}
})
}
}

View File

@@ -23,6 +23,7 @@ use crate::block::blocks::conduit::ConduitBlock;
use crate::block::blocks::coral::coral_block::CoralBlock;
use crate::block::blocks::coral::coral_fan::CoralFanBlock;
use crate::block::blocks::coral::coral_plant::CoralPlantBlock;
use crate::block::blocks::decorated_pot::DecoratedPotBlock;
use crate::block::blocks::dirt_path::DirtPathBlock;
use crate::block::blocks::doors::DoorBlock;
use crate::block::blocks::dripstone::DripstoneBlock;
@@ -252,6 +253,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
manager.register(TNTBlock);
manager.register(TrialSpawnerBlock);
manager.register(VaultBlock);
manager.register(DecoratedPotBlock);
manager.register(BushBlock);
manager.register(FlowerBlock);
manager.register(PotatoBlock);

View File

@@ -5291,10 +5291,12 @@ impl World {
pub fn get_block_entity(&self, block_pos: &BlockPos) -> Option<Arc<dyn BlockEntity>> {
let chunk_pos = block_pos.chunk_position();
if let Some(chunk_block_entities) = self.block_entities.get(&chunk_pos)
&& let Some(entity) = chunk_block_entities.get(block_pos)
if let Some(entity) = self
.block_entities
.get(&chunk_pos)
.and_then(|m| m.get(block_pos).cloned())
{
return Some(entity.clone());
return Some(entity);
}
let nbt = self