# Entity System

The entity system connects your scene objects to the Spark framework. Every gameplay object (player, NPC, interactable, chest, crafting station) uses a `SparkEntity` component to identify itself and provide fast component access.

## SparkEntity Component

`SparkEntity` is a MonoBehaviour that you add to any GameObject that needs to participate in Spark systems. It provides:

* A unique entity ID for lookups
* Cached component access (faster than `GetComponent<T>()`)
* Automatic registration with `SparkEntityRegistry`
* Display name binding for UI

### Entity IDs

Each entity has an ID and an ID source that determines how it's generated:

| ID Source   | When to Use                                           | How It Works                                                                 |
| ----------- | ----------------------------------------------------- | ---------------------------------------------------------------------------- |
| `Local`     | Dynamically spawned objects                           | Auto-generated GUID + timestamp. Unique per session but different each time. |
| `Static`    | Persistent world objects (NPCs, interactables, doors) | Manually assigned in the inspector. Stable across sessions for save/load.    |
| `Networked` | Multiplayer-synced objects                            | Assigned by the server at runtime. Shared across all clients.                |

For most gameplay objects, use `Static` so they can be saved and referenced by ID. Use `Local` for objects that are created dynamically at runtime (spawned enemies, dropped items).

### Component Caching

`SparkEntity` caches references to other components on the same GameObject. This is faster than Unity's `GetComponent<T>()` for repeated lookups:

```csharp
SparkEntity entity = SparkEntityRegistry.GetPlayerEntity();

// Fast cached lookup (preferred)
var inventory = entity.GetSparkComponent<InventoryEntity>();

// Also available
bool hasEquipment = entity.HasComponent<EquipmentEntity>();

// Try pattern
if (entity.TryGetSparkComponent<QuestTrackerEntity>(out var tracker))
{
    // Use tracker
}

// Get all components of a type (for multi-instance)
var allBuffs = entity.GetSparkComponents<BuffComponent>();
```

The cache is built on `Awake()` and can be refreshed with `RefreshCache()` if components are added or removed at runtime.

### API Reference

```csharp
// Core properties
string entity.EntityId           // The unique ID
string entity.DisplayName        // Display name for UI
bool entity.IsLocalPlayer        // Whether this is the local player

// Component access
T GetSparkComponent<T>()                    // Single component (cached)
bool TryGetSparkComponent<T>(out T result)  // Try pattern
T[] GetSparkComponents<T>()                 // All components of type
bool HasComponent<T>()                      // Existence check
bool HasComponent(Type type)                // Existence check by Type
void RefreshCache()                         // Rebuild the cache
Type[] GetCachedComponentTypes()            // All cached types

// ID management (usually set in inspector)
void SetIdSource(EntityIdSource source)
void GenerateStaticId()                     // Editor only
void ResetStaticId()                        // Editor only
void AssignNetworkId(string networkId)      // For multiplayer
void RestoreLocalId()                       // Revert from network ID
void SetIsLocalPlayer(bool value)
```

## SparkEntityRegistry

The registry is a static service that tracks all active `SparkEntity` instances. Entities register automatically in `OnEnable()` and unregister in `OnDestroy()`.

### Lookups

All lookups are O(1) dictionary access:

```csharp
// By entity ID string
SparkEntity entity = SparkEntityRegistry.GetEntityById("npc_blacksmith");

// By GameObject reference
SparkEntity entity = SparkEntityRegistry.GetEntityFromGameObject(gameObject);

// By Collider (memoized for repeated calls)
SparkEntity entity = SparkEntityRegistry.GetEntityFromCollider(hitCollider);

// The player entity (cached for fast access)
SparkEntity player = SparkEntityRegistry.GetPlayerEntity();
```

### TryGet Variants

Every lookup has a safe `TryGet` version:

```csharp
if (SparkEntityRegistry.TryGetEntity("npc_blacksmith", out SparkEntity npc))
{
    var dialogue = npc.GetSparkComponent<DialogueEntity>();
    // ...
}
```

### Tag-Based Lookups

Query entities by their Unity tag:

```csharp
List<SparkEntity> enemies = SparkEntityRegistry.GetEntitiesByTag("Enemy");
SparkEntity firstEnemy = SparkEntityRegistry.GetFirstEntityByTag("Enemy");
```

### All Entities

Get every registered entity:

```csharp
List<SparkEntity> allEntities = SparkEntityRegistry.GetAllEntities();
```

## InteractorEntity

`InteractorEntity` handles player interaction detection. It uses camera raycasting to find `IInteractable` objects in the world and manages targeting, indicator ranges, and input.

Attach it to the player character alongside `SparkEntity`. Configure:

* **Targeting Angle Threshold**: How precisely the player needs to aim at an interactable.
* **Input Action**: The Input System action that triggers interaction.

It automatically communicates with `InteractablesManager` to show/hide interaction UI indicators.

## Creating Custom Entity Components

To create a component that works with the Spark entity system:

```csharp
using UnityEngine;

public class StaminaEntity : MonoBehaviour
{
    [SerializeField] private float maxStamina = 100f;
    [SerializeField] private float regenRate = 5f;

    private float _currentStamina;

    private void Awake()
    {
        _currentStamina = maxStamina;
    }

    public float CurrentStamina => _currentStamina;
    public float MaxStamina => maxStamina;

    public void UseStamina(float amount)
    {
        _currentStamina = Mathf.Max(0, _currentStamina - amount);
    }

    public void Regenerate(float deltaTime)
    {
        _currentStamina = Mathf.Min(maxStamina, _currentStamina + regenRate * deltaTime);
    }
}
```

Then access it through the entity's cache:

```csharp
var entity = SparkEntityRegistry.GetPlayerEntity();
var stamina = entity.GetSparkComponent<StaminaEntity>();
if (stamina != null && stamina.CurrentStamina > 10f)
{
    stamina.UseStamina(10f);
}
```

Any MonoBehaviour on the same GameObject as a `SparkEntity` is automatically included in the component cache.

## Best Practices

* Use `Static` IDs for any object that needs to persist across save/load.
* Prefer `TryGetEntity` or `TryGetSparkComponent` over direct lookups followed by null checks.
* Cache entity references in long-running systems rather than looking them up every frame.
* Call `RefreshCache()` after adding or removing components at runtime.
* Never store `SparkEntity` references across scene loads. Look them up again after loading.
* Use tags for group queries (enemies, collectibles) but entity IDs for specific objects (a particular NPC).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sparkframework.dev/documentation/developer-guide/core-systems/entity-system.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
