# Entity Component System (ECS)

The Hytale server uses an Entity Component System architecture for managing game entities. This provides high
performance and flexibility for handling large numbers of entities with varied behaviors.

## ECS Concepts

### Overview

The ECS pattern separates data (Components) from behavior (Systems):

- **Entities**: Unique identifiers (IDs) that represent game objects
- **Components**: Pure data containers attached to entities
- **Systems**: Logic that operates on entities with specific component combinations
- **Stores**: Data storage containers that hold components
- **Archetypes**: Predefined combinations of components

### Key Classes

| Class               | Description                          |
|---------------------|--------------------------------------|
| `Component<S>`      | Base component interface             |
| `ComponentRegistry` | Central registry for component types |
| `Store`             | ECS data storage                     |
| `Ref`               | Entity reference (ID wrapper)        |
| `Holder<C>`         | Component holder/accessor            |
| `Archetype`         | Entity archetype definition          |
| `SystemType`        | System type definition               |
| `Query`             | ECS query for finding entities       |

## Components

### Defining a Component

Components are pure data classes implementing `Component<Store>`:

```java
public class HealthComponent implements Component<EntityStore> {
    public static final ComponentRegistry.Entry<HealthComponent> ENTRY = 
        EntityStore.REGISTRY.register("health", HealthComponent.class, HealthComponent::new);
    
    private float health;
    private float maxHealth;
    
    public HealthComponent() {
        this.health = 20.0f;
        this.maxHealth = 20.0f;
    }
    
    public float getHealth() {
        return health;
    }
    
    public void setHealth(float health) {
        this.health = Math.max(0, Math.min(health, maxHealth));
    }
    
    public float getMaxHealth() {
        return maxHealth;
    }
    
    public void setMaxHealth(float maxHealth) {
        this.maxHealth = maxHealth;
    }
    
    public boolean isDead() {
        return health <= 0;
    }
    
    public void damage(float amount) {
        setHealth(health - amount);
    }
    
    public void heal(float amount) {
        setHealth(health + amount);
    }
}
```

### Built-in Components

The server provides several built-in components in `EntityStore.REGISTRY`:

| Component                | Description                       |
|--------------------------|-----------------------------------|
| `TransformComponent`     | Position, rotation, and scale     |
| `UUIDComponent`          | Unique entity identifier          |
| `ModelComponent`         | Visual model reference            |
| `MovementAudioComponent` | Movement sound effects            |
| `PositionDataComponent`  | Position tracking data            |
| `HeadRotation`           | Head rotation for living entities |

### Registering Components

Register custom components in your plugin's `setup()`:

```java
@Override
protected void setup() {
    // Components are registered through the EntityStoreRegistry
    getEntityStoreRegistry().registerComponent(MyComponent.ENTRY);
}
```

## Entities

### Entity Hierarchy

```
Component<EntityStore>
└── Entity                    // Base entity
    └── LivingEntity         // Has health and can take damage
        ├── Player           // Player entity
        └── NPCEntity        // NPC entity
```

### Creating a Custom Entity

```java
public class CustomEntity extends Entity {
    
    public static final Codec<CustomEntity> CODEC = BuilderCodec.of(CustomEntity::new)
        // Add codec fields
        .build();
    
    private int customData;
    
    public CustomEntity(World world) {
        super(world);
        this.customData = 0;
    }
    
    public int getCustomData() {
        return customData;
    }
    
    public void setCustomData(int data) {
        this.customData = data;
    }
    
    @Override
    public void tick() {
        super.tick();
        // Custom tick logic
    }
}
```

### Registering Entities

```java
@Override
protected void setup() {
    getEntityRegistry().register(
        "customEntity",
        CustomEntity.class,
        CustomEntity::new
    );
    
    // With serialization codec
    getEntityRegistry().register(
        "customEntity",
        CustomEntity.class,
        CustomEntity::new,
        CustomEntity.CODEC
    );
}
```

### Accessing Entity Components

```java
Entity entity = world.getEntity(entityId);

// Get a component
TransformComponent transform = entity.get(TransformComponent.ENTRY);
if (transform != null) {
    Vector3d position = transform.getPosition();
}

// Check if entity has component
if (entity.has(HealthComponent.ENTRY)) {
    // Entity has health
}

// Add a component
entity.add(MyComponent.ENTRY, new MyComponent());

// Remove a component
entity.remove(MyComponent.ENTRY);
```

## Entity Store

The `EntityStore` manages entity data within a world:

```java
World world = Universe.get().getWorld("default");
EntityStore store = world.getEntityStore();

// Create entity
Ref entityRef = store.create();

// Add components to entity
store.add(entityRef, TransformComponent.ENTRY, new TransformComponent(position));
store.add(entityRef, HealthComponent.ENTRY, new HealthComponent());

// Get component from entity
HealthComponent health = store.get(entityRef, HealthComponent.ENTRY);

// Remove entity
store.remove(entityRef);
```

