ArgumentOutOfRangeException for Native Lists

Hello all, I keep getting the error of

ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: Value -1 must be positive.
Unity.Collections.NativeList`1[T].CheckArgInRange (System.Int32 value, System.Int32 length) (at Library/PackageCache/com.unity.collections@0.9.0-preview.6/Unity.Collections/NativeList.cs:783)
Unity.Collections.NativeList`1[T].RemoveAtSwapBack (System.Int32 index) (at Library/PackageCache/com.unity.collections@0.9.0-preview.6/Unity.Collections/NativeList.cs:302)
X1Tools.Unity.Grid.Pathfinding.Advanced.DataOrientedAStar.Execute () (at Assets/Main Assets/Scripts/Enemies/Calculations/DataOrientedAStar.cs:122)
Unity.Jobs.IJobExtensions+JobStruct`1[T].Execute (T& data, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at <a979f18d51af41179d12b797e8c5be14>:0)

and I dont know where it’s coming from- any suggestions?

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;

namespace X1Tools.Unity.Grid.Pathfinding.Advanced
{
  
    public struct DataOrientedAStar : IJob
    {
        #region Variables

        /// <summary>
        /// Allows you to use the A* Pathfinding System with Unity Jobs
        /// This is much, much faster than the normal A* Pathfinding System.
        /// </summary>

        //Return type (Redacted until bugs resolved)
       // public NativeList<int2> result;
       

        //General inputs
        public int2 gridSize;
        public NativeList<int2> unwalkableAreas;

        //Specific inputs
        public int2 origin;
        public int2 destination;

        #endregion

        struct PathNode
        {
            public int originWeight;
            public int destinationWeight;
            public int totalWeight;

            public int x;
            public int y;

            public int index;
            public int previousNodeIndex;

            public void CalculateFCost()
            {
                totalWeight = originWeight + destinationWeight;
            }
        }

        public void Execute()
        {
            NativeArray<PathNode> entireGrid = new NativeArray<PathNode>(gridSize.x * gridSize.y, Allocator.Temp);

            for (int x = 0; x < gridSize.x; x++)
            {
                for (int y = 0; y < gridSize.y; y++)
                {
                    PathNode p = new PathNode
                    {
                        x = x,
                        y = y,

                        index = CalculateIndex(x, y, gridSize.x),

                        originWeight = CalculateOriginWeight(new int2(x,y)),
                        destinationWeight = CalculateDestinationWeight(new int2(x, y)),

                        previousNodeIndex = -1
                };

                    p.CalculateFCost();

                    entireGrid[p.index] = p;

                }
            }

            PathNode startNode = entireGrid[CalculateIndex(origin.x, origin.y, gridSize.x)];
            startNode.originWeight = 0;
            startNode.CalculateFCost();
            entireGrid[startNode.index] = startNode;

            int endNodeIndex = CalculateIndex(destination.x, destination.y, gridSize.x);

            NativeList<int> open = new NativeList<int>(Allocator.Temp);
            NativeList<int> closed = new NativeList<int>(Allocator.Temp);

            open.Add(startNode.index);

            while(open.Length > 0)
            {
                int currentNodeIndex = GetLowestFCostIndex(open,entireGrid);
                if (currentNodeIndex == endNodeIndex) { break; }

                closed.Add(currentNodeIndex);

                    open.RemoveAtSwapBack(open.IndexOf(currentNodeIndex));
               

                var surroundingTiles = GetSurroundingTiles(new int2(entireGrid[currentNodeIndex].x, entireGrid[currentNodeIndex].y));
               
                foreach (var i in surroundingTiles)
                {
                    if (!unwalkableAreas.Contains(new int2(entireGrid[i].x, entireGrid[i].y)) && !closed.Contains(i)) { open.Add(i); }
                }
                surroundingTiles.Dispose();
               
            }

           var result = new NativeList<int2>(Allocator.Temp);

            int finalNodeIndex = endNodeIndex;
            while (!result.Contains(origin))
            {
                result.Add(new int2(entireGrid[finalNodeIndex].x, entireGrid[finalNodeIndex].y));

                    closed.RemoveAtSwapBack(closed.IndexOf(finalNodeIndex));
               
                if (finalNodeIndex == startNode.index) { break; }

                var f = GetSurroundingTiles(new int2(entireGrid[finalNodeIndex].x, entireGrid[finalNodeIndex].y));

                NativeList<int> surroundingClosedTiles = new NativeList<int>(Allocator.Temp);

                foreach (var i in f)
                {
                    if (closed.Contains(i)) { surroundingClosedTiles.Add(i); }
                }

                finalNodeIndex = GetLowestGCostIndex(surroundingClosedTiles, entireGrid);
                f.Dispose();
                surroundingClosedTiles.Dispose();
            }

            result.Reverse();

            entireGrid.Dispose();
            open.Dispose();
            closed.Dispose();

            //Dispose of until all bugs cleared
            result.Dispose();

        }

        private NativeList<int> GetSurroundingTiles(int2 o)
        {

            int2 l = o + new int2(1, 0);
            int2 lu = o + new int2(1, 1);
            int2 ld = o + new int2(1, -1);
            int2 c = o + new int2(0, 0);
            int2 cu = o + new int2(0, 1);
            int2 cd = o + new int2(0, -1);
            int2 r = o + new int2(-1, 0);
            int2 ru = o + new int2(-1, 1);
            int2 rd = o + new int2(-1, -1);

            NativeList<int> ret = new NativeList<int>(Allocator.Temp);

            if (l.x > gridSize.x || l.y > gridSize.y) { ret.Add(CalculateIndex(l.x, l.y, gridSize.x)); }
            if (ld.x > gridSize.x || ld.y > gridSize.y) { ret.Add(CalculateIndex(ld.x, ld.y, gridSize.x)); }
            if (lu.x > gridSize.x || lu.y > gridSize.y) { ret.Add(CalculateIndex(lu.x, lu.y, gridSize.x)); }
            if (c.x > gridSize.x || c.y > gridSize.y) { ret.Add(CalculateIndex(c.x, c.y, gridSize.x)); }
            if (cu.x > gridSize.x || cu.y > gridSize.y) { ret.Add(CalculateIndex(cu.x, cu.y, gridSize.x)); }
            if (cd.x > gridSize.x || cd.y > gridSize.y) { ret.Add(CalculateIndex(cd.x, cd.y, gridSize.x)); }
            if (r.x > gridSize.x || r.y > gridSize.y) { ret.Add(CalculateIndex(r.x, r.y, gridSize.x)); }
            if (ru.x > gridSize.x || ru.y > gridSize.y) { ret.Add(CalculateIndex(ru.x, ru.y, gridSize.x)); }
            if (rd.x > gridSize.x || rd.y > gridSize.y) { ret.Add(CalculateIndex(rd.x, rd.y, gridSize.x)); }

            return ret;
        }

        private int CalculateIndex(int x, int y, int gridWidth)
        {
            return x + y * gridWidth;
        }

        private int CalculateOriginWeight(int2 location)
        {
            var x = Mathf.Abs(location.x - origin.x);
            var y = Mathf.Abs(location.y - origin.y);
            var both = Mathf.Abs(x - y);
            return 14 * Mathf.Min(x, y) + 10 * both;
        }

        private int CalculateDestinationWeight(int2 location)
        {
            var x = Mathf.Abs(location.x - destination.x);
            var y = Mathf.Abs(location.y - destination.y);
            var both = Mathf.Abs(x - y);
            return 14 * Mathf.Min(x, y) + 10 * both;
        }

        private int GetLowestFCostIndex(NativeList<int> l,NativeArray<PathNode> h)
        {

            int currentBestIndex = -1;
            int currentBestFCost = -1;

            NativeList<PathNode> i = new NativeList<PathNode>(Allocator.Temp);
            foreach (var x in h)
            {
                if (l.Contains(x.index)) { i.Add(x); }
            }

            foreach (var j in i)
            {
                if (j.totalWeight > currentBestFCost) { currentBestIndex = j.index; currentBestFCost = j.totalWeight; }
            }

            i.Dispose();
            return currentBestIndex;
        }
        private int GetLowestGCostIndex(NativeList<int> l, NativeArray<PathNode> h)
        {

            int currentBestIndex = -1;
            int currentBestFCost = int.MaxValue;

            NativeList<PathNode> i = new NativeList<PathNode>(Allocator.Temp);
            foreach (var x in h)
            {
                if (l.Contains(x.index)) { i.Add(x); }
            }

            foreach (var j in i)
            {
                if (j.originWeight > currentBestFCost) { currentBestIndex = j.index; currentBestFCost = j.originWeight; }
            }

            i.Dispose();
            return currentBestIndex;
        }
    }
}

Thanks in advance!

The problem is, that the error comes from the the NativeList, but it looks like, that you return -1 in your “GetLowestFCostIndex”, but an Index (of a list) can not be negative. Can you check which value is returned on that method?

Hmm… I changed it’s default index to 0, on the GetLowestFCostIndex, and it’s GCost counterpart, but it’s still got the same error.

My new code is:

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;

namespace X1Tools.Unity.Grid.Pathfinding.Advanced
{
  
    public struct DataOrientedAStar : IJob
    {
        #region Variables

        /// <summary>
        /// Allows you to use the A* Pathfinding System with Unity Jobs
        /// This is much, much faster than the normal A* Pathfinding System.
        /// </summary>

        //Return type (Redacted until bugs resolved)
       // public NativeList<int2> result;
       

        //General inputs
        public int2 gridSize;
        public NativeList<int2> unwalkableAreas;

        //Specific inputs
        public int2 origin;
        public int2 destination;

        #endregion

        struct PathNode
        {
            public int originWeight;
            public int destinationWeight;
            public int totalWeight;

            public int x;
            public int y;

            public int index;
        //    public int previousNodeIndex;

            public void CalculateFCost()
            {
                totalWeight = originWeight + destinationWeight;
            }
        }

        public void Execute()
        {
            NativeArray<PathNode> entireGrid = new NativeArray<PathNode>(gridSize.x * gridSize.y, Allocator.Temp);

            for (int x = 0; x < gridSize.x; x++)
            {
                for (int y = 0; y < gridSize.y; y++)
                {
                    PathNode p = new PathNode
                    {
                        x = x,
                        y = y,

                        index = CalculateIndex(x, y, gridSize.x),

                        originWeight = CalculateOriginWeight(new int2(x,y)),
                        destinationWeight = CalculateDestinationWeight(new int2(x, y)),

                     //   previousNodeIndex = -1
                };

                    p.CalculateFCost();

                    entireGrid[p.index] = p;

                }
            }

            PathNode startNode = entireGrid[CalculateIndex(origin.x, origin.y, gridSize.x)];
            startNode.originWeight = 0;
            startNode.CalculateFCost();
            entireGrid[startNode.index] = startNode;

            int endNodeIndex = CalculateIndex(destination.x, destination.y, gridSize.x);

            NativeList<int> open = new NativeList<int>(Allocator.Temp);
            NativeList<int> closed = new NativeList<int>(Allocator.Temp);

            open.Add(startNode.index);

            while(open.Length > 0)
            {
                int currentNodeIndex = GetLowestFCostIndex(open,entireGrid);
                if (currentNodeIndex == endNodeIndex) { break; }

                closed.Add(currentNodeIndex);

                    open.RemoveAtSwapBack(open.IndexOf(currentNodeIndex));
               

                var surroundingTiles = GetSurroundingTiles(new int2(entireGrid[currentNodeIndex].x, entireGrid[currentNodeIndex].y));
               
                foreach (var i in surroundingTiles)
                {
                    if (!unwalkableAreas.Contains(new int2(entireGrid[i].x, entireGrid[i].y)) && !closed.Contains(i)) { open.Add(i); }
                }
                surroundingTiles.Dispose();
               
            }

           var result = new NativeList<int2>(Allocator.Temp);

            int finalNodeIndex = endNodeIndex;
            while (!result.Contains(origin))
            {
                result.Add(new int2(entireGrid[finalNodeIndex].x, entireGrid[finalNodeIndex].y));

                    closed.RemoveAtSwapBack(closed.IndexOf(finalNodeIndex));
               
                if (finalNodeIndex == startNode.index) { break; }

                var f = GetSurroundingTiles(new int2(entireGrid[finalNodeIndex].x, entireGrid[finalNodeIndex].y));

                NativeList<int> surroundingClosedTiles = new NativeList<int>(Allocator.Temp);

                foreach (var i in f)
                {
                    if (closed.Contains(i)) { surroundingClosedTiles.Add(i); }
                }

                finalNodeIndex = GetLowestGCostIndex(surroundingClosedTiles, entireGrid);
                f.Dispose();
                surroundingClosedTiles.Dispose();
            }

            result.Reverse();

            entireGrid.Dispose();
            open.Dispose();
            closed.Dispose();

            //Dispose of until all bugs cleared
            result.Dispose();

        }

        private NativeList<int> GetSurroundingTiles(int2 o)
        {

            int2 l = o + new int2(1, 0);
            int2 lu = o + new int2(1, 1);
            int2 ld = o + new int2(1, -1);
            int2 c = o + new int2(0, 0);
            int2 cu = o + new int2(0, 1);
            int2 cd = o + new int2(0, -1);
            int2 r = o + new int2(-1, 0);
            int2 ru = o + new int2(-1, 1);
            int2 rd = o + new int2(-1, -1);

            NativeList<int> ret = new NativeList<int>(Allocator.Temp);

            if (l.x > gridSize.x || l.y > gridSize.y) { ret.Add(CalculateIndex(l.x, l.y, gridSize.x)); }
            if (ld.x > gridSize.x || ld.y > gridSize.y) { ret.Add(CalculateIndex(ld.x, ld.y, gridSize.x)); }
            if (lu.x > gridSize.x || lu.y > gridSize.y) { ret.Add(CalculateIndex(lu.x, lu.y, gridSize.x)); }
            if (c.x > gridSize.x || c.y > gridSize.y) { ret.Add(CalculateIndex(c.x, c.y, gridSize.x)); }
            if (cu.x > gridSize.x || cu.y > gridSize.y) { ret.Add(CalculateIndex(cu.x, cu.y, gridSize.x)); }
            if (cd.x > gridSize.x || cd.y > gridSize.y) { ret.Add(CalculateIndex(cd.x, cd.y, gridSize.x)); }
            if (r.x > gridSize.x || r.y > gridSize.y) { ret.Add(CalculateIndex(r.x, r.y, gridSize.x)); }
            if (ru.x > gridSize.x || ru.y > gridSize.y) { ret.Add(CalculateIndex(ru.x, ru.y, gridSize.x)); }
            if (rd.x > gridSize.x || rd.y > gridSize.y) { ret.Add(CalculateIndex(rd.x, rd.y, gridSize.x)); }

            return ret;
        }

        private int CalculateIndex(int x, int y, int gridWidth)
        {
            return x + y * gridWidth;
        }

        private int CalculateOriginWeight(int2 location)
        {
            var x = Mathf.Abs(location.x - origin.x);
            var y = Mathf.Abs(location.y - origin.y);
            var both = Mathf.Abs(x - y);
            return 14 * Mathf.Min(x, y) + 10 * both;
        }

        private int CalculateDestinationWeight(int2 location)
        {
            var x = Mathf.Abs(location.x - destination.x);
            var y = Mathf.Abs(location.y - destination.y);
            var both = Mathf.Abs(x - y);
            return 14 * Mathf.Min(x, y) + 10 * both;
        }

        private int GetLowestFCostIndex(NativeList<int> l,NativeArray<PathNode> h)
        {

            int currentBestIndex = 0;
            int currentBestFCost = 0;

            NativeList<PathNode> i = new NativeList<PathNode>(Allocator.Temp);
            foreach (var x in h)
            {
                if (l.Contains(x.index)) { i.Add(x); }
            }

            foreach (var j in i)
            {
                if (j.totalWeight > currentBestFCost) { currentBestIndex = j.index; currentBestFCost = j.totalWeight; }
            }

            i.Dispose();
            return currentBestIndex;
        }
        private int GetLowestGCostIndex(NativeList<int> l, NativeArray<PathNode> h)
        {

            int currentBestIndex = 0;
            int currentBestFCost = int.MaxValue;

            NativeList<PathNode> i = new NativeList<PathNode>(Allocator.Temp);
            foreach (var x in h)
            {
                if (l.Contains(x.index)) { i.Add(x); }
            }

            foreach (var j in i)
            {
                if (j.originWeight > currentBestFCost) { currentBestIndex = j.index; currentBestFCost = j.originWeight; }
            }

            i.Dispose();
            return currentBestIndex;
        }
    }
}

Can you check, what the value for startNode.index from line 122 is ? Just put a Debug.Log(startNode.index) before.

I put in the Debug.Log, on line 121, and it didn’t output anything, strangely. This means that the error is before that point. When i put the Debug.Log on line 85, I got the index(s) of all of my enemies positions (the origin is the enemies vector 2 position, as an int2):

  • 1799
  • 626
  • 2168
  • 739
  • 1630
  • 1926
  • 325
  • 734

Note: this code is running through the Job system, meaning that it’s threaded.

Hmm ok, cause on the error messages it says:
“X1Tools.Unity.Grid.Pathfinding.Advanced.DataOrientedAStar.Execute () (at Assets/Main Assets/Scripts/Enemies/Calculations/DataOrientedAStar.cs:122)”

But how can that be, if it doesn´t reach line 122 ? Ok sry, then i have no idea. Any1 with better knowladge has to look here.

The only thing i can say is, that i would put more logs in the script, to figure out on which line it fails and check the values that are used there.

Line 122 is in the execute function

I made a mistake, Sphinks- it’s from 125-148…
Nonetheless, I’ve fixed the issue now- thanks for the help!
However, now it gets stuck in an indefinite for loop…

2 Likes