Skip to main content

Overview

The entity system provides a hierarchy of traits and structs for working with entities in Pumpkin:
  • Entity - Base entity struct with position, rotation, velocity, etc.
  • EntityBase - Trait for all entity types
  • LivingEntity - Entities with health, effects, combat
  • Player - Player-specific functionality

EntityBase Trait

pub trait EntityBase: Send + Sync + NBTStorage {
    fn tick<'a>(
        &'a self,
        caller: Arc<dyn EntityBase>,
        server: &'a Server,
    ) -> EntityBaseFuture<'a, ()>;
    
    fn teleport(
        self: Arc<Self>,
        position: Vector3<f64>,
        yaw: Option<f32>,
        pitch: Option<f32>,
        world: Arc<World>,
    ) -> TeleportFuture;
    
    fn damage<'a>(
        &'a self,
        caller: &'a dyn EntityBase,
        amount: f32,
        damage_type: DamageType,
    ) -> EntityBaseFuture<'a, bool>;
    
    fn get_entity(&self) -> &Entity;
    fn get_living_entity(&self) -> Option<&LivingEntity>;
    fn get_player(&self) -> Option<&Player>;
}

tick

Called every game tick for this entity.
caller
Arc<dyn EntityBase>
required
Reference to the entity being ticked
server
&Server
required
Server instance

teleport

Teleports the entity to a new position and/or world.
position
Vector3<f64>
required
Target position
yaw
Option<f32>
Optional new yaw rotation
pitch
Option<f32>
Optional new pitch rotation
world
Arc<World>
required
Target world (can be same or different dimension)
Example:
entity.clone().teleport(
    Vector3::new(100.0, 64.0, 100.0),
    Some(90.0), // Face east
    Some(0.0),  // Look straight ahead
    world.clone()
).await;

damage

Applies damage to the entity.
caller
&dyn EntityBase
required
Entity receiving damage
amount
f32
required
Damage amount
damage_type
DamageType
required
Type of damage (GENERIC, FIRE, FALL, etc.)
returns
bool
true if damage was successful
Example:
use pumpkin_data::damage::DamageType;

let damaged = entity.damage(entity.as_ref(), 5.0, DamageType::GENERIC).await;
if damaged {
    println!("Entity took damage!");
}

Entity Struct

pub struct Entity {
    pub entity_id: i32,
    pub entity_uuid: uuid::Uuid,
    pub entity_type: &'static EntityType,
    pub world: ArcSwap<World>,
    pub pos: AtomicCell<Vector3<f64>>,
    pub velocity: AtomicCell<Vector3<f64>>,
    pub yaw: AtomicCell<f32>,
    pub pitch: AtomicCell<f32>,
    pub on_ground: AtomicBool,
    pub bounding_box: AtomicCell<BoundingBox>,
    // ... many more fields
}

Creating Entities

impl Entity {
    pub fn new(
        world: Arc<World>,
        position: Vector3<f64>,
        entity_type: &'static EntityType,
    ) -> Self
}
Example:
use pumpkin::entity::Entity;
use pumpkin_data::entity::EntityType;
use pumpkin_util::math::vector3::Vector3;

let zombie = Entity::new(
    world.clone(),
    Vector3::new(0.0, 64.0, 0.0),
    &EntityType::ZOMBIE
);

Position and Movement

set_pos

pub fn set_pos(&self, new_position: Vector3<f64>)
Sets the entity’s position and updates block/chunk coordinates.
new_position
Vector3<f64>
required
New position

move_pos

pub fn move_pos(&self, delta: Vector3<f64>)
Moves the entity by a delta.
delta
Vector3<f64>
required
Position delta to add

set_velocity

pub async fn set_velocity(&self, velocity: Vector3<f64>)
Sets the entity’s velocity and broadcasts it.
velocity
Vector3<f64>
required
New velocity vector

add_velocity

pub async fn add_velocity(&self, velocity: Vector3<f64>)
Adds to the entity’s current velocity.
velocity
Vector3<f64>
required
Velocity to add

Rotation

look_at

pub fn look_at(&self, target: Vector3<f64>)
Makes the entity look at a target position.
target
Vector3<f64>
required
Target position to look at

rotation

pub fn rotation(&self) -> Vector3<f32>
Returns the entity’s rotation as a direction vector.
returns
Vector3<f32>
Direction vector based on yaw and pitch

Metadata

send_meta_data

pub async fn send_meta_data(&self, metadata: &[Metadata])
Sends entity metadata updates to clients.
metadata
&[Metadata]
required
Array of metadata entries
Example:
use pumpkin_data::meta_data_type::MetaDataType;
use pumpkin_data::tracked_data::TrackedData;
use pumpkin_protocol::java::client::play::Metadata;

entity.send_meta_data(&[
    Metadata::new(
        TrackedData::DATA_CUSTOM_NAME,
        MetaDataType::OPTIONAL_TEXT_COMPONENT,
        Some(TextComponent::text("Custom Name"))
    )
]).await;

Knockback

apply_knockback

pub fn apply_knockback(&self, strength: f64, x: f64, z: f64)
Applies knockback to the entity.
strength
f64
required
Knockback strength
x
f64
required
X direction component
z
f64
required
Z direction component

Entity Types

use pumpkin_data::entity::EntityType;

// Common entity types
EntityType::PLAYER
EntityType::ZOMBIE
EntityType::SKELETON
EntityType::CREEPER
EntityType::ITEM
EntityType::ARROW
EntityType::MINECART
EntityType::BOAT
// ... many more

Example: Spawning and Moving Entity

use pumpkin::entity::Entity;
use pumpkin_data::entity::EntityType;
use pumpkin_util::math::vector3::Vector3;

// Create zombie
let zombie = Arc::new(Entity::new(
    world.clone(),
    Vector3::new(0.0, 64.0, 0.0),
    &EntityType::ZOMBIE
));

// Spawn in world
world.spawn_entity(zombie.clone()).await;

// Make it look at player
if let Some(player) = world.get_player_by_name("Player1") {
    zombie.look_at(player.living_entity.entity.pos.load());
}

// Apply velocity upward
zombie.set_velocity(Vector3::new(0.0, 0.5, 0.0)).await;

// Apply knockback
zombie.apply_knockback(1.0, 1.0, 0.0);

Example: Custom Entity Interaction

use pumpkin::entity::*;

struct MyHandler;

impl EventHandler<PlayerInteractEntityEvent> for MyHandler {
    fn handle<'a>(
        &'a self,
        server: &'a Arc<Server>,
        event: &'a PlayerInteractEntityEvent
    ) -> BoxFuture<'a, ()> {
        Box::pin(async move {
            // Get the entity that was interacted with
            if let Some(entity) = server
                .get_world_from_dimension(&event.player.world.load().dimension)
                .entities
                .load()
                .iter()
                .find(|e| e.get_entity().entity_id == event.entity_id)
            {
                // Teleport entity to player
                entity.clone().teleport(
                    event.player.position(),
                    None,
                    None,
                    event.player.world.load().clone()
                ).await;
            }
        })
    }
}

Passengers and Vehicles

// Get entity's passengers
let passengers = entity.passengers.lock().await;
for passenger in passengers.iter() {
    println!("Passenger: {:?}", passenger.get_entity().entity_type);
}

// Get entity's vehicle
if let Some(vehicle) = entity.vehicle.lock().await.as_ref() {
    println!("Riding: {:?}", vehicle.get_entity().entity_type);
}

Build docs developers (and LLMs) love