IndexOutOfRangeException - Pathfinding.ECS.ManagedState.PopNextLinkFromPath ()

Hi, I’m getting this exception at random when AI is traversing the off mesh links. It seems to be quite random. I’m attaching log from exception and my custom off mesh link handler.

Astar version = 5.3.8

Unity version = 6.0.58f2

Log:

IndexOutOfRangeException: Index was outside the bounds of the array.
Pathfinding.PathTracer.GetPartType (System.Int32 partIndex) (at ./Packages/com.arongranberg.astar/Utilities/PathTracer.cs:1601)
Pathfinding.ECS.ManagedState.PopNextLinkFromPath () (at ./Packages/com.arongranberg.astar/Core/ECS/Components/ManagedState.cs:191)
Pathfinding.ECS.JobManagedOffMeshLinkTransition.MoveNext (Unity.Entities.Entity entity, Pathfinding.ECS.ManagedState state, Unity.Transforms.LocalTransform& transform, Pathfinding.ECS.AgentMovementPlane& movementPlane, Pathfinding.ECS.MovementControl& movementControl, Pathfinding.ECS.MovementSettings& movementSettings, Pathfinding.ECS.AgentOffMeshLinkTraversal& linkInfo, Pathfinding.ECS.ManagedAgentOffMeshLinkTraversal managedLinkInfo, Unity.Entities.EnabledRefRW1[T] movementDisabled, System.Single deltaTime) (at ./Packages/com.arongranberg.astar/Core/ECS/Jobs/JobManagedOffMeshLinkTransition.cs:82) Pathfinding.ECS.JobManagedOffMeshLinkTransition.Execute (Unity.Entities.Entity entity, Pathfinding.ECS.ManagedState state, Unity.Transforms.LocalTransform& transform, Pathfinding.ECS.AgentMovementPlane& movementPlane, Pathfinding.ECS.MovementControl& movementControl, Pathfinding.ECS.MovementSettings& movementSettings, Pathfinding.ECS.AgentOffMeshLinkTraversal& linkInfo, Pathfinding.ECS.ManagedAgentOffMeshLinkTraversal managedLinkInfo, Unity.Entities.EnabledRefRW1[T] movementDisabled) (at ./Packages/com.arongranberg.astar/Core/ECS/Jobs/JobManagedOffMeshLinkTransition.cs:18)
Pathfinding.ECS.JobManagedOffMeshLinkTransition.Execute (Unity.Entities.ArchetypeChunk& chunk, System.Int32 chunkIndexInQuery, System.Boolean useEnabledMask, Unity.Burst.Intrinsics.v128& chunkEnabledMask) (at ./JobEntityGenerator/Unity.Entities.SourceGen.JobEntityGenerator.JobEntityGenerator/Temp/GeneratedCode/AstarPathfindingProject/JobManagedOffMeshLinkTransition__JobEntity_112353378111.g.cs:42)
Pathfinding.ECS.JobManagedOffMeshLinkTransition.Unity.Entities.IJobChunk.Execute (Unity.Entities.ArchetypeChunk& chunk, System.Int32 unfilteredChunkIndex, System.Boolean useEnabledMask, Unity.Burst.Intrinsics.v128& chunkEnabledMask) (at <60c022f740d44e50aa0026e5df261358>:0)
Unity.Entities.JobChunkExtensions.RunByRefWithoutJobs[T] (T& jobData, Unity.Entities.EntityQuery query) (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/IJobChunk.cs:271)
Unity.Entities.Internal.InternalCompilerInterface+JobChunkInterface.RunByRefWithoutJobs[T] (T& jobData, Unity.Entities.EntityQuery query) (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/Internal/InternalCompilerInterface.cs:495)
Pathfinding.ECS.RepairPathSystem.__ScheduleViaJobChunkExtension_3 (Pathfinding.ECS.JobManagedOffMeshLinkTransition job, Unity.Entities.EntityQuery query, Unity.Jobs.JobHandle dependency, Unity.Entities.SystemState& state, System.Boolean hasUserDefinedQuery) (at ./SystemGenerator/Unity.Entities.SourceGen.SystemGenerator.SystemGenerator/Temp/GeneratedCode/AstarPathfindingProject/RepairPathSystem__System_16699096710.g.cs:552)
Pathfinding.ECS.RepairPathSystem.ProcessActiveOffMeshLinkTraversal (Unity.Entities.SystemState& systemState) (at ./Packages/com.arongranberg.astar/Core/ECS/Systems/RepairPathSystem.cs:234)
Pathfinding.ECS.RepairPathSystem.OnUpdate (Unity.Entities.SystemState& systemState) (at ./Packages/com.arongranberg.astar/Core/ECS/Systems/RepairPathSystem.cs:83)
Pathfinding.ECS.RepairPathSystem.__codegen__OnUpdate (System.IntPtr self, System.IntPtr state) (at <60c022f740d44e50aa0026e5df261358>:0)
Unity.Entities.SystemBaseRegistry+<>c__DisplayClass9_0.b__0 (System.IntPtr system, System.IntPtr state) (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/SystemBaseRegistry.cs:249)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/Stubs/Unity/Debug.cs:17)
Unity.Entities.<>c__DisplayClass9_0:b__0(IntPtr, IntPtr) (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/SystemBaseRegistry.cs:253)
Unity.Entities.UnmanagedUpdate_00001677$BurstDirectCall:wrapper_native_indirect_00000211F7DC82B0(IntPtr&, Void*)
Unity.Entities.UnmanagedUpdate_00001677$BurstDirectCall:Invoke(Void*)
Unity.Entities.WorldUnmanagedImpl:UnmanagedUpdate(Void*)
Unity.Entities.WorldUnmanagedImpl:UpdateSystem(SystemHandle) (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/WorldUnmanaged.cs:891)
Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/ComponentSystemGroup.cs:717)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/ComponentSystemGroup.cs:687)
Pathfinding.ECS.AIMovementSystemGroup:OnUpdate() (at ./Packages/com.arongranberg.astar/Core/ECS/Systems/AIMovementSystemGroup.cs:188)
Unity.Entities.SystemBase:Update() (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/SystemBase.cs:418)
Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/ComponentSystemGroup.cs:723)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/ComponentSystemGroup.cs:681)
Unity.Entities.SystemBase:Update() (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/SystemBase.cs:418)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at ./Library/PackageCache/com.unity.entities@e581b903be8e/Unity.Entities/ScriptBehaviourUpdateOrder.cs:523)

