mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
feat(block): implement decorated pot block logic and fix deadlock
This commit is contained in:
131
crates/pumpkin/src/block/blocks/decorated_pot.rs
Normal file
131
crates/pumpkin/src/block/blocks/decorated_pot.rs
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user