> For the complete documentation index, see [llms.txt](https://morningheartgames.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://morningheartgames.gitbook.io/docs/gameplay-ability-toolkit-ecs/start/getting-started.md).

# Getting started with the ECS runtime

This page builds a small, complete example: a hero entity that loses 15 health every second and uses a heal ability when its health drops below 50. On the way you use every part a real game needs: toolkit assets, a SubScene, a system that sends requests to the runtime, and a system that reads the results. It takes about twenty minutes.

**Before you start**

* Unity 6000.6 or newer, with Gameplay Ability Toolkit 1.2.0 or newer and this add-on imported. See [Requirements](/docs/gameplay-ability-toolkit-ecs/start/documentation.md#requirements).
* New to Entities? Hold on to one idea: a **SubScene** is where GameObjects are converted ("baked") into entities. Everything the runtime simulates lives inside a SubScene.

**Want to see the result first?** Open **Tools > Gameplay Ability Toolkit > Dashboard > ECS Start** and click **Make It** on the **Starter scene** tile. It creates this page's assets, scene and scripts in `Assets/GasEcsStarter`. Press Play and watch the Console. Under **Or build it yourself**, the same page checks each step below as you do it.

## 1. Install Entities

1. Open **Tools > Gameplay Ability Toolkit > Dashboard** and go to the **Dependencies** page.
2. In the **Entities** row, click **Package Manager**, then install Entities 6.6.0 or newer from the Unity Registry. Unity recompiles.
3. The Dashboard now has an **ECS Runtime** page. It checks your scene's ECS setup and, in Play mode, lists the running actors and queues. You use it in step 6.

There is nothing else to set up. The ECS assemblies switch on by themselves when Entities is installed, and from then on the runtime's systems run in every Entities world. In a world without a catalog they do nothing.

## 2. Create the assets

These are ordinary toolkit assets, the same ones the GameObject runtime uses. Create them in a folder of your own, for example `Assets/Hero`.

1. **Attributes.** Choose **Assets > Create > Gameplay Ability Toolkit > Attributes > AttributeSetDefinition** and name it `HeroAttributes`. In its Inspector, under **Add New Attribute**, set **Attribute Name** to `Health` and **Base Value** to `100`. Tick **Enable Clamping**, set **Min Value** to `0` and **Max Value** to `100`, then click **Add Attribute**.
2. **Attribute set.** Choose **Assets > Create > Gameplay Ability Toolkit > Attributes > AttributeSet** and name it `AS_Hero`. Under **Add Definition**, set **Definition** to `HeroAttributes` and click **Add**. An actor carries a set, and the set can override base values per actor.
3. **Effects.** Choose **Assets > Create > Gameplay Ability Toolkit > Effects > Base Gameplay Effect Definition** twice and name the assets `GE_Wound` and `GE_Heal`. Leave **Type** on its default, Instant. On each effect's **Modifiers** tab, click **Add** and fill in the modifier. Leave **Magnitude > Type** on its default, and set **Base Value**:

   | Asset      | Attribute | Operation | Base Value |
   | ---------- | --------- | --------- | ---------- |
   | `GE_Wound` | `Health`  | Add       | `-15`      |
   | `GE_Heal`  | `Health`  | Add       | `40`       |
4. **Ability.** Choose **Assets > Create > Gameplay Ability Toolkit > ECS > Ability** and name it `GA_Heal`. In the Inspector, open the **Effects** tab, click **Add**, and pick `GE_Heal` as a granted effect. Then open the **Costs** tab and set **Cooldowns > Base Value** to `3`.

`GA_Heal` is a `GasEntityAbility`, an ability that needs no script. When it activates, it applies its granted effects to the actor that owns it, then ends. The ECS runtime does not run ability code, so this is the usual type to start with. [Authoring](/docs/gameplay-ability-toolkit-ecs/build-with-it/authoring.md) covers abilities that stay active and wait for something.

For more on these assets, see the toolkit's [Authoring Abilities](https://morningheartgames.gitbook.io/docs/gameplay-ability-toolkit/foundations/03-authoring-abilities) and [Authoring Effects](https://morningheartgames.gitbook.io/docs/gameplay-ability-toolkit/foundations/04-authoring-effects) pages.

## 3. Build the scene

1. Create a new scene and save it.
2. In the Hierarchy, right-click and choose **New Sub Scene > Empty Scene**. Save the SubScene next to your scene when asked. Leave its checkbox ticked so it stays open for editing.
3. Inside the SubScene, create an empty GameObject named `GAS Catalog`. Click **Add Component** and choose **Gameplay Ability Toolkit > Entities > Gas Catalog Authoring**. Leave **Auto Collect Definitions** on: the catalog then lists every attribute set, effect and ability in the project, and keeps the list up to date as you add assets.
4. Inside the SubScene, create another empty GameObject named `Hero` and add **Gameplay Ability Toolkit > Entities > Gas Entity Authoring**. Set **Attribute Set** to `AS_Hero` and add `GA_Heal` to **Abilities**. **Catalog** fills itself in, because the SubScene has exactly one catalog.

That is all the runtime needs. A world has exactly one catalog, and every GameObject with `GasEntityAuthoring` bakes into an actor: an entity with its attributes, tags, ability slots and the buffers the runtime works on.

Your own systems also need a way to find the hero. In Entities the usual way is a tag component, added by a small authoring component of your own. Create `HeroAuthoring.cs`:

```csharp
using Unity.Entities;
using UnityEngine;

public struct Hero : IComponentData
{
}

public sealed class HeroAuthoring : MonoBehaviour
{
    sealed class Baker : Unity.Entities.Baker<HeroAuthoring>
    {
        public override void Bake(HeroAuthoring authoring)
        {
            AddComponent<Hero>(GetEntity(TransformUsageFlags.None));
        }
    }
}
```

Add `HeroAuthoring` to the `Hero` GameObject.

## 4. Send requests to the runtime

Gameplay code never changes an actor's attributes or tags directly. It **asks**: it adds a request to one of the runtime's queues. The runtime serves every request in the same frame and checks cooldowns, costs and tag requirements as it goes. Put systems that make requests in `GasRequestSystemGroup`, which runs just before the runtime.

Create `HeroSystem.cs`:

```csharp
using GameplayAbilityToolkit.Entities;
using Unity.Entities;

[UpdateInGroup(typeof(GasRequestSystemGroup))]
public partial struct HeroSystem : ISystem
{
    int _health;
    int _wound;
    int _heal;
    float _untilNextWound;

    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate<GasCatalog>();
        state.RequireForUpdate<Hero>();
        _health = -1;
    }

    public void OnUpdate(ref SystemState state)
    {
        // The runtime addresses everything by its index in the baked catalog. Look the indices up by name once,
        // and keep them.
        if (_health < 0)
        {
            var catalog = SystemAPI.GetSingleton<GasCatalog>().Value;
            _health = catalog.Value.FindAttributeIndex("HeroAttributes", "Health");
            _wound = catalog.Value.FindEffectIndex("GE_Wound");
            _heal = catalog.Value.FindAbilityIndex("GA_Heal");
        }

        var hero = SystemAPI.GetSingletonEntity<Hero>();

        // Take a wound every second.
        _untilNextWound -= SystemAPI.Time.DeltaTime;
        if (_untilNextWound <= 0f)
        {
            _untilNextWound = 1f;
            GasEntityFactory.RequestInstantEffect(state.EntityManager, hero, _wound);
        }

        // Read the hero's health. A read-only lookup, because a read-write access tells the runtime the actor changed
        // and makes it recalculate the actor for nothing.
        float health = SystemAPI.GetBufferLookup<GasAttributeValue>(true)[hero][_health].CurrentValue;
        if (health < 50f)
        {
            // Asked every frame while the hero is low. The cooldown decides how often it actually runs.
            GasEntityFactory.RequestActivation(state.EntityManager, hero, _heal);
        }
    }
}
```

In short, the system:

* looks up the `Health` attribute, the `GE_Wound` effect and the `GA_Heal` ability by name once, and keeps their indices;
* requests `GE_Wound` on the hero once a second, through `GasEntityFactory.RequestInstantEffect`;
* reads the hero's health from its `GasAttributeValue` buffer, read-only;
* requests `GA_Heal` every frame while health is below 50, through `GasEntityFactory.RequestActivation`. The 3-second cooldown decides how often the heal actually runs.

## 5. Read the results

Every activation request gets an answer: an event that says whether the ability ran and, if not, why. The runtime adds these events to a queue and leaves them there, so the code that reads them must also clear them. Put systems that read results in `GasResultSystemGroup`, which runs just after the runtime.

Create `HeroResultSystem.cs`:

```csharp
using GameplayAbilityToolkit.Entities;
using Unity.Entities;
using UnityEngine;

[UpdateInGroup(typeof(GasResultSystemGroup))]
public partial struct HeroResultSystem : ISystem
{
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate<GasAbilityActivationEventQueue>();
        state.RequireForUpdate<Hero>();
    }

    public void OnUpdate(ref SystemState state)
    {
        var results = SystemAPI.GetBuffer<GasAbilityActivationEvent>(
            SystemAPI.GetSingletonEntity<GasAbilityActivationEventQueue>());

        foreach (var result in results)
        {
            if (result.Succeeded)
            {
                Debug.Log("The hero healed.");
            }
        }

        // One system clears the results, after everything that reads them.
        results.Clear();
    }
}
```

A refused request arrives the same way, with `Succeeded` false and `FailureReason` set to a `GasAbilityFailureReason` such as `Cooldown`, `Cost`, `TagRequirements` or `InvalidRequest`. This hero asks every frame while its health is low, so most answers are `Cooldown`.

Clear the queue in one system only, and run it after every system that reads the queue. This system also requires `Hero`, so it runs only in a world that has a hero. Without that requirement it would clear the results in every world, including results that other systems still need.

## 6. Press Play

Press Play. Once the hero's health drops below 50, the Console prints "The hero healed." about every three seconds.

To watch the numbers change:

* **Window > Entities > Hierarchy** lists the hero entity. Select it, and the Inspector shows its `GasAttributeValue` buffer.
* **Tools > Gameplay Ability Toolkit > ECS > Actor Debugger** shows the selected actor's attributes, tags, abilities with their cooldowns, and active effects, by name.
* **Tools > Gameplay Ability Toolkit > Dashboard > ECS Runtime** shows the actors, what each queue holds, and the catalog's bake report.

If nothing happens, see [Troubleshooting](/docs/gameplay-ability-toolkit-ecs/reference/troubleshooting.md).

## Next steps

* [ECS Swarm demo](/docs/gameplay-ability-toolkit-ecs/start/swarm-demo.md): the same ideas with up to 1,000,000 enemies, area effects, slows, stuns, a sword combo driven by montages, and a HUD.
* [How it works](/docs/gameplay-ability-toolkit-ecs/build-with-it/concepts.md): what the catalog, the queues and the system groups are, and the order they run in.
* [Writing gameplay code](/docs/gameplay-ability-toolkit-ecs/build-with-it/gameplay-code.md): every way to make requests and to read state.
* [Abilities that reach other actors](/docs/gameplay-ability-toolkit-ecs/build-with-it/delivery.md): abilities that hit other actors, made in the Inspector or with **Tools > Gameplay Ability Toolkit > ECS > New Ability**.
