Pumpkin/pumpkin/src/entity/falling.rs
2026-07-13 12:53:33 +02:00

136 lines
3.8 KiB
Rust

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<World>, 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<dyn EntityBase>,
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
}
}