# Creating Your First Plugin

This walkthrough builds a complete Spark plugin from scratch. By the end, you will have a working plugin with a database entry, a scene entity, a command, an event, and a tab in the Spark Editor.

We will build a generic plugin called **MyPlugin** that you can adapt to any purpose.

## Step 1: Create the Folder Structure

Inside your project, create the following folder structure:

```
Assets/MyPlugins/MyPlugin/
    Editor/
        Scripts/
    Runtime/
        Scripts/
            API/
            Data/
            Components/
            Events/
            Commands/
            Persistence/
        Resources/
            MyPluginData/
```

This follows the standard Spark plugin layout. `Runtime/` holds gameplay code, `Editor/` holds editor-only code, and `Resources/MyPluginData/` is where database entries will be stored.

## Step 2: Create Assembly Definitions

Create two assembly definition files:

**Runtime/Spark.MyPlugin.asmdef**

```json
{
    "name": "Spark.MyPlugin",
    "rootNamespace": "",
    "references": [
        "Spark.Core"
    ],
    "includePlatforms": [],
    "excludePlatforms": [],
    "allowUnsafeCode": false,
    "overrideReferences": false,
    "precompiledReferences": [],
    "autoReferenced": true,
    "defineConstraints": [],
    "versionDefines": [],
    "noEngineReferences": false
}
```

**Editor/Spark.MyPlugin.Editor.asmdef**

```json
{
    "name": "Spark.MyPlugin.Editor",
    "rootNamespace": "",
    "references": [
        "Spark.Core",
        "Spark.Core.Editor",
        "Spark.MyPlugin"
    ],
    "includePlatforms": ["Editor"],
    "excludePlatforms": [],
    "allowUnsafeCode": false,
    "overrideReferences": false,
    "precompiledReferences": [],
    "autoReferenced": true,
    "defineConstraints": [],
    "versionDefines": [],
    "noEngineReferences": false
}
```

## Step 3: Define the Plugin Interface

Create the interface that other plugins will use to access your plugin's functionality.

**Runtime/Scripts/API/IMyPlugin.cs**

```csharp
using System.Collections.Generic;

public interface IMyPlugin
{
    List<MyPluginEntry> GetAllEntries();
    MyPluginEntry GetEntry(string entryId);
    bool HasEntry(string entryId);
}
```

Keep the interface focused on read operations. Actions that modify state should go through commands.

## Step 4: Create the Database Entry

This is the data type that appears in the Spark Editor.

**Runtime/Scripts/Data/MyPluginEntry.cs**

```csharp
using UnityEngine;

[CreateAssetMenu(
    fileName = "New MyPlugin Entry",
    menuName = "Spark/MyPlugin/Entry")]
public class MyPluginEntry : SparkDatabaseEntry
{
    [Section("General Settings")]
    [SerializeField] private int defaultValue = 0;

    [SerializeField] private int minValue = 0;

    [SerializeField] private int maxValue = 1000;

    public int DefaultValue => defaultValue;
    public int MinValue => minValue;
    public int MaxValue => maxValue;
}
```

The `[Section]` attribute creates collapsible groups in the Spark Editor's inspector. The `[SerializeField] private` pattern with public getters is the standard Spark convention for entry fields.

## Step 5: Define Events

Events notify other systems when something happens in your plugin.

**Runtime/Scripts/Events/MyPluginValueChangedEvent.cs**

```csharp
public class MyPluginValueChangedEvent : SparkEventBase
{
    public override string EventType => "MyPluginValueChanged";
    public string CharacterId { get; }
    public string EntryId { get; }
    public int OldValue { get; }
    public int NewValue { get; }
    public int Delta { get; }

    public MyPluginValueChangedEvent(
        string characterId,
        string entryId,
        int oldValue,
        int newValue,
        string source = null)
    {
        CharacterId = characterId;
        EntryId = entryId;
        OldValue = oldValue;
        NewValue = newValue;
        Delta = newValue - oldValue;
        Source = source;
    }
}
```

## Step 6: Define Commands and Handlers

Commands are the actions your plugin supports. Handlers contain the logic.

**Runtime/Scripts/Commands/ModifyMyPluginValueCommand.cs**

```csharp
public class ModifyMyPluginValueCommand : ICommand
{
    public string CharacterId { get; set; }
    public string EntryId { get; set; }
    public int Amount { get; set; }
    public string Source { get; set; }
}
```

**Runtime/Scripts/Commands/ModifyMyPluginValueCommandHandler.cs**

```csharp
using UnityEngine;

public class ModifyMyPluginValueCommandHandler
    : ICommandHandler<ModifyMyPluginValueCommand>
{
    public void Handle(ModifyMyPluginValueCommand command)
    {
        // Find the entity
        if (!SparkEntityRegistry.TryGetEntity(
                command.CharacterId, out SparkEntity entity))
        {
            Debug.LogWarning($"Entity not found: {command.CharacterId}");
            return;
        }

        // Get the plugin component
        var tracker = entity.GetSparkComponent<MyPluginTrackerEntity>();
        if (tracker == null)
        {
            Debug.LogWarning(
                $"No MyPluginTrackerEntity on {command.CharacterId}");
            return;
        }

        // Get the entry for validation
        MyPluginEntry entry =
            SparkDatabaseRegistry.GetEntry<MyPluginEntry>(command.EntryId);
        if (entry == null)
        {
            Debug.LogWarning($"Entry not found: {command.EntryId}");
            return;
        }

        // Apply the change
        int oldVal = tracker.GetValue(command.EntryId);
        int newVal = Mathf.Clamp(
            oldVal + command.Amount,
            entry.MinValue,
            entry.MaxValue);

        tracker.SetValue(command.EntryId, newVal);

        // Publish event
        SparkEventBus.Publish(new MyPluginValueChangedEvent(
            command.CharacterId,
            command.EntryId,
            oldVal,
            newVal,
            command.Source));
    }
}
```

