# Networking

Spark's networking layer is an abstraction that routes commands through a provider. In single-player, commands execute locally. In multiplayer, a custom provider can route them to a server. Your game logic stays the same either way.

## Architecture

The networking system has three pieces:

1. **INetworkProvider**: The interface that all providers implement.
2. **NetworkProviderBase**: An abstract base class with reflection-based command dispatch.
3. **LocalNetworkProvider**: The default provider for single-player/offline games.

## INetworkProvider

```csharp
public interface INetworkProvider
{
    bool IsServer { get; }
    void ExecuteCommand(ICommand command);
    void RegisterHandler<T>(ICommandHandler<T> handler) where T : ICommand;
}
```

| Member                        | Description                                                                                 |
| ----------------------------- | ------------------------------------------------------------------------------------------- |
| `IsServer`                    | Whether this instance has authority. True in single-player, depends on role in multiplayer. |
| `ExecuteCommand(ICommand)`    | Dispatches a command to its registered handler.                                             |
| `RegisterHandler<T>(handler)` | Associates a handler with a command type.                                                   |

## NetworkProviderBase

The abstract base class stores handlers in a `Dictionary<Type, object>` and uses reflection to invoke the correct `Handle()` method when a command is executed:

```csharp
public abstract class NetworkProviderBase : INetworkProvider
{
    private Dictionary<Type, object> _handlers = new();

    public abstract bool IsServer { get; }

    public void RegisterHandler<T>(ICommandHandler<T> handler) where T : ICommand
    {
        _handlers[typeof(T)] = handler;
    }

    public void ExecuteCommand(ICommand command)
    {
        var commandType = command.GetType();
        if (_handlers.TryGetValue(commandType, out var handler))
        {
            // Reflection-based dispatch to Handle(T command)
            var method = handler.GetType().GetMethod("Handle");
            method.Invoke(handler, new object[] { command });
        }
    }
}
```

When you create a custom provider, inherit from `NetworkProviderBase` and override `RegisterDefaultHandlers()`:

```csharp
public abstract class NetworkProviderBase : INetworkProvider
{
    protected abstract void RegisterDefaultHandlers();
}
```

## LocalNetworkProvider

The default provider used in single-player games. It:

* Auto-registers at `BeforeSceneLoad` if no other provider is set
* Executes commands immediately and synchronously
* Always reports `IsServer => true`
* Registers the built-in `DragDropCommandHandler`

You don't need to do anything to use it. It's set up automatically.

## Setting Up a Network Provider

To use a custom provider (for multiplayer), register it before any plugins try to execute commands:

```csharp
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void SetupNetworking()
{
    var provider = new MyMultiplayerProvider();
    Spark.SetNetworkProvider(provider);
}
```

Listen for provider readiness:

```csharp
Spark.OnNetworkProviderReady += (provider) =>
{
    Debug.Log($"Network provider ready. IsServer: {provider.IsServer}");
};
```

## Implementing a Custom Network Provider

Here is a skeleton for a multiplayer provider:

```csharp
public class MyMultiplayerProvider : NetworkProviderBase
{
    public override bool IsServer => _isServer;
    private bool _isServer;

    public MyMultiplayerProvider(bool isServer)
    {
        _isServer = isServer;
        RegisterDefaultHandlers();
    }

    protected override void RegisterDefaultHandlers()
    {
        // Register handlers for built-in commands
        RegisterHandler<DragDropCommand>(new DragDropCommandHandler());
    }

    public override void ExecuteCommand(ICommand command)
    {
        if (_isServer)
        {
            // Server: execute locally
            base.ExecuteCommand(command);
        }
        else
        {
            // Client: serialize and send to server
            byte[] data = Serialize(command);
            SendToServer(data);
        }
    }

    // Called when the server receives a command from a client
    public void OnCommandReceived(byte[] data)
    {
        ICommand command = Deserialize(data);
        base.ExecuteCommand(command);
    }
}
```

The key idea is that `ExecuteCommand` on the client sends the command over the network, while the server calls `base.ExecuteCommand()` to dispatch it locally through the handler.

## Command Serialization

For multiplayer, commands need to be serializable. This is why commands should use simple types (strings, ints, floats, bools) and entry IDs instead of direct object references.

```csharp
// Good: all fields are serializable
public class DealDamageCommand : ICommand
{
    public string AttackerId { get; set; }  // Entity ID string
    public string TargetId { get; set; }    // Entity ID string
    public string AbilityId { get; set; }   // Database entry ID
    public float Damage { get; set; }
}

// Bad: contains Unity references that can't be serialized over the network
public class BadCommand : ICommand
{
    public GameObject Target { get; set; }
    public Transform SpawnPoint { get; set; }
}
```

## Best Practices

* Design commands for serialization from the start, even if you are building single-player.
* Use `Spark.Network?.ExecuteCommand()` with the null-conditional operator. This gracefully handles the case where no provider is set.
* Register command handlers in your plugin's `RegisterPlugin()` method.
* For multiplayer, validate commands on the server. Don't trust client input.
* Keep the `LocalNetworkProvider` as your development default. Swap to a multiplayer provider when your networking layer is ready.


---

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