public static void Process(PNavMesh pNavMesh)
        {
            using (new SProfiler("Finding Islands"))
            {
                // find islands
                List <PNavIsland> islands = new List <PNavIsland>();
                int        maxX           = pNavMesh.columns.GetLength(0) - 1;
                int        maxZ           = pNavMesh.columns.GetLength(1) - 1;
                PNavPoint  pointMax       = new PNavPoint(maxX, maxZ);
                int        islandIndex    = 0;
                PNavIsland island         = new PNavIsland();

                for (int x = 0; x < maxX; x++)
                {
                    for (int z = 0; z < maxZ; z++)
                    {
                        PNavPoint point       = new PNavPoint(x, z);
                        bool      foundIsland = DetectIsland(pNavMesh.columns, point, pointMax, 1, pNavMesh.verticalDrop, islandIndex, island);
                        if (foundIsland)
                        {
                            islandIndex++;
                            islands.Add(island);
                            PNavMeshHelper.DetectEdgeCorner(pNavMesh.columns, pointMax, island);
                            PNavMeshHelper.ApplyEdgeGap(pNavMesh.columns, pointMax, island, pNavMesh.edgeGap);

                            island = new PNavIsland();
                        }
                    }
                }

                pNavMesh.islands = islands;
                Debug.Log($"Found {islands.Count} islands");
            }
        }
        static bool isWalkableNode(PNavPoint self, PNavPoint max, PNavPoint delta, PNavColumn[,] columns)
        {
            PNavPoint pOut;
            bool      valid = PNavMeshHelper.GetPoint(self, max, delta, out pOut);

            if (valid)
            {
                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();

                valid = (n != null && n.walkable);
            }

            return(valid);
        }
        static bool isInnerNode(PNavPoint point, PNavPoint max, PNavPoint delta, int nodes, PNavColumn[,] columns)
        {
            PNavPoint pOut;
            PNavPoint newDelta = new PNavPoint(delta.x * nodes, delta.z * nodes);
            bool      valid    = PNavMeshHelper.GetPoint(point, max, newDelta, out pOut);

            if (valid)
            {
                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();

                valid = (n != null && n.IsInner);
            }

            return(valid);
        }
        static bool isEdgeNode(PNavPoint point, PNavPoint max, PNavPoint delta, PNavColumn[,] columns)
        {
            PNavPoint pOut;
            bool      valid = PNavMeshHelper.GetPoint(point, max, delta, out pOut);

            if (valid)
            {
                PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();

                if (n == null)
                {
                    return(false);
                }

                return(n.IsLeftEdge || n.IsRghtEdge || n.IsBackEdge || n.IsFrontEdge);
            }

            return(false);
        }
        static bool CheckIfNodeIsValidEdge(PNavNode node, PNavColumn[,] columns, PNavPoint pointMax)
        {
            node.isEdge = false;

            node.edgeFlag = 0;

            bool allSurroundingAreInner = true;

            for (int i = 0; i < 8; i++)
            {
                walkables[i] = false;

                PNavPoint pOut;
                bool      valid = PNavMeshHelper.GetPoint(node.point, pointMax, points2[i], out pOut);

                if (valid)
                {
                    PNavNode n = columns[pOut.x, pOut.z].SurfaceNode();

                    if (n != null)
                    {
                        if (n.walkable)
                        {
                            walkables[i]  = true;
                            node.edgeFlag = (byte)(node.edgeFlag | 1 << i);
                        }

                        if (!n.IsInner)
                        {
                            allSurroundingAreInner = false;
                        }
                    }
                }
            }

            if (!allSurroundingAreInner)
            {
                node.isEdge = true;
            }

            if (walkables[0] != walkables[4]) //left and right
            {
                node.isEdge = true;

                // if top and bot are not walkable, not valid
                if (!walkables[2] && !walkables[6])
                {
                    node.isEdge = false;
                }
            }

            if (walkables[2] != walkables[6]) // top and bot
            {
                node.isEdge = true;

                // if left and right are not walkable, not valid
                if (!walkables[0] && !walkables[4])
                {
                    node.isEdge = false;
                }
            }

            // if all diagonal nodes are not walkable, not valid
            if (!walkables[1] && !walkables[3] && !walkables[5] && !walkables[7])
            {
                node.isEdge = false;
            }

            return(node.isEdge);
        }
        static bool DetectEdgeLoop(PNavNode node, PNavEdgeLoop edgeLoop, int edgeLoopIndex, PNavColumn[,] columns, PNavPoint pointMax)
        {
            bool foundLoop = false;

            if (node == null || !node.walkable || node.edgeLoopIndex >= 0)
            {
                return(false);
            }

            bool isEdge = CheckIfNodeIsValidEdge(node, columns, pointMax);

            if (!isEdge)
            {
                return(false);
            }

            Stack <PNavNode> stack = new Stack <PNavNode>();

            stack.Push(node);

            while (stack.Count > 0)
            {
                PNavNode n = stack.Pop();

                //possible to be added more than once
                if (n.edgeLoopIndex >= 0)
                {
                    continue;
                }

                edgeLoop.nodes.Add(n);
                n.edgeLoopIndex = edgeLoopIndex;
                foundLoop       = true;

                for (int i = 0; i < 8; i++)
                {
                    PNavPoint pOut;
                    bool      valid = PNavMeshHelper.GetPoint(n.point, pointMax, points[i], out pOut);

                    if (valid)
                    {
                        PNavNode nPush = columns[pOut.x, pOut.z].SurfaceNode();
                        if (nPush != null)
                        {
                            if (!nPush.walkable || nPush.edgeLoopIndex >= 0)
                            {
                                continue;
                            }

                            bool isEdge1 = CheckIfNodeIsValidEdge(nPush, columns, pointMax);

                            if (!isEdge1)
                            {
                                continue;
                            }

                            stack.Push(nPush);
                        }
                    }
                }
            }

            return(foundLoop);
        }
        static bool DetectIsland(PNavColumn[,] columns, PNavPoint point, PNavPoint pointMax, int edgeGap, int verticalDrop, int islandIndex, PNavIsland island)
        {
            PNavColumn column = columns[point.x, point.z];

            if (column.type != ParallelNavColumnType.Walkable)
            {
                return(false);
            }

            PNavNode surfaceNode = column.SurfaceNode();

            if (surfaceNode == null)
            {
                return(false);
            }

            //already checked
            if (surfaceNode.islandIndex >= 0)
            {
                return(false);
            }

            surfaceNode.islandIndex = islandIndex;

            island.nodes.Add(surfaceNode);

            Queue <PNavPoint> queue = new Queue <PNavPoint>();

            queue.Enqueue(point);

            while (queue.Count > 0)
            {
                PNavPoint p = queue.Dequeue();

                PNavColumn c = columns[p.x, p.z];

                //check top edge
                PNavPoint pTopOut;

                bool addedTop = PNavMeshHelper.AddTop(columns, p, out pTopOut, pointMax, verticalDrop, edgeGap, islandIndex, island);

                if (addedTop)
                {
                    queue.Enqueue(pTopOut);
                }

                //check bottom edge
                PNavPoint pBottomOut;
                bool      addedBottom = PNavMeshHelper.AddBottom(columns, p, out pBottomOut, pointMax, verticalDrop, edgeGap, islandIndex, island);

                if (addedBottom)
                {
                    queue.Enqueue(pBottomOut);
                }

                //search left
                PNavPoint left = p;

                while (true)
                {
                    PNavPoint pLeftOut;

                    bool added = PNavMeshHelper.AddLeft(columns, left, out pLeftOut, pointMax, verticalDrop, edgeGap, islandIndex, island, queue);

                    if (!added)
                    {
                        break;
                    }
                    else
                    {
                        left = pLeftOut;
                    }
                }

                //search right

                PNavPoint right = p;

                while (true)
                {
                    PNavPoint pRightOut;

                    bool added = PNavMeshHelper.AddRight(columns, right, out pRightOut, pointMax, verticalDrop, edgeGap, islandIndex, island, queue);

                    if (!added)
                    {
                        break;
                    }
                    else
                    {
                        right = pRightOut;
                    }
                }
            }

            return(true);
        }