feat: Implement all missing block entites
This commit is contained in:
parent
9eab7581fd
commit
3c6557d6db
@ -179,7 +179,7 @@ tracing-subscriber = { version = "0.3.23", default-features = false, features =
|
|||||||
] }
|
] }
|
||||||
slotmap = { version = "1.1", default-features = false, features = ["std"] }
|
slotmap = { version = "1.1", default-features = false, features = ["std"] }
|
||||||
temp-dir = { version = "0.2.0", default-features = false }
|
temp-dir = { version = "0.2.0", default-features = false }
|
||||||
thread_local = { version = "1.1.9", default-features = false }
|
thread_local = { version = "1.1.10", default-features = false }
|
||||||
time = { version = "0.3", default-features = false, features = ["std"] }
|
time = { version = "0.3", default-features = false, features = ["std"] }
|
||||||
arc-swap = { version = "1.9", default-features = false }
|
arc-swap = { version = "1.9", default-features = false }
|
||||||
tokio-util = { version = "0.7.18", default-features = false }
|
tokio-util = { version = "0.7.18", default-features = false }
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::block::{
|
use crate::block::{
|
||||||
BlockBehaviour, BlockFuture, GetStateForNeighborUpdateArgs, OnPlaceArgs, OnScheduledTickArgs,
|
BlockBehaviour, BlockFuture, GetStateForNeighborUpdateArgs, OnPlaceArgs, OnScheduledTickArgs,
|
||||||
|
PlacedArgs,
|
||||||
};
|
};
|
||||||
use crate::entity::EntityBase;
|
use crate::entity::EntityBase;
|
||||||
use pumpkin_data::BlockStateId;
|
use pumpkin_data::BlockStateId;
|
||||||
@ -9,10 +10,20 @@ use pumpkin_util::math::position::BlockPos;
|
|||||||
use pumpkin_world::tick::TickPriority;
|
use pumpkin_world::tick::TickPriority;
|
||||||
use pumpkin_world::world::{BlockAccessor, BlockFlags};
|
use pumpkin_world::world::{BlockAccessor, BlockFlags};
|
||||||
|
|
||||||
|
use crate::block::entities::banner::BannerBlockEntity;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[pumpkin_block_from_tag("minecraft:banners")]
|
#[pumpkin_block_from_tag("minecraft:banners")]
|
||||||
pub struct BannerBlock;
|
pub struct BannerBlock;
|
||||||
|
|
||||||
impl BlockBehaviour for BannerBlock {
|
impl BlockBehaviour for BannerBlock {
|
||||||
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let entity = BannerBlockEntity::new(*args.position);
|
||||||
|
args.world.add_block_entity(Arc::new(entity));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
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 mut props = WhiteBannerLikeProperties::default(args.block);
|
let mut props = WhiteBannerLikeProperties::default(args.block);
|
||||||
|
|||||||
@ -9,18 +9,27 @@ use pumpkin_data::{
|
|||||||
use pumpkin_macros::pumpkin_block_from_tag;
|
use pumpkin_macros::pumpkin_block_from_tag;
|
||||||
use pumpkin_world::tick::TickPriority;
|
use pumpkin_world::tick::TickPriority;
|
||||||
|
|
||||||
|
use crate::block::entities::campfire::CampfireBlockEntity;
|
||||||
use crate::{
|
use crate::{
|
||||||
block::{
|
block::{
|
||||||
BlockBehaviour, BlockFuture, BlockIsReplacing, GetStateForNeighborUpdateArgs,
|
BlockBehaviour, BlockFuture, BlockIsReplacing, GetStateForNeighborUpdateArgs,
|
||||||
OnEntityCollisionArgs, OnPlaceArgs,
|
OnEntityCollisionArgs, OnPlaceArgs, PlacedArgs,
|
||||||
},
|
},
|
||||||
entity::EntityBase,
|
entity::EntityBase,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[pumpkin_block_from_tag("minecraft:campfires")]
|
#[pumpkin_block_from_tag("minecraft:campfires")]
|
||||||
pub struct CampfireBlock;
|
pub struct CampfireBlock;
|
||||||
|
|
||||||
impl BlockBehaviour for CampfireBlock {
|
impl BlockBehaviour for CampfireBlock {
|
||||||
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let entity = CampfireBlockEntity::new(*args.position);
|
||||||
|
args.world.add_block_entity(Arc::new(entity));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: cooking food on campfire (CampfireBlockEntity)
|
// TODO: cooking food on campfire (CampfireBlockEntity)
|
||||||
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
use crate::block::{BlockBehaviour, BlockFuture, OnPlaceArgs};
|
use crate::block::entities::conduit::ConduitBlockEntity;
|
||||||
|
use crate::block::{BlockBehaviour, BlockFuture, OnPlaceArgs, PlacedArgs};
|
||||||
use pumpkin_data::BlockStateId;
|
use pumpkin_data::BlockStateId;
|
||||||
use pumpkin_data::block_properties::BlockProperties;
|
use pumpkin_data::block_properties::BlockProperties;
|
||||||
use pumpkin_macros::pumpkin_block;
|
use pumpkin_macros::pumpkin_block;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[pumpkin_block("minecraft:conduit")]
|
#[pumpkin_block("minecraft:conduit")]
|
||||||
pub struct ConduitBlock;
|
pub struct ConduitBlock;
|
||||||
@ -16,4 +18,11 @@ impl BlockBehaviour for ConduitBlock {
|
|||||||
props.to_state_id(args.block)
|
props.to_state_id(args.block)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let entity = ConduitBlockEntity::new(*args.position);
|
||||||
|
args.world.add_block_entity(Arc::new(entity));
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::block::entities::enchanting_table::EnchantingTableBlockEntity;
|
||||||
use crate::block::registry::BlockActionResult;
|
use crate::block::registry::BlockActionResult;
|
||||||
use crate::block::{BlockBehaviour, BlockFuture, NormalUseArgs};
|
use crate::block::{BlockBehaviour, BlockFuture, NormalUseArgs, PlacedArgs};
|
||||||
use pumpkin_data::{Block, BlockStateId, translation};
|
use pumpkin_data::{Block, BlockStateId, 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;
|
||||||
@ -18,6 +19,13 @@ use tokio::sync::Mutex;
|
|||||||
pub struct EnchantingTableBlock;
|
pub struct EnchantingTableBlock;
|
||||||
|
|
||||||
impl BlockBehaviour for EnchantingTableBlock {
|
impl BlockBehaviour for EnchantingTableBlock {
|
||||||
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let entity = EnchantingTableBlockEntity::new(*args.position);
|
||||||
|
args.world.add_block_entity(Arc::new(entity));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
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 mut bookshelf_count = 0;
|
let mut bookshelf_count = 0;
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
use crate::block::{BlockBehaviour, BlockFuture, OnPlaceArgs};
|
use crate::block::entities::dispenser::DispenserBlockEntity;
|
||||||
|
use crate::block::{BlockBehaviour, BlockFuture, OnPlaceArgs, PlacedArgs};
|
||||||
use crate::entity::EntityBase;
|
use crate::entity::EntityBase;
|
||||||
use pumpkin_data::BlockStateId;
|
use pumpkin_data::BlockStateId;
|
||||||
use pumpkin_data::block_properties::{BlockProperties, DispenserLikeProperties};
|
use pumpkin_data::block_properties::{BlockProperties, DispenserLikeProperties};
|
||||||
use pumpkin_macros::pumpkin_block;
|
use pumpkin_macros::pumpkin_block;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[pumpkin_block("minecraft:dispenser")]
|
#[pumpkin_block("minecraft:dispenser")]
|
||||||
pub struct DispenserBlock;
|
pub struct DispenserBlock;
|
||||||
@ -15,4 +17,12 @@ impl BlockBehaviour for DispenserBlock {
|
|||||||
props.to_state_id(args.block)
|
props.to_state_id(args.block)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let dispenser_block_entity = DispenserBlockEntity::new(*args.position);
|
||||||
|
args.world
|
||||||
|
.add_block_entity(Arc::new(dispenser_block_entity));
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,10 @@ use pumpkin_data::BlockStateId;
|
|||||||
use pumpkin_data::block_properties::{AcaciaShelfLikeProperties, BlockProperties};
|
use pumpkin_data::block_properties::{AcaciaShelfLikeProperties, BlockProperties};
|
||||||
use pumpkin_macros::pumpkin_block_from_tag;
|
use pumpkin_macros::pumpkin_block_from_tag;
|
||||||
|
|
||||||
use crate::block::{BlockBehaviour, BlockFuture, OnPlaceArgs};
|
use crate::block::entities::shelf::ShelfBlockEntity;
|
||||||
|
use crate::block::{BlockBehaviour, BlockFuture, OnPlaceArgs, PlacedArgs};
|
||||||
use crate::entity::EntityBase;
|
use crate::entity::EntityBase;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[pumpkin_block_from_tag("minecraft:wooden_shelves")]
|
#[pumpkin_block_from_tag("minecraft:wooden_shelves")]
|
||||||
pub struct ShelfBlock;
|
pub struct ShelfBlock;
|
||||||
@ -19,4 +21,11 @@ impl BlockBehaviour for ShelfBlock {
|
|||||||
properties.to_state_id(args.block)
|
properties.to_state_id(args.block)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let entity = ShelfBlockEntity::new(*args.position);
|
||||||
|
args.world.add_block_entity(Arc::new(entity));
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
use crate::block::entities::hanging_sign::HangingSignBlockEntity;
|
||||||
use crate::block::entities::sign::SignBlockEntity;
|
use crate::block::entities::sign::SignBlockEntity;
|
||||||
use pumpkin_data::Block;
|
use pumpkin_data::Block;
|
||||||
use pumpkin_data::BlockDirection;
|
use pumpkin_data::BlockDirection;
|
||||||
@ -308,8 +309,13 @@ impl BlockBehaviour for SignBlock {
|
|||||||
|
|
||||||
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 {
|
||||||
args.world
|
if args.block.name.contains("hanging") {
|
||||||
.add_block_entity(Arc::new(SignBlockEntity::empty(*args.position)));
|
args.world
|
||||||
|
.add_block_entity(Arc::new(HangingSignBlockEntity::empty(*args.position)));
|
||||||
|
} else {
|
||||||
|
args.world
|
||||||
|
.add_block_entity(Arc::new(SignBlockEntity::empty(*args.position)));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,18 @@ impl BlockMetadata for SkullBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::block::PlacedArgs;
|
||||||
|
use crate::block::entities::skull::SkullBlockEntity;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
impl BlockBehaviour for SkullBlock {
|
impl BlockBehaviour for SkullBlock {
|
||||||
|
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let entity = SkullBlockEntity::new(*args.position);
|
||||||
|
args.world.add_block_entity(Arc::new(entity));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
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 mut props = SkeletonSkullLikeProperties::default(args.block);
|
let mut props = SkeletonSkullLikeProperties::default(args.block);
|
||||||
|
|||||||
@ -19,6 +19,9 @@ impl BlockBehaviour for WitherSkeletonSkullBlock {
|
|||||||
|
|
||||||
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 entity = crate::block::entities::skull::SkullBlockEntity::new(*args.position);
|
||||||
|
args.world.add_block_entity(std::sync::Arc::new(entity));
|
||||||
|
|
||||||
let world = args.world;
|
let world = args.world;
|
||||||
let pos = args.position;
|
let pos = args.position;
|
||||||
|
|
||||||
|
|||||||
65
pumpkin/src/block/entities/banner.rs
Normal file
65
pumpkin/src/block/entities/banner.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_nbt::tag::NbtTag;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct BannerBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub custom_name: Mutex<Option<String>>,
|
||||||
|
pub patterns: Mutex<Option<Vec<NbtTag>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for BannerBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let custom_name = nbt.get_string("CustomName").map(ToString::to_string);
|
||||||
|
let patterns = nbt.get_list("patterns").map(<[_]>::to_vec);
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
custom_name: Mutex::new(custom_name),
|
||||||
|
patterns: Mutex::new(patterns),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(name) = self.custom_name.lock().await.as_ref() {
|
||||||
|
nbt.put_string("CustomName", name.clone());
|
||||||
|
}
|
||||||
|
if let Some(pats) = self.patterns.lock().await.as_ref() {
|
||||||
|
nbt.put_list("patterns", pats.clone());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BannerBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:banner";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
custom_name: Mutex::const_new(None),
|
||||||
|
patterns: Mutex::const_new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
75
pumpkin/src/block/entities/beehive.rs
Normal file
75
pumpkin/src/block/entities/beehive.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_nbt::tag::NbtTag;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct BeehiveBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub bees: Mutex<Option<Vec<NbtTag>>>,
|
||||||
|
pub flower_pos: Mutex<Option<BlockPos>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for BeehiveBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let bees = nbt.get_list("Bees").map(<[_]>::to_vec);
|
||||||
|
let flower_pos = nbt.get_compound("FlowerPos").map(|c| {
|
||||||
|
BlockPos::new(
|
||||||
|
c.get_int("X").unwrap_or(0),
|
||||||
|
c.get_int("Y").unwrap_or(0),
|
||||||
|
c.get_int("Z").unwrap_or(0),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
bees: Mutex::new(bees),
|
||||||
|
flower_pos: Mutex::new(flower_pos),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(b) = self.bees.lock().await.as_ref() {
|
||||||
|
nbt.put_list("Bees", b.clone());
|
||||||
|
}
|
||||||
|
if let Some(fp) = self.flower_pos.lock().await.as_ref() {
|
||||||
|
let mut fp_nbt = NbtCompound::new();
|
||||||
|
fp_nbt.put_int("X", fp.0.x);
|
||||||
|
fp_nbt.put_int("Y", fp.0.y);
|
||||||
|
fp_nbt.put_int("Z", fp.0.z);
|
||||||
|
nbt.put_compound("FlowerPos", fp_nbt);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BeehiveBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:beehive";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
bees: Mutex::const_new(None),
|
||||||
|
flower_pos: Mutex::const_new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
pumpkin/src/block/entities/brushable_block.rs
Normal file
72
pumpkin/src/block/entities/brushable_block.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_data::item_stack::ItemStack;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct BrushableBlockBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub item: Mutex<Option<ItemStack>>,
|
||||||
|
pub hits: Mutex<i32>,
|
||||||
|
pub direction: Mutex<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for BrushableBlockBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let item = nbt
|
||||||
|
.get_compound("item")
|
||||||
|
.and_then(ItemStack::read_item_stack);
|
||||||
|
let hits = nbt.get_int("hits").unwrap_or(0);
|
||||||
|
let direction = nbt.get_byte("direction").unwrap_or(0) as u8;
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
item: Mutex::new(item),
|
||||||
|
hits: Mutex::new(hits),
|
||||||
|
direction: Mutex::new(direction),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(it) = self.item.lock().await.as_ref() {
|
||||||
|
let mut it_nbt = NbtCompound::new();
|
||||||
|
it.write_item_stack(&mut it_nbt);
|
||||||
|
nbt.put_compound("item", it_nbt);
|
||||||
|
}
|
||||||
|
nbt.put_int("hits", *self.hits.lock().await);
|
||||||
|
nbt.put_byte("direction", *self.direction.lock().await as i8);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BrushableBlockBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:brushable_block";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
item: Mutex::const_new(None),
|
||||||
|
hits: Mutex::const_new(0),
|
||||||
|
direction: Mutex::const_new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
pumpkin/src/block/entities/calibrated_sculk_sensor.rs
Normal file
58
pumpkin/src/block/entities/calibrated_sculk_sensor.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct CalibratedSculkSensorBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub last_vibration_frequency: Mutex<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for CalibratedSculkSensorBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let last_vibration_frequency = nbt.get_int("last_vibration_frequency").unwrap_or(0);
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
last_vibration_frequency: Mutex::new(last_vibration_frequency),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
nbt.put_int(
|
||||||
|
"last_vibration_frequency",
|
||||||
|
*self.last_vibration_frequency.lock().await,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalibratedSculkSensorBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:calibrated_sculk_sensor";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
last_vibration_frequency: Mutex::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
pumpkin/src/block/entities/campfire.rs
Normal file
111
pumpkin/src/block/entities/campfire.rs
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_data::item_stack::ItemStack;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_nbt::tag::NbtTag;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct CampfireBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub items: [Arc<Mutex<ItemStack>>; 4],
|
||||||
|
pub cooking_times: [tokio::sync::Mutex<i32>; 4],
|
||||||
|
pub cooking_total_times: [tokio::sync::Mutex<i32>; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for CampfireBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let mut items = std::array::from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone())));
|
||||||
|
if let Some(list) = nbt.get_list("Items") {
|
||||||
|
for tag in list {
|
||||||
|
if let Some(compound) = tag.extract_compound() {
|
||||||
|
let slot = compound.get_byte("Slot").unwrap_or(0) as usize;
|
||||||
|
if slot < 4
|
||||||
|
&& let Some(stack) = ItemStack::read_item_stack(compound)
|
||||||
|
{
|
||||||
|
items[slot] = Arc::new(Mutex::new(stack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut cooking_times = [Mutex::new(0), Mutex::new(0), Mutex::new(0), Mutex::new(0)];
|
||||||
|
if let Some(arr) = nbt.get_int_array("CookingTimes") {
|
||||||
|
for (i, &val) in arr.iter().enumerate().take(4) {
|
||||||
|
cooking_times[i] = Mutex::new(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut cooking_total_times = [Mutex::new(0), Mutex::new(0), Mutex::new(0), Mutex::new(0)];
|
||||||
|
if let Some(arr) = nbt.get_int_array("CookingTotalTimes") {
|
||||||
|
for (i, &val) in arr.iter().enumerate().take(4) {
|
||||||
|
cooking_total_times[i] = Mutex::new(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
items,
|
||||||
|
cooking_times,
|
||||||
|
cooking_total_times,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let mut list = Vec::new();
|
||||||
|
for (i, item_mutex) in self.items.iter().enumerate() {
|
||||||
|
let stack = item_mutex.lock().await;
|
||||||
|
if !stack.is_empty() {
|
||||||
|
let mut item_nbt = NbtCompound::new();
|
||||||
|
item_nbt.put_byte("Slot", i as i8);
|
||||||
|
stack.write_item_stack(&mut item_nbt);
|
||||||
|
list.push(NbtTag::Compound(item_nbt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nbt.put_list("Items", list);
|
||||||
|
|
||||||
|
let mut times = Vec::new();
|
||||||
|
for m in &self.cooking_times {
|
||||||
|
times.push(*m.lock().await);
|
||||||
|
}
|
||||||
|
nbt.put("CookingTimes", NbtTag::IntArray(times));
|
||||||
|
|
||||||
|
let mut total_times = Vec::new();
|
||||||
|
for m in &self.cooking_total_times {
|
||||||
|
total_times.push(*m.lock().await);
|
||||||
|
}
|
||||||
|
nbt.put("CookingTotalTimes", NbtTag::IntArray(total_times));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CampfireBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:campfire";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
items: std::array::from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
||||||
|
cooking_times: [Mutex::new(0), Mutex::new(0), Mutex::new(0), Mutex::new(0)],
|
||||||
|
cooking_total_times: [Mutex::new(0), Mutex::new(0), Mutex::new(0), Mutex::new(0)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
pumpkin/src/block/entities/conduit.rs
Normal file
63
pumpkin/src/block/entities/conduit.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_nbt::tag::NbtTag;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct ConduitBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub active: Mutex<bool>,
|
||||||
|
pub target: Mutex<Option<NbtTag>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for ConduitBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let active = nbt.get_bool("Active").unwrap_or(false);
|
||||||
|
let target = nbt.get("Target").cloned();
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
active: Mutex::new(active),
|
||||||
|
target: Mutex::new(target),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
nbt.put_bool("Active", *self.active.lock().await);
|
||||||
|
if let Some(tgt) = self.target.lock().await.as_ref() {
|
||||||
|
nbt.put("Target", tgt.clone());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConduitBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:conduit";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
active: Mutex::new(false),
|
||||||
|
target: Mutex::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
pumpkin/src/block/entities/copper_golem_statue.rs
Normal file
46
pumpkin/src/block/entities/copper_golem_statue.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
|
||||||
|
use super::BlockEntity;
|
||||||
|
|
||||||
|
pub struct CopperGolemStatueBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for CopperGolemStatueBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(_nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
_nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CopperGolemStatueBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:copper_golem_statue";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
}
|
||||||
160
pumpkin/src/block/entities/crafter.rs
Normal file
160
pumpkin/src/block/entities/crafter.rs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
use crate::block::entities::BlockEntity;
|
||||||
|
use pumpkin_data::item_stack::ItemStack;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use pumpkin_world::inventory::{Clearable, Inventory, InventoryFuture, split_stack};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::array::from_fn;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct CrafterBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub items: [Arc<Mutex<ItemStack>>; Self::INVENTORY_SIZE],
|
||||||
|
pub crafting_ticks_remaining: AtomicI32,
|
||||||
|
pub triggered: AtomicBool,
|
||||||
|
pub dirty: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for CrafterBlockEntity {
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
self.write_inventory_nbt(nbt, true).await;
|
||||||
|
nbt.put_int(
|
||||||
|
"crafting_ticks_remaining",
|
||||||
|
self.crafting_ticks_remaining.load(Ordering::Relaxed),
|
||||||
|
);
|
||||||
|
nbt.put_bool("triggered", self.triggered.load(Ordering::Relaxed));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let crafter = Self {
|
||||||
|
position,
|
||||||
|
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
||||||
|
crafting_ticks_remaining: AtomicI32::new(
|
||||||
|
nbt.get_int("crafting_ticks_remaining").unwrap_or(0),
|
||||||
|
),
|
||||||
|
triggered: AtomicBool::new(nbt.get_bool("triggered").unwrap_or(false)),
|
||||||
|
dirty: AtomicBool::new(false),
|
||||||
|
};
|
||||||
|
|
||||||
|
crafter.read_data(nbt, &crafter.items);
|
||||||
|
|
||||||
|
crafter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_inventory(self: Arc<Self>) -> Option<Arc<dyn Inventory>> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_dirty(&self) -> bool {
|
||||||
|
self.dirty.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_dirty(&self) {
|
||||||
|
self.dirty.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CrafterBlockEntity {
|
||||||
|
pub const INVENTORY_SIZE: usize = 9;
|
||||||
|
pub const ID: &'static str = "minecraft:crafter";
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
||||||
|
crafting_ticks_remaining: AtomicI32::new(0),
|
||||||
|
triggered: AtomicBool::new(false),
|
||||||
|
dirty: AtomicBool::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inventory for CrafterBlockEntity {
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
self.items.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
||||||
|
Box::pin(async move {
|
||||||
|
for slot in &self.items {
|
||||||
|
if !slot.lock().await.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_stack(&self, slot: usize) -> InventoryFuture<'_, Arc<Mutex<ItemStack>>> {
|
||||||
|
Box::pin(async move { self.items[slot].clone() })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_stack(&self, slot: usize) -> InventoryFuture<'_, ItemStack> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let mut removed = ItemStack::EMPTY.clone();
|
||||||
|
let mut guard = self.items[slot].lock().await;
|
||||||
|
std::mem::swap(&mut removed, &mut *guard);
|
||||||
|
self.mark_dirty();
|
||||||
|
removed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_stack_specific(&self, slot: usize, amount: u8) -> InventoryFuture<'_, ItemStack> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let res = split_stack(&self.items, slot, amount).await;
|
||||||
|
self.mark_dirty();
|
||||||
|
res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
*self.items[slot].lock().await = stack;
|
||||||
|
self.mark_dirty();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_dirty(&self) {
|
||||||
|
self.dirty.store(true, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clearable for CrafterBlockEntity {
|
||||||
|
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
for slot in &self.items {
|
||||||
|
*slot.lock().await = ItemStack::EMPTY.clone();
|
||||||
|
}
|
||||||
|
self.mark_dirty();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
46
pumpkin/src/block/entities/creaking_heart.rs
Normal file
46
pumpkin/src/block/entities/creaking_heart.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
|
||||||
|
use super::BlockEntity;
|
||||||
|
|
||||||
|
pub struct CreakingHeartBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for CreakingHeartBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(_nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
_nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CreakingHeartBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:creaking_heart";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
}
|
||||||
70
pumpkin/src/block/entities/decorated_pot.rs
Normal file
70
pumpkin/src/block/entities/decorated_pot.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_data::item_stack::ItemStack;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_nbt::tag::NbtTag;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct DecoratedPotBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub sherds: Mutex<Option<Vec<NbtTag>>>,
|
||||||
|
pub item: Mutex<Option<ItemStack>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for DecoratedPotBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let sherds = nbt.get_list("sherds").map(<[_]>::to_vec);
|
||||||
|
let item = nbt
|
||||||
|
.get_compound("item")
|
||||||
|
.and_then(ItemStack::read_item_stack);
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
sherds: Mutex::new(sherds),
|
||||||
|
item: Mutex::new(item),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(sh) = self.sherds.lock().await.as_ref() {
|
||||||
|
nbt.put_list("sherds", sh.clone());
|
||||||
|
}
|
||||||
|
if let Some(it) = self.item.lock().await.as_ref() {
|
||||||
|
let mut it_nbt = NbtCompound::new();
|
||||||
|
it.write_item_stack(&mut it_nbt);
|
||||||
|
nbt.put_compound("item", it_nbt);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DecoratedPotBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:decorated_pot";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
sherds: Mutex::const_new(None),
|
||||||
|
item: Mutex::const_new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
160
pumpkin/src/block/entities/dispenser.rs
Normal file
160
pumpkin/src/block/entities/dispenser.rs
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
use crate::block::entities::BlockEntity;
|
||||||
|
use pumpkin_data::item_stack::ItemStack;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use pumpkin_world::inventory::{Clearable, Inventory, InventoryFuture, split_stack};
|
||||||
|
use rand::{RngExt, rng};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::array::from_fn;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use tokio::sync::{Mutex, MutexGuard};
|
||||||
|
|
||||||
|
pub struct DispenserBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub items: [Arc<Mutex<ItemStack>>; Self::INVENTORY_SIZE],
|
||||||
|
pub dirty: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for DispenserBlockEntity {
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
self.write_inventory_nbt(nbt, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let dispenser = Self {
|
||||||
|
position,
|
||||||
|
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
||||||
|
dirty: AtomicBool::new(false),
|
||||||
|
};
|
||||||
|
|
||||||
|
dispenser.read_data(nbt, &dispenser.items);
|
||||||
|
|
||||||
|
dispenser
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_inventory(self: Arc<Self>) -> Option<Arc<dyn Inventory>> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_dirty(&self) -> bool {
|
||||||
|
self.dirty.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_dirty(&self) {
|
||||||
|
self.dirty.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DispenserBlockEntity {
|
||||||
|
pub const INVENTORY_SIZE: usize = 9;
|
||||||
|
pub const ID: &'static str = "minecraft:dispenser";
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
||||||
|
dirty: AtomicBool::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_random_slot(&self) -> Option<MutexGuard<'_, ItemStack>> {
|
||||||
|
let mut ret = None;
|
||||||
|
let mut j = 1;
|
||||||
|
for i in &self.items {
|
||||||
|
let item = i.lock().await;
|
||||||
|
if !item.is_empty() {
|
||||||
|
if rng().random_range(0..j) == 0 {
|
||||||
|
ret = Some(item);
|
||||||
|
}
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inventory for DispenserBlockEntity {
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
self.items.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
||||||
|
Box::pin(async move {
|
||||||
|
for slot in &self.items {
|
||||||
|
if !slot.lock().await.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_stack(&self, slot: usize) -> InventoryFuture<'_, Arc<Mutex<ItemStack>>> {
|
||||||
|
Box::pin(async move { self.items[slot].clone() })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_stack(&self, slot: usize) -> InventoryFuture<'_, ItemStack> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let mut removed = ItemStack::EMPTY.clone();
|
||||||
|
let mut guard = self.items[slot].lock().await;
|
||||||
|
std::mem::swap(&mut removed, &mut *guard);
|
||||||
|
self.mark_dirty();
|
||||||
|
removed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_stack_specific(&self, slot: usize, amount: u8) -> InventoryFuture<'_, ItemStack> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let res = split_stack(&self.items, slot, amount).await;
|
||||||
|
self.mark_dirty();
|
||||||
|
res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
*self.items[slot].lock().await = stack;
|
||||||
|
self.mark_dirty();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_dirty(&self) {
|
||||||
|
self.dirty.store(true, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clearable for DispenserBlockEntity {
|
||||||
|
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
for slot in &self.items {
|
||||||
|
*slot.lock().await = ItemStack::EMPTY.clone();
|
||||||
|
}
|
||||||
|
self.mark_dirty();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
57
pumpkin/src/block/entities/enchanting_table.rs
Normal file
57
pumpkin/src/block/entities/enchanting_table.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct EnchantingTableBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub custom_name: Mutex<Option<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for EnchantingTableBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let custom_name = nbt.get_string("CustomName").map(ToString::to_string);
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
custom_name: Mutex::new(custom_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(name) = self.custom_name.lock().await.as_ref() {
|
||||||
|
nbt.put_string("CustomName", name.clone());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnchantingTableBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:enchanting_table";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
custom_name: Mutex::const_new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
77
pumpkin/src/block/entities/end_gateway.rs
Normal file
77
pumpkin/src/block/entities/end_gateway.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct EndGatewayBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub age: Mutex<i64>,
|
||||||
|
pub exact_teleport: Mutex<bool>,
|
||||||
|
pub exit_portal: Mutex<Option<BlockPos>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for EndGatewayBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let age = nbt.get_long("Age").unwrap_or(0);
|
||||||
|
let exact_teleport = nbt.get_bool("ExactTeleport").unwrap_or(false);
|
||||||
|
let exit_portal = nbt.get_compound("ExitPortal").map(|c| {
|
||||||
|
BlockPos::new(
|
||||||
|
c.get_int("X").unwrap_or(0),
|
||||||
|
c.get_int("Y").unwrap_or(0),
|
||||||
|
c.get_int("Z").unwrap_or(0),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
age: Mutex::new(age),
|
||||||
|
exact_teleport: Mutex::new(exact_teleport),
|
||||||
|
exit_portal: Mutex::new(exit_portal),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
nbt.put_long("Age", *self.age.lock().await);
|
||||||
|
nbt.put_bool("ExactTeleport", *self.exact_teleport.lock().await);
|
||||||
|
if let Some(exit) = self.exit_portal.lock().await.as_ref() {
|
||||||
|
let mut exit_nbt = NbtCompound::new();
|
||||||
|
exit_nbt.put_int("X", exit.0.x);
|
||||||
|
exit_nbt.put_int("Y", exit.0.y);
|
||||||
|
exit_nbt.put_int("Z", exit.0.z);
|
||||||
|
nbt.put_compound("ExitPortal", exit_nbt);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EndGatewayBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:end_gateway";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
age: Mutex::new(0),
|
||||||
|
exact_teleport: Mutex::new(false),
|
||||||
|
exit_portal: Mutex::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
110
pumpkin/src/block/entities/hanging_sign.rs
Normal file
110
pumpkin/src/block/entities/hanging_sign.rs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
use std::{
|
||||||
|
pin::Pin,
|
||||||
|
sync::{
|
||||||
|
Arc,
|
||||||
|
atomic::{AtomicBool, Ordering},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::BlockEntity;
|
||||||
|
use crate::block::entities::sign::Text;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct HangingSignBlockEntity {
|
||||||
|
pub front_text: Text,
|
||||||
|
pub back_text: Text,
|
||||||
|
pub is_waxed: AtomicBool,
|
||||||
|
position: BlockPos,
|
||||||
|
pub currently_editing_player: Arc<Mutex<Option<uuid::Uuid>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for HangingSignBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let front_text = nbt
|
||||||
|
.get("front_text")
|
||||||
|
.cloned()
|
||||||
|
.map(Text::from)
|
||||||
|
.unwrap_or_default();
|
||||||
|
let back_text = nbt
|
||||||
|
.get("back_text")
|
||||||
|
.cloned()
|
||||||
|
.map(Text::from)
|
||||||
|
.unwrap_or_default();
|
||||||
|
let is_waxed = nbt.get_bool("is_waxed").unwrap_or(false);
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
front_text,
|
||||||
|
back_text,
|
||||||
|
is_waxed: AtomicBool::new(is_waxed),
|
||||||
|
currently_editing_player: Arc::new(Mutex::new(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
nbt.put("front_text", self.front_text.clone());
|
||||||
|
nbt.put("back_text", self.back_text.clone());
|
||||||
|
nbt.put_bool("is_waxed", self.is_waxed.load(Ordering::Relaxed));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chunk_data_nbt(&self) -> Option<NbtCompound> {
|
||||||
|
let mut nbt = NbtCompound::new();
|
||||||
|
nbt.put("front_text", self.front_text.clone());
|
||||||
|
nbt.put("back_text", self.back_text.clone());
|
||||||
|
nbt.put_bool("is_waxed", self.is_waxed.load(Ordering::Relaxed));
|
||||||
|
Some(nbt)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HangingSignBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:hanging_sign";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos, is_front: bool, messages: [Box<str>; 4]) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
is_waxed: AtomicBool::new(false),
|
||||||
|
front_text: if is_front {
|
||||||
|
Text::new(messages.clone())
|
||||||
|
} else {
|
||||||
|
Text::default()
|
||||||
|
},
|
||||||
|
back_text: if is_front {
|
||||||
|
Text::default()
|
||||||
|
} else {
|
||||||
|
Text::new(messages)
|
||||||
|
},
|
||||||
|
currently_editing_player: Arc::new(Mutex::new(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn empty(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
is_waxed: AtomicBool::new(false),
|
||||||
|
front_text: Text::default(),
|
||||||
|
back_text: Text::default(),
|
||||||
|
currently_editing_player: Arc::new(Mutex::new(None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,6 +37,32 @@ pub mod sign;
|
|||||||
pub mod smoker;
|
pub mod smoker;
|
||||||
pub mod trapped_chest;
|
pub mod trapped_chest;
|
||||||
|
|
||||||
|
pub mod banner;
|
||||||
|
pub mod beehive;
|
||||||
|
pub mod brushable_block;
|
||||||
|
pub mod calibrated_sculk_sensor;
|
||||||
|
pub mod campfire;
|
||||||
|
pub mod conduit;
|
||||||
|
pub mod copper_golem_statue;
|
||||||
|
pub mod crafter;
|
||||||
|
pub mod creaking_heart;
|
||||||
|
pub mod decorated_pot;
|
||||||
|
pub mod dispenser;
|
||||||
|
pub mod enchanting_table;
|
||||||
|
pub mod end_gateway;
|
||||||
|
pub mod hanging_sign;
|
||||||
|
pub mod potent_sulfur;
|
||||||
|
pub mod sculk_catalyst;
|
||||||
|
pub mod sculk_sensor;
|
||||||
|
pub mod sculk_shrieker;
|
||||||
|
pub mod shelf;
|
||||||
|
pub mod skull;
|
||||||
|
pub mod structure_block;
|
||||||
|
pub mod test_block;
|
||||||
|
pub mod test_instance_block;
|
||||||
|
pub mod trial_spawner;
|
||||||
|
pub mod vault;
|
||||||
|
|
||||||
pub use furnace_like_block_entity::ExperienceContainer;
|
pub use furnace_like_block_entity::ExperienceContainer;
|
||||||
pub use pumpkin_world::block::entities::PropertyDelegate;
|
pub use pumpkin_world::block::entities::PropertyDelegate;
|
||||||
|
|
||||||
@ -148,6 +174,7 @@ pub fn block_entity_from_generic<T: BlockEntity>(nbt: &NbtCompound) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>> {
|
pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>> {
|
||||||
let id = nbt.get_string("id")?;
|
let id = nbt.get_string("id")?;
|
||||||
let x = nbt.get_int("x")?;
|
let x = nbt.get_int("x")?;
|
||||||
@ -222,6 +249,75 @@ pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>>
|
|||||||
lectern::LecternBlockEntity::ID => {
|
lectern::LecternBlockEntity::ID => {
|
||||||
Some(Arc::new(lectern::LecternBlockEntity::from_nbt(nbt, pos)))
|
Some(Arc::new(lectern::LecternBlockEntity::from_nbt(nbt, pos)))
|
||||||
}
|
}
|
||||||
|
dispenser::DispenserBlockEntity::ID => Some(Arc::new(
|
||||||
|
dispenser::DispenserBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
hanging_sign::HangingSignBlockEntity::ID => Some(Arc::new(
|
||||||
|
hanging_sign::HangingSignBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
creaking_heart::CreakingHeartBlockEntity::ID => Some(Arc::new(
|
||||||
|
creaking_heart::CreakingHeartBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
enchanting_table::EnchantingTableBlockEntity::ID => Some(Arc::new(
|
||||||
|
enchanting_table::EnchantingTableBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
skull::SkullBlockEntity::ID => Some(Arc::new(skull::SkullBlockEntity::from_nbt(nbt, pos))),
|
||||||
|
banner::BannerBlockEntity::ID => {
|
||||||
|
Some(Arc::new(banner::BannerBlockEntity::from_nbt(nbt, pos)))
|
||||||
|
}
|
||||||
|
structure_block::StructureBlockBlockEntity::ID => Some(Arc::new(
|
||||||
|
structure_block::StructureBlockBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
end_gateway::EndGatewayBlockEntity::ID => Some(Arc::new(
|
||||||
|
end_gateway::EndGatewayBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
conduit::ConduitBlockEntity::ID => {
|
||||||
|
Some(Arc::new(conduit::ConduitBlockEntity::from_nbt(nbt, pos)))
|
||||||
|
}
|
||||||
|
campfire::CampfireBlockEntity::ID => {
|
||||||
|
Some(Arc::new(campfire::CampfireBlockEntity::from_nbt(nbt, pos)))
|
||||||
|
}
|
||||||
|
beehive::BeehiveBlockEntity::ID => {
|
||||||
|
Some(Arc::new(beehive::BeehiveBlockEntity::from_nbt(nbt, pos)))
|
||||||
|
}
|
||||||
|
sculk_sensor::SculkSensorBlockEntity::ID => Some(Arc::new(
|
||||||
|
sculk_sensor::SculkSensorBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
calibrated_sculk_sensor::CalibratedSculkSensorBlockEntity::ID => Some(Arc::new(
|
||||||
|
calibrated_sculk_sensor::CalibratedSculkSensorBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
sculk_catalyst::SculkCatalystBlockEntity::ID => Some(Arc::new(
|
||||||
|
sculk_catalyst::SculkCatalystBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
sculk_shrieker::SculkShriekerBlockEntity::ID => Some(Arc::new(
|
||||||
|
sculk_shrieker::SculkShriekerBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
shelf::ShelfBlockEntity::ID => Some(Arc::new(shelf::ShelfBlockEntity::from_nbt(nbt, pos))),
|
||||||
|
brushable_block::BrushableBlockBlockEntity::ID => Some(Arc::new(
|
||||||
|
brushable_block::BrushableBlockBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
decorated_pot::DecoratedPotBlockEntity::ID => Some(Arc::new(
|
||||||
|
decorated_pot::DecoratedPotBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
crafter::CrafterBlockEntity::ID => {
|
||||||
|
Some(Arc::new(crafter::CrafterBlockEntity::from_nbt(nbt, pos)))
|
||||||
|
}
|
||||||
|
trial_spawner::TrialSpawnerBlockEntity::ID => Some(Arc::new(
|
||||||
|
trial_spawner::TrialSpawnerBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
vault::VaultBlockEntity::ID => Some(Arc::new(vault::VaultBlockEntity::from_nbt(nbt, pos))),
|
||||||
|
test_block::TestBlockBlockEntity::ID => Some(Arc::new(
|
||||||
|
test_block::TestBlockBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
test_instance_block::TestInstanceBlockBlockEntity::ID => Some(Arc::new(
|
||||||
|
test_instance_block::TestInstanceBlockBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
copper_golem_statue::CopperGolemStatueBlockEntity::ID => Some(Arc::new(
|
||||||
|
copper_golem_statue::CopperGolemStatueBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
|
potent_sulfur::PotentSulfurBlockEntity::ID => Some(Arc::new(
|
||||||
|
potent_sulfur::PotentSulfurBlockEntity::from_nbt(nbt, pos),
|
||||||
|
)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,3 +326,112 @@ pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>>
|
|||||||
pub fn has_block_block_entity(block: &Block) -> bool {
|
pub fn has_block_block_entity(block: &Block) -> bool {
|
||||||
BLOCK_ENTITY_TYPES.contains(&block.name)
|
BLOCK_ENTITY_TYPES.contains(&block.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
pub fn create_block_entity(
|
||||||
|
block_entity_type_id: u16,
|
||||||
|
position: BlockPos,
|
||||||
|
) -> Option<Arc<dyn BlockEntity>> {
|
||||||
|
use pumpkin_data::block_properties::FacingHopper;
|
||||||
|
if block_entity_type_id == u16::MAX {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let name = BLOCK_ENTITY_TYPES.get(block_entity_type_id as usize)?;
|
||||||
|
match *name {
|
||||||
|
"furnace" => Some(Arc::new(furnace::FurnaceBlockEntity::new(position))),
|
||||||
|
"chest" => Some(Arc::new(chest::ChestBlockEntity::new(position))),
|
||||||
|
"trapped_chest" => Some(Arc::new(trapped_chest::TrappedChestBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"ender_chest" => Some(Arc::new(ender_chest::EnderChestBlockEntity::new(position))),
|
||||||
|
"jukebox" => Some(Arc::new(jukebox::JukeboxBlockEntity::new(position))),
|
||||||
|
"dispenser" => Some(Arc::new(dispenser::DispenserBlockEntity::new(position))),
|
||||||
|
"dropper" => Some(Arc::new(dropper::DropperBlockEntity::new(position))),
|
||||||
|
"sign" => Some(Arc::new(sign::SignBlockEntity::empty(position))),
|
||||||
|
"hanging_sign" => Some(Arc::new(hanging_sign::HangingSignBlockEntity::empty(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"mob_spawner" => Some(Arc::new(mob_spawner::MobSpawnerBlockEntity::new(
|
||||||
|
position, None,
|
||||||
|
))),
|
||||||
|
"creaking_heart" => Some(Arc::new(creaking_heart::CreakingHeartBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"brewing_stand" => Some(Arc::new(brewing_stand::BrewingStandBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"enchanting_table" => Some(Arc::new(enchanting_table::EnchantingTableBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"end_portal" => Some(Arc::new(end_portal::EndPortalBlockEntity::new(position))),
|
||||||
|
"beacon" => Some(Arc::new(beacon::BeaconBlockEntity::new(position))),
|
||||||
|
"skull" => Some(Arc::new(skull::SkullBlockEntity::new(position))),
|
||||||
|
"daylight_detector" => Some(Arc::new(
|
||||||
|
daylight_detector::DaylightDetectorBlockEntity::new(position),
|
||||||
|
)),
|
||||||
|
"hopper" => Some(Arc::new(hopper::HopperBlockEntity::new(
|
||||||
|
position,
|
||||||
|
FacingHopper::Down,
|
||||||
|
))),
|
||||||
|
"comparator" => Some(Arc::new(comparator::ComparatorBlockEntity::new(position))),
|
||||||
|
"banner" => Some(Arc::new(banner::BannerBlockEntity::new(position))),
|
||||||
|
"structure_block" => Some(Arc::new(structure_block::StructureBlockBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"end_gateway" => Some(Arc::new(end_gateway::EndGatewayBlockEntity::new(position))),
|
||||||
|
"command_block" => Some(Arc::new(command_block::CommandBlockEntity::new(
|
||||||
|
position, true, false,
|
||||||
|
))),
|
||||||
|
"shulker_box" => Some(Arc::new(shulker_box::ShulkerBoxBlockEntity::new(position))),
|
||||||
|
"conduit" => Some(Arc::new(conduit::ConduitBlockEntity::new(position))),
|
||||||
|
"barrel" => Some(Arc::new(barrel::BarrelBlockEntity::new(position))),
|
||||||
|
"smoker" => Some(Arc::new(smoker::SmokerBlockEntity::new(position))),
|
||||||
|
"blast_furnace" => Some(Arc::new(blasting_furnace::BlastingFurnaceBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"lectern" => Some(Arc::new(lectern::LecternBlockEntity::new(position))),
|
||||||
|
"bell" => Some(Arc::new(bell::BellBlockEntity::new(position))),
|
||||||
|
"jigsaw" => Some(Arc::new(jigsaw_block::JigsawBlockEntity::new(position))),
|
||||||
|
"campfire" => Some(Arc::new(campfire::CampfireBlockEntity::new(position))),
|
||||||
|
"beehive" => Some(Arc::new(beehive::BeehiveBlockEntity::new(position))),
|
||||||
|
"sculk_sensor" => Some(Arc::new(sculk_sensor::SculkSensorBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"calibrated_sculk_sensor" => Some(Arc::new(
|
||||||
|
calibrated_sculk_sensor::CalibratedSculkSensorBlockEntity::new(position),
|
||||||
|
)),
|
||||||
|
"sculk_catalyst" => Some(Arc::new(sculk_catalyst::SculkCatalystBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"sculk_shrieker" => Some(Arc::new(sculk_shrieker::SculkShriekerBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"chiseled_bookshelf" => Some(Arc::new(
|
||||||
|
chiseled_bookshelf::ChiseledBookshelfBlockEntity::new(position),
|
||||||
|
)),
|
||||||
|
"shelf" => Some(Arc::new(shelf::ShelfBlockEntity::new(position))),
|
||||||
|
"brushable_block" => Some(Arc::new(brushable_block::BrushableBlockBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"decorated_pot" => Some(Arc::new(decorated_pot::DecoratedPotBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"crafter" => Some(Arc::new(crafter::CrafterBlockEntity::new(position))),
|
||||||
|
"trial_spawner" => Some(Arc::new(trial_spawner::TrialSpawnerBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
"vault" => Some(Arc::new(vault::VaultBlockEntity::new(position))),
|
||||||
|
"test_block" => Some(Arc::new(test_block::TestBlockBlockEntity::new(position))),
|
||||||
|
"test_instance_block" => Some(Arc::new(
|
||||||
|
test_instance_block::TestInstanceBlockBlockEntity::new(position),
|
||||||
|
)),
|
||||||
|
"copper_golem_statue" => Some(Arc::new(
|
||||||
|
copper_golem_statue::CopperGolemStatueBlockEntity::new(position),
|
||||||
|
)),
|
||||||
|
"potent_sulfur" => Some(Arc::new(potent_sulfur::PotentSulfurBlockEntity::new(
|
||||||
|
position,
|
||||||
|
))),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
46
pumpkin/src/block/entities/potent_sulfur.rs
Normal file
46
pumpkin/src/block/entities/potent_sulfur.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
|
||||||
|
use super::BlockEntity;
|
||||||
|
|
||||||
|
pub struct PotentSulfurBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for PotentSulfurBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(_nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
_nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PotentSulfurBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:potent_sulfur";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
}
|
||||||
55
pumpkin/src/block/entities/sculk_catalyst.rs
Normal file
55
pumpkin/src/block/entities/sculk_catalyst.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct SculkCatalystBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub decay_delay: Mutex<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for SculkCatalystBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let decay_delay = nbt.get_int("decay_delay").unwrap_or(0);
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
decay_delay: Mutex::new(decay_delay),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
nbt.put_int("decay_delay", *self.decay_delay.lock().await);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SculkCatalystBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:sculk_catalyst";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
decay_delay: Mutex::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
pumpkin/src/block/entities/sculk_sensor.rs
Normal file
58
pumpkin/src/block/entities/sculk_sensor.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct SculkSensorBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub last_vibration_frequency: Mutex<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for SculkSensorBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let last_vibration_frequency = nbt.get_int("last_vibration_frequency").unwrap_or(0);
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
last_vibration_frequency: Mutex::new(last_vibration_frequency),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
nbt.put_int(
|
||||||
|
"last_vibration_frequency",
|
||||||
|
*self.last_vibration_frequency.lock().await,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SculkSensorBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:sculk_sensor";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
last_vibration_frequency: Mutex::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
pumpkin/src/block/entities/sculk_shrieker.rs
Normal file
55
pumpkin/src/block/entities/sculk_shrieker.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct SculkShriekerBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub warning_level: Mutex<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for SculkShriekerBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let warning_level = nbt.get_int("warning_level").unwrap_or(0);
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
warning_level: Mutex::new(warning_level),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
nbt.put_int("warning_level", *self.warning_level.lock().await);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SculkShriekerBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:sculk_shrieker";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
warning_level: Mutex::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
145
pumpkin/src/block/entities/shelf.rs
Normal file
145
pumpkin/src/block/entities/shelf.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
use crate::block::entities::BlockEntity;
|
||||||
|
use pumpkin_data::item_stack::ItemStack;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use pumpkin_world::inventory::{Clearable, Inventory, InventoryFuture, split_stack};
|
||||||
|
use std::any::Any;
|
||||||
|
use std::array::from_fn;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct ShelfBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub items: [Arc<Mutex<ItemStack>>; Self::INVENTORY_SIZE],
|
||||||
|
pub dirty: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for ShelfBlockEntity {
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
self.write_inventory_nbt(nbt, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let shelf = Self {
|
||||||
|
position,
|
||||||
|
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
||||||
|
dirty: AtomicBool::new(false),
|
||||||
|
};
|
||||||
|
|
||||||
|
shelf.read_data(nbt, &shelf.items);
|
||||||
|
|
||||||
|
shelf
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_inventory(self: Arc<Self>) -> Option<Arc<dyn Inventory>> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_dirty(&self) -> bool {
|
||||||
|
self.dirty.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_dirty(&self) {
|
||||||
|
self.dirty.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ShelfBlockEntity {
|
||||||
|
pub const INVENTORY_SIZE: usize = 9;
|
||||||
|
pub const ID: &'static str = "minecraft:shelf";
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
||||||
|
dirty: AtomicBool::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Inventory for ShelfBlockEntity {
|
||||||
|
fn size(&self) -> usize {
|
||||||
|
self.items.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
||||||
|
Box::pin(async move {
|
||||||
|
for slot in &self.items {
|
||||||
|
if !slot.lock().await.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_stack(&self, slot: usize) -> InventoryFuture<'_, Arc<Mutex<ItemStack>>> {
|
||||||
|
Box::pin(async move { self.items[slot].clone() })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_stack(&self, slot: usize) -> InventoryFuture<'_, ItemStack> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let mut removed = ItemStack::EMPTY.clone();
|
||||||
|
let mut guard = self.items[slot].lock().await;
|
||||||
|
std::mem::swap(&mut removed, &mut *guard);
|
||||||
|
self.mark_dirty();
|
||||||
|
removed
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove_stack_specific(&self, slot: usize, amount: u8) -> InventoryFuture<'_, ItemStack> {
|
||||||
|
Box::pin(async move {
|
||||||
|
let res = split_stack(&self.items, slot, amount).await;
|
||||||
|
self.mark_dirty();
|
||||||
|
res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> {
|
||||||
|
Box::pin(async move {
|
||||||
|
*self.items[slot].lock().await = stack;
|
||||||
|
self.mark_dirty();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_dirty(&self) {
|
||||||
|
self.dirty.store(true, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clearable for ShelfBlockEntity {
|
||||||
|
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
for slot in &self.items {
|
||||||
|
*slot.lock().await = ItemStack::EMPTY.clone();
|
||||||
|
}
|
||||||
|
self.mark_dirty();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -196,7 +196,8 @@ impl From<NbtTag> for Text {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Text {
|
impl Text {
|
||||||
fn new(messages: [Box<str>; 4]) -> Self {
|
#[must_use]
|
||||||
|
pub fn new(messages: [Box<str>; 4]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
has_glowing_text: AtomicBool::new(false),
|
has_glowing_text: AtomicBool::new(false),
|
||||||
color: AtomicI8::new(DyeColor::default() as i8),
|
color: AtomicI8::new(DyeColor::default() as i8),
|
||||||
|
|||||||
64
pumpkin/src/block/entities/skull.rs
Normal file
64
pumpkin/src/block/entities/skull.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct SkullBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub note_block_sound: Mutex<Option<String>>,
|
||||||
|
pub profile: Mutex<Option<NbtCompound>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for SkullBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let note_block_sound = nbt.get_string("note_block_sound").map(ToString::to_string);
|
||||||
|
let profile = nbt.get_compound("profile").cloned();
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
note_block_sound: Mutex::new(note_block_sound),
|
||||||
|
profile: Mutex::new(profile),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(sound) = self.note_block_sound.lock().await.as_ref() {
|
||||||
|
nbt.put_string("note_block_sound", sound.clone());
|
||||||
|
}
|
||||||
|
if let Some(prof) = self.profile.lock().await.as_ref() {
|
||||||
|
nbt.put_compound("profile", prof.clone());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SkullBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:skull";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
note_block_sound: Mutex::const_new(None),
|
||||||
|
profile: Mutex::const_new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
118
pumpkin/src/block/entities/structure_block.rs
Normal file
118
pumpkin/src/block/entities/structure_block.rs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct StructureBlockBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub name: Mutex<String>,
|
||||||
|
pub author: Mutex<String>,
|
||||||
|
pub metadata: Mutex<String>,
|
||||||
|
pub pos_x: Mutex<i32>,
|
||||||
|
pub pos_y: Mutex<i32>,
|
||||||
|
pub pos_z: Mutex<i32>,
|
||||||
|
pub size_x: Mutex<i32>,
|
||||||
|
pub size_y: Mutex<i32>,
|
||||||
|
pub size_z: Mutex<i32>,
|
||||||
|
pub rotation: Mutex<String>,
|
||||||
|
pub mirror: Mutex<String>,
|
||||||
|
pub mode: Mutex<String>,
|
||||||
|
pub ignore_entities: Mutex<bool>,
|
||||||
|
pub show_air: Mutex<bool>,
|
||||||
|
pub show_bounding_box: Mutex<bool>,
|
||||||
|
pub integrity: Mutex<f32>,
|
||||||
|
pub seed: Mutex<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for StructureBlockBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
name: Mutex::new(nbt.get_string("name").unwrap_or("").to_string()),
|
||||||
|
author: Mutex::new(nbt.get_string("author").unwrap_or("").to_string()),
|
||||||
|
metadata: Mutex::new(nbt.get_string("metadata").unwrap_or("").to_string()),
|
||||||
|
pos_x: Mutex::new(nbt.get_int("posX").unwrap_or(0)),
|
||||||
|
pos_y: Mutex::new(nbt.get_int("posY").unwrap_or(0)),
|
||||||
|
pos_z: Mutex::new(nbt.get_int("posZ").unwrap_or(0)),
|
||||||
|
size_x: Mutex::new(nbt.get_int("sizeX").unwrap_or(0)),
|
||||||
|
size_y: Mutex::new(nbt.get_int("sizeY").unwrap_or(0)),
|
||||||
|
size_z: Mutex::new(nbt.get_int("sizeZ").unwrap_or(0)),
|
||||||
|
rotation: Mutex::new(nbt.get_string("rotation").unwrap_or("NONE").to_string()),
|
||||||
|
mirror: Mutex::new(nbt.get_string("mirror").unwrap_or("NONE").to_string()),
|
||||||
|
mode: Mutex::new(nbt.get_string("mode").unwrap_or("DATA").to_string()),
|
||||||
|
ignore_entities: Mutex::new(nbt.get_bool("ignoreEntities").unwrap_or(true)),
|
||||||
|
show_air: Mutex::new(nbt.get_bool("showAir").unwrap_or(false)),
|
||||||
|
show_bounding_box: Mutex::new(nbt.get_bool("showBoundingBox").unwrap_or(true)),
|
||||||
|
integrity: Mutex::new(nbt.get_float("integrity").unwrap_or(1.0)),
|
||||||
|
seed: Mutex::new(nbt.get_long("seed").unwrap_or(0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
nbt.put_string("name", self.name.lock().await.clone());
|
||||||
|
nbt.put_string("author", self.author.lock().await.clone());
|
||||||
|
nbt.put_string("metadata", self.metadata.lock().await.clone());
|
||||||
|
nbt.put_int("posX", *self.pos_x.lock().await);
|
||||||
|
nbt.put_int("posY", *self.pos_y.lock().await);
|
||||||
|
nbt.put_int("posZ", *self.pos_z.lock().await);
|
||||||
|
nbt.put_int("sizeX", *self.size_x.lock().await);
|
||||||
|
nbt.put_int("sizeY", *self.size_y.lock().await);
|
||||||
|
nbt.put_int("sizeZ", *self.size_z.lock().await);
|
||||||
|
nbt.put_string("rotation", self.rotation.lock().await.clone());
|
||||||
|
nbt.put_string("mirror", self.mirror.lock().await.clone());
|
||||||
|
nbt.put_string("mode", self.mode.lock().await.clone());
|
||||||
|
nbt.put_bool("ignoreEntities", *self.ignore_entities.lock().await);
|
||||||
|
nbt.put_bool("showAir", *self.show_air.lock().await);
|
||||||
|
nbt.put_bool("showBoundingBox", *self.show_bounding_box.lock().await);
|
||||||
|
nbt.put_float("integrity", *self.integrity.lock().await);
|
||||||
|
nbt.put_long("seed", *self.seed.lock().await);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StructureBlockBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:structure_block";
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
name: Mutex::new(String::new()),
|
||||||
|
author: Mutex::new(String::new()),
|
||||||
|
metadata: Mutex::new(String::new()),
|
||||||
|
pos_x: Mutex::new(0),
|
||||||
|
pos_y: Mutex::new(0),
|
||||||
|
pos_z: Mutex::new(0),
|
||||||
|
size_x: Mutex::new(0),
|
||||||
|
size_y: Mutex::new(0),
|
||||||
|
size_z: Mutex::new(0),
|
||||||
|
rotation: Mutex::new("NONE".to_string()),
|
||||||
|
mirror: Mutex::new("NONE".to_string()),
|
||||||
|
mode: Mutex::new("DATA".to_string()),
|
||||||
|
ignore_entities: Mutex::new(true),
|
||||||
|
show_air: Mutex::new(false),
|
||||||
|
show_bounding_box: Mutex::new(true),
|
||||||
|
integrity: Mutex::new(1.0),
|
||||||
|
seed: Mutex::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
pumpkin/src/block/entities/test_block.rs
Normal file
46
pumpkin/src/block/entities/test_block.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
|
||||||
|
use super::BlockEntity;
|
||||||
|
|
||||||
|
pub struct TestBlockBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for TestBlockBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(_nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
_nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestBlockBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:test_block";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
}
|
||||||
46
pumpkin/src/block/entities/test_instance_block.rs
Normal file
46
pumpkin/src/block/entities/test_instance_block.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
|
||||||
|
use super::BlockEntity;
|
||||||
|
|
||||||
|
pub struct TestInstanceBlockBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for TestInstanceBlockBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(_nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
_nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async {})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestInstanceBlockBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:test_instance_block";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self { position }
|
||||||
|
}
|
||||||
|
}
|
||||||
68
pumpkin/src/block/entities/trial_spawner.rs
Normal file
68
pumpkin/src/block/entities/trial_spawner.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct TrialSpawnerBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub normal_config: Mutex<Option<NbtCompound>>,
|
||||||
|
pub ominous_config: Mutex<Option<NbtCompound>>,
|
||||||
|
pub spawner_data: Mutex<Option<NbtCompound>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for TrialSpawnerBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
normal_config: Mutex::new(nbt.get_compound("normal_config").cloned()),
|
||||||
|
ominous_config: Mutex::new(nbt.get_compound("ominous_config").cloned()),
|
||||||
|
spawner_data: Mutex::new(nbt.get_compound("spawner_data").cloned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(cfg) = self.normal_config.lock().await.as_ref() {
|
||||||
|
nbt.put_compound("normal_config", cfg.clone());
|
||||||
|
}
|
||||||
|
if let Some(cfg) = self.ominous_config.lock().await.as_ref() {
|
||||||
|
nbt.put_compound("ominous_config", cfg.clone());
|
||||||
|
}
|
||||||
|
if let Some(data) = self.spawner_data.lock().await.as_ref() {
|
||||||
|
nbt.put_compound("spawner_data", data.clone());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrialSpawnerBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:trial_spawner";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
normal_config: Mutex::const_new(None),
|
||||||
|
ominous_config: Mutex::const_new(None),
|
||||||
|
spawner_data: Mutex::const_new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
pumpkin/src/block/entities/vault.rs
Normal file
62
pumpkin/src/block/entities/vault.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use super::BlockEntity;
|
||||||
|
use pumpkin_nbt::compound::NbtCompound;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct VaultBlockEntity {
|
||||||
|
pub position: BlockPos,
|
||||||
|
pub config: Mutex<Option<NbtCompound>>,
|
||||||
|
pub server_data: Mutex<Option<NbtCompound>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockEntity for VaultBlockEntity {
|
||||||
|
fn resource_location(&self) -> &'static str {
|
||||||
|
Self::ID
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_position(&self) -> BlockPos {
|
||||||
|
self.position
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_nbt(nbt: &pumpkin_nbt::compound::NbtCompound, position: BlockPos) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
config: Mutex::new(nbt.get_compound("config").cloned()),
|
||||||
|
server_data: Mutex::new(nbt.get_compound("server_data").cloned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_nbt<'a>(
|
||||||
|
&'a self,
|
||||||
|
nbt: &'a mut NbtCompound,
|
||||||
|
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
if let Some(cfg) = self.config.lock().await.as_ref() {
|
||||||
|
nbt.put_compound("config", cfg.clone());
|
||||||
|
}
|
||||||
|
if let Some(data) = self.server_data.lock().await.as_ref() {
|
||||||
|
nbt.put_compound("server_data", data.clone());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VaultBlockEntity {
|
||||||
|
pub const ID: &'static str = "minecraft:vault";
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(position: BlockPos) -> Self {
|
||||||
|
Self {
|
||||||
|
position,
|
||||||
|
config: Mutex::const_new(None),
|
||||||
|
server_data: Mutex::const_new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -919,6 +919,15 @@ impl BlockRegistry {
|
|||||||
old_state_id: BlockStateId,
|
old_state_id: BlockStateId,
|
||||||
notify: bool,
|
notify: bool,
|
||||||
) {
|
) {
|
||||||
|
let state = world.get_block_state(position);
|
||||||
|
if state.block_entity_type != u16::MAX
|
||||||
|
&& world.get_block_entity(position).is_none()
|
||||||
|
&& let Some(entity) =
|
||||||
|
crate::block::entities::create_block_entity(state.block_entity_type, *position)
|
||||||
|
{
|
||||||
|
world.add_block_entity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
let pumpkin_block = self.get_pumpkin_block(block.id);
|
let pumpkin_block = self.get_pumpkin_block(block.id);
|
||||||
if let Some(pumpkin_block) = pumpkin_block {
|
if let Some(pumpkin_block) = pumpkin_block {
|
||||||
pumpkin_block
|
pumpkin_block
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user