Skip to main content

Overview

The entity system manages all dynamic objects in the world including players, mobs, items, projectiles, and vehicles. Entities are updated every tick and synchronized between client and server.

Entity Base Class

All entities derive from the Entity base class:
class Entity : public enable_shared_from_this<Entity> {
public:
    int entityId;                  // Unique identifier
    Level* level;                  // World reference
    double x, y, z;               // Position
    double xd, yd, zd;            // Velocity
    float yRot, xRot;             // Rotation (yaw, pitch)
    AABB* bb;                     // Bounding box
    bool onGround;                // Collision state
    bool removed;                 // Marked for removal
    int tickCount;                // Age in ticks
    shared_ptr<SynchedEntityData> entityData;  // Networked data
};
Location: Entity.cpp:328

Entity ID System

The game uses a dual ID system: Small IDs (0-2047):
  • Used for networked entities
  • Efficient 11-bit network encoding
  • Allocated from a shared pool
  • Must be explicitly freed
int Entity::getSmallId() {
    // Allocate from 2048-entry bitfield
    for (int i = 0; i < (2048/32); i++) {
        unsigned int flags = entityIdUsedFlags[i];
        if (flags != 0xffffffff) {
            // Find free bit and allocate
        }
    }
}
Large IDs (2048+):
  • Used for client-side only entities (particles)
  • Simple incrementing counter
  • No network synchronization
Location: Entity.cpp:37-98

Entity Hierarchy

Core Types

Entity
├── Mob                    // Living entities
│   ├── Player            // Human players
│   │   ├── ServerPlayer     // Server-side player
│   │   └── LocalPlayer      // Client-side player
│   ├── Monster           // Hostile mobs
│   │   ├── Zombie
│   │   ├── Skeleton
│   │   ├── Creeper
│   │   └── Spider
│   └── Animal            // Passive mobs
│       ├── Pig
│       ├── Cow
│       ├── Sheep
│       └── Chicken
├── ItemEntity            // Dropped items
├── PrimedTnt             // Live explosives
├── Minecart              // Vehicles
├── Boat                  // Water transport
└── Projectile            // Arrows, snowballs, etc.
    ├── Arrow
    ├── Snowball
    └── ThrownEgg

Mob System

Mob Base Class

class Mob : public Entity {
public:
    int health;                    // Hit points
    float walkingSpeed;            // Movement speed
    LookControl* lookControl;      // Head tracking
    MoveControl* moveControl;      // Movement AI
    JumpControl* jumpControl;      // Jump handling
    PathNavigation* navigation;    // Pathfinding
    Sensing* sensing;              // Awareness
    
    shared_ptr<Mob> target;        // Attack target
    int attackTime;                // Attack cooldown
    int hurtTime;                  // Damage animation
};
Location: Mob.cpp:123

AI Components

LookControl - Manages head rotation:
class LookControl {
public:
    void setLookAt(Entity* target, float maxYRot, float maxXRot);
    void tick();  // Interpolate to target look direction
};
MoveControl - Handles movement:
class MoveControl {
public:
    void setWantedPosition(double x, double y, double z, float speed);
    void tick();  // Apply movement forces
};
PathNavigation - Pathfinding system:
class PathNavigation {
public:
    Path* createPath(int x, int y, int z);
    bool moveTo(Entity* target, float speed);
    void tick();  // Follow current path
};
Location: Mob.cpp:166-188

Player System

Player Class

class Player : public Mob {
public:
    shared_ptr<Inventory> inventory;           // Items
    Container* containerMenu;                  // Open GUI
    int experienceLevel;                       // XP level
    float experienceProgress;                  // XP bar
    FoodData foodData;                         // Hunger
    PlayerAbilities abilities;                 // Flight, etc.
    
    int dimension;                             // Current dimension
    Pos* respawnPosition;                      // Bed spawn
    bool isSleeping;                          // In bed
};
Location: Player.cpp:124

Player Types

ServerPlayer - Authoritative server instance:
  • Processes player input
  • Applies game rules
  • Broadcasts actions to clients
  • Handles inventory management
LocalPlayer - Client-side representation:
  • Captures input
  • Predicts movement
  • Renders player model
  • Receives corrections from server
MultiplayerLocalPlayer - Split-screen local player:
  • Extends LocalPlayer
  • Manages viewport
  • Handles local input
  • Connects to local server

Entity Lifecycle

Creation

// Server creates entity
shared_ptr<Entity> entity = EntityIO::newByType(type, level);
entity->moveTo(x, y, z, yRot, xRot);
level->addEntity(entity);

Addition to World

bool Level::addEntity(shared_ptr<Entity> e) {
    int xc = Mth::floor(e->x / 16);
    int zc = Mth::floor(e->z / 16);
    
    getChunk(xc, zc)->addEntity(e);
    entities.push_back(e);
    entityAdded(e);  // Notify listeners
    
    return true;
}
Location: Level.cpp:1659

Update Cycle

void Entity::tick() {
    baseTick();  // Common updates
}

void Entity::baseTick() {
    tickCount++;
    
    // Update previous position
    xo = x; yo = y; zo = z;
    
    // Process effects, fire, drowning
    // Handle riding entities
    // Spawn particles
}
Location: Entity.cpp:475-440

Removal