OffMeshLinkHandler:

        private void OnEnable()
        {
            if (TryGetComponent(out FollowerEntity ai))
                ai.onTraverseOffMeshLink = this;
        }

        private void OnDisable()
        {
            if (TryGetComponent(out FollowerEntity ai))
                ai.onTraverseOffMeshLink = null;
        }

        public IOffMeshLinkStateMachine GetOffMeshLinkStateMachine(AgentOffMeshLinkTraversalContext context)
        {
            return this;
        }

        public IEnumerable OnTraverseOffMeshLink(AgentOffMeshLinkTraversalContext context)
        {
            context.enableBuiltInMovement = false;

            var linkStartPosition = (Vector3)context.transform.Position;
            var linkEndPosition = AIUtils.SampleNavMesh(context.link.relativeEnd, out var hit, navMeshSampleDistance, navMeshAgent.Constraint)
                ? hit.position
                : context.link.relativeEnd;
            var diff = linkEndPosition - linkStartPosition;
            // find target rotation
            var startRotation = context.transform.Rotation;
            var targetRotation = quaternion.LookRotation(new Vector3(diff.x, 0f, diff.z).normalized, Vector3.up);

            float timer = 0f;
            float lerpDuration = Mathf.Max(diff.magnitude / navMeshAgent.speed, 0.1f); // at least 0.1s
            float rotationLerpDuration = Mathf.Min(lerpDuration, rotationDuration);
            while (timer < lerpDuration)
            {
                timer += Time.deltaTime;
                float lerpValue = timer / lerpDuration;
                float rotationLerpValue = Mathf.Clamp01(timer / rotationLerpDuration);

                // lerp movement
                var start = linkStartPosition;
                var end = linkEndPosition;
                var position = Vector3.Lerp(start, end, lerpValue);
                var rotation = math.slerp(startRotation, targetRotation, rotationLerpValue);

                context.transform.Position = position;
                context.transform.Rotation = rotation;
                yield return null;
            }

            yield break;
        }

        public void OnFinishTraversingOffMeshLink(AgentOffMeshLinkTraversalContext context)
        {
            context.enableBuiltInMovement = true;
        }

        public void OnAbortTraversingOffMeshLink()
        {

        }

