use pumpkin_data::Block; use pumpkin_data::BlockStateId; use pumpkin_data::damage::DamageType; use pumpkin_data::entity::EntityType; 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, 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 (synchronous) pub 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, ); 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_non_save(entity); } } impl EntityBase for FallingEntity { fn tick(&self, caller: &Arc, server: &Server) { let entity = &self.entity; let mut velo = entity.velocity.load(); velo.y -= self.get_gravity(); entity.velocity.store(velo); entity.move_entity(caller, velo); entity.tick_block_collisions(caller, server); 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, ); self.entity.remove(); } 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) { self.entity.send_meta_data( &[Metadata::new( pumpkin_data::tracked_data::falling_block::START_POS, self.entity.block_pos.load(), )], None, ); } fn get_entity(&self) -> &Entity { &self.entity } fn get_living_entity(&self) -> Option<&LivingEntity> { None } fn damage(&self, _caller: &dyn EntityBase, _amount: f32, _damage_type: DamageType) -> bool { false } fn get_gravity(&self) -> f64 { 0.04 } fn cast_any(&self) -> &dyn std::any::Any { self } }