# Command System

Commands represent actions that change game state. They are the standard way to perform mutations in Spark: giving items, dealing damage, accepting quests, modifying reputation, and so on.

## Why Commands?

Commands exist for two reasons:

1. **Validation**: Every action goes through a handler that can validate inputs before applying changes.
2. **Networking**: Commands are routed through the network provider. In single-player, they execute locally. In multiplayer, they can be sent to the server for authoritative execution. The calling code doesn't need to know which mode it's in.

## ICommand Interface

`ICommand` is a marker interface with no methods or properties:

```csharp
public interface ICommand { }
```

Commands are simple data containers. They hold the parameters needed to perform an action but contain no logic:

```csharp
public class GiveItemCommand : ICommand
{
    public string TargetEntityId { get; set; }
    public string ItemEntryId { get; set; }
    public int Quantity { get; set; }
}
```

## ICommandHandler Interface

The handler contains all the logic for processing a command:

```csharp
public interface ICommandHandler<T> where T : ICommand
{
    void Handle(T command);
}
```

A typical handler follows this pattern:

```csharp
public class GiveItemCommandHandler : ICommandHandler<GiveItemCommand>
{
    public void Handle(GiveItemCommand command)
    {
        // 1. Validate inputs
        if (string.IsNullOrEmpty(command.TargetEntityId))
        {
            Debug.LogWarning("GiveItemCommand: No target entity specified.");
            return;
        }

        var entry = SparkDatabaseRegistry.GetEntry<ItemEntry>(command.ItemEntryId);
        if (entry == null)
        {
            Debug.LogWarning($"GiveItemCommand: Item not found: {command.ItemEntryId}");
            return;
        }

        // 2. Find the target entity
        if (!SparkEntityRegistry.TryGetEntity(command.TargetEntityId, out SparkEntity entity))
        {
            Debug.LogWarning($"GiveItemCommand: Entity not found: {command.TargetEntityId}");
            return;
        }

        var inventory = entity.GetSparkComponent<InventoryEntity>();
        if (inventory == null)
        {
            Debug.LogWarning($"GiveItemCommand: No inventory on entity.");
            return;
        }

        // 3. Apply the state change
        inventory.AddItem(command.ItemEntryId, command.Quantity);

        // 4. Publish an event
        SparkEventBus.Publish(new ItemGivenEvent(
            command.TargetEntityId,
            command.ItemEntryId,
            command.Quantity));
    }
}
```

The four-step pattern is consistent across all Spark command handlers: validate, find, apply, publish.

## Registering Command Handlers

Register handlers in your plugin's registration method:

```csharp
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void RegisterPlugin()
{
    if (!_hasRegistered)
    {
        _instance = new MyPlugin();
        Spark.RegisterPlugin<IMyPlugin>(_instance);

        // Register command handlers
        Spark.Network?.RegisterHandler<GiveItemCommand>(
            new GiveItemCommandHandler());

        _hasRegistered = true;
    }
}
```

Each command type has exactly one handler. Registering a handler for a type that already has one will overwrite the previous handler.

## Executing Commands

Execute commands through the network provider:

```csharp
Spark.Network?.ExecuteCommand(new GiveItemCommand
{
    TargetEntityId = "player_01",
    ItemEntryId = "iron_sword",
    Quantity = 1
});
```

The `?.` null-conditional is important. If no network provider is set up, the command silently does nothing rather than throwing.

## How Execution Works

When `ExecuteCommand` is called:

1. The network provider receives the command.
2. It looks up the registered handler for the command's type.
3. It invokes `Handle()` on the handler using reflection-based dispatch (in `NetworkProviderBase`).
4. The handler runs its validation and logic.

In single-player mode, `LocalNetworkProvider` executes everything immediately and locally. In multiplayer, a custom network provider could serialize the command and send it to the server.

## LocalNetworkProvider

`LocalNetworkProvider` is the default provider. It:

* Registers automatically if no other provider is set
* Executes all commands immediately and locally
* Reports `IsServer => true` (since single-player is effectively the server)
* Registers built-in handlers like `DragDropCommandHandler`

You don't need to configure it. It just works.

## Command Design Guidelines

Keep commands as simple data containers:

```csharp
// Good: flat, serializable properties
public class HealCommand : ICommand
{
    public string TargetId { get; set; }
    public float Amount { get; set; }
    public string SourceAbilityId { get; set; }
}

// Avoid: complex objects, logic, or Unity references
public class BadCommand : ICommand
{
    public GameObject Target { get; set; }    // Not serializable
    public void Execute() { /* ... */ }       // Logic belongs in handler
}
```

Commands should be serializable for networking compatibility. Use entry IDs (strings) instead of direct object references.

## Best Practices

* One command per action. Don't bundle multiple actions into one command.
* Validate everything in the handler. Don't assume inputs are valid.
* Always publish an event after applying state changes. This keeps the rest of the framework in sync.
* Use descriptive names: `{Verb}{Noun}Command` (e.g., `AcceptQuestCommand`, `CraftItemCommand`).
* Keep commands idempotent where possible. Running the same command twice should produce predictable results.
* Log warnings for validation failures. This makes debugging much easier.


---

# 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/command-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.