## Queries

Queries find entities with specific component combinations:

```java
// Query for entities with both Transform and Health components
Query query = Query.builder()
    .with(TransformComponent.ENTRY)
    .with(HealthComponent.ENTRY)
    .build();

// Execute query
EntityStore store = world.getEntityStore();
store.query(query, (ref, transform, health) -> {
    // Process each matching entity
    if (health.isDead()) {
        // Handle dead entity
    }
});
```

### Query Builder

```java
Query query = Query.builder()
    .with(ComponentA.ENTRY)        // Must have ComponentA
    .with(ComponentB.ENTRY)        // Must have ComponentB
    .without(ComponentC.ENTRY)     // Must NOT have ComponentC
    .build();
```

## Archetypes

Archetypes define common component combinations for entity types:

```java
// Define an archetype for enemies
Archetype enemyArchetype = Archetype.builder()
    .add(TransformComponent.ENTRY)
    .add(HealthComponent.ENTRY)
    .add(AIComponent.ENTRY)
    .add(CombatComponent.ENTRY)
    .build();

// Create entity with archetype
Ref enemy = store.create(enemyArchetype);
```

## Systems

Systems contain the logic that operates on entities:

```java
public class HealthRegenSystem implements System {
    
    private static final Query QUERY = Query.builder()
        .with(HealthComponent.ENTRY)
        .build();
    
    @Override
    public void tick(World world) {
        EntityStore store = world.getEntityStore();
        
        store.query(QUERY, (ref, health) -> {
            if (!health.isDead() && health.getHealth() < health.getMaxHealth()) {
                // Regenerate 0.1 health per tick
                health.heal(0.1f);
            }
        });
    }
}
```

### Registering Systems

```java
@Override
protected void setup() {
    // Register system with the world module
    getEntityStoreRegistry().registerSystem(new HealthRegenSystem());
}
```

## Working with Players

### Getting Players

```java
// Get all players
Collection<Player> players = Universe.get().getPlayers();

// Get player by name
Player player = Universe.get().getPlayer("PlayerName");

// Get player by UUID
Player player = Universe.get().getPlayer(uuid);

// Get players in world
World world = Universe.get().getWorld("default");
Collection<Player> worldPlayers = world.getPlayers();
```

### Player Properties

```java
Player player = getPlayer();

// Position
Vector3d position = player.getPosition();
player.setPosition(new Vector3d(x, y, z));

// Rotation
float yaw = player.getYaw();
float pitch = player.getPitch();

// Health (if LivingEntity)
player.setHealth(20.0f);
float health = player.getHealth();

// Game mode
GameMode mode = player.getGameMode();
player.setGameMode(GameMode.CREATIVE);

// Inventory
Inventory inventory = player.getInventory();
```

## Living Entities

`LivingEntity` extends `Entity` with health and damage capabilities:

```java
public class CustomMob extends LivingEntity {
    
    public CustomMob(World world) {
        super(world);
        setMaxHealth(50.0f);
        setHealth(50.0f);
    }
    
    @Override
    public void onDamage(DamageSource source, float amount) {
        super.onDamage(source, amount);
        // Custom damage handling
    }
    
    @Override
    public void onDeath() {
        super.onDeath();
        // Drop loot, play effects, etc.
    }
}
```

## Entity Events

Subscribe to entity-related events:

```java
// Entity removed from world
getEventRegistry().register(EntityRemoveEvent.class, event -> {
    Entity entity = event.getEntity();
    // Handle entity removal
});

// Living entity uses block
getEventRegistry().register(LivingEntityUseBlockEvent.class, event -> {
    LivingEntity entity = event.getEntity();
    // Handle block usage
});
```

## Spawning Entities

```java
// Get the world
World world = Universe.get().getWorld("default");

// Spawn entity at position
Vector3d position = new Vector3d(100, 64, 100);
CustomEntity entity = new CustomEntity(world);
entity.setPosition(position);
world.addEntity(entity);

// Spawn with specific properties
CustomEntity entity = new CustomEntity(world);
entity.setPosition(position);
entity.setCustomData(42);
world.addEntity(entity);
```

## Best Practices

1. **Keep components data-only** - Components should not contain logic, only data
2. **Use systems for behavior** - Put game logic in systems, not components
3. **Prefer composition** - Use multiple small components instead of large monolithic ones
4. **Query efficiently** - Cache queries and reuse them
5. **Use archetypes** - Define archetypes for common entity types
6. **Handle null components** - Always check if a component exists before using it
7. **Clean up entities** - Remove entities when they're no longer needed
8. **Use appropriate entity types** - Extend `LivingEntity` for damageable entities
