Pumpkin/pumpkin-world/src/block/entities/mod.rs
Alexander Medvedev 835262a85a chore: move chunk gen settings from runtime to compile time parsing
Bin size decreased, Startup time decreased by a lot in debug, lower memory usage
2026-02-03 23:35:31 +01:00

176 lines
6.2 KiB
Rust

use std::pin::Pin;
use std::{any::Any, sync::Arc};
use barrel::BarrelBlockEntity;
use bed::BedBlockEntity;
use chest::ChestBlockEntity;
use comparator::ComparatorBlockEntity;
use end_portal::EndPortalBlockEntity;
use furnace::FurnaceBlockEntity;
use piston::PistonBlockEntity;
use pumpkin_data::{Block, block_properties::BLOCK_ENTITY_TYPES};
use pumpkin_nbt::compound::NbtCompound;
use pumpkin_util::math::position::BlockPos;
use sign::SignBlockEntity;
use crate::block::entities::blasting_furnace::BlastingFurnaceBlockEntity;
use crate::block::entities::command_block::CommandBlockEntity;
use crate::block::entities::ender_chest::EnderChestBlockEntity;
use crate::block::entities::hopper::HopperBlockEntity;
use crate::block::entities::mob_spawner::MobSpawnerBlockEntity;
use crate::block::entities::shulker_box::ShulkerBoxBlockEntity;
use crate::block::entities::smoker::SmokerBlockEntity;
use crate::{
BlockStateId, block::entities::chiseled_bookshelf::ChiseledBookshelfBlockEntity,
block::entities::dropper::DropperBlockEntity, inventory::Inventory, world::SimpleWorld,
};
pub mod barrel;
pub mod bed;
pub mod blasting_furnace;
pub mod chest;
pub mod chiseled_bookshelf;
pub mod command_block;
pub mod comparator;
pub mod dropper;
pub mod end_portal;
pub mod ender_chest;
pub mod furnace;
pub mod furnace_like_block_entity;
pub mod hopper;
pub mod mob_spawner;
pub mod piston;
pub mod shulker_box;
pub mod sign;
pub mod smoker;
//TODO: We need a mark_dirty for chests
pub trait BlockEntity: Send + Sync {
fn write_nbt<'a>(
&'a self,
nbt: &'a mut NbtCompound,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
fn from_nbt(nbt: &NbtCompound, position: BlockPos) -> Self
where
Self: Sized;
fn tick<'a>(
&'a self,
_world: &'a Arc<dyn SimpleWorld>,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async {})
}
fn resource_location(&self) -> &'static str;
fn get_position(&self) -> BlockPos;
fn write_internal<'a>(
&'a self,
nbt: &'a mut NbtCompound,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {
nbt.put_string("id", self.resource_location().to_string());
let position = self.get_position();
nbt.put_int("x", position.0.x);
nbt.put_int("y", position.0.y);
nbt.put_int("z", position.0.z);
self.write_nbt(nbt).await;
})
}
fn get_id(&self) -> u32 {
pumpkin_data::block_properties::BLOCK_ENTITY_TYPES
.iter()
.position(|block_entity_name| {
*block_entity_name == self.resource_location().split(':').next_back().unwrap()
})
.unwrap() as u32
}
/// Obtain NBT data for sending to the client in [`ChunkData`](crate::chunk::ChunkData)
fn chunk_data_nbt(&self) -> Option<NbtCompound> {
None
}
fn get_inventory(self: Arc<Self>) -> Option<Arc<dyn Inventory>> {
None
}
fn set_block_state(&mut self, _block_state: BlockStateId) {}
fn on_block_replaced<'a>(
self: Arc<Self>,
world: Arc<dyn SimpleWorld>,
position: BlockPos,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>
where
Self: 'a,
{
Box::pin(async move {
if let Some(inventory) = self.get_inventory() {
// Assuming scatter_inventory is an async method on SimpleWorld
world.scatter_inventory(&position, &inventory).await;
}
})
}
fn is_dirty(&self) -> bool {
false
}
fn as_any(&self) -> &dyn Any;
fn to_property_delegate(self: Arc<Self>) -> Option<Arc<dyn PropertyDelegate>> {
None
}
}
#[must_use]
pub fn block_entity_from_generic<T: BlockEntity>(nbt: &NbtCompound) -> T {
let x = nbt.get_int("x").unwrap();
let y = nbt.get_int("y").unwrap();
let z = nbt.get_int("z").unwrap();
T::from_nbt(nbt, BlockPos::new(x, y, z))
}
#[must_use]
pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option<Arc<dyn BlockEntity>> {
Some(match nbt.get_string("id").unwrap() {
ChestBlockEntity::ID => Arc::new(block_entity_from_generic::<ChestBlockEntity>(nbt)),
EnderChestBlockEntity::ID => {
Arc::new(block_entity_from_generic::<EnderChestBlockEntity>(nbt))
}
SignBlockEntity::ID => Arc::new(block_entity_from_generic::<SignBlockEntity>(nbt)),
BedBlockEntity::ID => Arc::new(block_entity_from_generic::<BedBlockEntity>(nbt)),
ComparatorBlockEntity::ID => {
Arc::new(block_entity_from_generic::<ComparatorBlockEntity>(nbt))
}
BarrelBlockEntity::ID => Arc::new(block_entity_from_generic::<BarrelBlockEntity>(nbt)),
HopperBlockEntity::ID => Arc::new(block_entity_from_generic::<HopperBlockEntity>(nbt)),
MobSpawnerBlockEntity::ID => {
Arc::new(block_entity_from_generic::<MobSpawnerBlockEntity>(nbt))
}
DropperBlockEntity::ID => Arc::new(block_entity_from_generic::<DropperBlockEntity>(nbt)),
ShulkerBoxBlockEntity::ID => {
Arc::new(block_entity_from_generic::<ShulkerBoxBlockEntity>(nbt))
}
PistonBlockEntity::ID => Arc::new(block_entity_from_generic::<PistonBlockEntity>(nbt)),
EndPortalBlockEntity::ID => {
Arc::new(block_entity_from_generic::<EndPortalBlockEntity>(nbt))
}
ChiseledBookshelfBlockEntity::ID => Arc::new(block_entity_from_generic::<
ChiseledBookshelfBlockEntity,
>(nbt)),
FurnaceBlockEntity::ID => Arc::new(block_entity_from_generic::<FurnaceBlockEntity>(nbt)),
CommandBlockEntity::ID => Arc::new(block_entity_from_generic::<CommandBlockEntity>(nbt)),
BlastingFurnaceBlockEntity::ID => {
Arc::new(block_entity_from_generic::<BlastingFurnaceBlockEntity>(nbt))
}
SmokerBlockEntity::ID => Arc::new(block_entity_from_generic::<SmokerBlockEntity>(nbt)),
_ => return None,
})
}
#[must_use]
pub fn has_block_block_entity(block: &Block) -> bool {
BLOCK_ENTITY_TYPES.contains(&block.name)
}
pub trait PropertyDelegate: Sync + Send {
fn get_property(&self, _index: i32) -> i32;
fn set_property(&self, _index: i32, _value: i32);
fn get_properties_size(&self) -> i32;
}