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 abstract_wall_mounting;
|
||||||
|
|
||||||
pub mod beacon;
|
pub mod beacon;
|
||||||
|
pub mod decorated_pot;
|
||||||
pub mod trial_spawner;
|
pub mod trial_spawner;
|
||||||
pub mod vault;
|
pub mod vault;
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ impl BlockEntity for DecoratedPotBlockEntity {
|
|||||||
|
|
||||||
impl DecoratedPotBlockEntity {
|
impl DecoratedPotBlockEntity {
|
||||||
pub const ID: &'static str = "minecraft:decorated_pot";
|
pub const ID: &'static str = "minecraft:decorated_pot";
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(position: BlockPos) -> Self {
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -84,4 +85,45 @@ impl DecoratedPotBlockEntity {
|
|||||||
item: Mutex::const_new(None),
|
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_block::CoralBlock;
|
||||||
use crate::block::blocks::coral::coral_fan::CoralFanBlock;
|
use crate::block::blocks::coral::coral_fan::CoralFanBlock;
|
||||||
use crate::block::blocks::coral::coral_plant::CoralPlantBlock;
|
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::dirt_path::DirtPathBlock;
|
||||||
use crate::block::blocks::doors::DoorBlock;
|
use crate::block::blocks::doors::DoorBlock;
|
||||||
use crate::block::blocks::dripstone::DripstoneBlock;
|
use crate::block::blocks::dripstone::DripstoneBlock;
|
||||||
@@ -252,6 +253,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
|||||||
manager.register(TNTBlock);
|
manager.register(TNTBlock);
|
||||||
manager.register(TrialSpawnerBlock);
|
manager.register(TrialSpawnerBlock);
|
||||||
manager.register(VaultBlock);
|
manager.register(VaultBlock);
|
||||||
|
manager.register(DecoratedPotBlock);
|
||||||
manager.register(BushBlock);
|
manager.register(BushBlock);
|
||||||
manager.register(FlowerBlock);
|
manager.register(FlowerBlock);
|
||||||
manager.register(PotatoBlock);
|
manager.register(PotatoBlock);
|
||||||
|
|||||||
@@ -5291,10 +5291,12 @@ impl World {
|
|||||||
|
|
||||||
pub fn get_block_entity(&self, block_pos: &BlockPos) -> Option<Arc<dyn BlockEntity>> {
|
pub fn get_block_entity(&self, block_pos: &BlockPos) -> Option<Arc<dyn BlockEntity>> {
|
||||||
let chunk_pos = block_pos.chunk_position();
|
let chunk_pos = block_pos.chunk_position();
|
||||||
if let Some(chunk_block_entities) = self.block_entities.get(&chunk_pos)
|
if let Some(entity) = self
|
||||||
&& let Some(entity) = chunk_block_entities.get(block_pos)
|
.block_entities
|
||||||
|
.get(&chunk_pos)
|
||||||
|
.and_then(|m| m.get(block_pos).cloned())
|
||||||
{
|
{
|
||||||
return Some(entity.clone());
|
return Some(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
let nbt = self
|
let nbt = self
|
||||||
|
|||||||
Reference in New Issue
Block a user