Add Pumpkin carving

also replace send_meta_packet with init_data_tracker, this removes the need to clone as well
This commit is contained in:
Alexander Medvedev 2025-05-11 22:56:52 +02:00
parent cb51228adb
commit 3a7f68d049
12 changed files with 86 additions and 37 deletions

View File

@ -39,7 +39,7 @@ impl ScreenHandlerFactory for BarrelScreenFactory {
}
fn get_display_name(&self) -> TextComponent {
TextComponent::translate("container.barrel", vec![])
TextComponent::translate("container.barrel", &[])
}
}

View File

@ -16,6 +16,7 @@ pub mod jukebox;
pub mod logs;
pub mod nether_portal;
pub mod note;
pub mod pumpkin;
pub mod redstone;
pub mod signs;
pub mod slabs;

View File

@ -135,6 +135,7 @@ impl PumpkinBlock for NoteBlock {
_server: &Server,
_world: &Arc<World>,
) -> BlockActionResult {
// TODO
BlockActionResult::Continue
}

View File

@ -0,0 +1,44 @@
use crate::entity::item::ItemEntity;
use crate::server::Server;
use crate::world::{BlockFlags, World};
use crate::{block::registry::BlockActionResult, entity::player::Player};
use async_trait::async_trait;
use pumpkin_data::Block;
use pumpkin_data::entity::EntityType;
use pumpkin_data::item::Item;
use pumpkin_macros::pumpkin_block;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::item::ItemStack;
use std::sync::Arc;
#[pumpkin_block("minecraft:pumpkin")]
pub struct PumpkinBlock;
#[async_trait]
impl crate::block::pumpkin_block::PumpkinBlock for PumpkinBlock {
async fn use_with_item(
&self,
_block: &Block,
_player: &Player,
pos: BlockPos,
item: &Item,
_server: &Server,
world: &Arc<World>,
) -> BlockActionResult {
if item != &Item::SHEARS {
return BlockActionResult::Continue;
}
// TODO: set direction
world
.set_block_state(
&pos,
Block::CARVED_PUMPKIN.default_state_id,
BlockFlags::NOTIFY_ALL,
)
.await;
let entity = world.create_entity(pos.to_f64(), EntityType::ITEM);
let item_entity =
Arc::new(ItemEntity::new(entity, ItemStack::new(4, &Item::PUMPKIN_SEEDS)).await);
world.spawn_entity(item_entity).await;
BlockActionResult::Consume
}
}

View File

@ -27,8 +27,7 @@ impl TNTBlock {
let entity = world.create_entity(location.to_f64(), EntityType::TNT);
let pos = entity.pos.load();
let tnt = Arc::new(TNTEntity::new(entity, DEFAULT_POWER, DEFAULT_FUSE));
world.spawn_entity(tnt.clone()).await;
tnt.send_meta_packet().await;
world.spawn_entity(tnt).await;
world
.play_sound(
pumpkin_data::sound::Sound::EntityTntPrimed,
@ -100,8 +99,7 @@ impl PumpkinBlock for TNTBlock {
.await;
let fuse = rand::thread_rng().gen_range(0..DEFAULT_FUSE / 4) + DEFAULT_FUSE / 8;
let tnt = Arc::new(TNTEntity::new(entity, DEFAULT_POWER, fuse));
world.spawn_entity(tnt.clone()).await;
tnt.send_meta_packet().await;
world.spawn_entity(tnt).await;
}
fn should_drop_items_on_explosion(&self) -> bool {

View File

@ -13,6 +13,7 @@ use blocks::iron_bars::IronBarsBlock;
use blocks::logs::LogBlock;
use blocks::nether_portal::NetherPortalBlock;
use blocks::note::NoteBlock;
use blocks::pumpkin::PumpkinBlock;
use blocks::redstone::buttons::ButtonBlock;
use blocks::redstone::observer::ObserverBlock;
use blocks::redstone::piston::PistonBlock;
@ -90,6 +91,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
manager.register(WallBlock);
manager.register(NetherPortalBlock);
manager.register(NoteBlock);
manager.register(PumpkinBlock);
// Fire
manager.register(SoulFireBlock);
@ -163,8 +165,7 @@ async fn drop_stack(world: &Arc<World>, pos: &BlockPos, stack: ItemStack) {
let entity = world.create_entity(pos, EntityType::ITEM);
let item_entity = Arc::new(ItemEntity::new(entity, stack).await);
world.spawn_entity(item_entity.clone()).await;
item_entity.send_meta_packet().await;
world.spawn_entity(item_entity).await;
}
pub async fn calc_block_breaking(player: &Player, state: &BlockState, block_name: &str) -> f32 {

View File

@ -59,15 +59,6 @@ impl ItemEntity {
pickup_delay: Mutex::new(pickup_delay), // Vanilla pickup delay is 10 ticks
}
}
pub async fn send_meta_packet(&self) {
self.entity
.send_meta_data(&[Metadata::new(
8,
MetaDataType::ItemStack,
&ItemStackSerializer::from(*self.item_stack.lock().await),
)])
.await;
}
}
#[async_trait]
@ -86,6 +77,16 @@ impl EntityBase for ItemEntity {
}
}
async fn init_data_tracker(&self) {
self.entity
.send_meta_data(&[Metadata::new(
8,
MetaDataType::ItemStack,
&ItemStackSerializer::from(*self.item_stack.lock().await),
)])
.await;
}
async fn damage(&self, _amount: f32, _damage_type: DamageType) -> bool {
false
}
@ -123,7 +124,7 @@ impl EntityBase for ItemEntity {
self.entity.remove().await;
} else {
// Update entity
self.send_meta_packet().await;
self.init_data_tracker().await;
}
}
}

