# AddDependency(JobHandle)

> Tells the NavMesh world to halt any changes until the specified job is completed.

## Definition

* **Type:** Method
* **Namespace:** [Unity.AI.Navigation.LowLevel](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel.md)
* **Assembly:** UnityEngine.AIModule

```csharp
public readonly void AddDependency(JobHandle job)
```

### Parameters

**** (\[JobHandle]\(/engine/6000.5/script-reference/unity/jobs/jobhandle)): The job to complete before the NavMesh world changes in any way.

### Remarks

When jobs process [NavWorld](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navworld.md) operations, it is essential that the NavMesh data doesn't change. Every time you schedule a job that contains NavWorld operations, call this method to pass the job's [JobHandle](/engine/6000.5/script-reference/unity/jobs/jobhandle.md) to the NavWorld. Otherwise, in the Editor, Unity logs an error and forces the job to complete before it allows the NavMesh data to change.

Additional Resources: [IJob](/engine/6000.5/script-reference/unity/jobs/ijob.md), [IJobFor](/engine/6000.5/script-reference/unity/jobs/ijobfor.md)

### Examples

```csharp
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using Unity.AI.Navigation.LowLevel;

public class NavWorldDependencyExample : MonoBehaviour
{
    public Transform target;

    struct MapPositionJob : IJob
    {
        public NavWorld world;
        public Vector3 position;
        public NativeArray<NavLocation> result;

        public void Execute()
        {
            result[0] = world.MapLocation(position, Vector3.one, 0);
        }
    }

    void Update()
    {
        using NavWorld world = NavWorld.GetDefaultWorld();
        NativeArray<NavLocation> result = new NativeArray<NavLocation>(1, Allocator.TempJob);

        JobHandle handle = new MapPositionJob
        {
            world = world,
            position = target.position,
            result = result
        }.Schedule();

        // Prevent the NavMesh from being modified while the job runs. Call this from the main
        // thread only; AddDependency throws when it is called from inside a job.
        world.AddDependency(handle);

        // Complete the job before the world and the result buffer go out of scope.
        handle.Complete();
        result.Dispose();
    }
}
```

```csharp
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using Unity.AI.Navigation.LowLevel;

public class FindPathJobExample : MonoBehaviour
{
    // The node pool limits how many nodes a search can visit, and therefore also the
    // largest path it can return.
    const int k_MaxNodesToVisit = 1024;

    public Transform target;

    NavWorld m_World;
    NavQueryBuffer m_Buffer;
    NativeArray<int> m_PathSize;
    JobHandle m_SearchJob;
    bool m_JobScheduled;

    // Runs the search, but does not retrieve the path. The number of nodes in the result
    // is only known once the search has finished, so it is reported back to the caller.
    struct SearchPathJob : IJob
    {
        [ReadOnly]
        public NavWorld world;
        public NavQueryBuffer buffer;
        public NavLocation start;
        public NavLocation end;

        // Element 0 receives the number of nodes the path is made of.
        public NativeArray<int> pathSize;

        public void Execute()
        {
            pathSize[0] = 0;

            NavQueryStatus status = world.BeginFindPath(buffer, start, end);
            while ((status & NavQueryStatus.InProgress) != 0)
                status = world.ContinueFindPath(buffer, 64, out int _);

            if ((status & NavQueryStatus.Success) == 0)
                return;

            status = world.EndFindPath(buffer, out int pathSizeFound);
            if ((status & NavQueryStatus.Success) == 0)
                return;

            pathSize[0] = pathSizeFound;
        }
    }

    // Copies the path that the search left in the query buffer. Keeping this separate means
    // the destination array can be allocated to the exact size the search reported, so no
    // node is ever dropped.
    struct ReadPathJob : IJob
    {
        [ReadOnly]
        public NavWorld world;
        public NavQueryBuffer buffer;
        public NativeArray<NavNode> path;

        public void Execute()
        {
            world.GetResultFromFindPath(buffer, path);
        }
    }

    void OnEnable()
    {
        m_World = NavWorld.GetDefaultWorld();
        m_Buffer = new NavQueryBuffer(m_World, Allocator.Persistent, k_MaxNodesToVisit);
        m_PathSize = new NativeArray<int>(1, Allocator.Persistent);
    }

    void Update()
    {
        NavLocation start = m_World.MapLocation(transform.position, 5f *Vector3.one, 0);
        NavLocation end = m_World.MapLocation(target.position, 5f * Vector3.one, 0);
        if (!m_World.IsValid(start) || !m_World.IsValid(end))
            return;

        m_SearchJob = new SearchPathJob
        {
            world = m_World,
            buffer = m_Buffer,
            start = start,
            end = end,
            pathSize = m_PathSize
        }.Schedule();

        // Register the job so that nothing modifies the NavMesh while
        // the search runs. Call this from the main thread only, because
        // AddDependency throws when called from inside a job.
        m_World.AddDependency(m_SearchJob);
        m_JobScheduled = true;
    }

    void LateUpdate()
    {
        if (!m_JobScheduled)
            return;

        // Complete the search only where the result is needed, so that it overlaps with the
        // rest of the frame instead of blocking the main thread right after scheduling it.
        m_SearchJob.Complete();
        m_JobScheduled = false;

        int pathSize = m_PathSize[0];
        if (pathSize == 0)
            return;

        // EndFindPath reported how many nodes the path contains, so this array fits it exactly.
        NativeArray<NavNode> path = new NativeArray<NavNode>(pathSize, Allocator.TempJob);

        // EndFindPath leaves the result in the query buffer, so a later job can still copy it
        // out. Both jobs use the same buffer, so this one must never run at the same time as
        // the search. Retrieving the path is only a copy, which is why completing it right
        // away costs little compared to the search itself.
        JobHandle readJob = new ReadPathJob
        {
            world = m_World,
            buffer = m_Buffer,
            path = path
        }.Schedule();

        m_World.AddDependency(readJob);
        readJob.Complete();

        // The path is a corridor of nodes, not a list of waypoints. Draw the gate that each
        // pair of consecutive nodes shares to see the corridor the agent can move through.
        for (int i = 0; i < path.Length - 1; i++)
        {
            if (m_World.GetPortalPoints(path[i], path[i + 1], out Vector3 left, out Vector3 right))
                Debug.DrawLine(left, right, Color.magenta);
        }

        path.Dispose();
    }

    void OnDisable()
    {
        // Never dispose a container, or the world, while a job that uses it is still running.
        m_SearchJob.Complete();

        m_PathSize.Dispose();
        m_Buffer.Dispose();
        m_World.Dispose();
    }
}
```
