# Introduction


# What is Goap?

Goal Oriented Action Planning (GOAP) is a technique commonly used in game AI to create agents that can autonomously determine their actions and achieve specific goals within the game environment. GOAP can be used to create complex and adaptive behavior for non-player characters (NPCs) in a game.

The basic idea of GOAP is to break down a complex task or goal into a series of smaller, simpler actions that an agent can perform. These actions are then organized into a plan or sequence of actions that will lead the agent towards the desired goal.

GOAP begins with the agent evaluating its current state and the desired goal state. The agent then searches through a library of available actions to find a series of actions that will transform the current state into the desired goal state. Each action is associated with a set of preconditions that must be met in order for the action to be executed. For example, an action to pick up a key might have a precondition that the key is in the same room as the agent.

Once a plan has been created, the agent executes the first action in the plan. As the agent completes each action, it re-evaluates its state and the remaining actions in the plan to ensure that it is still on track towards its goal. If the agent encounters an obstacle or a change in the game environment, it can dynamically adjust its plan to find a new sequence of actions that will still lead to the desired goal.

GOAP is particularly useful in games with complex environments and multiple goals, as it allows NPCs to adapt to changing situations and make decisions based on their current state and the desired outcome. It can also be used to create NPCs with different personalities or behavior patterns by adjusting the weighting of different actions or goals in their decision-making process.

Overall, GOAP is a powerful technique for creating intelligent and adaptive agents in games that can perform complex tasks and achieve specific goals within the game world.


# Tutorial


# 1. Getting Started

## Tutorials