void Entity::remove() {
    removed = true;
}

void Level::removeEntity(shared_ptr<Entity> e) {
    e->remove();
    
    if (Player* player = dynamic_cast<Player*>(e.get())) {
        players.erase(find(players.begin(), players.end(), e));
    }
}
Location: Level.cpp:1736

Entity Updates

Entities are updated in several phases:

Phase 1: Base Tick

void Entity::baseTick() {
    // Age tracking
    tickCount++;
    
    // Position history
    xo = x; yo = y; zo = z;
    
    // Fire damage
    if (onFire > 0) {
        if (onFire % 20 == 0) {
            hurt(DamageSource::onFire, 1);
        }
        onFire--;
    }
    
    // Drowning
    if (isInWater() && !canBreatheUnderwater()) {
        airSupply--;
        if (airSupply <= -20) {
            hurt(DamageSource::drown, 2);
        }
    }
}
Location: Entity.cpp:480

Phase 2: AI Tick (Mobs)

void Mob::aiStep() {
    // Update AI components
    sensing->tick();
    targetSelector->tick();
    goalSelector->tick();
    
    // Navigation
    navigation->tick();
    moveControl->tick();
    lookControl->tick();
    jumpControl->tick();
}

Phase 3: Physics Tick

void Mob::aiStep() {
    // Apply forces
    move(xd, yd, zd);
    
    // Ground detection
    onGround = (verticalCollision && yd < 0);
    
    // Velocity damping
    if (onGround) {
        xd *= 0.6; zd *= 0.6;
    }
    yd -= 0.08;  // Gravity
}

Entity Tracking

The server tracks which entities each player can see:
class EntityTracker {
    map<int, TrackedEntity> trackedEntities;
    
public:
    void track(shared_ptr<Entity> entity);
    void untrack(shared_ptr<Entity> entity);
    void tick();
};
Tracking Logic:
  1. Determine range based on entity type
  2. Find players within range
  3. Send spawn packet if newly visible
  4. Send movement/data updates
  5. Send destroy packet if out of range
Location: EntityTracker.cpp (referenced in MinecraftServer.cpp)

Entity Synchronization

Synched Entity Data

Entities use a data watcher system for network sync:
class SynchedEntityData {
    map<int, DataItem*> itemsById;
    
public:
    void define(int id, byte value);
    void set(int id, byte value);
    byte get(int id);
    bool isDirty();  // Has changed since last send
};
Common Data Slots:
  • DATA_SHARED_FLAGS_ID = 0 - On fire, crouching, sprinting
  • DATA_AIR_SUPPLY_ID = 1 - Drowning bubbles
  • DATA_CUSTOM_NAME_ID = 2 - Name tag (not in this version)
Location: Referenced in Entity.cpp:338

Movement Synchronization

Absolute Position:
entity->moveTo(x, y, z, yRot, xRot);
// Sent when delta too large or teleporting
Relative Movement:
deltaX = (int)((newX - oldX) * 32);
deltaY = (int)((newY - oldY) * 32);
deltaZ = (int)((newZ - oldZ) * 32);
// Sent every tick if moved, using 3 bytes per axis

Entity Collections

The level maintains multiple entity collections:
class Level {
    vector<shared_ptr<Entity>> entities;          // All entities
    vector<shared_ptr<Entity>> entitiesToRemove;  // Pending removal
    vector<shared_ptr<Player>> players;           // Player subset
    vector<shared_ptr<TileEntity>> tileEntityList; // Block entities
};
Thread Safety:
EnterCriticalSection(&m_entitiesCS);
entities.push_back(entity);
LeaveCriticalSection(&m_entitiesCS);
Location: Level.cpp:522-523

Entity Types

Entity type system for network spawning:
enum eINSTANCEOF {
    eTYPE_ITEM = 1,
    eTYPE_XPORB = 2,
    eTYPE_PAINTING = 9,
    eTYPE_ARROW = 10,
    eTYPE_SNOWBALL = 11,
    eTYPE_FIREBALL = 12,
    // ... 50+ entity types
};
Factory Method:
shared_ptr<Entity> EntityIO::newByType(eINSTANCEOF type, Level* level) {
    switch(type) {
        case eTYPE_ITEM: return make_shared<ItemEntity>(level);
        case eTYPE_XPORB: return make_shared<ExperienceOrb>(level);
        // ...
    }
}

Riding System

Entities can ride other entities:
void Entity::ride(shared_ptr<Entity> vehicle) {
    if (riding != NULL) {
        riding->rider.reset();
    }
    
    riding = vehicle;
    
    if (riding != NULL) {
        riding->rider = shared_from_this();
    }
}
Updates:
// Rider follows vehicle
if (riding != NULL) {
    riding->rideTick();
    rideY += riding->getPassengerRideOffset();
    x = riding->x;
    z = riding->z;
}
Location: Referenced in Entity.cpp:485

Key Takeaways

  1. Dual ID System: Efficient network IDs for synchronized entities
  2. Component-Based AI: Separate controls for looking, moving, jumping
  3. Entity Hierarchy: Shared base with specialized derived classes
  4. Lifecycle Management: Create → Add → Tick → Remove
  5. Network Sync: Data watchers and delta movement encoding
  6. Thread Safety: Critical sections protect entity collections

Build docs developers (and LLMs) love