View File

@ -66,6 +66,8 @@ pub trait EntityBase: Send + Sync {
}
}
async fn init_data_tracker(&self) {}
/// Returns if damage was successful or not
async fn damage(&self, amount: f32, damage_type: DamageType) -> bool {
if let Some(living) = self.get_living_entity() {

View File

@ -1331,8 +1331,7 @@ impl Player {
// TODO: Merge stacks together
let item_entity =
Arc::new(ItemEntity::new_with_velocity(entity, item_stack, velocity, 40).await);
self.world().await.spawn_entity(item_entity.clone()).await;
item_entity.send_meta_packet().await;
self.world().await.spawn_entity(item_entity).await;
}
pub async fn drop_held_item(&self, drop_stack: bool) {

View File

@ -27,7 +27,24 @@ impl TNTEntity {
fuse: AtomicU32::new(fuse),
}
}
pub async fn send_meta_packet(&self) {
}
#[async_trait]
impl EntityBase for TNTEntity {
async fn tick(&self, server: &Server) {
let fuse = self.fuse.fetch_sub(1, Relaxed);
if fuse == 0 {
self.entity.remove().await;
self.entity
.world
.read()
.await
.explode(server, self.entity.pos.load(), self.power)
.await;
}
}
async fn init_data_tracker(&self) {
// TODO: Yes, this is the wrong function, but we need to send this after spawning the entity.
let pos: f64 = rand::random::<f64>() * TAU;
@ -50,22 +67,7 @@ impl TNTEntity {
])
.await;
}
}
#[async_trait]
impl EntityBase for TNTEntity {
async fn tick(&self, server: &Server) {
let fuse = self.fuse.fetch_sub(1, Relaxed);
if fuse == 0 {
self.entity.remove().await;
self.entity
.world
.read()
.await
.explode(server, self.entity.pos.load(), self.power)
.await;
}
}
async fn damage(&self, _amount: f32, _damage_type: DamageType) -> bool {
false
}

View File

@ -98,8 +98,7 @@ impl PumpkinItem for HoeItem {
let item_entity = Arc::new(
ItemEntity::new(entity, ItemStack::new(1, &Item::HANGING_ROOTS)).await,
);
world.spawn_entity(item_entity.clone()).await;
item_entity.send_meta_packet().await;
world.spawn_entity(item_entity).await;
}
}
}

View File

@ -1291,6 +1291,7 @@ impl World {
let base_entity = entity.get_entity();
self.broadcast_packet_all(&base_entity.create_spawn_packet())
.await;
entity.init_data_tracker().await;
let mut current_living_entities = self.entities.write().await;
current_living_entities.insert(base_entity.entity_uuid, entity);
}