* [**YouTube tutorials**](https://www.youtube.com/playlist?list=PLZWmMt_TbeYeatHa9hntDPu4zGEBAFffn) on how to use the library.
* [**YouTube references**](https://www.youtube.com/playlist?list=PLZWmMt_TbeYdBZKvlsRuuOubPTTfPuZot) discussing GOAP in general.

## Installation

Add the package to your project using the package manager. Add the following URL to the package manager:

```
https://github.com/crashkonijn/GOAP.git?path=/Package#3.1.2
```

Alternatively install through [OpenUPM](https://openupm.com/packages/com.crashkonijn.goap/) or the [Unity Asset Store](https://assetstore.unity.com/packages/slug/252687).

{% hint style="info" %}
**Version** This package was build using unity 2022.2. Any newer version should work!
{% endhint %}

## What is included in this library

This library provides the following:

* Everything you need to create, manage, run and debug your own GOAP setup.
* It can resolve the best action to perform based on the current state of the world, for a given (set of) goal(s).
* It provides an agent that can actually run the actions.

{% hint style="warning" %}
Deciding what the best goal is to perform is very game specific and as such this library doesn't provide any tools to help you with that. Any algorithm that fits your game best could be used to determine the best goal to perform. The examples use a simple FSM to determine the best goal, but you could also use a utility system, behavior trees, etc.
{% endhint %}

## How does GOAP work

The GOAP algorithm is a way to determine the best action to perform based on the current state of the world and a set of goals. The algorithm works by creating a tree of possible actions and then selecting the best path through that tree to reach the goal. The algorithm is based on the A\* algorithm, but with some modifications to make it work better for GOAP.

GOAP uses two algorithms to work:

1. The first algorithm is the `GraphBuilder`. It uses your configuration of goals, actions, conditions and effects to build a graph of possible actions their connections. This is only done once whenever a new `AgentType` is created.
2. The second algorithm is the `Resolver`. It uses the graph created by the `GraphBuilder` to determine the best path through the graph to reach the goal based on the current game state. The algorithm does this in reverse, starting from the goal and working its way back until it finds an action that can be performed.

## Graph Builder

The graph builder requires the following information to build the graph:

* **Goals**: The goals that the agent can try to achieve.
  * Each goal has a list of conditions that need to be met to achieve the goal.
* **Actions**: The actions that the agent can perform.
  * Each action has a list of conditions that need to be met to perform the action.
  * Each action has a list of effects that the action has on the world.
* **Conditions**: The conditions that are required to perform an action (or complete a goal)
  * Each condition references a `WorldKey`, comparison and a value.
  * For example `AppleCount` `GreaterThanOrEqual` `5`.
* **Effects**: The effects that a action has on the world.
  * Each effect references a `WorldKey`, an `Effect Direction`.
  * For example `AppleCount` `Increase`.
  * Important: The system doesn't apply any effects to the world, it's up to you to do this. The system only uses the effects direction to determine its connection to conditions.
* **WorldKeys**: The keys that are used in the conditions and effects. Each `WorldKey` belongs to a value in the world.
  * For example `AppleCount`.

Based on their conditions and effects the GraphBuilder can connect them to each other. For example a condition of `AppleCount >= 5` can be connected to an action that `increases` the `AppleCount`.

![A connected graph](/files/6rOYwGuE8yfbOyJOWp3R)

## Resolver

The resolver uses the current `WorldState` and the `Graph` to determine the action with the lowest `Cost` that can be performed to reach a goal.

In order to prevent you from having to create a `MoveToXAction` before every action, you can assign a `TargetKey` to an `Action`. This `TargetKey` represents a position in the world where an action can take place, the `Agent` will move there before performing the action and the resolver will also take this into account when determining the best action to perform.

## WorldState

The resolver uses the graph created by the `GraphBuilder` to determine the best action to perform based on the current `WorldState` and the currently requested `Action(s)`.

To let the resolver know what the current state of the world is, you need to provide this information using a `Sensor`. A sensor can read a value from you own `MonoBehaviours` and provide this information to the resolver when it's needed.

There are two types of keys that can be used in the `WorldState`:

* **WorldKey**: A WorldKey references a value in the world. For example `AppleCount`. All values must be represented by `ints`.
* **TargetKey**: A TargetKey references a position in the world. For example `AppleTree`. All positions must be represented by `Vector3`.

## Sensors

A `Sensor` is a class that reads the current state of the world and provides this information to the `WorldState` when it's needed. The `Resolver` uses this information to determine the best action to perform based on the current state of the world.

Sensors can provide the values for two types of data/keys:

* **WorldKey**: A WorldKey references a value in the world. For example `AppleCount`. All values must be represented by `ints`.
* **TargetKey**: A TargetKey references a position in the world. For example `AppleTree`. All positions must be represented by `Vector3`.

Sensors can work in two scopes: `Global` or `Local`.

* **Global**: These sensors give information for all agents of an `AgentType`. For instance, `IsDaytimeSensor` checks if it's day or night for everyone.
* **Local**: They give information for just one agent. For example, `ClosestAppleSensor` finds the nearest apple for a specific agent.

![Sensor data flow](/files/dgwWM589V1H0Pt6cw6iT)

## Action Provider

An `ActionProvider` (in this case always the `GoapActionProvider`) is a class that uses the `Resolver` to determine the best action to perform based on the current `WorldState` and the currently requested `Action(s)`. The `ActionProvider` then sets the `Action` that the `Agent` should perform.

The GOAP system itself doesn't know anything about how to run actions.

## Agent

An `Agent` is any GameObject that holds the `AgentBehaviour` script. The `AgentBehaviour` is responsible for running the actions that are set by the `ActionProvider`. The `AgentBehaviour` will run any action given to it until the action is completed or stopped. If an action requires to be performed at a specific position, the agent will move to that position before performing the action.

## Overview

Below is a quick overview of the different components of classes and how they are connected to an Action.

![Class overview](/files/ZKM3qJ89n3NN6cfUWd2Z)


# 2. Idle

## Goal

In this tutorial we will create a simple GOAP system that will make an agent wander around when idle. The agent can also pick up apples and eat them. The agent will only eat apples when it's hungry.

## Setup in Unity

1. The package comes with a `Generator Scriptable` that can help you quickly boilerplate all the classes that are used by the GOAP system. Let's get started by creating a new location for our scripts to go. Create a new folder called `Getting Started` in your `Assets` folder.
2. Right-click the `Getting Started` folder and select `Create > GOAP > Generator`. Call the scriptable `GettingStartedGenerator`.
3. When you select the `GettingStartedGenerator` you can see all it's properties in the inspector. The generator requires you to set a base namespace in the inspector. To make following the getting started easier, please set the namespace to `CrashKonijn.Docs.GettingStarted`.

   ![Getting Started Generator](/files/F38JEhRyXOYfkDU2DPp1)
4. If you like using assembly definitions you can add it to the `Getting Started` folder. Please make sure to also set the `Root Namespace` to `CrashKonijn.Docs.GettingStarted`. Also make sure to include the `com.crashkonijn.goap.core`, `com.crashkonijn.goap.runtime`, `com.crashkonijn.agent.core` and `com.crashkonijn.agent.runtime` assemblies.

   ![Assembly Definition](https://github.com/crashkonijn/GOAP/blob/master/Package/Documentation/images/getting_started/assembly_definition.png)

{% hint style="info" %}
**Generator** For setup through scriptable objects the generator is required!

The generator is a scoped entrypoint (when using ScriptableObjects) that will keep track of all available GOAP classes within it's scope. All classes (`goals`, `actions`, `sensors` and `keys`) and SO Configs (`Capabilities` and `Agent Types`) must be in subfolders of a generator.
{% endhint %}

## Generating classes

{% hint style="info" %}
**Namespace** Don't forget to set the namespace you want to use. All classes must be in this namespace in order for the generator/system to find them. The tutorial uses `CrashKonijn.Docs.GettingStarted`.
{% endhint %}

1. Let's generate the required `Goals`, `Actions`, `WorldKeys` and `TargetKeys` using the generator. In the inspector of the `GettingStartedGenerator` please fill in the following classes in their respective fields:

   * Goals: `IdleGoal`
   * Actions: `IdleAction`
   * WorldKeys: `IsIdle`
   * TargetKeys: `IdleTarget`

   ![Generator classes](/files/xBAmPmV1ElalZTMgbhVu)
2. Hit the `Generate` button! The generator will now create all the classes for you. Unity doesn't always register the new files, you can fix this by going to another program and then going back to Unity. All the classes should now be visible in the `Getting Started` folder, in their respective subfolders.
3. Later on we also need sensor classes, but these can't be generated by the generator.

## Sensors

Each `WorldKey` or `TargetKey` that is used in general also needs a value assigned to it. To get this value we use `Sensors`. Sensors are classes that can read the current state of the world and provide this information to the `WorldState` when it's needed.

In this part of the demo we use two keys, the `IsIdle (WorldKey)` and the `IdleTarget (TargetKey)`. The `IsIdle` key in this example is mostly used to match the `IdleGoal` and `IdleAction` together, it doesn't actually require to actually update the value. 'Manually' coupling a goal and action together is generally bad practice, but for this demo it's fine.

The `IdleTarget` key does need a value, so we need to create a sensor for it. To create a sensor we need to use the correct base class. The correct base class is determined by the `Type` of key (Eg `WorldKey` or `TargetKey`) and the `Scope` of the sensor (Eg `Global` or `Local`). Global sensors are used to provide information for all agents (eg `PlayerPosition`), while local sensors are used to provide information for a single agent (eg `ClosestTree`).

|           | Local                 | Global                 |
| --------- | --------------------- | ---------------------- |
| WorldKey  | LocalWorldSensorBase  | GlobalWorldSensorBase  |
| TargetKey | LocalTargetSensorBase | GlobalTargetSensorBase |

In this case the `IdleTarget` is a `TargetKey` and it is for a single `Agent`, so we require the `LocalTargetSensorBase`.

1. Let's create a new folder in the `Getting Started` folder called `Sensors`.
2. In the `Sensors` folder create a new script called `IdleTargetSensor` that extends `LocalTargetSensorBase`.

{% code title="IdleTargetSensor.cs" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Goap.Runtime;
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Sensors
{
    // Defining a GoapId is only necessary when using the ScriptableObject configuration method.
    [GoapId("IdleTargetSensor-c34e9575-d171-4044-9b83-a91a1c32e214")]
    public class IdleTargetSensor : LocalTargetSensorBase
    {
        private static readonly Bounds Bounds = new(Vector3.zero, new Vector3(15, 0, 8));

        // Is called when this script is initialzed
        public override void Created() { }

        // Is called every frame that an agent of an `AgentType` that uses this sensor needs it.
        // This can be used to 'cache' data that is used in the `Sense` method.
        // Eg look up all the trees in the scene, and then find the closest one in the Sense method.
        public override void Update() { }

        public override ITarget Sense(IActionReceiver agent, IComponentReference references, ITarget existingTarget)
        {
            var random = this.GetRandomPosition(agent);

            // If the existing target is a `PositionTarget`, we can reuse it and just update the position.
            if (existingTarget is PositionTarget positionTarget)
            {
                return positionTarget.SetPosition(random);
            }

            return new PositionTarget(random);
        }

        private Vector3 GetRandomPosition(IActionReceiver agent)
        {
            var random = Random.insideUnitCircle * 3f;
            var position = agent.Transform.position + new Vector3(random.x, 0f, random.y);

            // Check if the position is within the bounds of the world.
            if (Bounds.Contains(position))
                return position;

            return Bounds.ClosestPoint(position);
        }
    }
}
```

{% endcode %}

## ScriptableObjects or Code

The GOAP system can be setup in two ways. You can either use `Code` or `ScriptableObjects`. The `Code` way is more flexible and allows you to create your own setup systems and use generics. The `ScriptableObjects` way is more visual and allows you to set up the system in the Unity Editor. Please pick the one that fits your project best.

## Creating the scene

1. In the `Getting Started` folder create a new scene called `GettingStarted`. Open this scene.

## Adding the GOAP system

1. Create a new GameObject and name it `GOAP`.
2. Add the `GoapBehaviour` to the `GOAP` GameObject.
3. Each `GoapBehaviour` needs a `Controller`. The controllers determine when and how the resolver is run. For the demo we will use the `ReactiveController`. Add the `ReactiveControllerBehaviour` to the `GOAP` GameObject.

## Capabilities

The GOAP system is build around the concept of `Capabilities`. These capabilities are used to determine what an `AgentType` can do. Each `AgentType` can have multiple capabilities. Capabilities are re-usable subset of `Goals`, `Actions` and `Sensors` that are merged together into an `AgentType`.\
For this demo we will start with a single capability called `IdleCapability`.

1. Let's create a new folder in the `Getting Started` folder called `Capabilities`.

{% tabs %}
{% tab title="Code" %}

1. In our newly created folder lets create a script called `IdleCapabilityFactory`. This script will include a `CapabilityBuilder` that will help us create our `Capability`.

{% code title="IdleCapabilityFactory.cs" %}

```csharp
using CrashKonijn.Docs.GettingStarted.Sensors;
using CrashKonijn.Goap.Core;
using CrashKonijn.Goap.Runtime;

namespace CrashKonijn.Docs.GettingStarted.Capabilities
{
    public class IdleCapabilityFactory : CapabilityFactoryBase
    {
        public override ICapabilityConfig Create()
        {
            var builder = new CapabilityBuilder("IdleCapability");

            builder.AddGoal<IdleGoal>()
                .AddCondition<IsIdle>(Comparison.GreaterThanOrEqual, 1)
                .SetBaseCost(2);

            builder.AddAction<IdleAction>()
                .AddEffect<IsIdle>(EffectType.Increase)
                .SetTarget<IdleTarget>();

            builder.AddTargetSensor<IdleTargetSensor>()
                .SetTarget<IdleTarget>();
            
            return builder.Build();
        }
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Scriptables" %}

1. In our newly created folder lets create a scriptable object called `IdleCapabilityConfig`. Right-click on the folder and go to `Create > GOAP > Capability Config`. Call the scriptable object `IdleCapabilityConfig`.
2. In the inspector of the `IdleCapabilityConfig`, add a new `Goal` to the `Goals` list. Set the `Goal` to `IdleGoal` using the button next to the `Goal` field.
3. Add a condition to the goal and set the `Key` to `IsIdle`, the `Comparison` to `GreaterThanOrEqual` and the `Value` to `1`.

   ![Idle Goal](/files/Puczg5RGjG0WqdqOD2ua)
4. Add a new action. Select the `IdleAction` and the `IdleTarget`. Add an effect to the action and set the `Key` to `IsIdle` and the `Effect` to `Increase`.
5. Add a new target sensor. Select the `IdleTargetSensor` and the `IdleTarget`.
6. Click the `Check Issues` button to see if your config has any issues.

![Idle Capability Config](/files/PnxEf8Qrhmj40IQDad4D)
{% endtab %}
{% endtabs %}

## Agent Type

Each agent belongs to an `AgentType`. The `AgentType` holds all available goals, actions and sensors for the agent to use and are shared between all agent of that same `AgentType`.

1. Let's create a new folder in the `Getting Started` folder called `AgentTypes`.

{% hint style="warning" %}
Because **ALL** goals, actions and sensors are shared between all agents of the same `AgentType` it is important to make sure that all these classes are **Stateless**. This means that you can not store any information in these classes that is specific to a single agent. The system provides various ways to store or access agent specific information.
{% endhint %}

{% tabs %}
{% tab title="Code" %}

1. In our newly created folder lets create a script called `DemoAgentTypeFactory`. This script will include an `AgentTypeBuilder` that will help us create our `AgentType`.

{% code title="DemoAgentTypeFactory.cs" %}

```csharp
using CrashKonijn.Goap.Core;
using CrashKonijn.Goap.Runtime;

namespace CrashKonijn.Docs.GettingStarted.AgentTypes
{
    public class DemoAgentTypeFactory : AgentTypeFactoryBase
    {
        public override IAgentTypeConfig Create()
        {
            var factory = new AgentTypeBuilder("ScriptDemoAgent");
            
            factory.AddCapability<IdleCapabilityFactory>();

            return factory.Build();
        }
    }
}
```

{% endcode %}

2. In the open scene, add a child GameObject to the GOAP called `ScriptDemoAgent`
3. Add the newly created `DemoAgentTypeFactory` script to the `ScriptDemoAgent` GameObject.
4. On the `GOAP` GameObject, add the `ScriptDemoAgent` GameObject to the `Agent Type Config Factories` list.

   ![GOAP Behaviour](/files/6y3wo25PInHh2V2rRTcn)
5. With the `ScriptDemoAgent` GameObject selected, you can now open up the `Graph Viewer` to view the generated graph for this `AgentType`. You can open the `Graph Viewer` by going to `Tools > GOAP > Graph Viewer`, or by pressing the shortcut `Ctrl + G` or `Cmd + G` (on Mac)
   {% endtab %}

{% tab title="Scriptables" %}

1. In our newly create folder lets create a scriptable object called `DemoAgentTypeConfig`. Right-click on the folder and go to `Create > GOAP > Agent Type Config`. Call the scriptable object `DemoAgentTypeConfig`.
2. Select the newly created `DemoAgentTypeConfig` and add a new `Capability` to the `Capabilities` list. Set the `Capability` to `IdleCapabilityConfig`.![Agent Type config](/files/YbQrxGZuTB7XS80fRSY2)
3. In the open scene, add a child GameObject to the GOAP called `DemoAgentConfig`. Add the `AgentTypeBehaviour` to the `DemoAgentConfig` GameObject.
4. In the `AgentTypeBehaviour` set the `AgentTypeConfig` to the `DemoAgentTypeConfig`.
5. As the Runner, select the `GOAP` GameObject.
6. With the `DemoAgentTypeConfig` GameObject still selected, you can now open up the `Graph Viewer` to view the generated graph for this `AgentType`. You can open the `Graph Viewer` by going to `Tools > GOAP > Graph Viewer`, or by pressing the shortcut `Ctrl + G` or `Cmd + G` (on Mac)
   {% endtab %}
   {% endtabs %}

![Graph Viewer](/files/sOxQ7fe4afERKvfLcCwH)

## Creating the agent

1. Let's create a sphere in the scene and call it `Agent`. (GameObject > 3D Object > Sphere) This will be our agent that will wander around.
2. Make sure the `Agent` is at the position `(0, 0, 0)`, or at least withing the bounds defined in the `IdleTargetSensor`.
3. For this demo we won't use any physics. You can remove the `Sphere Collider` from the `Agent`.
4. Each agent always needs an `AgentBehaviour` component. Add the `AgentBehaviour` component to the `Agent`.
5. Each agent also needs an `ActionProvider`, let's add the `GoapActionProvider` to the `Agent`.
6. On the `AgentBehaviour`, set the `Action Provider Base` value to that of the `GoapActionProvider` on the same GameObject.

{% tabs %}
{% tab title="Code" %}
No further steps required for code.
{% endtab %}

{% tab title="Scriptables" %}

1. On the `GoapActionProvider`, set the `AgentTypeBehaviour` to the `DemoAgentTypeConfig` GameObject.
   {% endtab %}
   {% endtabs %}

## Moving the agent

In order to move the agent you can use the `events` on the `AgentBehaviour`. These events are called when the agent is in range of a target, when the target changes and when the target is no in range. Based on these events you can determine when and where to move the agent.

1. Let's create a new folder in the `Getting Started` folder called `Behaviours`.
2. In the `Behaviours` folder create a new script called `AgentMoveBehaviour`.

{% code title="AgentMoveBehaviour.cs" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Agent.Runtime;
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Behaviours
{
    public class AgentMoveBehaviour : MonoBehaviour
    {
        private AgentBehaviour agent;
        private ITarget currentTarget;
        private bool shouldMove;

        private void Awake()
        {
            this.agent = this.GetComponent<AgentBehaviour>();
        }

        private void OnEnable()
        {
            this.agent.Events.OnTargetInRange += this.OnTargetInRange;
            this.agent.Events.OnTargetChanged += this.OnTargetChanged;
            this.agent.Events.OnTargetNotInRange += this.TargetNotInRange;
            this.agent.Events.OnTargetLost += this.TargetLost;
        }

        private void OnDisable()
        {
            this.agent.Events.OnTargetInRange -= this.OnTargetInRange;
            this.agent.Events.OnTargetChanged -= this.OnTargetChanged;
            this.agent.Events.OnTargetNotInRange -= this.TargetNotInRange;
            this.agent.Events.OnTargetLost -= this.TargetLost;
        }
        
        private void TargetLost()
        {
            this.currentTarget = null;
            this.shouldMove = false;
        }

        private void OnTargetInRange(ITarget target)
        {
            this.shouldMove = false;
        }

        private void OnTargetChanged(ITarget target, bool inRange)
        {
            this.currentTarget = target;
            this.shouldMove = !inRange;
        }

        private void TargetNotInRange(ITarget target)
        {
            this.shouldMove = true;
        }

        public void Update()
        {
          if (this.agent.IsPaused)
                return;

            if (!this.shouldMove)
                return;
            
            if (this.currentTarget == null)
                return;
            
            this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(this.currentTarget.Position.x, this.transform.position.y, this.currentTarget.Position.z), Time.deltaTime);
        }

        private void OnDrawGizmos()
        {
            if (this.currentTarget == null)
                return;
            
            Gizmos.DrawLine(this.transform.position, this.currentTarget.Position);
        }
    }
}
```

{% endcode %}

3. Add the `AgentMoveBehaviour` to the `Agent` GameObject.

## Deciding what goal to perform

Deciding what goal to perform is very game specific and can be done in many different ways. For this demo we will use a simple 'FSM' script that I like to call a `Brain`. The `Brain` will decide what goal to perform based on the current state of the agent.

1. Let's create a script called `AgentBrain` that extends `MonoBehaviour`.

{% code title="AgentBrain.cs" %}

```csharp
using CrashKonijn.Agent.Runtime;
using CrashKonijn.Goap.Runtime;
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Behaviours
{
    public class BrainBehaviour : MonoBehaviour
    {
        private AgentBehaviour agent;
        private GoapActionProvider provider;
        private GoapBehaviour goap;
        
        private void Awake()
        {
            this.goap = FindObjectOfType<GoapBehaviour>();
            this.agent = this.GetComponent<AgentBehaviour>();
            this.provider = this.GetComponent<GoapActionProvider>();
            
            // This only applies sto the code demo
            if (this.provider.AgentTypeBehaviour == null)
                this.provider.AgentType = this.goap.GetAgentType("ScriptDemoAgent");
        }

        private void Start()
        {
            this.provider.RequestGoal<IdleGoal>();
        }
    }
}
```

{% endcode %}

2. Add it to the `Agent` GameObject.

## Play the scene!

When you play the scene, your freshly created agent should start moving around!

You can open up the `Graph Viewer` and select the agent in the scene to see what it's doing!

![First idle run](/files/qgYPxCowbbWRZQJYisSo)

## Updating the IdleAction

Currently, our idle action works because it's target is a random position. The agent will move in range of that target, then start performing the action. By default, the action script immediately completes the action and the resolver will kick off again. This will result in the agent moving to a new random position.

Let's update the `IdleAction` to actually wait for a few seconds before completing the action.

1. The `Generator` created a boilerplate including all the possible method you can use. We only use the `Start` and `Perform` methods right now. The other ones can be removed.
2. Update the `Data` subclass to include a `public float Timer { get; set; }` property.
3. In the `Start` method, let's initialize the `Timer` to a random value between 0.5f and 1.5f.

```csharp
data.Timer = Random.Range(0.5f, 1.5f); 
```

4. In the `Perform` method, let's update the `Timer` and check if it's below 0. If it is, we can complete the action.

```csharp
if (data.Timer <= 0f)
    // Return completed to stop the action
    return ActionRunState.Completed;

// Lower the timer for the next frame
data.Timer -= context.DeltaTime;

// Return continue to keep the action running
return ActionRunState.Continue;
```

Your `IdleAction` should now look like this:

{% code title="IdleAction.cs" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Goap.Runtime;
using Random = UnityEngine.Random;

namespace CrashKonijn.Docs.GettingStarted.Actions
{
    // The GoapId attribute is used to identify the action, even when you change the name
    // This is used when using the Scriptable Object method of configuring actions
    [GoapId("Idle-ccc6f46c-1626-44aa-b90d-1b2741642166")]
    public class IdleAction : GoapActionBase<IdleAction.Data>
    {
        // This method is called when the action is started
        // This method is optional and can be removed
        public override void Start(IMonoAgent agent, Data data)
        {
            data.Timer = Random.Range(0.5f, 1.5f);
        }

        // This method is called every frame while the action is running
        // This method is required
        public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
        {
            if (data.Timer <= 0f)
                // Return completed to stop the action
                return ActionRunState.Completed;
            
            // Lower the timer for the next frame
            data.Timer -= context.DeltaTime;
            
            // Return continue to keep the action running
            return ActionRunState.Continue;
        }
        
        // The action class itself must be stateless!
        // All data should be stored in the data class
        public class Data : IActionData
        {
            public ITarget Target { get; set; }
            public float Timer { get; set; }
        }
    }
}
```

{% endcode %}

When playing the scene the agent will now wait for a while before moving to a new position!

![Second idle run](/files/NDx105S4bWMGPmmdXPWj)


# 3. Pears

## Pears

In this part of the tutorial we will add a `PickupPearGoal` and let the agent pickup pears if it comes close to them.

## Creating the classes

1. Let's start by boiler plating the files that we need. Use the generator to create the following files:
   * Goals: `PickupPearGoal`, `EatGoal`
   * Actions: `PickupPearAction`, `EatAction`
   * WorldKeys: `PearCount`, `Hunger`
   * TargetKeys: `ClosestPear`
2. We will implement the classes in a bit, first let's make sure that we know what pears are. Create a new class called `PearBehaviour` in the `Behaviours` folder and add the following code:

{% code title="PearBehaviour.cs" %}

```csharp
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Behaviours
{
    public class PearBehaviour : MonoBehaviour
    {
    }
}
```

{% endcode %}

3. In our scene, create a new GameObject using `GameObject > 3D Object > Sphere`. Rename the object to `Pear` and add the `PearBehaviour` component to it. Pears are generally smaller than agents, so let's adjust the scale to `0.5` on all axes. You can remove the collider as we won't need it.
4. Let's create a new material for the pear. Right-click in the `Assets` folder and select `Create > Material`. Rename the material to `PearMaterial` and change the color to a nice yellow/green. Drag the material onto the `Pear` object.
5. In the `GettingStarted` folder let's create a new folder called `Prefabs`. Drag the `Pear` object into this folder to create a prefab.
6. Let's duplicate the pear a couple of times in the scene and place them in different locations. Please make sure al your pears are on 0 on the y-axis of their positions.
7. For these actions we need data that represents the `PearCount` and `Hunger` values. The **source of truth** for these values must be our own `MonoBehaviours`. Let's create a script called `DataBehaviour` in the `Behaviours` folder and add the following code:

{% code title="DataBehaviour.cs" %}

```csharp
using System;
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Behaviours
{
    public class DataBehaviour : MonoBehaviour
    {
        public int pearCount = 0;
        public float hunger = 0f;
        
        private void Update()
        {
            // For simplicity, we will increase the hunger over time in this class.
            this.hunger += Time.deltaTime * 5f;
        }
    }
}
```

{% endcode %}

8. Add the new `DataBehaviour` to the `Agent` object in the scene.
9. Create the sensors required for the `PearCount` and `ClosestPear` keys. This time we'll use something called a `MultiSensor`. This sensor can provide multiple keys at once. Create a new class called `PearSensor` in the `Sensors` folder and inherit from `MultiSensorBase`.

{% code title="PearSensor.cs" %}

```csharp
using System.Collections.Generic;
using CrashKonijn.Docs.GettingStarted.Behaviours;
using CrashKonijn.Goap.Runtime;
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Sensors
{
    // Defining a GoapId is only necessary when using the ScriptableObject configuration method.
    [GoapId("PearSensor-d68c875d-29c0-43f3-9d79-054d4cc6505d")]
    public class PearSensor : MultiSensorBase
    {
        // A cache of all the pears in the world
        private PearBehaviour[] pears;

        // You must use the constructor to register all the sensors
        // This can also be called outside of the gameplay loop to validate the configuration
        public PearSensor()
        {
            this.AddLocalWorldSensor<PearCount>((agent, references) =>
            {
                // Get a cached reference to the DataBehaviour on the agent
                var data = references.GetCachedComponent<DataBehaviour>();

                return data.pearCount;
            });

            this.AddLocalWorldSensor<Hunger>((agent, references) =>
            {
                // Get a cached reference to the DataBehaviour on the agent
                var data = references.GetCachedComponent<DataBehaviour>();

                // We need to cast the float to an int, because the hunger is an int
                // We will lose the decimal values, but we don't need them for this example
                return (int) data.hunger;
            });

            this.AddLocalTargetSensor<ClosestPear>((agent, references, target) =>
            {
                // Use the cashed pears list to find the closest pear
                var closestPear = this.Closest(this.pears, agent.Transform.position);

                if (closestPear == null)
                    return null;

                // If the target is a transform target, set the target to the closest pear
                if (target is TransformTarget transformTarget)
                    return transformTarget.SetTransform(closestPear.transform);

                return new TransformTarget(closestPear.transform);
            });
        }

        // The Created method is called when the sensor is created
        // This can be used to gather references to objects in the scene
        public override void Created() { }

        // This method is equal to the Update method of a local sensor.
        // It can be used to cache data, like gathering a list of all pears in the scene.
        public override void Update()
        {
            this.pears = Object.FindObjectsOfType<PearBehaviour>();
        }

        // Returns the closest item in a list
        private T Closest<T>(IEnumerable<T> list, Vector3 position)
            where T : MonoBehaviour
        {
            T closest = null;
            var closestDistance = float.MaxValue; // Start with the largest possible distance

            foreach (var item in list)
            {
                var distance = Vector3.Distance(item.gameObject.transform.position, position);

                if (!(distance < closestDistance))
                    continue;

                closest = item;
                closestDistance = distance;
            }

            return closest;
        }
    }
}
```

{% endcode %}

### Editing the PickupPearAction

Let's implement the `PickupPearAction` so it actually performs the action of picking up a pear.

{% code title="PickupPearAction.cs" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Agent.Runtime;
using CrashKonijn.Docs.GettingStarted.Behaviours;
using CrashKonijn.Goap.Runtime;
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Actions
{
    [GoapId("PickupPear-06ef21a4-059b-4314-800a-e7c2622637fb")]
    public class PickupPearAction : GoapActionBase<PickupPearAction.Data>
    {
        // This method is called every frame while the action is running
        public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
        {
            // Instead of using a timer, we can use the Wait ActionRunState.
            // The system will wait for the specified time before completing the action
            // Whilst waiting, the Perform method won't be called again
            return ActionRunState.WaitThenComplete(0.5f);
        }

        // This method is called when the action is completed
        public override void Complete(IMonoAgent agent, Data data)
        {
            if (data.Target is not TransformTarget transformTarget)
                return;
            
            data.DataBehaviour.pearCount++;
            GameObject.Destroy(transformTarget.Transform.gameObject);
        }

        // The action class itself must be stateless!
        // All data should be stored in the data class
        public class Data : IActionData
        {
            public ITarget Target { get; set; }
            
            // When using the GetComponent attribute, the system will automatically inject the reference
            [GetComponent]
            public DataBehaviour DataBehaviour { get; set; }
        }
    }
}
```

{% endcode %}

### Configuring the PickupPearGoal

{% tabs %}
{% tab title="Code" %}

1. In the `Capabilities` folder let's create the `PearCapability` class and add the following code:

{% code title="PearCapability.cs" %}

```csharp
using CrashKonijn.Docs.GettingStarted.Actions;
using CrashKonijn.Goap.Core;
using CrashKonijn.Goap.Runtime;

namespace CrashKonijn.Docs.GettingStarted.Capabilities
{
    public class PearCapability : CapabilityFactoryBase
    {
        public override ICapabilityConfig Create()
        {
            var builder = new CapabilityBuilder("PearCapability");

            builder.AddGoal<PickupPearGoal>()
                .AddCondition<PearCount>(Comparison.GreaterThanOrEqual, 3);
            
            builder.AddAction<PickupPearAction>()
                .AddEffect<PearCount>(EffectType.Increase)
                .SetTarget<ClosestPear>();

            builder.AddMultiSensor<PearSensor>();

            return builder.Build();
        }
    }
}
```

{% endcode %}

2. Edit the `DemoAgentTypeFactory` and add the `PearCapability` to the list of capabilities.

{% code title="DemoAgentTypeFactory.cs" %}

```csharp
factory.AddCapability<PearCapability>();
```

{% endcode %}
{% endtab %}

{% tab title="Scriptables" %}

1. In the `Capabilities` folder create a new `CapabilityConfig` asset and name it `PearCapability`.
2. Add a new `Goal`, select the `PickupPearGoal` and add a condition of `PearCount` `GreaterThanOrEqual` `3`.
3. Add a new `Action`, select the `PickupPearAction` and add an effect of `PearCount` `Increase`. Set the target to `ClosestPear`.
4. Add a new MultiSensor and select the `PearSensor`.
5. Select the `DemoAgentTypeConfig` and add the `PearCapability` to the list of capabilities.
   {% endtab %}
   {% endtabs %}

### Adding the PickupPearGoal to the brain.

1. Adjust the `RequestGoal` call in our `BrainBehaviour` to include the `PickupPearGoal`.

{% code title="BrainBehaviour.cs" %}

```csharp
this.provider.RequestGoal<IdleGoal, PickupPearGoal>();
```

{% endcode %}

2. Start the scene and watch the agent pickup pears when it comes close enough!

![Pears](/files/vZsKIUOBQ15vTBJcGWqn)

You graph should now look like this:

![New Graph](/files/tpyiraAPnzGCmGJUzdlS)

## Adding the EatGoal and EatAction

### Adjusting the EatAction

1. Let's adjust the `EatAction` to consume the pears that the agent has picked up.

{% code title="EatAction.cs" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Agent.Runtime;
using CrashKonijn.Docs.GettingStarted.Behaviours;
using CrashKonijn.Goap.Runtime;

namespace CrashKonijn.Docs.GettingStarted.Actions
{
    [GoapId("Eat-b235695c-727b-41a5-aa66-4757ce65719d")]
    public class EatAction : GoapActionBase<EatAction.Data>
    {
        // This method is called every frame while the action is running
        public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
        {
            // Instead of using a timer, we can use the Wait ActionRunState.
            // The system will wait for the specified time before completing the action
            // Whilst waiting, the Perform method won't be called again
            return ActionRunState.WaitThenComplete(5f);
        }

        // This method is called when the action is completed
        public override void Complete(IMonoAgent agent, Data data)
        {
            data.DataBehaviour.pearCount--;
            data.DataBehaviour.hunger = 0f;
        }

        // The action class itself must be stateless!
        // All data should be stored in the data class
        public class Data : IActionData
        {
            public ITarget Target { get; set; }
            
            // When using the GetComponent attribute, the system will automatically inject the reference
            [GetComponent]
            public DataBehaviour DataBehaviour { get; set; }
        }
    }
}
```

{% endcode %}

### Creating the EatCapability

1. This is your time to shine, create a new capability called `EatCapability` that uses the `EatGoal` and `EatAction`.

```
EatGoal
   Conditions
      - Hunger <= 0
      
EatAction
   Effects
      - Hunger--
   Conditions
      - PearCount >= 1
   Target: none
   RequiresTarget: false
```

2. Add the capability to you agent type.

### Adjusting the brain

Let's adjust the `BrainBehaviour` to include the `EatGoal` when the hunger is higher than 50!

{% code title="BrainBehaviour.cs" %}

```csharp
using System;
using CrashKonijn.Agent.Core;
using CrashKonijn.Agent.Runtime;
using CrashKonijn.Goap.Runtime;
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Behaviours
{
    public class BrainBehaviour : MonoBehaviour
    {
        private AgentBehaviour agent;
        private GoapActionProvider provider;
        private GoapBehaviour goap;
        private DataBehaviour data;
        
        private void Awake()
        {
            this.goap = FindObjectOfType<GoapBehaviour>();
            this.agent = this.GetComponent<AgentBehaviour>();
            this.provider = this.GetComponent<GoapActionProvider>();
            this.data = this.GetComponent<DataBehaviour>();
            
            // This only applies sto the code demo
            if (this.provider.AgentTypeBehaviour == null)
                this.provider.AgentType = this.goap.GetAgentType("DemoAgent");
        }

        private void Start()
        {
            this.provider.RequestGoal<IdleGoal, PickupPearGoal>();
        }

        private void OnEnable()
        {
            this.agent.Events.OnActionEnd += this.OnActionEnd;
        }

        private void OnDisable()
        {
            this.agent.Events.OnActionEnd -= this.OnActionEnd;
        }

        private void OnActionEnd(IAction action)
        {
            if (this.data.hunger > 50)
            {
                this.provider.RequestGoal<EatGoal>();
                return;
            }
            
            this.provider.RequestGoal<IdleGoal, PickupPearGoal>();
        }
    }
}
```

{% endcode %}

### A mixed graph

Play the scene and watch the agent eat the pears when it's hungry!

Your graph should now look like this. As you can see the actions of the different capabilities are mixed into a single graph. The `PickupPearAction` can now also be performed when the `EatGoal` is active.

![Mixed Graph](/files/7jMAZaclLxruNYNNpqYS)


# FAQ

## How can I support this project?

The best way to support this project is to use it, and provide feedback. If you find a bug, or have a feature request, please create an issue on the [GitHub repository](https://github.com/crashkonijn/GOAP). Making your own contributions is also a great way to support the project. This can be done by creating a pull request on the [GitHub repository](https://github.com/crashkonijn/GOAP).

If you want to support the project financially, you can do so by donating to the [GitHub Sponsor](https://github.com/sponsors/crashkonijn) page or by buying the [Support Edition](https://assetstore.unity.com/packages/slug/298995) on the Unity Asset Store.

## Why does each action need a target?

Unless you're creating a 0 dimension game, there are actions that take place at a specific position. When there are actions that require positions there a 3 possible solutions for handling the movement.

### 1. There are move actions in the graph.

This approach is extremely inefficient. The graph would become much larger, which makes it much more expensive to calculate the best action. This also requires each specific action to have a specific move action (aka MoveToPlayerAction, MoveToAmmoAction), or you can create a generic action. The generic action however would need to receive data from other actions during the resolving of the graph (aka the previous action would determine the target of the move action).

### 2. Each action is handling movement.

This does make the graph much smaller. However each action would require logic for movement, making them much more complicated. (You'd probably end up with a small FSM in each action; MovingTo, Performing). This also makes it hard to calculate a cost value, including distance between actions. This would again require the previous action in the graph to be provided to each action.

### 3. Each action is performed at a position.

This is the option this project uses. This uses a smaller graph than option 1. This doesn't need to perform movement in an action, keeping them simpler. The graph calculates distance between two actions, adding that cost automatically. Actions don't need to be aware of each other, or their relative position in the graph, making them simpler.

![With move actions](/files/9mj0Jmk6YYVMjTG5kn56) ![Without move actions](/files/s9w7yrYqRlNgc5b9snvP)


# Upgrading


# V3.1 Upgrade guide

## Breaking changes

### AgentTypeBuilder

Instead of manually creating an `AgentTypeBuilder` instance, you should now use the `CreateBuilder` method on the `AgentTypeFactoryBase` class.

```csharp
// Old way
var builder = new AgentTypeBuilder(SetIds.Smith);

// New way
var builder = this.CreateBuilder(SetIds.Smith);
```

### IGoapInjector

The `IGoapInjector` interface has been expanded with two new methods:

```csharp
public interface IGoapInjector
{
    void Inject(IAction action);
    void Inject(IGoal goal);
    void Inject(ISensor sensor);
    // New methods
    void Inject(IAgentTypeFactory factory);
    void Inject(ICapabilityFactory factory);
}
```

## New Features

### You can now make dynamic conditions (code only)!

```csharp
builder.AddAction<EatAction>()
    .AddCondition<Hunger, LowHunger>(Comparison.GreaterThanOrEqual);
```

### AgenTypeFactory and CapabilityFactory can now be injected

You can now inject into `AgentTypeFactoryBase` and `CapabilityFactoryBase` classes, similar to other actions, goals and sensors.

### You can now manually call AgentBehaviour.Run() with custom deltaTimes

This allows you to determine the rate at which agents are updated, for example agents further away from the player.

Make sure to set `AgentBehaviour.RunInUnityUpdate` to false before calling `Run` yourself!

```csharp
agentBehaviour.RunInUnityUpdate = false;
agentBehaviour.Run(1f);

// In actions
public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
{
    // Make sure to use the deltaTime provided in the context!
    var deltaTime = context.DeltaTime;
}
```


# V3.0 Changes

{% hint style="info" %}
V3 has been tested with all major versions of Unity 2021.3 and newer!
{% endhint %}

## Goap Resolver

For v3 the GOAP resolver has been greatly improved, resulting in even smarter AI!

The following improvements have been made:

* The resolver has improved heuristics, making it easier to find the best action to perform.
* The resolver now also supports multiple goals at the same time!
* The resolver has improved handling of actions that require a target.
* The resolver now supports disabling actions. These actions (and their children) will not be considered by the resolver.
* The resolver now better calculates the distance cost between actions!

## Agents and Action Providers

In v3, we've introduced the concept of **Agents** and **Action Providers**. Agents are the entities that perform actions on your behalf, while Action Providers are the entities that provide the actions that Agents can perform. In v2, these concepts were combined in the **AgentBehaviour**.

In the future, we plan to introduce more types of providers.

![../images/v3\_agent\_and\_action\_provider.png](/files/pAcQgMxJL19kBTLYDwJ3)

### AgentBehaviour

The **AgentBehaviour** only knows how to perform actions. It doesn't know how to decide which actions to perform. All it does is take an action and perform it. All goap related methods (such as SetGoal) have been moved to the **GoapActionProvider** class.

The **AgentBehaviour** doesn't know about the **GoapActionProvider**, it only knows about a simple **IActionProvider**.

### GoapActionProvider

The **GoapActionProvider** is a new class that provides the actions that an Agent can perform. It is responsible for deciding which actions to perform and when to perform them. It also contains all the goap related methods that were previously in the **AgentBehaviour** class.

The **GoapActionProvider** doesn't know about the **AgentBehaviour**, it only knows about a simple **IActionReceiver**.

## AgentType and Capabilities

In v3, we've introduced the concept of **AgentType** (previously known as **GoapSet**) and **Capabilities**. An **AgentType** holds a list of **Capabilities**. A **Capability** is a collection of **Goals**, **Actions** and **Sensors** that an Agent can use.

This makes it easier to create different types of Agents that share some common goals, actions and sensors.

### Scriptable AgentTypes

Scriptable **AgentTypes** not only allow you to define scriptable object **Capabilities**, but you can also add a script that extends from **ScriptableCapabilityFactoryBase**. This allows you to create **Capabilities** in code and add them to the scriptable **AgentType** as well!

### Scriptable Capabilities

Scriptable Capabilities are a new feature in v3. They allow you to define **Capabilities** in a scriptable object. This config file can configure multiple **Goals**, **Actions** and **Sensors** at the same time. This makes it easier to create and manage **Capabilities**.

![../images/v3\_capability\_inspector.gif](/files/qYfQSmQgZqhu94x2mK7Q)

## Boiler plate code generation

In v3, we've introduced a new code generation system. This system can boilerplate code for all **Goals**, **Actions** and **Sensors** in your configuration. You can simply add a new **Goal**, **Action** or **Sensor** to your configuration and the code generation system will create the boilerplate code for you.

You also manually let it generate many classes for you easily by using the **GeneratorScriptable**.

![../images/v3\_generator.png](/files/5aXlQJa5RA57EqatHqSc)

### GoapId

In v3, we've introduced the concept of a **GoapId**. This is a unique identifier for each **Goal**, **Action** and **Sensor**. This makes it easier to reference these objects in the inspector. When a class has the `[GoapId]` attribute it will keep the reference to that object even if the class is moved to another namespace or renamed!

A class reference in the inspector is now done by using the classname and the GoapId. As long as one of these matches a script the system can restore these references to the correct object. You can fix most issues by using the **Check Issues** and **Fix Issues** buttons in the inspector!

```csharp
[GoapId("HasApple-60e317a0-75e4-419c-8439-45873af983a2")]
public class HasApple : WorldKeyBase {}
```

![../images/v3\_inspector\_class\_reference.png](/files/9rUptPEUStvsZ9Lrc6Ss)

## Namespaces

In v3, we've introduced simpler namespaces to better organize the code. All namespaces have been renamed to follow a consistent pattern.

```csharp
// All GOAP classes
using CrashKonijn.Goap.Runtime;
// All GOAP related interfaces
using CrashKonijn.Goap.Core;
// All agent classes
using CrashKonijn.Agent.Runtime;
// All agent related interfaces
using CrashKonijn.Agent.Core;
```

## Actions

In v3 we've spent a lot of time improving the **Actions**. We've added a lot of new features that make them more powerful and easier to use.

Main changes:

* Conditions for actions are now re-validated every frame before the action is performed! Only the required sensors are checked.
* In addition to **OnStop**, **OnCompleted** and **OnEnd** events/methods have been introduced!
* The **BeforePerform** method has been added. This is called the first time the action is performed.
* The **ActionContext** has been changed to **IActionContext**.
* The **InRange** config has been renamed to **StoppingDistance**.
* The **RequiresTarget** setting has been added. This setting determines if the action requires a target to be set before it can be performed.
* The **ValidateConditions** setting has been added. This setting determines if the conditions should be re-validated every frame before the action is performed.
* Actions can now be **Disabled**!

```csharp
public class ExampleAction : GoapActionBase<ExampleAction.Data>
{
    // This method is called when the action is created
    // This method is optional and can be removed
    public override void Created()
    {
    }

    // This method is called every frame before the action is performed
    // If this method returns false, the action will be stopped
    // This method is optional and can be removed
    public override bool IsValid(IActionReceiver agent, Data data)
    {
        return true;
    }

    // This method is called when the action is started
    // This method is optional and can be removed
    public override void Start(IMonoAgent agent, Data data)
    {
    }

    // This method is called once before the action is performed
    // This method is optional and can be removed
    public override void BeforePerform(IMonoAgent agent, Data data)
    {
    }

    // This method is called every frame while the action is running
    // This method is required
    public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
    {
        return ActionRunState.Completed;
    }

    // This method is called when the action is completed
    // This method is optional and can be removed
    public override void Complete(IMonoAgent agent, Data data)
    {
    }

    // This method is called when the action is stopped
    // This method is optional and can be removed
    public override void Stop(IMonoAgent agent, Data data)
    {
    }

    // This method is called when the action is completed or stopped
    // This method is optional and can be removed
    public override void End(IMonoAgent agent, Data data)
    {
    }

    // The action class itself must be stateless!
    // All data should be stored in the data class
    public class Data : IActionData
    {
        public ITarget Target { get; set; }
    }
}
```

* The concept of an **IActionProperties** class has been introduced. This class can be used to store properties that are shared between all instances of an action. These properties can be set in the inspector or in the builder!

![../images/v3\_action\_props.png](/files/f9bybxn6rFgFk3yW9ySN)

```csharp
// Set the second generic type for the properties
public class WanderAction : GoapActionBase<WanderAction.Data, WanderAction.Props>
{
    public override void Start(IMonoAgent agent, Data data)
    {
        // Read the properties that have been set in the inspector or builder
        var wait = Random.Range(this.Properties.minTimer, this.Properties.maxTimer);
        
        // Create a Wait run state. This will wait for the specified time before continueing to perform the action.
        data.Timer = ActionRunState.Wait(wait);
    }

    public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
    {
        // Check if the timer is still running
        if (data.Timer.IsRunning())
            // Return the timer run state
            return data.Timer;
        
        return ActionRunState.Completed;
    }

    public override void Stop(IMonoAgent agent, Data data)
    {
    }

    public override void Complete(IMonoAgent agent, Data data)
    {
    }

    [Serializable]
    public class Props : IActionProperties
    {
        public float minTimer;
        public float maxTimer;
    }

    public class Data : IActionData
    {
        public ITarget Target { get; set; }
        public IActionRunState Timer { get; set; }
    }
}
```

* **ActionRunState** has been changed to **IActionRunState**. This interface can be used to create custom run states for actions. These determine when an action should be stopped, completed or even be updated at all.

```csharp
public interface IActionRunState
{
    void Update(IAgent agent, IActionContext context);
    bool ShouldStop(IAgent agent);
    bool ShouldPerform(IAgent agent);
    bool IsCompleted(IAgent agent);
    bool MayResolve(IAgent agent);
    bool IsRunning();
}
```

A couple different action run states have been provided out of the box:

```csharp
public static class ActionRunState {
    public static readonly IActionRunState Continue = new ContinueActionRunState();
    public static readonly IActionRunState ContinueOrResolve = new ContinueOrResolveActionRunState();
    public static readonly IActionRunState Stop = new StopActionRunState();
    public static readonly IActionRunState Completed = new CompletedActionRunState();
    public static IActionRunState Wait(float time, bool mayResolve = false) => new WaitActionRunState(time, mayResolve);
    public static IActionRunState WaitThenComplete(float time, bool mayResolve = false) => new WaitThenCompleteActionRunState(time, mayResolve);
    public static IActionRunState WaitThenStop(float time, bool mayResolve = false) => new WaitThenStopActionRunState(time, mayResolve);
    public static IActionRunState StopAndLog(string message) => new StopAndLog(message);
}
```

## All new Graph Viewer!

In v3, we've introduced a new Graph Viewer. This viewer allows you to see the current state of the GOAP graph in real-time. You can see all the nodes and connections between them.

Unlike the previous version this viewer simply shows the graph of the selected object in the editor. This can be an **AgentTypes** and **Capabilities**, no matter if they are in the scene or not! During and outside of play mode!

![../images/v3\_graph\_viewer.gif](/files/lsSvbMmY6DL2ZfhYo3Xk)

## Goals

In v3 we've spent a lot of time improving the **Goals**. We've added a lot of new features that make them more powerful and easier to use.

Main changes:

* **Goals** are now **requested** instead of **set**. The currently running action will only be changed if an executable action is found.
* You can now request **multiple** goals at the same time. The resolver will pick the best action to perform for any of the requested goals.
* Goals now have a **BaseCost** setting.

```csharp
this.GetComponent<GoapActionProvider>().RequestGoal<CleanItemsGoal, FixHungerGoal, WanderGoal>(true);
```

## Sensor runner

The sensor runner has been upgraded, it now only runs the sensors that are required for the currently requested goals!

## Sensors

Sensor have been improved in v3, giving you more control over how they work!

### Sensor Timer

In v3 you can now set a timer for each sensor. This timer determines how often the sensor should be run. This makes it easier to create sensors that don't need to be run every frame.

By default three timers are available:

```csharp
public static class SensorTimer
{
    public static AlwaysSensorTimer Always { get; } = new(); // Runs every time it is called
    public static OnceSensorTimer Once { get; } = new(); // Runs only once
    public static IntervalSensorTimer Interval(float interval) => new(interval); // Runs every x seconds
}
```

```csharp
public class AgentSensor : LocalTargetSensorBase
{
    // You can override the timer for the sensor
    public override ISensorTimer Timer { get; } = SensorTimer.Once;

    public override void Created()
    {
    }

    public override void Update()
    {
    }

    public override ITarget Sense(IActionReceiver agent, IComponentReference references, ITarget target)
    {
        return new TransformTarget(agent.Transform);
    }
}
```

### Previous Target

In v3 you now get access to the previous `ITarget` instance that was returned in the target sense method, allowing you to re-use it in the next frame!

## Multi-Sensors

In v3 we've introduced the concept of **Multi-Sensors**. A **Multi-Sensor** is a sensor that can return multiple values at the same time. This makes it easier to create sensors that return multiple values.

```csharp
public class AppleSensor : MultiSensorBase
{
    private AppleCollection apples;
    private TreeBehaviour[] trees;

    public override void Created()
    {
        this.apples = Object.FindObjectOfType<AppleCollection>();
        this.trees = Object.FindObjectsOfType<TreeBehaviour>();
    }

    public override void Update()
    {
        
    }

    public AppleSensor()
    {
        this.AddLocalTargetSensor<ClosestApple>((agent, references) =>
        {
            var closestApple = this.apples.Get().Closest(agent.Transform.position);

            if (closestApple is null)
                return null;
        
            return new TransformTarget(closestApple.transform);
        });
        
        this.AddLocalTargetSensor<ClosestTree>((agent, references) =>
        {
            return new TransformTarget(this.trees.Closest(agent.Transform.position).transform);
        });
        
        this.AddLocalWorldSensor<HasApple>((agent, references) =>
        {
            var inventory = references.GetCachedComponent<InventoryBehaviour>();

            if (inventory == null)
                return false;
            
            return inventory.Apples.Count > 0;
        });
        
        this.AddGlobalWorldSensor<ThereAreApples>(() =>
        {
            return this.apples.Any();
        });
    }
}
```

## Goap Controllers

In v3 we've introduced the concept of **Goap Controllers**. A **Goap Controller** is a class that has controll over how the GOAP system is run. It handles when and how the sensors and resolver are run, enabling new kinds of behaviours!

Each **GoapBehaviour** requires a **Goap Controller** to be set. This controller will determine how the GOAP system is run.

We've introduced 3 different controllers:

* **ReactiveController** - This controller handles sensors and the resolver equal to how it was done in v2. Whenever an agent needs a new action the resolver is called.
* **ProactiveController** - This controller handles sensors and the resolver in a proactive way. It will run the sensors and resolver every x time, even if the agent doesn't need a new action. If another action is found, the agent will switch to that action.
* **ManualController** - This controller allows you to manually run the sensors and resolver. This will immediately run the sensors and resolver whenever a resolve is requested by an agent.

```csharp
public class ReactiveController : IGoapController
{
    private IGoap goap;
    private Dictionary<IAgentType, HashSet<IMonoGoapActionProvider>> agents = new();

    public void Initialize(IGoap goap)
    {
        this.goap = goap;
        this.goap.Events.OnAgentResolve += this.OnAgentResolve;
        this.goap.Events.OnNoActionFound += this.OnNoActionFound;
    }

    public void Disable()
    {
        this.goap.Events.OnAgentResolve -= this.OnAgentResolve;
        this.goap.Events.OnNoActionFound -= this.OnNoActionFound;
    }

    public void OnUpdate()
    {
        foreach (var (type, runner) in this.goap.AgentTypeRunners)
        {
            var queue = this.GetQueue(type);
            
            runner.Run(queue);
            
            queue.Clear();
        }
        
        foreach (var agent in this.goap.Agents)
        {
            if (agent.IsNull())
                continue;
            
            if (agent.Receiver == null)
                continue;
            
            // Update the action sensors for the agent
            agent.AgentType.SensorRunner.SenseLocal(agent, agent.Receiver.ActionState.Action as IGoapAction);
        }
    }

    public void OnLateUpdate()
    {
        foreach (var runner in this.goap.AgentTypeRunners.Values)
        {
            runner.Complete();
        }
    }

    private void OnNoActionFound(IMonoGoapActionProvider actionProvider, IGoalRequest request)
    {
        this.GetQueue(actionProvider.AgentType).Add(actionProvider);
    }

    private void OnAgentResolve(IMonoGoapActionProvider actionProvider)
    {
        this.GetQueue(actionProvider.AgentType).Add(actionProvider);
    }
    
    private HashSet<IMonoGoapActionProvider> GetQueue(IAgentType agentType)
    {
        if (!this.agents.ContainsKey(agentType))
            this.agents.Add(agentType, new HashSet<IMonoGoapActionProvider>());
        
        return this.agents[agentType];
    }
}
```


# V3.0 Upgrade guide

Before upgrading, please make sure to read the **v3 Core Concepts**!

{% hint style="info" %}
**Version** For v3 support for 2021.x is dropped. This package was build using unity 2022.2. Any newer version should work!
{% endhint %}

## 1. The package

* Remove the v2 package from your project!
* Add the v3 package to your project.

## Add the UpgradeExtensions.cs

* Add this file to your project. This will guide you through the upgrade process:

```csharp
using System;
using CrashKonijn.Agent.Core;
using CrashKonijn.Goap.Core;

namespace CrashKonijn.Goap.Core
{
    [Obsolete("Use IGoal instead")]
    public interface IGoalBase : IGoal {}
    
    [Obsolete("Use IAction instead")]
    public interface IActionBase : IAction {}

    [Obsolete("Use IGoap instead")]
    public interface IGoapRunner : IGoap {}
    
    [Obsolete("Use IAgentTypeConfig instead")]
    public interface IGoapSetConfig : IAgentTypeConfig {}
    
    [Obsolete("This doesn't exist anymore")]
    public interface IAgentDebugger {}

    public static class UpgradeExtensions
    {
        [Obsolete("Use GetAgentType instead")]
        public static object GetGoapSet(this IGoap goap, string id) => default;
    }
}

namespace CrashKonijn.Goap.Runtime
{
    [Obsolete("Use GoapBehaviour instead")]
    public class GoapRunnerBehaviour : GoapBehaviour, IGoapRunner {}
    
    [Obsolete("Use CapabilityFactoryBase instead")]
    public abstract class GoapSetFactoryBase : CapabilityFactoryBase {}
    
    [Obsolete("Use CapabilityBuilder instead")]
    public class GoapSetBuilder : CapabilityBuilder
    {
        public GoapSetBuilder(string name) : base(name)
        {
        }
    }
    
    public static class UpgradeExtensions
    {
        [Obsolete("This doesn't exist anymore")]
        public static void SetAgentDebugger<T>(this GoapSetBuilder builder) {}
        [Obsolete("This doesn't exist anymore")]
        public static void SetAgentDebugger<T>(this CapabilityBuilder builder) {}
    }
}

namespace CrashKonijn.Agent.Runtime
{
    public static class UpgradeExtensions
    {
        [Obsolete("Use GoapActionProvider.RequestGoal instead")]
        public static void SetGoal<T>(this IAgent agent, bool stopAction = true)
        {
        }
        [Obsolete("Use GoapActionProvider.RequestGoal instead")]
        public static void SetGoal(this IAgent agent, IGoal goal, bool stopAction = true)
        {
        }
    }
}
```

## 2. Namespaces

Remove all `CrashKonijn.Goap.X` namespaces. They have been simplified and all possible classes now live under these 4 namespaces. In every script that used the old namespaces, paste these 4 in. You can remove any that you don't use.

```csharp
using CrashKonijn.Goap.Runtime;
using CrashKonijn.Goap.Core;
using CrashKonijn.Agent.Runtime;
using CrashKonijn.Agent.Core;
```

## 3. AgentBehaviour and ActionProvider

In v3 the **AgentBehaviour** has been split into the **AgentBehaviour** and the **GoapActionProvider**. Any GOAP specific data, methods and events have been moved over to the **GoapActionProvider**.

* In any script where you're using GOAP related data, actions and events make sure to also get a reference to the **GoapActionProvider**. Change the GOAP reference to the new action provider.

```csharp
var agent = this.GetComponent<AgentBehaviour>();
var provider = this.GetComponent<GoapActionProvider>();

provider.RequestGoal<FixHungerGoal>();

Debug.Log(agent.ActionState.Action)
Debug.Log(provider.CurrentPlan.Goal)

agent.Events.OnTargetInRange += this.OnTargetInRange;
agent.Events.OnTargetChanged += this.OnTargetChanged;

provider.Events.OnNoActionFound += this.OnNoActionFound;
provider.Events.OnGoalCompleted += this.OnGoalCompleted;
```

## Actions

* Extend from `GoapActionBase` instead of `ActionBase`.
* Change the signature from the `Perform` method to the new signature.
  * `ActionRunState` is now `IActionRunState`
  * `ActionContext` is now `IActionContext`

```csharp
// Old
public override ActionRunState Perform(IMonoAgent agent, Data data, ActionContext context)

// New
public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
```

## Sensors

* In any sensor that extends **LocalTargetSensorBase** or **LocalWorldSensorBase**, change the `IMonoAgent` variable in the `Sense` method to `IActionReceiver`.
* If you use any references to `.transform` or `.gameObject`, please use `.Transform` or `.Transform.GameObject`

## GoapConfigInitializer

* The `GoapConfig` parameter has been replaced with `IGoapConfig`

## GoapInjector

* `IActionBase` has been replaced with `IAction`
* `IGoalBase` has been replaced with `IGoal`
* Both `IWorldSensor` and `ITargetSensor` methods have been replaced with the `ISensor` method.

## Factories

**GoapSets** have been split into **AgentTypes** and **Capabilities**. The easest way to upgrade is to convert **GoapSetFactoryBase** clases to **CapabilityFactoryBase** classes.

* Optional: Rename any reference to `GoapSet` in the name of the class to `Capability`
* Change `GoapSetFactoryBase` to `CapabilityFactoryBase`
* Change the `IGoapSetConfig` return type of the `Create` method to `ICapabilityConfig`
* Change the `GoapSetBuilder` to `CapabilityBuilder`
* The `AgentDebugger` has be removed

### Create the AgentTypeFactory

Create the AgentTypeFactory, and add the capability factory you've just upgraded.

Below is an example from the demo.

```csharp
public class CleanerAgentTypeFactory : AgentTypeFactoryBase
{
    public override IAgentTypeConfig Create()
    {
        var builder = new AgentTypeBuilder(SetIds.Cleaner);
        
        builder.AddCapability<BaseCapability>();
        builder.AddCapability<WanderCapability>();
        builder.AddCapability<HungerCapability>();

        builder.CreateCapability("CleanCapability", (capability) =>
        {
            capability.AddGoal<CleanItemsGoal>()
                .SetBaseCost(20)
                .AddCondition<ItemsOnFloor>(Comparison.SmallerThanOrEqual, 0);
            
            capability.AddAction<HaulItemAction>()
                .SetTarget<HaulTarget>()
                .AddEffect<ItemsOnFloor>(EffectType.Decrease)
                .AddCondition<ItemsOnFloor>(Comparison.GreaterThanOrEqual, 1)
                .SetMoveMode(ActionMoveMode.PerformWhileMoving);
            
            capability.AddWorldSensor<ItemOnFloorSensor>()
                .SetKey<ItemsOnFloor>();

            capability.AddTargetSensor<HaulTargetSensor>()
                .SetTarget<HaulTarget>();
        });

        return builder.Build();
    }
}
```

## Fixing all errors and obsolete issues

* Fix all **errors** in your code.
* After it compiles, make sure you fix all **obsolete** warnings.

## Updating prefabs

### GoapRunnerBehaviour

* The **GoapRunnerBehaviour** has been renamed to **GoapBehaviour**. Make sure to replace it.
* Each **GoapBehaviour** needs a **GoapController**. Add the **ReactiveController** or the **ProactiveController** to the same GameObject. The **ReactiveController** behaves the same as in v2.
* Remove your old **GoapSet** script from the GameObject.
* Add your new **AgentTypeFactories**. It's advised to use a single child GameObject per AgentType. This ensures you can preview them in the graph viewer.

### GoapSetBehaviours (for scriptable configs)

* Make sure you've added the **AgentTypeBehaviour** to any GameObject that has the **GoapSetBehaviour** component.
* Copy your settings to the new script and remove the **GoapSetBehaviour** scripts.
* For each **AgentType**, create a scriptable **AgentTypeConfig** using `create > Goap > AgentTypeConfig`. Give the file the name of your new agent type.
* Reference your new AgentType scriptable on the **AgentTypeBehaviour**

### Agent

* On your agent prefabs make sure to add the **GoapActionProvider** script.
* Reference your new **GoapActionProvider** script in the `ActionProviderBase` value on the **AgentBehaviour**
* When using scriptable configs, reference the correct **AgentTypeBehaviour** on the **GoapActionProvider**

## Remove the UpgradeExtensions file

At this point the UpgradeExtensions should not be needed anymore, please remove it.

## MoveBehaviour

In v2 the `OnTargetChanged` event would also be called with null, in v3 the `OnTargetLost` event gets called instead if the target is null. You should implement this event on your move script.

## Generator

The generator can help you quickly boilerplate your new classes. To use the generator please make sure to follow these steps:

* Add a generator to your project by going `right click in your project view > Create > GOAP > Generator`
* In the inspector of the generator set namespace as your root namespace.
  * For example if the namespace for your actions is `CrashKonijn.Example.Actions` than the root namespace is `CrashKonijn.Example`.
* Make sure the folder structure for `goals`, `actions`, `world keys` and `target keys` match this screenshot. The folders for your `sensors` should also be here, but they don't require a specific name.
* You can press the **Check** button on the generator the view all classes that it can find. Make sure it finds all your classes!

![../images/v3\_folder\_structure.png](/files/2zBgN1TTdjlhh0eecYuo)

## Scriptable configs

### GoapId's

If you're using scriptable objects as your configuration method you should add `[GoapId]` attributes to your `goal`, `action`, `key` and `sensor` classes. These will help the system keep track of your classes, even when you change their name or namespaces!

```csharp
// This can be any name, as long is is unique
// This is an example of what the generator will create for you when using the geneartor.
[GoapId("WanderTarget-ae7344be-5223-4260-acac-f33c9eb260f5")]
public class WanderTarget : TargetKeyBase {}
```

### Scriptable GoapSet's

There's an automatic upgrader for your scriptable **GoapSets**! For each set do the following:

* Create a new scriptable **CapabilityConfig** using `Create > Goap > CapabilityConfig`. Make sure to match the name of the file to the goap set that you're upgrading. The new **CapabilityConfig** MUST be in a subfolder of a GoapGenerator!
* Select the **GoapSet** and in the inspector assign the new **CapabilityConfig** in the `CapabilityConfig` field above the **Upgrade** button.
* Press the **Upgrade** button!
* Your **CapabilityConfig** should now contain all `goals`, `actions` and `sensors` of your **GoapSet**!
* You can use the **Check Issues** and then **Fix Issues** buttons to see and fix most reference issues.
* Add your **CapabilityConfig** to the correct **AgentType** config.


# V2.1 Upgrade guide

## Upgrading from 2.0 to 2.1

### IAgentMover is removed

`IAgentMover` is removed in favor of having movement based events on the agent.

{% code title="AgentMoveBehaviour.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;

public class AgentMoveBehaviour : MonoBehaviour
{
    private AgentBehaviour agent;
    private ITarget currentTarget;
    private bool shouldMove;

    private void Awake()
    {
        this.agent = this.GetComponent<AgentBehaviour>();
    }

    private void OnEnable()
    {
        this.agent.Events.OnTargetInRange += this.OnTargetInRange;
        this.agent.Events.OnTargetChanged += this.OnTargetChanged;
        this.agent.Events.OnTargetOutOfRange += this.OnTargetOutOfRange;
    }

    private void OnDisable()
    {
        this.agent.Events.OnTargetInRange -= this.OnTargetInRange;
        this.agent.Events.OnTargetChanged -= this.OnTargetChanged;
        this.agent.Events.OnTargetOutOfRange -= this.OnTargetOutOfRange;
    }

    private void OnTargetInRange(ITarget target)
    {
        this.shouldMove = false;
    }

    private void OnTargetChanged(ITarget target, bool inRange)
    {
        this.currentTarget = target;
        this.shouldMove = !inRange;
    }

    private void OnTargetOutOfRange(ITarget target)
    {
        this.shouldMove = true;
    }

    public void Update()
    {
        if (!this.shouldMove)
            return;
        
        if (this.currentTarget == null)
            return;
        
        this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(this.currentTarget.Position.x, this.transform.position.y, this.currentTarget.Position.z), Time.deltaTime);
    }
}
```

{% endcode %}

### Setup through code now requires actual classes as the WorldKey and TargetKey.

{% code lineNumbers="true" %}

```csharp
public class WanderTarget : TargetKeyBase
{
}

public class IsWandering : WorldKeyBase
{
}

public class GoapSetConfigFactory : GoapSetFactoryBase
{
    public override IGoapSetConfig Create()
    {
        var builder = new GoapSetBuilder("GettingStartedSet");
        
        // Goals
        builder.AddGoal<WanderGoal>()
            .AddCondition<IsWandering>(Comparison.GreaterThanOrEqual, 1);

        // Actions
        builder.AddAction<WanderAction>()
            .SetTarget<WanderTarget>()
            .AddEffect<IsWandering>(true)
            .SetBaseCost(1)
            .SetInRange(0.3f);

        // Target Sensors
        builder.AddTargetSensor<WanderTargetSensor>()
            .SetTarget<WanderTarget>();

        // World Sensors
        // This example doesn't have any world sensors. Look in the examples for more information on how to use them.

        return builder.Build();
    }
}
```

{% endcode %}


# Config


# Through ScriptableObjects

The ScriptableObjects are the main way to configure the GOAP system. They are used to define the goals, actions, sensors, world keys and target keys. This method of configuration is the most simple way to configure the GOAP system and is done by creating scriptable objects through the Unity Editor.

{% hint style="warning" %}
**Warning** Please keep in mind that this method prevents you from using generic classes. If you need to use generic classes, you should use the code configuration method.
{% endhint %}

{% hint style="info" %}
**Example** The simple demo uses the ScriptableObjects configuration method.
{% endhint %}

## AgentType

To create an agent type, you must create a new `AgentTypeScriptable` asset in the Unity Editor. This asset contains the configuration for the agent type, including the capabilities it has.

To create a new `AgentTypeScriptable`, right-click in the Project window and select `Create > GOAP > Agent Type`. This will create a new asset that you can customize in the Inspector.

## Capability

To create a capability, you must create a new `CapabilityScriptable` asset in the Unity Editor. This asset contains the configuration for the capability, including the actions, sensors, world keys and target keys it has.

To create a new `CapabilityScriptable`, right-click in the Project window and select `Create > GOAP > Capability`. This will create a new asset that you can customize in the Inspector.

![scriptable\_configs.png](/files/PLFISQ8Uf2Dxg0UUttSa)


# Through Code

Setting up your GOAP system using code is the most flexible way to configure your GOAP system. This method is more difficult to use than the `ScriptableObjects` method, but allows for a much more dynamic setup.

{% hint style="info" %}
**Info** By using code to setup your GOAP system, you can use generic classes. This can make the setup of your GOAP system more flexible.
{% endhint %}

{% hint style="info" %}
**Example** The complex demo uses code as the configuration method.
{% endhint %}

## AgentType

To create an agent type, you must create a class that inherits from `AgentTypeFactoryBase`. This class must implement the `Create` method which returns a `IAgentTypeConfig`. To make building the set easier, you can use the `AgentTypeBuilder` class.

{% code title="GoapSetConfigFactory.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Docs.GettingStarted.Capabilities;
using CrashKonijn.Goap.Core;
using CrashKonijn.Goap.Runtime;

namespace CrashKonijn.Docs.GettingStarted.AgentTypes
{
    public class DemoAgentTypeFactory : AgentTypeFactoryBase
    {
        public override IAgentTypeConfig Create()
        {
            var factory = new AgentTypeBuilder("DemoAgent");
            
            factory.AddCapability<IdleCapabilityFactory>();
            factory.AddCapability<PearCapability>();

            return factory.Build();
        }
    }
}

```

{% endcode %}

## Capabilities

To create a capability, you must create a class that inherits from `CapabilityFactoryBase`. This class must implement the `Create` method which returns a `ICapabilityConfig`. To make building the set easier, you can use the `CapabilityBuilder` class.

{% code title="IdleCapabilityFactory.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Docs.GettingStarted.Actions;
using CrashKonijn.Docs.GettingStarted.Sensors;
using CrashKonijn.Goap.Core;
using CrashKonijn.Goap.Runtime;

namespace CrashKonijn.Docs.GettingStarted.Capabilities
{
    public class IdleCapabilityFactory : CapabilityFactoryBase
    {
        public override ICapabilityConfig Create()
        {
            var builder = new CapabilityBuilder("IdleCapability");

            builder.AddGoal<IdleGoal>()
                .AddCondition<IsIdle>(Comparison.GreaterThanOrEqual, 1)
                .SetBaseCost(2);

            builder.AddAction<IdleAction>()
                .AddEffect<IsIdle>(EffectType.Increase)
                .SetTarget<IdleTarget>();

            builder.AddTargetSensor<IdleTargetSensor>()
                .SetTarget<IdleTarget>();
            
            return builder.Build();
        }
    }
}
```

{% endcode %}

### Dynamic Conditions

Since v3.1 you can now add dynamic conditions!

{% code lineNumbers="true" %}

```csharp
builder.AddAction<EatAction>()
    .AddCondition<Hunger, LowHunger>(Comparison.GreaterThanOrEqual);
```

{% endcode %}

### Callbacks

In v3 you can add a callback to your builder methods, giving you access to the instance of each class. This allows you to set extra data.

{% code lineNumbers="true" %}

```csharp
capability.AddAction<HaulItemAction>()
    .SetCallback((action) =>
    {
        action.CustomData = "Example";
    });
```

{% endcode %}

### Adding the set to GOAP

Add the created class to a GameObject in the scene. Add it to the list on the `GoapBehaviour` component. This will initialize the set.

![Goap Behaviour component](/files/gHfFlcSbos8dXf23T1Qm)

### Adding the set to the agent.

Using a script, set the `AgentType` property on an agent.

{% code lineNumbers="true" %}

```csharp
var goap = FindObjectOfType<GoapBehaviour>();
var type = goap.GetAgentType("DemoAgent");

agent.GetComponent<GoapActionProvider>.AgentType = type;
```

{% endcode %}


# Classes


# Goals

In the GOAP system, `Goals` represent the desired outcomes or objectives that an agent aims to achieve. They serve as the starting points for the `Planner`, guiding it in determining the most suitable `Action` to take in order to fulfill a particular `Goal`.

## Goal Config

The `GoalConfig` provides the necessary settings to define and shape a `Goal`. It encompasses several properties:

### 1. Class Type

**Description**: This property specifies the exact type or category of the `Goal`. It helps in identifying and categorizing different goals within the system.

### 2. Conditions

**Description**: Conditions are a set of criteria based on `WorldKeys` that must be met for the `Goal` to be considered achieved. These conditions guide the `Planner` in its decision-making process, helping it select the best `Action` that aligns with the desired outcome.

For instance, if a `Goal` is to "Stay Safe", conditions might include `WorldKeys` like "IsHealthHigh" or "IsInSafeZone".

## Goal Class

The `Goal` class serves as the blueprint for creating specific goals. Key points about the `Goal` class:

* **Inheritance**: Every `Goal` class is derived from the foundational `GoalBase` class. This ensures that all goals share some basic properties and behaviors.
* **Statelessness**: A `Goal` class doesn't maintain any internal state. Its primary role is to provide criteria to the `Planner`, which then uses this information to decide on the most appropriate `Action` to execute.

By understanding and configuring `Goals` appropriately, game developers can guide agents towards desired behaviors, ensuring they act in ways that enhance the gameplay experience.

## Example

{% code title="FixHungerGoal.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;

namespace Demos.Goals
{
    public class FixHungerGoal : GoalBase
    {
    }
}
```

{% endcode %}


# Actions

In the GOAP system, an action represents a discrete step an agent can undertake to achieve a specific goal. Actions are defined by their requirements and effects, which guide the chaining of actions to form a plan.

## Components of an Action

Actions are composed of four primary parts:

1. **Config**: Configuration settings for the action.
2. **Action Class**: The logic and behavior of the action.
3. **Action Data**: Temporary data storage for the action's state.
4. **Action Props**: Additional properties for the action.

## Action Config

The configuration provides essential settings for the action, enabling its integration into the GOAP graph.

### Conditions

Conditions are a set of world states that must be met for the action to be executable. Each condition references a `WorldKey` and specifies whether its value should be true or false.

### Effects

Effects describe the changes in world states that result from performing the action. Each effect references a `WorldKey` and indicates the expected outcome (true or false).

### BaseCost

This represents the inherent cost of executing the action, excluding any additional costs (like distance) that the planner might add.

### Target

Every action has an associated target position. Before executing the action, the agent will move towards this target, depending on the `MoveMode`. Targets are identified using `TargetKey`, such as `ClosestApple` or `ClosestEnemy`.

### StopppingDistance

This value specifies the proximity required between the agent and the target position before the action can commence.

### RequiresTarget

This value determines if a valid Target is required for the action to be executable.

### ValidateTarget

This value determines if the target is validated whilst running.

### ValidateConditions

This determines if the conditions of this action are validated whilst running.

## MoveMode

`MoveMode` determines how the action and movement are coordinated:

* **MoveBeforePerforming**: The agent moves to the target position before initiating the action.
* **PerformWhileMoving**: The agent concurrently moves to the target and executes the action.

## Action Data

Action data provides temporary storage for the action's state for an individual agent. This data is not shared across agents or across multiple invocations of the same action.

## Action Props

Action props are additional properties that can be used to customize the action's behavior. They are defined as fields in the action class and can be set as configuration values on ScriptableObjects or through code.

{% code lineNumbers="true" %}

```csharp
[Serializable]
public class Props : IActionProperties
{
    public float minTimer;
    public float maxTimer;
}
```

{% endcode %}

### Action Data Injection

To reference other classes on the agent, use the `GetComponent` attribute. This provides a cached component instance, optimizing performance by avoiding frequent `GetComponent` calls.

{% code lineNumbers="true" %}

```csharp
public class Data : IActionData
{
    public ITarget Target { get; set; }
    
    [GetComponent]
    public ComplexInventoryBehaviour Inventory { get; set; }
}
```

{% endcode %}

## Action Class

The action class defines the behavior of the action. It should be stateless since a single instance might be used to execute the same action on different agents. The class inherits from `ActionBase<TData>`, where `TData` is the action data class.

### IActionRunState Interface

The `IActionRunState` interface is a crucial component in the GOAP system. It defines the contract for action run states, which are responsible for determining the behavior of actions during their execution. These states decide when an action should be updated, stopped, performed, completed, or even resolved. They can also be used to 'pause' running an action, and come back later to continue it.

### Enabling/Disabling Actions

Each action can be enabled or disabled using the `action.Enable()` or `action.Disable(IActionDisabler)` methods. By default the following disablers are available:

{% code lineNumbers="true" %}

```csharp
public static class ActionDisabler
{
    public static IActionDisabler Forever => new ForeverActionDisabler();
    public static IActionDisabler ForTime(float time) => new ForTimeActionDisabler(time);
}
```

{% endcode %}

#### Examples

{% code lineNumbers="true" %}

```csharp
foreach (var pickupAppleAction in this.actionProvider.GetActions<PickupAppleAction>())
{
    this.actionProvider.Disable(pickupAppleAction, ActionDisabler.Forever);
    this.actionProvider.Enable(pickupAppleAction);
}
```

{% endcode %}

{% code lineNumbers="true" %}

```csharp
this.actionProvider.Disable<PickupAppleAction>();
this.actionProvider.Enable<PickupAppleAction>();
```

{% endcode %}

{% code lineNumbers="true" %}

```csharp
public class EatAction : GoapActionBase<EatAction.Data>
{
    // Other methods omitted for brevity
    public override void End(IMonoAgent agent, Data data)
    {
        // This will disable the action for 5 seconds
        this.Disable(agent, ActionDisabler.ForTime(5f));
    }
}
```

{% endcode %}

#### Methods

* `void Update(IAgent agent, IActionContext context)`: Updates the state of the action based on the current context and agent state. This method is called every frame during the action's execution.
* `bool ShouldStop(IAgent agent)`: Determines whether the action should be stopped. If this method returns `true`, the action will be stopped.
* `bool ShouldPerform(IAgent agent)`: Determines whether the action should continue performing. If this method returns `true`, the action will continue its execution.
* `bool IsCompleted(IAgent agent)`: Checks if the action has been completed. If this method returns `true`, the action is considered completed.
* `bool MayResolve(IAgent agent)`: Determines whether the action may resolve based on the current state of the agent. This is used for actions that have conditional completion criteria.
* `bool IsRunning()`: Indicates whether the action is currently running. This can be used to check the state of the action outside of the usual update cycle.

#### Usage

`IActionRunState` allows for the creation of custom run states for actions, providing flexibility in how actions are executed within the GOAP system. By implementing this interface, developers can define custom logic for when actions should start, stop, or update, allowing for complex behavior patterns.

Several predefined action run states are provided out of the box, such as `Continue`, `Stop`, `Completed`, and various `Wait` states, to cover common use cases.

#### Example

Here's a simple example of a custom action run state that stops the action after a certain time has elapsed:

```csharp
public class TimedStopActionRunState : IActionRunState
{
    private float startTime;
    private float duration;

    public TimedStopActionRunState(float duration)
    {
        this.duration = duration;
    }

    public void Update(IAgent agent, IActionContext context)
    {
        if (startTime == 0)
            startTime = Time.time;
    }

    public bool ShouldStop(IAgent agent)
    {
        return Time.time - startTime >= duration;
    }

    public bool ShouldPerform(IAgent agent) => true;
    public bool IsCompleted(IAgent agent) => false;
    public bool MayResolve(IAgent agent) => true;
    public bool IsRunning() => true;
}
```

### Examples

The provided examples illustrate how to implement specific functionalities within the action class and action data. They've been retained in their original form for clarity.

### Examples

{% code title="ExampleAction.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Goap.Runtime;
using UnityEngine;

namespace CrashKonijn.Goap.Demos.Complex
{
    [GoapId("Example-93edf472-9fb5-4c55-84fa-5f6671992a6a")]
    public class ExampleAction : GoapActionBase<ExampleAction.Data>
    {
        // This method is called when the action is created
        // This method is optional and can be removed
        public override void Created()
        {
        }

        // This method is called every frame before the action is performed
        // If this method returns false, the action will be stopped
        // This method is optional and can be removed
        public override bool IsValid(IActionReceiver agent, Data data)
        {
            return true;
        }

        // This method is called when the action is started
        // This method is optional and can be removed
        public override void Start(IMonoAgent agent, Data data)
        {
        }

        // This method is called once before the action is performed
        // This method is optional and can be removed
        public override void BeforePerform(IMonoAgent agent, Data data)
        {
        }

        // This method is called every frame while the action is running
        // This method is required
        public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
        {
            return ActionRunState.Completed;
        }

        // This method is called when the action is completed
        // This method is optional and can be removed
        public override void Complete(IMonoAgent agent, Data data)
        {
        }

        // This method is called when the action is stopped
        // This method is optional and can be removed
        public override void Stop(IMonoAgent agent, Data data)
        {
        }

        // This method is called when the action is completed or stopped
        // This method is optional and can be removed
        public override void End(IMonoAgent agent, Data data)
        {
        }

        // The action class itself must be stateless!
        // All data should be stored in the data class
        public class Data : IActionData
        {
            public ITarget Target { get; set; }
        }
    }
}
```

{% endcode %}

{% code title="WanderAction.cs" lineNumbers="true" %}

```csharp
using System;
using CrashKonijn.Agent.Core;
using CrashKonijn.Goap.Runtime;
using Random = UnityEngine.Random;

namespace CrashKonijn.Goap.Demos.Complex.Actions
{
    public class WanderAction : GoapActionBase<WanderAction.Data, WanderAction.Props>
    {
        public override void Created()
        {
        }

        public override void Start(IMonoAgent agent, Data data)
        {
            var wait = Random.Range(this.Properties.minTimer, this.Properties.maxTimer);
            
            data.Timer = ActionRunState.Wait(wait);
        }

        public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
        {
            if (data.Timer.IsRunning())
                return data.Timer;
            
            return ActionRunState.Completed;
        }

        public override void Stop(IMonoAgent agent, Data data)
        {
        }

        public override void Complete(IMonoAgent agent, Data data)
        {
        }

        [Serializable]
        public class Props : IActionProperties
        {
            public float minTimer;
            public float maxTimer;
        }

        public class Data : IActionData
        {
            public ITarget Target { get; set; }
            public IActionRunState Timer { get; set; }
        }
    }
}
```

{% endcode %}


# AgentBehaviour and ActionProvider

## Overview

In version 3 (v3) of the GOAP framework, significant architectural changes have been introduced to enhance the flexibility and functionality of agents and their actions. One of the key changes is the separation of concerns between the AgentBehaviour and the GoapActionProvider. This document aims to explain the functionalities of both components and their relationship.

## AgentBehaviour

The AgentBehaviour component is responsible for the execution of actions. It acts as the executor that takes an action provided by the GoapActionProvider and performs it. The AgentBehaviour is designed to be agnostic of the decision-making process, focusing solely on action execution.

### Key Responsibilities

* **Action Execution**: Takes an action from the GoapActionProvider and executes it.
* **Event Handling**: Can subscribe to and trigger events related to action execution, such as OnActionStart, OnActionEnd, and OnActionComplete.

### Relationship with GoapActionProvider

The AgentBehaviour does not directly interact with the GoapActionProvider for decision-making. It only knows about a simple IActionProvider interface, which abstracts the source of actions.

## GoapActionProvider

The GoapActionProvider is a new addition in v3, designed to handle the decision-making process for the agent. It decides which actions to perform and when to perform them, based on the goals set and the current state of the world.

### Key Responsibilities

* **Action Decision**: Decides which actions are suitable for execution based on the current goals and state.
* **Goal Management**: Manages goals for the agent, including setting new goals and prioritizing between multiple goals.
* **GOAP Methods**: Contains all GOAP-related methods that were previously part of the AgentBehaviour, such as goal setting and action planning.

### Relationship with AgentBehaviour

The GoapActionProvider does not know about the AgentBehaviour. It interacts with the agent through a simple IActionReceiver interface, focusing on the decision-making process without concerning itself with how actions are executed.

## Interaction Example

Here is a simplified example of how AgentBehaviour and GoapActionProvider interact within the system:

{% code lineNumbers="true" %}

```csharp
// Getting references to both components
var agent = this.GetComponent<AgentBehaviour>();
var provider = this.GetComponent<GoapActionProvider>();

// Connecting the AgentBehaviour to the GoapActionProvider
agent.ActionProvider = provider;

// Setting a goal through the GoapActionProvider
provider.RequestGoal<FixHungerGoal>();

// Accessing the current action and goal for debugging
Debug.Log(agent.ActionState.Action);
Debug.Log(provider.CurrentPlan.Goal);

// Subscribing to events
agent.Events.OnTargetInRange += this.OnTargetInRange;
agent.Events.OnTargetChanged += this.OnTargetChanged;
provider.Events.OnGoalStart += this.OnGoalStart;
```

{% endcode %}

## Movement

Actions often have associated targets, indicating a position the agent should reach before executing the action. Since movement mechanics can vary based on the game's design, this package doesn't prescribe a specific movement implementation. However, it provides events to help developers determine when an agent should move.

### MoveMode

Some actions might need the agent to perform tasks while moving. The `MoveMode` in the `ActionConfig` allows for such configurations.

### Run In Unity Update

When set to true will call `Run` from the `Update` method. When set to false you must call `Run()` or `Run(float deltaTime)` yourself.

Calling the `Run` method manually gives you full control over the agent's update cycle.

```csharp
agentBehaviour.RunInUnityUpdate = false;
agentBehaviour.Run(1f);

// In actions
public override IActionRunState Perform(IMonoAgent agent, Data data, IActionContext context)
{
    // Make sure to use the deltaTime provided in the context!
    var deltaTime = context.DeltaTime;
}
```

### Distance Multiplier

The primary objective of actions is to achieve goals swiftly. If the action's cost equates to its completion time, then the heuristic's distance value should be divided by the agent's movement speed. Using `SetDistanceMultiplierSpeed(float speed)` sets the agent's (max/average) speed, enabling the planner to more precisely ascertain the optimal action.

### Custom Distance Calculation

By default, the agent calculates distance using `Vector3.Distance`. However, for more complex scenarios, like using a nav mesh, you can override this by assigning your custom `IAgentDistanceObserver` to the `agent.DistanceObserver`.

### Example

{% code title="NavMeshDistanceObserver.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;
using UnityEngine.AI;

public class NavMeshDistanceObserver : MonoBehaviour, IAgentDistanceObserver
{
    private NavMeshAgent navMeshAgent;
    
    private void Awake()
    {
        this.navMeshAgent = this.GetComponent<NavMeshAgent>();
        this.GetComponent<AgentBehaviour>().DistanceObserver = this;
    }
    
    public float GetDistance(IMonoAgent agent, ITarget target, IComponentReference reference)
    {
        var distance = this.navMeshAgent.remainingDistance;
        
        // No path
        if (float.IsInfinity(distance))
            return 0f;
        
        return distance;
    }
}
```

{% endcode %}


# Sensors

A `Sensor` is a class that reads the current state of the world and provides this information to the `WorldState` when it's needed. The `Resolver` uses this information to determine the best action to perform based on the current state of the world.

Sensors can provide the values for two types of data/keys:

* **WorldKey**: A WorldKey references a value in the world. For example `AppleCount`. All values must be represented by `ints`.
* **TargetKey**: A TargetKey references a position in the world. For example `AppleTree`. All positions must be represented by `Vector3`.

Sensors can work in two scopes: `Global` or `Local`.

* **Global**: These sensors give information for all agents of an `AgentType`. For instance, `IsDaytimeSensor` checks if it's day or night for everyone.
* **Local**: They give information for just one agent. For example, `ClosestAppleSensor` finds the nearest apple for a specific agent.

|           | Local                 | Global                 |
| --------- | --------------------- | ---------------------- |
| WorldKey  | LocalWorldSensorBase  | GlobalWorldSensorBase  |
| TargetKey | LocalTargetSensorBase | GlobalTargetSensorBase |

![Sensor data flow](/files/dgwWM589V1H0Pt6cw6iT)

## WorldSensor

`WorldSensor` checks the game's situation for an agent. It uses `WorldKey` to show each situation. The `Planner` uses this to pick the best action.

Examples:

* `IsHungrySensor` checks if the agent is hungry.
* `HasAppleSensor` checks if the agent has an apple.

### Example

To create a new `WorldSensor`, create a new class that inherits from `LocalWorldSensorBase` or `GlobalWorldSensorBase` and implement its `Sense` method.

{% code title="IsHungrySensor.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Goap.Core;
using CrashKonijn.Goap.Demos.Simple.Behaviours;
using CrashKonijn.Goap.Runtime;

namespace CrashKonijn.Goap.Demos.Simple.Goap.Sensors.World
{
    [GoapId("Simple-IsHungrySensor")]
    public class IsHungrySensor : LocalWorldSensorBase
    {
        public override void Created()
        {
        }

        public override void Update()
        {
        }

        public override SenseValue Sense(IActionReceiver agent, IComponentReference references)
        {
            var hungerBehaviour = references.GetCachedComponent<SimpleHungerBehaviour>();

            if (hungerBehaviour == null)
                return false;

            return hungerBehaviour.hunger > 20;
        }
    }
}
```

{% endcode %}

## TargetSensor

`TargetSensor` finds a position for a `TargetKey`. The `Planner` uses this to know how far actions are.

There are two kinds of `Target`: `TransformTarget` and `PositionTarget`.

* **TransformTarget**: Use this when the target can move. For example, `ClosestEnemySensor` finds a moving enemy.
* **PositionTarget**: Use this for a fixed spot. Like, `WanderTargetSensor` finds a random spot that doesn't move.

### Example

To create a new `TargetSensor`, create a new class that inherits from `LocalTargetSensorBase` or `GlobalTargetSensorBase` and implement its `Sense` method.

{% code title="ClosestTreeSensor.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Goap.Demos.Simple.Behaviours;
using CrashKonijn.Goap.Runtime;
using Demos;

namespace CrashKonijn.Goap.Demos.Simple.Goap.Sensors.Target
{
    [GoapId("Simple-ClosestTreeSensor")]
    public class ClosestTreeSensor : LocalTargetSensorBase
    {
        private TreeBehaviour[] trees;

        public override void Created()
        {            
            this.trees = Compatibility.FindObjectsOfType<TreeBehaviour>();
        }

        public override void Update()
        {
        }

        public override ITarget Sense(IActionReceiver agent, IComponentReference references, ITarget target)
        {
            return new TransformTarget(this.trees.Closest(agent.Transform.position).transform);
        }
    }
}
```

{% endcode %}

{% code title="WanderTargetSensor.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Agent.Core;
using CrashKonijn.Goap.Runtime;
using UnityEngine;

namespace CrashKonijn.Goap.Demos.Simple.Goap.Sensors.Target
{
    [GoapId("Simple-WanderTargetSensor")]
    public class WanderTargetSensor : LocalTargetSensorBase
    {
        private static readonly Vector2 Bounds = new Vector2(15, 8);

        public override void Created()
        {
        }

        public override void Update()
        {
        }

        public override ITarget Sense(IActionReceiver agent, IComponentReference references, ITarget target)
        {
            var random = this.GetRandomPosition(agent);
            
            return new PositionTarget(random);
        }

        private Vector3 GetRandomPosition(IActionReceiver agent)
        {
            var random =  Random.insideUnitCircle * 5f;
            var position = agent.Transform.position + new Vector3(random.x, 0f, random.y);
            
            if (position.x > -Bounds.x && position.x < Bounds.x && position.z > -Bounds.y && position.z < Bounds.y)
                return position;

            return this.GetRandomPosition(agent);
        }
    }
}
```

{% endcode %}

## MultiSensor

`MultiSensor` is a sensor that combines multiple sensors. It can be used to combine multiple sensors into one sensor class. This can make it easier to manage multiple values that come from the same source.

### Example

{% code title="MultiSensor.cs" %}

```csharp
using System;
using System.Collections.Generic;
using CrashKonijn.Docs.GettingStarted.Behaviours;
using CrashKonijn.Goap.Runtime;
using UnityEngine;

namespace CrashKonijn.Docs.GettingStarted.Sensors
{
    public class PearSensor : MultiSensorBase
    {
        // A cache of all the pears in the world
        private PearBehaviour[] pears;

        // You must use the constructor to register all the sensors
        // This can also be called outside of the gameplay loop to validate the configuration
        public PearSensor()
        {
            this.AddLocalWorldSensor<PearCount>((agent, references) =>
            {
                // Get a cached reference to the DataBehaviour on the agent
                var data = references.GetCachedComponent<DataBehaviour>();

                return data.pearCount;
            });
            
            this.AddLocalWorldSensor<Hunger>((agent, references) =>
            {
                // Get a cached reference to the DataBehaviour on the agent
                var data = references.GetCachedComponent<DataBehaviour>();

                // We need to cast the float to an int, because the hunger is an int
                // We will lose the decimal values, but we don't need them for this example
                return (int) data.hunger;
            });
            
            this.AddLocalTargetSensor<ClosestPear>((agent, references, target) =>
            {
                // Use the cashed pears list to find the closest pear
                var closestPear = this.Closest(this.pears, agent.Transform.position);
                
                if (closestPear == null)
                    return null;
                
                // If the target is a transform target, set the target to the closest pear
                if (target is TransformTarget transformTarget)
                    return transformTarget.SetTransform(closestPear.transform);
                
                return new TransformTarget(closestPear.transform);
            });
        }

        // The Created method is called when the sensor is created
        // This can be used to gather references to objects in the scene
        public override void Created()
        {
        }
        
        // This method is equal to the Update method of a local sensor.
        // It can be used to cache data, like gathering a list of all pears in the scene.
        public override void Update()
        {
            this.pears = GameObject.FindObjectsOfType<PearBehaviour>();
        }

        // Returns the closest item in a list
        private T Closest<T>(IEnumerable<T> list, Vector3 position)
            where T : MonoBehaviour
        {
            T closest = null;
            var closestDistance = float.MaxValue; // Start with the largest possible distance

            foreach (var item in list)
            {
                var distance = Vector3.Distance(item.gameObject.transform.position, position);
                
                if (!(distance < closestDistance))
                    continue;
                
                closest = item;
                closestDistance = distance;
            }

            return closest;
        }
    }
}
```

{% endcode %}

## Sensor Timer

You can set a timer for a sensor to update at a specific interval. This can be useful when you want to update a sensor every few seconds instead of every frame, or when you want to update a sensor just a single time.

By default the following timers are provided, but custom implementations of `ISensorTimer` can be made.

{% code title="SensorTimer.cs" %}

```csharp
public static class SensorTimer
{
    public static AlwaysSensorTimer Always { get; } = new();
    public static OnceSensorTimer Once { get; } = new();
    public static IntervalSensorTimer Interval(float interval) => new(interval);
}
```

{% endcode %}

### World and Target Sensors

{% code title="SensorTimer.cs" %}

```csharp
public class AgentSensor : LocalTargetSensorBase
{
    // Set the timer to update the sensor once
    public override ISensorTimer Timer { get; } = SensorTimer.Once;

    public override void Created()
    {
    }

    public override void Update()
    {
    }

    public override ITarget Sense(IActionReceiver agent, IComponentReference references, ITarget target)
    {
        return new TransformTarget(agent.Transform);
    }
}
```

{% endcode %}

### Multi Sensors

{% code title="SensorTimer.cs" %}

```csharp
public class PearSensor : MultiSensorBase
{
    public PearSensor()
    {
        // You can set the timer for each sensor individually in the second parameter
        this.AddLocalWorldSensor<PearCount>((agent, references) =>
        {
            return 0;
        }, SensorTimer.Once);
    }
}
```

{% endcode %}


# TargetKeys

`TargetKeys` play a pivotal role in the GOAP system by specifying positions or locations within the game environment. These keys help the `Planner` calculate the distance (and added cost) between `Actions` and the precise location an `Agent` needs to reach before executing a particular action.

Each `TargetKey` is associated with a `TargetSensor`. This sensor is responsible for determining and providing the exact position corresponding to the `TargetKey`. In essence, while the `TargetKey` acts as a label or identifier for a location, the `TargetSensor` ensures that this label is mapped to a valid and up-to-date position in the game world.

## Creating a TargetKey

### Using ScriptableObject:

1. In the Unity editor, right-click on a desired folder.
2. Navigate to `Create > Goap > TargetKey` to generate a new `TargetKey`.

### Using Code:

To programmatically create a new `TargetKey`, you'll need to define a new class that inherits from the `TargetKeyBase` class.

#### Example:

{% code title="WanderTarget.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;

public class WanderTarget : TargetKeyBase
{
}
```

{% endcode %}


# WorldKeys

`WorldKeys` are important in the GOAP system. They point to specific things or situations in the game. The `Planner` uses these keys to decide what `Action` an agent should do next.

Each `WorldKey` is connected to a `WorldSensor`. This sensor checks and gives the current value for its `WorldKey`. So, the `WorldKey` tells us what to look for, and the `WorldSensor` tells us the current value of that thing in the game.

## Creating a WorldKey

### Using ScriptableObject:

1. In the Unity editor, right-click on the folder you want.
2. Go to `Create > Goap > WorldKey` to make a new `WorldKey`.

### Using Code:

You can also make a new `WorldKey` by writing a class that uses the `WorldKeyBase` class.

#### Example:

{% code title="IsHungry.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;

public class IsHungry : WorldKeyBase
{
}
```

{% endcode %}


# General


# AgentType & Capabilities

In the GOAP system, the concepts of `AgentTypes` and `Capabilities` play a crucial role in defining the behavior and abilities of agents within the environment. These concepts allow for a modular and flexible approach to designing agent behaviors, making it easier to create, manage, and extend the functionality of agents.

## AgentTypes

An `AgentType` represents a classification or category of agents within the GOAP system. It acts as a container for a set of `Capabilities` that define what the agent can do. Each agent is associated with an `AgentType`, and all agents of the same type share the same set of capabilities. This means that any goals, actions, and sensors defined within the `AgentType` are available to all agents of that type.

### Key Features of AgentTypes:

* **Shared Behavior**: Since all agents of the same `AgentType` share the same capabilities, they inherently share similar behaviors and abilities. This makes it easier to manage and update the behavior of multiple agents at once.
* **Modularity**: `AgentTypes` allow for the modular design of agent behaviors. By defining different types of agents, developers can easily create diverse ecosystems with varied agent behaviors.
* **Flexibility**: New `AgentTypes` can be created to introduce new kinds of agents into the system, providing flexibility in expanding the behavior space of the application.

## Capabilities

A `Capability` is a collection of goals, actions, and sensors that define a specific set of behaviors an agent can perform. Capabilities are used to modularize and reuse behavior definitions across different `AgentTypes`. Each `Capability` focuses on a particular aspect of behavior, such as navigation, combat, or resource gathering, and can be combined with other capabilities to form complex agent behaviors.

### Key Features of Capabilities:

* **Reusability**: Capabilities can be reused across different `AgentTypes`, allowing for the efficient creation of complex behaviors by combining existing capabilities.
* **Modularity**: By breaking down behaviors into smaller, focused capabilities, the system promotes a modular approach to behavior design. This makes it easier to manage, update, and extend agent behaviors.
* **Flexibility**: Developers can create new capabilities to introduce new behaviors into the system, enhancing the flexibility and adaptability of agents.

### Implementing Capabilities:

Capabilities can be implemented in two ways:

1. **Code**: This approach offers flexibility and allows developers to create custom setup systems and use generics. It is suitable for projects that require a high degree of customization and programmability.
2. **ScriptableObjects**: This approach is more visual and allows developers to set up the system in the Unity Editor. It is ideal for projects that benefit from a more graphical configuration and setup process.


# Controllers

In the GOAP framework, controllers play a crucial role in managing the behavior of agents within the system. A GOAP Controller is responsible for orchestrating how the GOAP system operates, specifically controlling the execution of sensors and the action resolution process. This allows for the creation of diverse behaviors tailored to the needs of different agents.

A Controller **MUST** be present on the `GoapBehaviour` GameObject in order for the system to work.

## Overview

A GOAP Controller determines the operational flow of the GOAP system, including when and how sensors are run and how actions are resolved. This level of control enables the implementation of various strategies for action planning and execution, leading to more dynamic and adaptable agent behaviors.

## Types of Controllers

The framework introduces three distinct types of controllers, each designed to handle the GOAP system's operations in a unique manner:

### ReactiveController

* **Description**: The ReactiveController operates similarly to the system's behavior in previous version. It activates sensors and the action resolver only when an agent requires a new action. This approach is straightforward and effective for scenarios where agents react to changes in their environment.
* **Usage**: Ideal for agents that operate based on immediate needs or react to changes in the environment.

### ProactiveController

* **Description**: Unlike the ReactiveController, the ProactiveController takes a more forward-looking approach. It periodically runs sensors and the action resolver, even if the agent does not currently need a new action. This proactive behavior can lead to the discovery of more optimal actions or the anticipation of future needs.
* **Usage**: Best suited for agents that benefit from planning ahead or those operating in rapidly changing environments where early action can lead to better outcomes.

#### MayResolve

When using the ProactiveController, sometimes you don't want to re-resolve when certain actions are running. The `IActionRunState` interface implements the `MayResolve` method, which allows you to specify if the resolver may run during this run state.

```csharp
public static readonly ActionRunState Continue = new ContinueActionRunState();
public static readonly ActionRunState ContinueOrResolve = new ContinueOrResolveActionRunState();
public static readonly ActionRunState Stop = new StopActionRunState();
public static readonly ActionRunState Completed = new CompletedActionRunState();
public static ActionRunState Wait(float time, bool mayResolve = false) => new WaitActionRunState(time, mayResolve);
public static ActionRunState WaitThenComplete(float time, bool mayResolve = false) => new WaitThenCompleteActionRunState(time, mayResolve);
public static ActionRunState WaitThenStop(float time, bool mayResolve = false) => new WaitThenStopActionRunState(time, mayResolve);
public static ActionRunState StopAndLog(string message) => new StopAndLog(message);
```

### ManualController

* **Description**: The ManualController provides the highest level of control, allowing for the manual execution of sensors and the action resolver. This controller is triggered explicitly by the agent, offering precise control over when the GOAP system is engaged.
* **Usage**: Useful for agents that require direct control over their planning process, such as those in scenarios where timing and precision are critical.


# Generator

{% hint style="info" %}
**Generator** For setup through scriptable objects the generator is required!

The generator is a scoped entrypoint (when using ScriptableObjects) that will keep track of all available GOAP classes within it's scope. All classes (`goals`, `actions`, `sensors` and `keys`) and SO Configs (`Capabilities` and `Agent Types`) must be in subfolders of a generator.
{% endhint %}

The GOAP Generator is a core component of the GOAP framework, designed to facilitate the quick creation of goals, actions, and target keys within the system. It is implemented as a `ScriptableObject` in Unity, allowing developers to easily create and manage instances within the Unity Editor.

## Overview

The `GeneratorScriptable` class can be used to quickly boilerplate `Goals`, `Actions`, `WorldKeys` and `TargetKeys` for the GOAP system. This is particularly useful when setting up a new project or adding new elements to an existing one.

## Usage

To use the generator, add a new one to your project by right-clicking in the Project window and selecting `Create > GOAP > Generator`. This will create a new `GeneratorScriptable` asset that you can customize in the Inspector.

All scripts created by the generator will be placed in subfolders according to their types.

{% hint style="info" %}
**Namespace** Don't forget to set the namespace you want to use. All classes must be in this namespace in order for the generator/system to find them.
{% endhint %}

![generator\_folder.png](/files/wL063dbVutxBHiPHbc2a) ![generator\_scriptable.png](/files/xEhqjHSQTOniD8M41pFl)


# WorldState

{% hint style="warning" %}
**Don't use the GOAP WorldState as a source of truth!** In the GOAP system, sensors update the agent's WorldState only when deciding the next action. This means the WorldState can often be outdated. Additionally, using just integers for the WorldState can oversimplify complex situations. For better accuracy and real-time updates, agents should store their data in dedicated MonoBehaviours.
{% endhint %}

## Enhanced GOAP with Integer Values:

In traditional GOAP implementations, the world state is often represented using string keys paired with boolean values. This can lead to redundancy, as multiple keys might be needed to represent related states. By transitioning to integer values, the GOAP system becomes more compact, versatile, and expressive.

### Conditions with Integer Values:

Conditions, which are the prerequisites or requirements for an action to be executed, benefit immensely from this shift:

* **Granular Checks**: Instead of binary checks like "Is the health low?", conditions can now evaluate a spectrum of values, such as:
  * **Health**: `< 30` (Is the health below 30?)
  * **Health**: `>= 70` (Is the health 70 or above?)
* **Comparison Types**: Conditions utilize specific comparison types (like SmallerThan, GreaterThanOrEqual, etc.) to evaluate the integer values of the `WorldKeys`. This allows for diverse condition checks, enabling actions to be contingent on specific thresholds.
* **Absence of "Equals" Comparison**: Notably, there isn't an "Equals" comparison in this system. The primary reason is that "Equals" doesn't indicate direction. In the GOAP system, especially with integer values, understanding the direction of change is crucial. For instance, knowing whether a value needs to increase or decrease to satisfy a condition is essential for planning actions. An "Equals" comparison would be ambiguous in this context, as it wouldn't provide clear guidance on which actions are needed to achieve the desired state.

### Effects with Integer Values:

Effects, which describe the changes an action brings about in the game's state, also gain enhanced expressiveness:

* **Direct Modification**: Instead of toggling boolean states, actions can directly modify integer values. For instance, an action might:
  * **Increase** the "Health" key, representing healing.
  * **Decrease** the "AmmoCount" key, signifying using ammunition.
* **Unified Representation**: Actions that have opposite effects on the same state can be represented using the same `WorldKey`. For example, both healing and taking damage modify the "Health" key, but in opposite directions.

### Benefits:

1. **Reduced Redundancy**: A single integer-based `WorldKey` can represent a range of states, eliminating the need for multiple boolean keys.
2. **Greater Expressiveness**: Conditions and effects can capture a spectrum of values, allowing for nuanced decision-making.
3. **Simplified Logic**: Evaluating conditions and predicting action outcomes become more straightforward with integer values and defined comparison/effect types.
4. **Consistency**: The risk of conflicting or ambiguous world states is reduced, ensuring a more reliable planning process.

### In Summary:

The shift to integer values in the GOAP system offers a more compact and versatile representation of world states, conditions, and effects. By combining integer values with specific comparison and effect types, and by deliberately omitting an "Equals" comparison, the system ensures clarity in action planning. This approach provides AI agents with a broader and more flexible decision-making framework, enabling more informed and context-aware behaviors.


# Conditions & Effects

## Conditions

Conditions are essentially the prerequisites or requirements that need to be met for an action to be executed. They are tied to the game's state, represented by `WorldKey`.

* **Key**: This is the `WorldKey` that the condition checks. Think of it as a variable or a state in the game world, like "PlayerHealth" or "HasAmmo."
* **Comparison**: This is how the `WorldKey` is compared to a specific value to determine if the condition is met. The available comparisons are "SmallerThan," "SmallerThanOrEqual," "GreaterThan," and "GreaterThanOrEqual."
* **Value**: This is the specific value that the `WorldKey` is compared against using the specified comparison.

For example, a condition might be set up like this:

* **Key**: PlayerHealth
* **Comparison**: GreaterThan
* **Value**: 50

This condition checks if the player's health is greater than 50.

## Effects

Effects describe the changes that an action brings about in the game's state, again represented by `WorldKey`.

* **Key**: This is the `WorldKey` that the effect modifies. For instance, "PlayerHealth" or "AmmoCount."
* **Type**: This indicates whether the `WorldKey` value will increase or decrease as a result of the action.

For instance, an effect might be:

* **Key**: AmmoCount
* **Type**: Decrease

This effect would decrease the ammo count when the action is executed.

## Matching Conditions and Effects

The system matches conditions and effects to determine the sequence of actions that lead to a goal. Here's how the matching works based on the provided documentation:

* **SmallerThan** and **SmallerThanOrEqual** comparisons in conditions look for actions with **negative effects**. This means if a condition requires a `WorldKey` to be less than a certain value, the system will look for actions that decrease that `WorldKey`.
* **GreaterThan** and **GreaterThanOrEqual** comparisons in conditions look for actions with **positive effects**. So, if a condition requires a `WorldKey` to be greater than a certain value, the system will search for actions that increase that `WorldKey`.

For example, if there's a condition that checks if "AmmoCount" is `SmallerThan` 5, the system might look for an action with a negative effect on "AmmoCount" (like "ShootBullet"). Conversely, if the condition checks if "AmmoCount" is `GreaterThan` 10, the system might look for an action with a positive effect on "AmmoCount" (like "ReloadGun").

In essence, the GOAP system uses these conditions and effects to build a graph of possible actions and sequences, which is then used by the planner to determine the best course of action to achieve a goal.

## Examples

Setting conditions and effects through code.

{% code title="Creat" lineNumbers="true" %}

```csharp
var builder = new GoapSetBuilder("GettingStartedSet");

builder.AddAction<ShootBullet>()
           .AddCondition<AmmoCount>(Comparison.GreaterThanOrEqual, 1)
           .AddEffect<AmmoCount>(false)
```

{% endcode %}

Setting conditions and effects through the inspector.

![action-config.png](https://github.com/crashkonijn/GOAP/blob/master/Package/Documentation/images/scriptable_action.png)


# Data Injection

**Data Injection** is a design pattern where an external system provides runtime data to another object or module. In the context of the Goal-Oriented Action Planning (GOAP) system, injection is used to provide specific scene data or dependencies to the core classes (`Goals`, `Actions`, and `Sensors`) managed by the GOAP system.

## Why is Data Injection Needed?

1. **Decoupling**: GOAP classes are designed to be generic and reusable. By injecting specific data or dependencies from the scene or other systems, you can customize their behavior without modifying their core logic. This separation ensures that the GOAP system remains modular and maintainable.
2. **Flexibility**: Different scenes or game scenarios might require different data or behaviors. Injection allows you to provide the necessary context to the GOAP classes, enabling them to adapt to various game situations.
3. **Integration with Third-party Libraries**: By using injection, you can easily integrate third-party libraries or systems with the GOAP framework. For instance, the documentation mentions integrating Zenject, a popular dependency injection framework in Unity.

## How Does It Work?

1. **Creating an Injector**: You create a `MonoBehaviour` class that implements the `IGoapInjector` interface. This class will contain methods that are called right after each GOAP class (`Goal`, `Action`, or `Sensor`) is instantiated. Within these methods, you can provide the necessary data or dependencies to the GOAP classes.
2. **Connecting the Injector**: To let the GOAP system know about your custom injector, you create a class extending `GoapConfigInitializerBase` and bind it to the `GoapRunnerBehaviour` component in the scene. This ensures that your injector is used instead of the default one.

## Example

In the provided example, the `GoapInjector` class is an injector that provides specific scene data (`ItemFactory`, `ItemCollection`, and `InstanceHandler`). The `CreateItemAction` class is an example of a GOAP action that requires this scene data. The method of signaling the injector to provide the necessary data can vary, and the `IInjectable` interface is just one possible approach.

{% code title="GoapInjector.cs" %}

```csharp
using CrashKonijn.Goap.Interfaces;

public class GoapInjector : MonoBehaviour, IGoapInjector
{
    public ItemFactory itemFactory;
    public ItemCollection itemCollection;
    public InstanceHandler instanceHandler;
    
    public void Inject(IActionBase action)
    {
        if (action is IInjectable injectable)
            injectable.Inject(this);
    }

    public void Inject(IGoalBase goal)
    {
    }

    public void Inject(IWorldSensor worldSensor)
    {
    }

    public void Inject(ITargetSensor targetSensor)
    {
    }
}
```

{% endcode %}

{% code title="CreateItemAction.cs" %}

```csharp
namespace Demos.Complex.Actions
{
    public class CreateItemAction<TCreatable> : ActionBase<CreateItemAction<TCreatable>.Data>, IInjectable
        where TCreatable : ItemBase, ICreatable
    {
        private ItemFactory itemFactory;
        private InstanceHandler instanceHandler;

        public void Inject(GoapInjector injector)
        {
            this.itemFactory = injector.itemFactory;
            this.instanceHandler = injector.instanceHandler;
        }
        
        // rest of class
    }
}
```

{% endcode %}

## Connecting the injector

In order to let the GOAP know you'd like to overwrite one of it's core settings, the `IGoapInjector` in this case you need to create a class that extends `GoapConfigInitializerBase`.

Add the script to the scene and bind it to the `GoapConfigInitializer` property of the `GoapRunnerBehaviour` component.

![Goap Config Initializer](/files/1UHeWXy1ZFN34nQJPo5h)

### Example

{% code title="GoapConfigInitializer.cs" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes;

namespace Demos.Complex.Goap
{
    public class GoapConfigInitializer : GoapConfigInitializerBase
    {
        public override void InitConfig(GoapConfig config)
        {
            config.GoapInjector = this.GetComponent<GoapInjector>();
        }
    }
}
```

{% endcode %}

## Zenject

It's very easy to use Zenject with the GOAP. The GOAP has a built-in injector that can be used to inject Zenject dependencies into the GOAP classes.

{% code title="ZenjectGoapInjector.cs" %}

```csharp
using CrashKonijn.Goap.Interfaces;
using UnityEngine;
using Zenject;

public class ZenjectGoapInjector : MonoBehaviour, IGoapInjector
{
    private DiContainer container;

    [Inject]
    private void Construct(DiContainer container)
    {
        this.container = container;
    }
    
    public void Inject(IActionBase action)
    {
        this.container.Inject(action);
    }

    public void Inject(IGoalBase goal)
    {
        this.container.Inject(goal);
    }

    public void Inject(IWorldSensor worldSensor)
    {
        this.container.Inject(worldSensor);
    }

    public void Inject(ITargetSensor targetSensor)
    {
        this.container.Inject(targetSensor);
    }
}
```

{% endcode %}


# Life Cycles

## Agent

![Agent.Run](/files/7nB7lapYX4wK2ofAi25e) ![Agent.SetGoal](/files/Nzjxs5IluvJhGZf7bkuG) ![Agent.SetAction](/files/DcISkSzqo33zW6Fgd6Hu)

## GoapRunner and GoapSet

![GoapRunner.Run](/files/U3JQT7aJbOSkQzQWCYNJ) ![GoapRunner.Complete](/files/FUWqHvKEwGq54EndQVJz)


# GraphViewer

The `Graph Viewer` is a tool that can be used to visualize any script, config or gameobject that has a (partial) GOAP config. Depending on the type of object it can show different information. For example, when selecting an agent during play it will also show the state of it's conditions based on the current WorldData.

The `Graph Viewer` can be accessed through `Tools/GOAP/Graph Viewer`, or by pressing `ctrl + g`.

The `Graph Viewer` can be used to visualize the following selected items:

* **AgentTypeScriptable**
* **CapabilityConfigScriptable**
* **ScriptableCapabilityFactoryBase**
* **AgentTypeFactoryBase**
* **AgentTypeBehaviour**
* **GoapActionProvider**

{% hint style="info" %}
The views look different when selecting a config, or when you select an agent during play. When viewing an agent during play certain information (effects, targetname) is ommitted to save space.
{% endhint %}

![Screenshot of NodeViewer](/files/MEHIU2G5HIznKqLiLZ2H)


# Examples


# Simple

The simple example use `ScriptableObject` as the configuration method. This is the easiest way to get started with GOAP. The demo scene can be found in `Demos/Simple/Scenes/SimpleDemo.unity`.

Each agent has 2 separate goals: `WanderGoal` and `FixHungerGoal`. The `WanderGoal` will make the agent wander around the scene. The `FixHungerGoal` will make the agent eat apples. The agent will only eat apples if it is hungry. The agent will only wander if it is not hungry.

Goals:

* WanderGoal
* FixHungerGoal

Actions:

* WanderAction
* EatAppleActions
* PickupAppleAction
* PluckAppleAction

## Rules

If the agent has a `hunger > 80`, it will switch to the `FixHungerGoal`. If the agent has a `hunger < 20`, it will switch to the `WanderGoal`.

![Simple Demo Graph](/files/WCmeempyknnm24Bg1nsf)


# Complex

The complex example uses code as the configuration method. The demo scene can be found in `Demos/Complex/Scenes/ComplexDemoScene.unity`.

There are 4 type of agents:

* Cleaner (Orange). They grab items laying on the floor and bring them to boxes.
* Smith (Blue). When there are enough materials he will craft an `Axe` or `Pickaxe`. He needs `Wood` and `Iron` to craft the tools.
* WoodCutter (Green). When there isn't enough `Wood` in the world, they will chop wood from trees.
* Miner (Pink). When there isn't enough `Iron` in the world, they will mine iron from rocks.

Each agent has 2 base goals: `WanderGoal` and `FixHungerGoal`. The `WanderGoal` will make the agent wander around the scene. The `FixHungerGoal` will make the agent eat apples. The agent will only eat apples if it is hungry. The agent will only wander if it is not hungry.

## Cleaner

The goap set builder can be found in `Demos/Complex/Factories/CleanerGoapSetConfigFactory.cs`.

![Cleaner graph](/files/hvoVZBjBhpuuEqkcmx8V)

## Smith

The goap set builder can be found in `Demos/Complex/Factories/SmithGoapSetConfigFactory.cs`.

![Smith graph](/files/ymRCdnbmeyLrItYdnPb8)

## Wood Cutter

The goap set builder can be found in `Demos/Complex/Factories/WoodCutterGoapSetConfigFactory.cs`.

![Wood Cutter graph](/files/u3j9f2ZeJMjWM99NhoDD)

## Miner

The goap set builder can be found in `Demos/Complex/Factories/MinerGoapSetConfigFactory.cs`.

![Miner graph](/files/UtFlPTqyKdGDCI7FNqcU)


# Introduction


# What is Goap?

Goal Oriented Action Planning (GOAP) is a technique commonly used in game AI to create agents that can autonomously determine their actions and achieve specific goals within the game environment. GOAP can be used to create complex and adaptive behavior for non-player characters (NPCs) in a game.

The basic idea of GOAP is to break down a complex task or goal into a series of smaller, simpler actions that an agent can perform. These actions are then organized into a plan or sequence of actions that will lead the agent towards the desired goal.

GOAP begins with the agent evaluating its current state and the desired goal state. The agent then searches through a library of available actions to find a series of actions that will transform the current state into the desired goal state. Each action is associated with a set of preconditions that must be met in order for the action to be executed. For example, an action to pick up a key might have a precondition that the key is in the same room as the agent.

Once a plan has been created, the agent executes the first action in the plan. As the agent completes each action, it re-evaluates its state and the remaining actions in the plan to ensure that it is still on track towards its goal. If the agent encounters an obstacle or a change in the game environment, it can dynamically adjust its plan to find a new sequence of actions that will still lead to the desired goal.

GOAP is particularly useful in games with complex environments and multiple goals, as it allows NPCs to adapt to changing situations and make decisions based on their current state and the desired outcome. It can also be used to create NPCs with different personalities or behavior patterns by adjusting the weighting of different actions or goals in their decision-making process.

Overall, GOAP is a powerful technique for creating intelligent and adaptive agents in games that can perform complex tasks and achieve specific goals within the game world.


# Getting Started

## Tutorials

* [**YouTube tutorials**](https://www.youtube.com/playlist?list=PLZWmMt_TbeYeatHa9hntDPu4zGEBAFffn) on how to use the library.
* [**YouTube references**](https://www.youtube.com/playlist?list=PLZWmMt_TbeYdBZKvlsRuuOubPTTfPuZot) discussing GOAP in general.

## Installation

Add the package to your project using the package manager. Add the following URL to the package manager:

```
https://github.com/crashkonijn/GOAP.git?path=/Package#2.1.22
```

Alternatively install through [OpenUPM](https://openupm.com/packages/com.crashkonijn.goap/) or the [Unity Asset Store](https://assetstore.unity.com/packages/slug/252687).

{% hint style="info" %}
**Version** This package was build using unity 2022.2, but also confirmed to be working with 2021.3.
{% endhint %}

## Overview

Below is a quick overview of the different components of classes and how they are connected to an Action.

![Class overview](/files/28xaCk1fkNYSkbWFYVJm)

## Setup in Unity

1. Create a class called `WanderGoal` that extends `GoalBase`.

{% code title="WanderGoal.cs" %}

```csharp
using CrashKonijn.Goap.Behaviours;

public class WanderGoal : GoalBase
{
}
```

{% endcode %}

2. Create a class called `WanderAction` that extends `ActionBase`. The generic value of the class is the type of the data class used in this goal.

{% code title="WanderAction.cs" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes;
using CrashKonijn.Goap.Enums;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;

public class WanderAction : ActionBase<WanderAction.Data>
{
    // Called when the class is created.
    public override void Created()
    {
    }

    // Called when the action is started for a specific agent.
    public override void Start(IMonoAgent agent, Data data)
    {
        // When the agent is at the target, wait a random amount of time before moving again.
        data.Timer = Random.Range(0.3f, 1f);
    }

    // Called each frame when the action needs to be performed. It is only called when the agent is in range of it's target.
    public override ActionRunState Perform(IMonoAgent agent, Data data, ActionContext context)
    {
        // Update timer.
        data.Timer -= context.DeltaTime;
        
        // If the timer is still higher than 0, continue next frame.
        if (data.Timer > 0)
            return ActionRunState.Continue;
        
        // This action is done, return stop. This will trigger the resolver for a new action.
        return ActionRunState.Stop;
    }

    // Called when the action is ended for a specific agent.
    public override void End(IMonoAgent agent, Data data)
    {
    }

    public class Data : IActionData
    {
        public ITarget Target { get; set; }
        public float Timer { get; set; }
    }
}
```

{% endcode %}

3. Create a class called `WanderTargetSensor` that extends `LocalTargetSensorBase`. The generic value of the class is the type of the data class used in this goal.

{% code title="WanderTargetSensor.cs" %}

```csharp
using CrashKonijn.Goap.Classes;
using CrashKonijn.Goap.Interfaces;
using CrashKonijn.Goap.Sensors;
using UnityEngine;

public class WanderTargetSensor : LocalTargetSensorBase
{
    // Called when the class is created.
    public override void Created()
    {
    }

    // Called each frame. This can be used to gather data from the world before the sense method is called.
    // This can be used to gather 'base data' that is the same for all agents, and otherwise would be performed multiple times during the Sense method.
    public override void Update()
    {
    }

    // Called when the sensor needs to sense a target for a specific agent.
    public override ITarget Sense(IMonoAgent agent, IComponentReference references)
    {
        var random = this.GetRandomPosition(agent);
        
        return new PositionTarget(random);
    }

    private Vector3 GetRandomPosition(IMonoAgent agent)
    {
        var random =  Random.insideUnitCircle * 5f;
        var position = agent.transform.position + new Vector3(random.x, 0f, random.y);

        return position;
    }
}
```

{% endcode %}

4. Create a class called `AgentMoveBehaviour`. This class will be called by the `AgentBehaviour` to move the agent to a target.

{% code title="AgentMoveBehaviour.cs" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;

public class AgentMoveBehaviour : MonoBehaviour
{
    private AgentBehaviour agent;
    private ITarget currentTarget;
    private bool shouldMove;

    private void Awake()
    {
        this.agent = this.GetComponent<AgentBehaviour>();
    }

    private void OnEnable()
    {
        this.agent.Events.OnTargetInRange += this.OnTargetInRange;
        this.agent.Events.OnTargetChanged += this.OnTargetChanged;
        this.agent.Events.OnTargetOutOfRange += this.OnTargetOutOfRange;
    }

    private void OnDisable()
    {
        this.agent.Events.OnTargetInRange -= this.OnTargetInRange;
        this.agent.Events.OnTargetChanged -= this.OnTargetChanged;
        this.agent.Events.OnTargetOutOfRange -= this.OnTargetOutOfRange;
    }

    private void OnTargetInRange(ITarget target)
    {
        this.shouldMove = false;
    }

    private void OnTargetChanged(ITarget target, bool inRange)
    {
        this.currentTarget = target;
        this.shouldMove = !inRange;
    }

    private void OnTargetOutOfRange(ITarget target)
    {
        this.shouldMove = true;
    }

    public void Update()
    {
        if (!this.shouldMove)
            return;
        
        if (this.currentTarget == null)
            return;
        
        this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(this.currentTarget.Position.x, this.transform.position.y, this.currentTarget.Position.z), Time.deltaTime);
    }
}
```

{% endcode %}

5. Create a script called `AgentBrain`.

{% code title="AgentBrain.cs" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using UnityEngine;

public class AgentBrain : MonoBehaviour
{
    private AgentBehaviour agent;

    private void Awake()
    {
        this.agent = this.GetComponent<AgentBehaviour>();
    }

    private void Start()
    {
        this.agent.SetGoal<WanderGoal>(false);
    }
}
```

{% endcode %}

## Choose your config style

Either continue the getting started by using `Code` or `ScriptableObjects`.


# Code

1. Create a new scene
2. Create a new GameObject called `Goap`, add the `GoapRunnerBehaviour` to it.

![Goap Runner Behaviour](/files/lnVDISg7kofijME9S8px)

3. Create a class called `WanderTarget` that extends `TargetKeyBase`.

{% code title="WanderTarget.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;

public class WanderTarget : TargetKeyBase
{
}
```

{% endcode %}

4. Create a class called `IsWandering` that extends `WorldKeyBase`.

{% code title="IsWandering.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;

public class IsWandering : WorldKeyBase
{
}
```

{% endcode %}

5. Create a class called `GoapSetConfigFactory` that extends `GoapSetConfigFactoryBase` and override the `Create` method.

{% code title="GoapSetConfigFactory.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes.Builders;
using CrashKonijn.Goap.Configs.Interfaces;
using CrashKonijn.Goap.Resolver;
using CrashKonijn.Goap.Enums;

public class GoapSetConfigFactory : GoapSetFactoryBase
{
    public override IGoapSetConfig Create()
    {
        var builder = new GoapSetBuilder("GettingStartedSet");
        
        // Goals
        builder.AddGoal<WanderGoal>()
            .AddCondition<IsWandering>(Comparison.GreaterThanOrEqual, 1);

        // Actions
        builder.AddAction<WanderAction>()
            .SetTarget<WanderTarget>()
            .AddEffect<IsWandering>(EffectType.Increase)
            .SetBaseCost(1)
            .SetInRange(0.3f);

        // Target Sensors
        builder.AddTargetSensor<WanderTargetSensor>()
            .SetTarget<WanderTarget>();

        // World Sensors
        // This example doesn't have any world sensors. Look in the examples for more information on how to use them.

        return builder.Build();
    }
}
```

{% endcode %}

6. Add the `GoapSetConfigFactory` to the `Goap` GameObject. Make sure to add the `GoapSetConfigFactory` to the `GoapRunnerBehaviour`'s factories property.

![Goap Runner](/files/p5O8f70KyT3eBjuOYlXX)

7. Create a script called `GoapSetBinder`. This script will assign a `GoapSet` to the `Agent`.

{% code title="GoapSetBinder.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using UnityEngine;

public class GoapSetBinder : MonoBehaviour {
    public void Awake() {
        var runner = FindObjectOfType<GoapRunnerBehaviour>();
        var agent = GetComponent<AgentBehaviour>();
        agent.GoapSet = runner.GetGoapSet("GettingStartedSet");
    }
}
```

{% endcode %}

8. Create a sphere `GameObject` called `Agent`. Add the `AgentBehaviour`, `AgentMoveBehaviour`, `AgentBrain` and `GoapSetBinder` to the `GameObject`.

![Agent](/files/v3CZ0JgCXtlrWNjUVvA6)

9. Run the scene. The agent should move around randomly.


# ScriptableObjects

## Setup in Unity

1. Create a new scene
2. Create a new GameObject called `Goap`, add the `GoapRunnerBehaviour` to it.

![Goap Runner Behaviour](/files/lnVDISg7kofijME9S8px)

3. Create a folder called `Configs`.
4. Within the `Configs` folder create a folder called `TargetKeys`. Within this folder press right click `Create > GOAP > Target Key Config`. Call the config `WanderTarget`.
5. Within the `Configs` folder create a folder called `WorldKeys`. Within this folder press right click `Create > GOAP > World Key Config`. Call the config `IsWandering`.
6. Within the `Configs` folder create a folder called `Goals`. Within this folder press right click `Create > GOAP > Goal Config`. Call the config `WanderGoal`.
   1. Select the `WanderGoal` script in the `class` property.
   2. Add a condition to the `conditions` property. Set the `key` to `IsWandering`, the `comparison` to `GreaterThanOrEqual` and the `value` to `1`.

![Wander Goal](/files/LNbdcNzCuRFRglI6aUFQ)

7. Within the `Configs` folder create a folder called `Actions`. Within this folder press right click `Create > GOAP > Action Config`. Call the config `WanderAction`.
   1. Select the `WanderAction` script in the `class` property.
   2. Set the `target` to `WanderTarget`.
   3. Add an effect to the `effects` property. Set the `key` to `IsWandering`, the `increase` to `true`.

![Wander Action](/files/FasDcrRD2o2U2HZWsKiV)

8. Within the `Configs` folder create a folder called `TargetSensors`. Within this folder press right click `Create > GOAP > Target Sensor Config`. Call the config `WanderTargetSensor`.
   1. Select the `WanderTargetSensor` script in the `class` property.
   2. Set the `key` to `WanderTarget`.

![Wander Target Sensor](/files/89eY1DDsWV1Ep0Ceoys2)

9. Within the `Configs` folder create a folder called `Sets`. Within this folder press right click `Create > GOAP > Goap Set Config`. Call the config `GettingStartedSet`.
   1. Add the `WanderGoal` config to the `goals` property.
   2. Add the `WanderAction` config to the `actions` property.
   3. Add the `WanderTargetSensor` config to the `targetSensors` property.

![Getting Started Set](/files/xCrzgSz28B8WtuQaFZYb)

10. In the scene, add a GameObject called `GoapSet`. Add the `GoapSetBehaviour` to it.
    1. In the `Config` property of the `GoapSetBehaviour` select the `GettingStartedSet` config.
    2. In the `Runner` property of the `GoapSetBehaviour` select the `Goap` GameObject.

![Goap Set](/files/1Q0hz8kyld5fT0EfIZNe)

11. Create a sphere `GameObject` called `Agent`. Add the `AgentBehaviour`, `AgentMoveBehaviour` and `AgentBrain` to the `GameObject`.
    1. In the `GoapSetConfig` property of the `AgentBehaviour` select the `GoapSet` GameObject.

![Agent](/files/W8XLlIICwvkgZx9II8MY)

12. Run the scene. The agent should move around randomly.


# FAQ

## Why does each action need a target?

Unless you're creating a 0 dimension game, there are actions that take place at a specific position. When there are actions that require positions there a 3 possible solutions for handling the movement.

### 1. There are move actions in the graph.

This approach is extremely inefficient. The graph would become much larger, which makes it much more expensive to calculate the best action. This also requires each specific action to have a specific move action (aka MoveToPlayerAction, MoveToAmmoAction), or you can create a generic action. The generic action however would need to receive data from other actions during the resolving of the graph (aka the previous action would determine the target of the move action).

### 2. Each action is handling movement.

This does make the graph much smaller. However each action would require logic for movement, making them much more complicated. (You'd probably end up with a small FSM in each action; MovingTo, Performing). This also makes it hard to calculate a cost value, including distance between actions. This would again require the previous action in the graph to be provided to each action.

### 3. Each action is performed at a position.

This is the option this project uses. This uses a smaller graph than option 1. This doesn't need to perform movement in an action, keeping them simpler. The graph calculates distance between two actions, adding that cost automatically. Actions don't need to be aware of each other, or their relative position in the graph, making them simpler.

![With move actions](/files/APSTbnnZbLrr3Z7QtBUb) ![Without move actions](/files/UvmFvDUx3Z3zFBAXHXp8)


# Upgrading

## Upgrading from 2.0 to 2.1

### IAgentMover is removed

`IAgentMover` is removed in favor of having movement based events on the agent.

{% code title="AgentMoveBehaviour.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;

public class AgentMoveBehaviour : MonoBehaviour
{
    private AgentBehaviour agent;
    private ITarget currentTarget;
    private bool shouldMove;

    private void Awake()
    {
        this.agent = this.GetComponent<AgentBehaviour>();
    }

    private void OnEnable()
    {
        this.agent.Events.OnTargetInRange += this.OnTargetInRange;
        this.agent.Events.OnTargetChanged += this.OnTargetChanged;
        this.agent.Events.OnTargetOutOfRange += this.OnTargetOutOfRange;
    }

    private void OnDisable()
    {
        this.agent.Events.OnTargetInRange -= this.OnTargetInRange;
        this.agent.Events.OnTargetChanged -= this.OnTargetChanged;
        this.agent.Events.OnTargetOutOfRange -= this.OnTargetOutOfRange;
    }

    private void OnTargetInRange(ITarget target)
    {
        this.shouldMove = false;
    }

    private void OnTargetChanged(ITarget target, bool inRange)
    {
        this.currentTarget = target;
        this.shouldMove = !inRange;
    }

    private void OnTargetOutOfRange(ITarget target)
    {
        this.shouldMove = true;
    }

    public void Update()
    {
        if (!this.shouldMove)
            return;
        
        if (this.currentTarget == null)
            return;
        
        this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(this.currentTarget.Position.x, this.transform.position.y, this.currentTarget.Position.z), Time.deltaTime);
    }
}
```

{% endcode %}

### Setup through code now requires actual classes as the WorldKey and TargetKey.

{% code lineNumbers="true" %}

```csharp
public class WanderTarget : TargetKeyBase
{
}

public class IsWandering : WorldKeyBase
{
}

public class GoapSetConfigFactory : GoapSetFactoryBase
{
    public override IGoapSetConfig Create()
    {
        var builder = new GoapSetBuilder("GettingStartedSet");
        
        // Goals
        builder.AddGoal<WanderGoal>()
            .AddCondition<IsWandering>(Comparison.GreaterThanOrEqual, 1);

        // Actions
        builder.AddAction<WanderAction>()
            .SetTarget<WanderTarget>()
            .AddEffect<IsWandering>(true)
            .SetBaseCost(1)
            .SetInRange(0.3f);

        // Target Sensors
        builder.AddTargetSensor<WanderTargetSensor>()
            .SetTarget<WanderTarget>();

        // World Sensors
        // This example doesn't have any world sensors. Look in the examples for more information on how to use them.

        return builder.Build();
    }
}
```

{% endcode %}


# Config


# Through ScriptableObjects

The ScriptableObjects are the main way to configure the GOAP system. They are used to define the goals, actions, sensors, world keys and target keys. This method of configuration is the most simple way to configure the GOAP system and is done by creating scriptable objects through the Unity Editor.

{% hint style="warning" %}
**Warning** Please keep in mind that this method prevents you from using generic classes. If you need to use generic classes, you should use the code configuration method.
{% endhint %}

{% hint style="info" %}
**Example** The simple demo uses the ScriptableObjects configuration method.
{% endhint %}

![scriptable\_configs.png](/files/nTR3TXELJkX8hKvvZKAO)

## Sets

To create a set, right click in the project window and select `Create > Goap > Goap Set Config`. This will create a new set config. On this config you must reference all other configs that are part of this set.

![goap-set.png](/files/XnTRPhOecV59vnsf3ilq)

## Goals

To create a goal, right click in the project window and select `Create > Goap > Goal Config`. This will create a new goal config.

![goal-config.png](/files/Op190XCfIYvKN5qRqXdv)

## Actions

To create an action, right click in the project window and select `Create > Goap > Action Config`. This will create a new action config.

![action-config.png](/files/laSjEaWksMKonKVqPtio)

## World Keys

To create an world key, right click in the project window and select `Create > Goap > World Key`. This will create a new world key.

## World Sensors

To create an world sensor, right click in the project window and select `Create > Goap > World Sensor Config`. This will create a new world sensor config.

![world-sensor-config.png](/files/WItJkrqIWGCDDJEjVYRG)

## Target Keys

To create an action, right click in the project window and select `Create > Goap > Target Key`. This will create a new world key.

## Target Sensors

To create a target sensor, right click in the project window and select `Create > Goap > Target Sensor Config`. This will create a new world sensor config.

![target-sensor-config.png](/files/7wIATXsOyKI6DXqGtpAn)


# Through Code

Setting up your GOAP system using code is the most flexible way to configure your GOAP system. This method is more difficult to use than the `ScriptableObjects` method, but allows for a much more dynamic setup.

{% hint style="info" %}
**Info** By using code to setup your GOAP system, you can use generic classes. This can make the setup of your GOAP system more flexible.
{% endhint %}

{% hint style="info" %}
**Example** The complex demo uses code as the configuration method.
{% endhint %}

## Sets

To create a set, you must create a class that inherits from `GoapSetFactoryBase`. This class must implement the `Create` method which returns a `IGoapSetConfig`. To make building the set easier, you can use the `GoapSetBuilder` class.

{% code title="GoapSetConfigFactory.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes.Builders;
using CrashKonijn.Goap.Configs.Interfaces;
using Demos.Complex.Classes;
using Demos.Complex.Classes.Items;
using Demos.Complex.Factories.Extensions;
using Demos.Complex.Interfaces;
using Demos.Shared;

public class GoapSetConfigFactory : GoapSetFactoryBase
{
    public override IGoapSetConfig Create()
    {
        var builder = new GoapSetBuilder("ComplexSet");
        
        // Goals
        builder.AddGoal<WanderGoal>()
            .AddCondition<IsWandering>(Comparison.GreaterThanOrEqual, 1);

        builder.AddGoal<FixHungerGoal>()
            .AddCondition<IsHungry>(Comparison.SmallerThanOrEqual, 0);

        // Actions
        builder.AddAction<WanderAction>()
            .SetTarget<WanderTarget>()
            .AddEffect<IsWandering>(true)
            .SetBaseCost(1f)
            .SetInRange(0.3f);

        builder.AddAction<PickupItemAction<IEatable>>()
            .SetTarget<ClosestTarget<IEatable>>()
            .AddEffect<IsHolding<IEatable>>(true)
            .AddCondition<IsInWorld<IEatable>>(Comparison.GreaterThanOrEqual, 1)
            .SetBaseCost(1f)
            .SetInRange(0.3f);

        // Target Sensors
        builder.AddTargetSensor<WanderTargetSensor>()
            .SetTarget<WanderTarget>();

        builder.AddTargetSensor<ClosestItemSensor<IEatable>>()
            .SetTarget<ClosestTarget<IEatable>>();

        // World Sensors
        builder.AddWorldSensor<IsHoldingSensor<IEatable>>()
            .SetKey<IsHolding<IEatable>>());

        builder.AddWorldSensor<IsInWorldSensor<IEatable>>()
            .SetKey<IsInWorld<IEatable>>();

        return builder.Build();
    }
}
```

{% endcode %}

### Adding the set to GOAP

Add the created class to a GameObject in the scene. Add it to the list on the `GoapRunnerBehaviour` component. This will initialize the set.

![Goap Runner Behaviour component](/files/wpLZJUl7w5qpeJ7jpKmf)

### Adding the set to the agent.

Using a script, set the `GoapSet` property on an agent.

{% code lineNumbers="true" %}

```csharp
var goapRunner = FindObjectOfType<GoapRunnerBehaviour>();
var set = goapRunner.GetSet("ComplexSet");

agent.GetComponent<AgentBehaviour>.GoapSet = set;
```

{% endcode %}


# Classes


# Goals

In the GOAP system, `Goals` represent the desired outcomes or objectives that an agent aims to achieve. They serve as the starting points for the `Planner`, guiding it in determining the most suitable `Action` to take in order to fulfill a particular `Goal`.

## Goal Config

The `GoalConfig` provides the necessary settings to define and shape a `Goal`. It encompasses several properties:

### 1. Class Type

**Description**: This property specifies the exact type or category of the `Goal`. It helps in identifying and categorizing different goals within the system.

### 2. Conditions

**Description**: Conditions are a set of criteria based on `WorldKeys` that must be met for the `Goal` to be considered achieved. These conditions guide the `Planner` in its decision-making process, helping it select the best `Action` that aligns with the desired outcome.

For instance, if a `Goal` is to "Stay Safe", conditions might include `WorldKeys` like "IsHealthHigh" or "IsInSafeZone".

## Goal Class

The `Goal` class serves as the blueprint for creating specific goals. Key points about the `Goal` class:

* **Inheritance**: Every `Goal` class is derived from the foundational `GoalBase` class. This ensures that all goals share some basic properties and behaviors.
* **Statelessness**: A `Goal` class doesn't maintain any internal state. Its primary role is to provide criteria to the `Planner`, which then uses this information to decide on the most appropriate `Action` to execute.

By understanding and configuring `Goals` appropriately, game developers can guide agents towards desired behaviors, ensuring they act in ways that enhance the gameplay experience.

## Example

{% code title="FixHungerGoal.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;

namespace Demos.Goals
{
    public class FixHungerGoal : GoalBase
    {
    }
}
```

{% endcode %}


# Actions

In the GOAP system, an action represents a discrete step an agent can undertake to achieve a specific goal. Actions are defined by their requirements and effects, which guide the chaining of actions to form a plan.

## Components of an Action

Actions are composed of three primary parts:

1. **Config**: Configuration settings for the action.
2. **Action Class**: The logic and behavior of the action.
3. **Action Data**: Temporary data storage for the action's state.

## Action Config

The configuration provides essential settings for the action, enabling its integration into the GOAP graph.

### Conditions

Conditions are a set of world states that must be met for the action to be executable. Each condition references a `WorldKey` and specifies whether its value should be true or false.

### Effects

Effects describe the changes in world states that result from performing the action. Each effect references a `WorldKey` and indicates the expected outcome (true or false).

### BaseCost

This represents the inherent cost of executing the action, excluding any additional costs (like distance) that the planner might add.

### Target

Every action has an associated target position. Before executing the action, the agent will move towards this target, depending on the `MoveMode`. Targets are identified using `TargetKey`, such as `ClosestApple` or `ClosestEnemy`.

### InRange

This value specifies the proximity required between the agent and the target position before the action can commence.

## MoveMode

`MoveMode` determines how the action and movement are coordinated:

* **MoveBeforePerforming**: The agent moves to the target position before initiating the action.
* **PerformWhileMoving**: The agent concurrently moves to the target and executes the action.

## Action Data

Action data provides temporary storage for the action's state for an individual agent. This data is not shared across agents or across multiple invocations of the same action.

### Action Data Injection

To reference other classes on the agent, use the `GetComponent` attribute. This provides a cached component instance, optimizing performance by avoiding frequent `GetComponent` calls.

{% code lineNumbers="true" %}

```csharp
public class Data : IActionData
{
    public ITarget Target { get; set; }
    
    [GetComponent]
    public ComplexInventoryBehaviour Inventory { get; set; }
}
```

{% endcode %}

## Action Class

The action class defines the behavior of the action. It should be stateless since a single instance might be used to execute the same action on different agents. The class inherits from `ActionBase<TData>`, where `TData` is the action data class.

### ActionRunState

This enum indicates the action's current state:

* **Continue**: The action will persist and be re-evaluated in the next frame.
* **Stop**: The action will terminate, and control will revert to the planner.

### Examples

The provided examples illustrate how to implement specific functionalities within the action class and action data. They've been retained in their original form for clarity.

### Examples

{% code title="WanderAction.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Enums;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;

namespace Demos.Actions
{
    public class WanderAction : ActionBase<WanderAction.Data>
    {
        // You can implement a custom cost function. This is useful if you want to add dynamic costs to the action.
        public override float GetCost(IMonoAgent agent, IComponentReference references)
        {
            return 5f;
        }
        
        // This method is called to determine if the agent is in range for the action. It is called every frame while the action is running.
        // This could be used to perform a physics check to actually guarantee line of sight for example.
        public virtual bool IsInRange(IMonoAgent agent, float distance, IActionData data, IComponentReference references)
        {
            return distance <= this.config.InRange;
        }
    
        // This methods is called when the action is created. It is used to initialize the action.
        public override void Created()
        {
        }
    
        // This method is called when the action is started. It is used to initialize the action.
        public override void Start(IMonoAgent agent, Data data)
        {
        }

        // This method is called every frame while the action is running. It is used to perform the action.
        public override ActionRunState OnPerform(IMonoAgent agent, Data data, ActionContext context)
        {
            return ActionRunState.Stop;
        }

        // This method is called when the action is stopped. It is used to clean up the action.
        public override void End(IMonoAgent agent, Data data)
        {
        }

        // Action data class. It stores the state of the action for a single agent. This data is not persistent between agents or between multiple runs of the same action.
        public class Data : IActionData
        {
            // The target position of the action. This is set by the planner.
            public ITarget Target { get; set; }
        }
    }
}
```

{% endcode %}

{% code title="EatAppleAction.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes;
using CrashKonijn.Goap.Enums;
using CrashKonijn.Goap.Interfaces;
using Demos.Shared.Behaviours;
using Demos.Simple.Behaviours;
using UnityEngine;

namespace Demos.Simple.Actions
{
    public class EatAppleAction : ActionBase<EatAppleAction.Data>
    {
        public override void Created()
        {
        }
    
        public override void OnStart(IMonoAgent agent, Data data)
        {
            if (data.Target is not TransformTarget)
                return;

            var inventory = agent.GetComponent<InventoryBehaviour>();

            if (inventory == null)
                return;
            
            data.Apple =  inventory.Get();
            data.Hunger = agent.GetComponent<HungerBehaviour>();
        }

        public override ActionRunState OnPerform(IMonoAgent agent, Data data, ActionContext context)
        {
            if (data.Apple == null || data.Hunger == null)
                return ActionRunState.Stop;

            var eatNutrition = context.DeltaTime * 20f;

            data.Apple.nutritionValue -= eatNutrition;
            data.Hunger.hunger -= eatNutrition;
            
            if (data.Apple.nutritionValue <= 0)
                GameObject.Destroy(data.Apple.gameObject);
            
            return ActionRunState.Continue;
        }
        
        public override void OnEnd(IMonoAgent agent, Data data)
        {
            if (data.Apple == null)
                return;
            
            var inventory = agent.GetComponent<InventoryBehaviour>();

            if (inventory == null)
                return;
            
            inventory.Put(data.Apple);
        }
        
        public class Data : IActionData
        {
            public ITarget Target { get; set; }
            public AppleBehaviour Apple { get; set; }
            public HungerBehaviour Hunger { get; set; }
        }
    }
}
```

{% endcode %}


# AgentBehaviour

The `AgentBehaviour` is a crucial component that must be attached to every agent leveraging the GOAP system to decide its subsequent actions. It links an agent to a specific `GoapSet`, which encompasses the configuration of all potential `Goals` and `Actions` the agent can undertake.

## Overview

* **Current Goal**: The objective the agent is currently trying to achieve.
* **Active Action**: The action the agent is currently executing to meet its goal.
* **WorldData**: Represents the game's current state, which the planner uses to decide the best action for the agent.

## Movement

Actions often have associated targets, indicating a position the agent should reach before executing the action. Since movement mechanics can vary based on the game's design, this package doesn't prescribe a specific movement implementation. However, it provides events to help developers determine when an agent should move.

### MoveMode

Some actions might need the agent to perform tasks while moving. The `MoveMode` in the `ActionConfig` allows for such configurations.

### Distance Multiplier

The primary objective of actions is to achieve goals swiftly. If the action's cost equates to its completion time, then the heuristic's distance value should be divided by the agent's movement speed. Using `SetDistanceMultiplierSpeed(float speed)` sets the agent's (max/average) speed, enabling the planner to more precisely ascertain the optimal action.

### Custom Distance Calculation

By default, the agent calculates distance using `Vector3.Distance`. However, for more complex scenarios, like using a nav mesh, you can override this by assigning your custom `IAgentDistanceObserver` to the `agent.DistanceObserver`.

### Example

{% code title="NavMeshDistanceObserver.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;
using UnityEngine.AI;

public class NavMeshDistanceObserver : MonoBehaviour, IAgentDistanceObserver
{
    private NavMeshAgent navMeshAgent;
    
    private void Awake()
    {
        this.navMeshAgent = this.GetComponent<NavMeshAgent>();
        this.GetComponent<AgentBehaviour>().DistanceObserver = this;
    }
    
    public float GetDistance(IMonoAgent agent, ITarget target, IComponentReference reference)
    {
        var distance = this.navMeshAgent.remainingDistance;
        
        // No path
        if (float.IsInfinity(distance))
            return 0f;
        
        return distance;
    }
}
```

{% endcode %}

## Methods

### SetGoal

This method allows for the modification of the agent's current goal. The `endAction` parameter decides if the ongoing action should terminate before setting the new goal.

{% code lineNumbers="true" %}

```csharp
public void SetGoal<TGoal>(bool endAction) where TGoal : IGoalBase;
public void SetGoal(IGoalBase goal, bool endAction);
```

{% endcode %}

## Determining the Goal

Choosing the best `Goal` is game-specific, and this package doesn't dictate a method. However, an example is provided below to illustrate how one might determine a goal based on an agent's hunger level.

### Example

This is an example of how to determine the best goal. In this example the agent will wander around until it's hunger is above 80. When it's hunger is above 80 it will try to fix it's hunger. When it's hunger is below 20 it will wander around again.

{% code title="AgentBrain.cs" lineNumbers="true" %}

```csharp
using System;
using CrashKonijn.Goap.Behaviours;
using Demos.Goals;
using UnityEngine;

namespace Demos.Behaviours
{
    public class AgentBrain : MonoBehaviour
    {
        private AgentBehaviour agent;
        private HungerBehaviour hunger;

        private void Awake()
        {
            this.agent = this.GetComponent<AgentBehaviour>();
            this.hunger = this.GetComponent<HungerBehaviour>();
        }

        private void Start()
        {
            this.agent.SetGoal<WanderGoal>(false);
        }

        private void FixedUpdate()
        {
            if (this.hunger.hunger > 80)
                this.agent.SetGoal<FixHungerGoal>(false);
            
            if (this.hunger.hunger < 20)
                this.agent.SetGoal<WanderGoal>(true);
        }
    }
}
```

{% endcode %}

## Events

`AgentBehaviour` offers several events that notify developers when the agent alters its goal or action. These events can be instrumental in managing agent behaviors and responses.

### Example

{% code title="EventExample.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;

namespace Demos.Complex.Behaviours
{
    public class EventExample : MonoBehaviour
    {
        private AgentBehaviour agent;

        private void Awake()
        {
            this.agent = this.GetComponent<AgentBehaviour>();
        }

        private void OnEnable()
        {
            this.agent.Events.OnActionStart += this.OnActionStart;
            this.agent.Events.OnActionStop += this.OnActionStop;
            this.agent.Events.OnGoalStart += this.OnGoalStart;
            this.agent.Events.OnNoActionFound += this.OnNoActionFound;
            this.agent.Events.OnGoalCompleted += this.OnGoalCompleted;
        }

        private void OnDisable()
        {
            this.agent.Events.OnActionStart -= this.OnActionStart;
            this.agent.Events.OnActionStop -= this.OnActionStop;
            this.agent.Events.OnGoalStart -= this.OnGoalStart;
            this.agent.Events.OnNoActionFound -= this.OnNoActionFound;
            this.agent.Events.OnGoalCompleted -= this.OnGoalCompleted;
        }

        private void OnActionStart(IActionBase action)
        {
            // Gets called when an action is started
        }

        private void OnActionStop(IActionBase action)
        {
            // Gets called when an action is stopped
            // This can be used to check for a new goal
        }

        private void OnGoalStart(IGoalBase goal)
        {
            // Gets called when a goal is started
        }

        private void OnGoalCompleted(IGoalBase goal)
        {
            // Gets called when a goal is completed
        }

        private void OnNoActionFound(IGoalBase goal)
        {
            // Gets called when no action is found for a goal
            // This can be used to add a backup goal for example
        }
    }
}
```

{% endcode %}

{% code title="AgentMoveBehaviour.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Interfaces;
using UnityEngine;

public class AgentMoveBehaviour : MonoBehaviour
{
    private AgentBehaviour agent;
    private ITarget currentTarget;
    private bool shouldMove;

    private void Awake()
    {
        this.agent = this.GetComponent<AgentBehaviour>();
    }

    private void OnEnable()
    {
        this.agent.Events.OnTargetInRange += this.OnTargetInRange;
        this.agent.Events.OnTargetChanged += this.OnTargetChanged;
        this.agent.Events.OnTargetOutOfRange += this.OnTargetOutOfRange;
    }

    private void OnDisable()
    {
        this.agent.Events.OnTargetInRange -= this.OnTargetInRange;
        this.agent.Events.OnTargetChanged -= this.OnTargetChanged;
        this.agent.Events.OnTargetOutOfRange -= this.OnTargetOutOfRange;
    }

    private void OnTargetInRange(ITarget target)
    {
        this.shouldMove = false;
    }

    private void OnTargetChanged(ITarget target, bool inRange)
    {
        this.currentTarget = target;
        this.shouldMove = !inRange;
    }

    private void OnTargetOutOfRange(ITarget target)
    {
        this.shouldMove = true;
    }

    public void Update()
    {
        if (!this.shouldMove)
            return;
        
        if (this.currentTarget == null)
            return;
        
        this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(this.currentTarget.Position.x, this.transform.position.y, this.currentTarget.Position.z), Time.deltaTime);
    }
}
```

{% endcode %}


# GoapSet

A `GoapSet` is a collection of all possible `Goals` and `Actions` that an agent can utilize. By using different `GoapSets`, you can customize the behavior of various agents, allowing each to have its unique set of `Goals` and `Actions`.

![GoapSet Configuration Screenshot](/files/XnTRPhOecV59vnsf3ilq)

## GoapSet Config

The `GoapSetConfig` is the tool used to define and organize a `GoapSet`. It comprises several properties that detail the available configurations for an agent:

### 1. Goals

**Description**: Goals represent the objectives or desires of an agent. They define what the agent wants to achieve.

This property holds a list of `GoalConfigs`, detailing the various objectives an agent can pursue.

### 2. Actions

**Description**: Actions are the tasks or behaviors an agent can perform. They are the means by which an agent tries to achieve its goals.

This property contains a list of `ActionConfigs`, outlining the set of actions available for the agent to execute.

### 3. Target Sensors

**Description**: Target Sensors help the agent identify and locate important positions or objects in the game world. They can point to static locations or dynamic entities that might move.

This is a list of `TargetSensorConfigs`, assisting the agent in determining key positions or targets it should be aware of.

### 4. World Sensors

**Description**: World Sensors allow the agent to perceive and understand various states or situations in the game. They provide the agent with information about the environment, helping it make informed decisions.

This property holds a list of `WorldSensorConfigs`, enabling the agent to gather data about the game's current state.

By configuring the `GoapSetConfig` appropriately, you can tailor the behavior and capabilities of agents, ensuring they act and react in ways that suit the game's requirements.

***

## Agent Debugger Class

By defining an agent debugger class you can customize the data show in the node viewer in the `Agent data` box. The agent debugger class must inherit from `IAgentDebugger` and be assigned to the property.

{% code title="AgentDebugger.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Interfaces;
using Demos.Shared.Behaviours;

public class AgentDebugger : IAgentDebugger
{
    public string GetInfo(IMonoAgent agent, IComponentReference references)
    {
        var hunger = references.GetCachedComponent<HungerBehaviour>();
        
        return $"Hunger: {hunger.hunger}";
    }
}
```

{% endcode %}


# Sensors

Sensors help the GOAP system understand the current game situation.

There are two main types of sensors: `WorldSensor` and `TargetSensor`.

## Global vs. Local Sensors

Sensors can work in two modes: `Global` or `Local`.

* **Global**: These sensors give information for all agents. For instance, `IsDaytimeSensor` checks if it's day or night for everyone.
* **Local**: These sensors check only when the `Planner` runs. They give information for just one agent. For example, `ClosestAppleSensor` finds the nearest apple for a specific agent.

## WorldSensor

`WorldSensor` checks the game's situation for an agent. It uses `WorldKey` to show each situation. The `Planner` uses this to pick the best action.

Examples:

* `IsHungrySensor` checks if the agent is hungry.
* `HasAppleSensor` checks if the agent has an apple.

### Example

To create a new `WorldSensor`, create a new class that inherits from `LocalWorldSensorBase` or `GlobalWorldSensorBase` and implement its `Sense` method.

{% code title="IsHungrySensor.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes;
using CrashKonijn.Goap.Classes.References;
using CrashKonijn.Goap.Sensors;
using Demos.Shared.Behaviours;

namespace Demos.Simple.Sensors.World
{
    public class IsHungrySensor : LocalWorldSensorBase
    {
        public override void Created()
        {
        }

        public override void Update()
        {
        }

        public override SenseValue Sense(IMonoAgent agent, IComponentReference references)
        {
            // References are cached by the agent.
            var hungerBehaviour = references.GetComponent<HungerBehaviour>();

            if (hungerBehaviour == null)
                return false;

            return hungerBehaviour.hunger > 20;
        }
    }
}
```

{% endcode %}

## TargetSensor

`TargetSensor` finds a position for a `TargetKey`. The `Planner` uses this to know how far actions are.

There are two kinds of `Target`: `TransformTarget` and `PositionTarget`.

* **TransformTarget**: Use this when the target can move. For example, `ClosestEnemySensor` finds a moving enemy.
* **PositionTarget**: Use this for a fixed spot. Like, `WanderTargetSensor` finds a random spot that doesn't move.

### Example

To create a new `TargetSensor`, create a new class that inherits from `LocalTargetSensorBase` or `GlobalTargetSensorBase` and implement its `Sense` method.

{% code title="ClosestAppleSensor.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes;
using CrashKonijn.Goap.Classes.References;
using CrashKonijn.Goap.Interfaces;
using CrashKonijn.Goap.Sensors;
using Demos.Simple.Behaviours;
using UnityEngine;

namespace Demos.Simple.Sensors.Target
{
    public class ClosestAppleSensor : LocalTargetSensorBase
    {
        private AppleCollection apples;

        public override void Created()
        {
            this.apples = GameObject.FindObjectOfType<AppleCollection>();
        }

        public override void Update()
        {
        }

        public override ITarget Sense(IMonoAgent agent, IComponentReference references)
        {
            var closestApple = this.apples.Get().Closest(agent.transform.position);

            if (closestApple is null)
                return null;
            
            return new TransformTarget(closestApple.transform);
        }
    }
}
```

{% endcode %}

{% code title="WanderTargetSensor.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes;
using CrashKonijn.Goap.Classes.References;
using CrashKonijn.Goap.Interfaces;
using CrashKonijn.Goap.Sensors;
using UnityEngine;

namespace Demos.Simple.Sensors.Target
{
    public class WanderTargetSensor : LocalTargetSensorBase
    {
        private static readonly Vector2 Bounds = new Vector2(15, 8);

        public override void Created()
        {
        }

        public override void Update()
        {
        }

        public override ITarget Sense(IMonoAgent agent, IComponentReference references)
        {
            var random = this.GetRandomPosition(agent);
            
            return new PositionTarget(random);
        }

        private Vector3 GetRandomPosition(IMonoAgent agent)
        {
            var random =  Random.insideUnitCircle * 5f;
            var position = agent.transform.position + new Vector3(random.x, 0f, random.y);
            
            if (position.x > -Bounds.x && position.x < Bounds.x && position.z > -Bounds.y && position.z < Bounds.y)
                return position;

            return this.GetRandomPosition(agent);
        }
    }
}
```

{% endcode %}


# TargetKeys

`TargetKeys` play a pivotal role in the GOAP system by specifying positions or locations within the game environment. These keys help the `Planner` calculate the distance (and added cost) between `Actions` and the precise location an `Agent` needs to reach before executing a particular action.

Each `TargetKey` is associated with a `TargetSensor`. This sensor is responsible for determining and providing the exact position corresponding to the `TargetKey`. In essence, while the `TargetKey` acts as a label or identifier for a location, the `TargetSensor` ensures that this label is mapped to a valid and up-to-date position in the game world.

## Creating a TargetKey

### Using ScriptableObject:

1. In the Unity editor, right-click on a desired folder.
2. Navigate to `Create > Goap > TargetKey` to generate a new `TargetKey`.

### Using Code:

To programmatically create a new `TargetKey`, you'll need to define a new class that inherits from the `TargetKeyBase` class.

#### Example:

{% code title="WanderTarget.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;

public class WanderTarget : TargetKeyBase
{
}
```

{% endcode %}


# WorldKeys

`WorldKeys` are important in the GOAP system. They point to specific things or situations in the game. The `Planner` uses these keys to decide what `Action` an agent should do next.

Each `WorldKey` is connected to a `WorldSensor`. This sensor checks and gives the current value for its `WorldKey`. So, the `WorldKey` tells us what to look for, and the `WorldSensor` tells us the current value of that thing in the game.

## Creating a WorldKey

### Using ScriptableObject:

1. In the Unity editor, right-click on the folder you want.
2. Go to `Create > Goap > WorldKey` to make a new `WorldKey`.

### Using Code:

You can also make a new `WorldKey` by writing a class that uses the `WorldKeyBase` class.

#### Example:

{% code title="IsHungry.cs" lineNumbers="true" %}

```csharp
using CrashKonijn.Goap.Behaviours;

public class IsHungry : WorldKeyBase
{
}
```

{% endcode %}


# General


# WorldState

{% hint style="warning" %}
**Don't use the GOAP WorldState as a source of truth!** In the GOAP system, sensors update the agent's WorldState only when deciding the next action. This means the WorldState can often be outdated. Additionally, using just integers for the WorldState can oversimplify complex situations. For better accuracy and real-time updates, agents should store their data in dedicated MonoBehaviours.
{% endhint %}

## Enhanced GOAP with Integer Values:

In traditional GOAP implementations, the world state is often represented using string keys paired with boolean values. This can lead to redundancy, as multiple keys might be needed to represent related states. By transitioning to integer values, the GOAP system becomes more compact, versatile, and expressive.

### Conditions with Integer Values:

Conditions, which are the prerequisites or requirements for an action to be executed, benefit immensely from this shift:

* **Granular Checks**: Instead of binary checks like "Is the health low?", conditions can now evaluate a spectrum of values, such as:
  * **Health**: `< 30` (Is the health below 30?)
  * **Health**: `>= 70` (Is the health 70 or above?)
* **Comparison Types**: Conditions utilize specific comparison types (like SmallerThan, GreaterThanOrEqual, etc.) to evaluate the integer values of the `WorldKeys`. This allows for diverse condition checks, enabling actions to be contingent on specific thresholds.
* **Absence of "Equals" Comparison**: Notably, there isn't an "Equals" comparison in this system. The primary reason is that "Equals" doesn't indicate direction. In the GOAP system, especially with integer values, understanding the direction of change is crucial. For instance, knowing whether a value needs to increase or decrease to satisfy a condition is essential for planning actions. An "Equals" comparison would be ambiguous in this context, as it wouldn't provide clear guidance on which actions are needed to achieve the desired state.

### Effects with Integer Values:

Effects, which describe the changes an action brings about in the game's state, also gain enhanced expressiveness:

* **Direct Modification**: Instead of toggling boolean states, actions can directly modify integer values. For instance, an action might:
  * **Increase** the "Health" key, representing healing.
  * **Decrease** the "AmmoCount" key, signifying using ammunition.
* **Unified Representation**: Actions that have opposite effects on the same state can be represented using the same `WorldKey`. For example, both healing and taking damage modify the "Health" key, but in opposite directions.

### Benefits:

1. **Reduced Redundancy**: A single integer-based `WorldKey` can represent a range of states, eliminating the need for multiple boolean keys.
2. **Greater Expressiveness**: Conditions and effects can capture a spectrum of values, allowing for nuanced decision-making.
3. **Simplified Logic**: Evaluating conditions and predicting action outcomes become more straightforward with integer values and defined comparison/effect types.
4. **Consistency**: The risk of conflicting or ambiguous world states is reduced, ensuring a more reliable planning process.

### In Summary:

The shift to integer values in the GOAP system offers a more compact and versatile representation of world states, conditions, and effects. By combining integer values with specific comparison and effect types, and by deliberately omitting an "Equals" comparison, the system ensures clarity in action planning. This approach provides AI agents with a broader and more flexible decision-making framework, enabling more informed and context-aware behaviors.


# Conditions & Effects

## Conditions

Conditions are essentially the prerequisites or requirements that need to be met for an action to be executed. They are tied to the game's state, represented by `WorldKey`.

* **Key**: This is the `WorldKey` that the condition checks. Think of it as a variable or a state in the game world, like "PlayerHealth" or "HasAmmo."
* **Comparison**: This is how the `WorldKey` is compared to a specific value to determine if the condition is met. The available comparisons are "SmallerThan," "SmallerThanOrEqual," "GreaterThan," and "GreaterThanOrEqual."
* **Value**: This is the specific value that the `WorldKey` is compared against using the specified comparison.

For example, a condition might be set up like this:

* **Key**: PlayerHealth
* **Comparison**: GreaterThan
* **Value**: 50

This condition checks if the player's health is greater than 50.

## Effects

Effects describe the changes that an action brings about in the game's state, again represented by `WorldKey`.

* **Key**: This is the `WorldKey` that the effect modifies. For instance, "PlayerHealth" or "AmmoCount."
* **Type**: This indicates whether the `WorldKey` value will increase or decrease as a result of the action.

For instance, an effect might be:

* **Key**: AmmoCount
* **Type**: Decrease

This effect would decrease the ammo count when the action is executed.

## Matching Conditions and Effects

The system matches conditions and effects to determine the sequence of actions that lead to a goal. Here's how the matching works based on the provided documentation:

* **SmallerThan** and **SmallerThanOrEqual** comparisons in conditions look for actions with **negative effects**. This means if a condition requires a `WorldKey` to be less than a certain value, the system will look for actions that decrease that `WorldKey`.
* **GreaterThan** and **GreaterThanOrEqual** comparisons in conditions look for actions with **positive effects**. So, if a condition requires a `WorldKey` to be greater than a certain value, the system will search for actions that increase that `WorldKey`.

For example, if there's a condition that checks if "AmmoCount" is `SmallerThan` 5, the system might look for an action with a negative effect on "AmmoCount" (like "ShootBullet"). Conversely, if the condition checks if "AmmoCount" is `GreaterThan` 10, the system might look for an action with a positive effect on "AmmoCount" (like "ReloadGun").

In essence, the GOAP system uses these conditions and effects to build a graph of possible actions and sequences, which is then used by the planner to determine the best course of action to achieve a goal.

## Examples

Setting conditions and effects through code.

{% code title="Creat" lineNumbers="true" %}

```csharp
var builder = new GoapSetBuilder("GettingStartedSet");

builder.AddAction<ShootBullet>()
           .AddCondition<AmmoCount>(Comparison.GreaterThanOrEqual, 1)
           .AddEffect<AmmoCount>(false)
```

{% endcode %}

Setting conditions and effects through the inspector.

![action-config.png](/files/laSjEaWksMKonKVqPtio)


# Data Injection

**Data Injection** is a design pattern where an external system provides runtime data to another object or module. In the context of the Goal-Oriented Action Planning (GOAP) system, injection is used to provide specific scene data or dependencies to the core classes (`Goals`, `Actions`, and `Sensors`) managed by the GOAP system.

## Why is Data Injection Needed?

1. **Decoupling**: GOAP classes are designed to be generic and reusable. By injecting specific data or dependencies from the scene or other systems, you can customize their behavior without modifying their core logic. This separation ensures that the GOAP system remains modular and maintainable.
2. **Flexibility**: Different scenes or game scenarios might require different data or behaviors. Injection allows you to provide the necessary context to the GOAP classes, enabling them to adapt to various game situations.
3. **Integration with Third-party Libraries**: By using injection, you can easily integrate third-party libraries or systems with the GOAP framework. For instance, the documentation mentions integrating Zenject, a popular dependency injection framework in Unity.

## How Does It Work?

1. **Creating an Injector**: You create a `MonoBehaviour` class that implements the `IGoapInjector` interface. This class will contain methods that are called right after each GOAP class (`Goal`, `Action`, or `Sensor`) is instantiated. Within these methods, you can provide the necessary data or dependencies to the GOAP classes.
2. **Connecting the Injector**: To let the GOAP system know about your custom injector, you create a class extending `GoapConfigInitializerBase` and bind it to the `GoapRunnerBehaviour` component in the scene. This ensures that your injector is used instead of the default one.

## Example

In the provided example, the `GoapInjector` class is an injector that provides specific scene data (`ItemFactory`, `ItemCollection`, and `InstanceHandler`). The `CreateItemAction` class is an example of a GOAP action that requires this scene data. The method of signaling the injector to provide the necessary data can vary, and the `IInjectable` interface is just one possible approach.

{% code title="GoapInjector.cs" %}

```csharp
using CrashKonijn.Goap.Interfaces;

public class GoapInjector : MonoBehaviour, IGoapInjector
{
    public ItemFactory itemFactory;
    public ItemCollection itemCollection;
    public InstanceHandler instanceHandler;
    
    public void Inject(IActionBase action)
    {
        if (action is IInjectable injectable)
            injectable.Inject(this);
    }

    public void Inject(IGoalBase goal)
    {
    }

    public void Inject(IWorldSensor worldSensor)
    {
    }

    public void Inject(ITargetSensor targetSensor)
    {
    }
}
```

{% endcode %}

{% code title="CreateItemAction.cs" %}

```csharp
namespace Demos.Complex.Actions
{
    public class CreateItemAction<TCreatable> : ActionBase<CreateItemAction<TCreatable>.Data>, IInjectable
        where TCreatable : ItemBase, ICreatable
    {
        private ItemFactory itemFactory;
        private InstanceHandler instanceHandler;

        public void Inject(GoapInjector injector)
        {
            this.itemFactory = injector.itemFactory;
            this.instanceHandler = injector.instanceHandler;
        }
        
        // rest of class
    }
}
```

{% endcode %}

## Connecting the injector

In order to let the GOAP know you'd like to overwrite one of it's core settings, the `IGoapInjector` in this case you need to create a class that extends `GoapConfigInitializerBase`.

Add the script to the scene and bind it to the `GoapConfigInitializer` property of the `GoapRunnerBehaviour` component.

![Goap Config Initializer](/files/9sMyF9PVs8Kpfmlb3Z1l)

### Example

{% code title="GoapConfigInitializer.cs" %}

```csharp
using CrashKonijn.Goap.Behaviours;
using CrashKonijn.Goap.Classes;

namespace Demos.Complex.Goap
{
    public class GoapConfigInitializer : GoapConfigInitializerBase
    {
        public override void InitConfig(GoapConfig config)
        {
            config.GoapInjector = this.GetComponent<GoapInjector>();
        }
    }
}
```

{% endcode %}

## Zenject

It's very easy to use Zenject with the GOAP. The GOAP has a built-in injector that can be used to inject Zenject dependencies into the GOAP classes.

{% code title="ZenjectGoapInjector.cs" %}

```csharp
using CrashKonijn.Goap.Interfaces;
using UnityEngine;
using Zenject;

public class ZenjectGoapInjector : MonoBehaviour, IGoapInjector
{
    private DiContainer container;

    [Inject]
    private void Construct(DiContainer container)
    {
        this.container = container;
    }
    
    public void Inject(IActionBase action)
    {
        this.container.Inject(action);
    }

    public void Inject(IGoalBase goal)
    {
        this.container.Inject(goal);
    }

    public void Inject(IWorldSensor worldSensor)
    {
        this.container.Inject(worldSensor);
    }

    public void Inject(ITargetSensor targetSensor)
    {
        this.container.Inject(targetSensor);
    }
}
```

{% endcode %}


# Life Cycles

## Agent

![Agent.Run](/files/9YWax7S5K5mhPkH31yMg) ![Agent.SetGoal](/files/GCHTS930YOU0yJjzjN2t) ![Agent.SetAction](/files/WbUdYSdtMnkq8IwcA4GR)

## GoapRunner and GoapSet

![GoapRunner.Run](/files/bQhisZOk2n63LxYiX5BF) ![GoapRunner.Complete](/files/NmyLOBphRCCsltfGylfc)


# NodeViewer

The `node viewer` is a tool that can be used to visualize the `Planner`'s graph. It can be used to debug the `Planner` and to see what the `Planner` is doing for a given agent.

The `node viewer` can be accessed through `Tools/GOAP/Node Viewer`.

![Screenshot of NodeViewer](/files/DXE50WLMN5c7gLxS9lIu)


# Examples


# Simple

The simple example use `ScriptableObject` as the configuration method. This is the easiest way to get started with GOAP. The demo scene can be found in `Demos/Simple/Scenes/SimpleDemo.unity`.

Each agent has 2 separate goals: `WanderGoal` and `FixHungerGoal`. The `WanderGoal` will make the agent wander around the scene. The `FixHungerGoal` will make the agent eat apples. The agent will only eat apples if it is hungry. The agent will only wander if it is not hungry.

Goals:

* WanderGoal
* FixHungerGoal

Actions:

* WanderAction
* EatAppleActions
* PickupAppleAction
* PluckAppleAction

## Rules

If the agent has a `hunger > 80`, it will switch to the `FixHungerGoal`. If the agent has a `hunger < 20`, it will switch to the `WanderGoal`.

![Simple Demo Graph](/files/ETmlHI0uKs5GpYmD7AAi)


# Complex

The complex example uses code as the configuration method. The demo scene can be found in `Demos/Complex/Scenes/ComplexDemoScene.unity`.

There are 4 type of agents:

* Cleaner (Orange). They grab items laying on the floor and bring them to boxes.
* Smith (Blue). When there are enough materials he will craft an `Axe` or `Pickaxe`. He needs `Wood` and `Iron` to craft the tools.
* WoodCutter (Green). When there isn't enough `Wood` in the world, they will chop wood from trees.
* Miner (Pink). When there isn't enough `Iron` in the world, they will mine iron from rocks.

Each agent has 2 base goals: `WanderGoal` and `FixHungerGoal`. The `WanderGoal` will make the agent wander around the scene. The `FixHungerGoal` will make the agent eat apples. The agent will only eat apples if it is hungry. The agent will only wander if it is not hungry.

## Cleaner

The goap set builder can be found in `Demos/Complex/Factories/CleanerGoapSetConfigFactory.cs`.

![Clenaer graph](/files/NF959T77I1e7sbYaTg1B)

## Smith

The goap set builder can be found in `Demos/Complex/Factories/SmithGoapSetConfigFactory.cs`.

![Smith graph](/files/mbcmx00d9vFIgy6SKVRa)

## Wood Cutter

The goap set builder can be found in `Demos/Complex/Factories/WoodCutterGoapSetConfigFactory.cs`.

![Wood Cutter graph](/files/8uFCVFPUuswsj2aDLXI2)

## Miner

The goap set builder can be found in `Demos/Complex/Factories/MinerGoapSetConfigFactory.cs`.

![Wood Cutter graph](/files/qPGTjW452dJzjOXfdGfC)


