use pumpkin_data::BlockStateId; use pumpkin_data::damage::DamageType; use pumpkin_data::entity::EntityType; use pumpkin_data::meta_data_type::MetaDataType; use pumpkin_data::{Block, tracked_data::TrackedData}; use pumpkin_protocol::java::client::play::Metadata; use pumpkin_util::math::position::BlockPos; use pumpkin_world::world::BlockFlags; use std::sync::{Arc, atomic::Ordering}; use crate::{ entity::{Entity, EntityBase, EntityBaseFuture, NBTStorage, living::LivingEntity}, server::Server, world::World, }; pub struct FallingEntity { entity: Entity, block_state_id: BlockStateId, } impl FallingEntity { pub const fn new(entity: Entity, block_state_id: BlockStateId) -> Self { Self { entity, block_state_id, } } /// Replaced the current Block and Spawns a new Falling one pub async fn replace_spawn(world: &Arc, position: BlockPos, block_state: BlockStateId) { // Replace the original block, TODO: use fluid state world .set_block_state( &position, Block::AIR.default_state.id, BlockFlags::NOTIFY_ALL, ) .await; let position = position.0.to_f64().add_raw(0.5, 0.0, 0.5); let entity = Entity::new(world.clone(), position, &EntityType::FALLING_BLOCK); entity .data .store(i32::from(block_state.as_u16()), Ordering::Relaxed); let entity = Arc::new(Self::new(entity, block_state)); world.spawn_entity(entity).await; } } impl NBTStorage for FallingEntity {} impl EntityBase for FallingEntity { fn tick<'a>( &'a self, caller: &'a Arc, server: &'a Server, ) -> EntityBaseFuture<'a, ()> { Box::pin(async move { let entity = &self.entity; entity.tick(caller, server).await; let original_velo = entity.velocity.load(); let mut velo = original_velo; velo.y -= self.get_gravity(); entity.velocity.store(velo); entity.move_entity(caller, velo).await; entity.tick_block_collisions(caller, server).await; if entity.on_ground.load(Ordering::Relaxed) { entity.velocity.store(velo.multiply(0.7, -0.5, 0.7)); entity .world .load() .set_block_state( &self.entity.block_pos.load(), self.block_state_id, BlockFlags::NOTIFY_ALL, ) .await; entity.remove().await; } entity.velocity.store(velo.multiply(0.98, 0.98, 0.98)); if entity.velocity_dirty.swap(false, Ordering::SeqCst) { entity.send_pos_rot(); entity.send_velocity(); } }) } fn init_data_tracker(&self) -> EntityBaseFuture<'_, ()> { Box::pin(async move { self.entity.send_meta_data( &[Metadata::new( TrackedData::START_POS, MetaDataType::BLOCK_POS, self.entity.block_pos.load(), )], None, ); }) } fn get_entity(&self) -> &Entity { &self.entity } fn get_living_entity(&self) -> Option<&LivingEntity> { None } fn as_nbt_storage(&self) -> &dyn NBTStorage { self } fn damage<'a>( &'a self, _caller: &'a dyn EntityBase, _amount: f32, _damage_type: DamageType, ) -> EntityBaseFuture<'a, bool> { Box::pin(async move { false }) } fn get_gravity(&self) -> f64 { 0.04 } fn cast_any(&self) -> &dyn std::any::Any { self } }