The handler follows the standard pattern: validate inputs, apply state changes, publish events.

## Step 7: Create the Scene Entity

This MonoBehaviour goes on a character's GameObject to track plugin data at runtime.

**Runtime/Scripts/Components/MyPluginTrackerEntity.cs**

```csharp
using System.Collections.Generic;
using UnityEngine;

public class MyPluginTrackerEntity : MonoBehaviour
{
    private Dictionary<string, int> _values =
        new Dictionary<string, int>();

    public int GetValue(string entryId)
    {
        return _values.TryGetValue(entryId, out int val)
            ? val
            : GetDefaultValue(entryId);
    }

    public void SetValue(string entryId, int value)
    {
        _values[entryId] = value;
    }

    public Dictionary<string, int> GetAllValues()
    {
        return new Dictionary<string, int>(_values);
    }

    private int GetDefaultValue(string entryId)
    {
        MyPluginEntry entry =
            SparkDatabaseRegistry.GetEntry<MyPluginEntry>(entryId);
        return entry != null ? entry.DefaultValue : 0;
    }
}
```

## Step 8: Implement the Plugin Class

This ties everything together. The plugin class registers itself with Spark and registers its command handlers with the network provider.

**Runtime/Scripts/API/MyPluginImplementation.cs**

```csharp
using System.Collections.Generic;
using UnityEngine;

public class MyPluginImplementation : IMyPlugin
{
    private static MyPluginImplementation _instance;
    private static bool _hasRegistered = false;

    [RuntimeInitializeOnLoadMethod(
        RuntimeInitializeLoadType.SubsystemRegistration)]
    private static void Reset()
    {
        _hasRegistered = false;
        _instance = null;
    }

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

            // Register command handlers
            Spark.Network?.RegisterHandler<ModifyMyPluginValueCommand>(
                new ModifyMyPluginValueCommandHandler());
        }
    }

    #if UNITY_EDITOR
    [UnityEditor.InitializeOnLoadMethod]
    private static void RegisterPluginInEditor()
    {
        Reset();
        RegisterPlugin();
    }
    #endif

    public List<MyPluginEntry> GetAllEntries()
    {
        return SparkDatabaseRegistry.GetAllEntries<MyPluginEntry>();
    }

    public MyPluginEntry GetEntry(string entryId)
    {
        return SparkDatabaseRegistry.GetEntry<MyPluginEntry>(entryId);
    }

    public bool HasEntry(string entryId)
    {
        return SparkDatabaseRegistry.HasEntry(entryId);
    }
}
```

## Step 9: Create the Plugin Manifest

The manifest tells the Spark Editor about your plugin. Create a ScriptableObject asset:

1. In Unity, right-click in your Editor folder.
2. Select **Create > Spark > Plugin Manifest** (or create a `PluginManifest` ScriptableObject).
3. Fill in the fields:
   * **Plugin Name**: MyPlugin
   * **Unique ID**: myplugin
   * **Version**: 1.0.0
   * **Author**: Your Name
   * **Folder Name**: MyPlugin
4. Add a Category called "My Plugin" with a tab:
   * **Tab ID**: myplugin\_tab
   * **Display Name**: My Plugin
   * **Asset Type**: Select `MyPluginEntry`
   * **Path**: The Resources path where entries are stored
   * **Tab Type**: Database

This creates a "My Plugin" tab in the Spark Editor where users can create and manage entries.

## Step 10: Using Your Plugin

Once everything is set up, here is how you use the plugin from other code:

```csharp
// Get the plugin
var myPlugin = Spark.GetPlugin<IMyPlugin>();

// Read entry data
MyPluginEntry entry = myPlugin?.GetEntry("my_entry_01");

// Modify values via command
Spark.Network?.ExecuteCommand(new ModifyMyPluginValueCommand
{
    CharacterId = "player_01",
    EntryId = "my_entry_01",
    Amount = 50,
    Source = "quest_completed"
});

// Listen for value changes
SparkEventBus.Subscribe<MyPluginValueChangedEvent>(myHandler);
```

## What You Have Built

Your plugin now has:

* A plugin interface (`IMyPlugin`) for other plugins to access
* A database entry type (`MyPluginEntry`) editable in the Spark Editor
* An event (`MyPluginValueChangedEvent`) that fires on data changes
* A command (`ModifyMyPluginValueCommand`) for modifying values
* A command handler that validates, applies changes, and publishes events
* A scene entity (`MyPluginTrackerEntity`) that stores data per character
* A plugin class that registers everything at startup
* A manifest that adds a tab to the Spark Editor

This follows the exact same patterns used by Spark's built-in plugins. From here, you could add save data persistence, custom trigger types, requirement types, and extensions to other plugins' entries.

## Next Steps

* [Database Entries](/documentation/developer-guide/core-systems/database-entries.md) for a deeper look at custom entry types
* [Extensions](/documentation/developer-guide/core-systems/extensions.md) to learn how to add fields to other plugins' entries
* [Event System](/documentation/developer-guide/core-systems/event-system.md) for advanced event patterns
* [Save System](/documentation/developer-guide/core-systems/save.md) to persist your plugin's data


---

# 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/creating-your-first-plugin.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.