Thank you for the bug report.

Do you think you could try to upgrade to the latest version of the package and see if the issue still persists?

Hey, looks like updating solved the problem.

Thanks for help.

1 Like

I’m on the latest version and I am getting this error also in a similar situation. It happens maybe once every 5-10 times that it uses the same NodeLink2 so I guess there is a race condition. Here is our OnTraverseOffMeshLink:

IEnumerable IOffMeshLinkStateMachine.OnTraverseOffMeshLink(AgentOffMeshLinkTraversalContext context) {
        context.enableBuiltInMovement = false;

        while (!context.MoveTowards(
            context.link.relativeStart,
            context.link.isReverse
                ? Link.EndTransform.rotation
                : Link.StartTransform.rotation,
            true,
            true).reached) {
            yield return null;
        }

        // Something else must have opened the door
        if (State != (byte)DoorState.Closed) yield break;

        // Open the door based on the direction the AI is traversing the link.
        // Note: This will cause UpdateGraph() to fire which updates the graph and disables the link.
        State = context.link.isReverse ? (byte)DoorState.OpenBackward : (byte)DoorState.OpenForward;

        float traverseTime = Time.time;

        if (BreakableObject != null &&
            !IsDestroyed &&
            context.gameObject.TryGetComponent(out CreatureController creatureController) &&
            creatureController.CanBreakDoor) {

            BreakableObject.PushDirection = State == (byte)DoorState.OpenBackward ? Vector3.back : Vector3.forward;
            BreakableObject.BreakObject();
            IsDestroyed = true;
        }
        else {
            bool didSetTime = false;
            if (context.gameObject.TryGetComponent(out BehaviorGraphAgent agent)) {
                if (agent.GetVariable("State", out BlackboardVariable<CreatureState> state)) {
                    if (state.Value is CreatureState.Chase) {
                        traverseTime += Random.Range(0.2f, 0.5f);
                        didSetTime = true;
                    }
                }
            }

            if (!didSetTime) {
                traverseTime += Random.Range(0.75f, 1f);
            }
        }

        // Important: The code below is required to ensure that this IEnumerable doesn't yield immediately.
        // It allows the creature to wait as the door opens and then transition through to the end of the link.
        // Note: We rush past this if the door was forcefully destroyed by the creature
        while (Time.time < traverseTime) yield return null;
        while (AstarPath.active.IsAnyGraphUpdateQueued || AstarPath.active.IsAnyGraphUpdateInProgress || AstarPath.active.IsAnyWorkItemInProgress) yield return null;
    }

    public void OnFinishTraversingOffMeshLink(AgentOffMeshLinkTraversalContext context) {
        context.enableBuiltInMovement = true;
    }

The only way I could reliably get the error to not show seemed to be changing code in ManagedState:

cc @aron_granberg

Hi

I have not been able to replicate this.

Does removing the graph updates make it always work?

If you see it again, could you post the stack trace that you get?