public Path Run <TMod>(LogLevel pathfindingLogLevel, Vector3 fromPoint, Vector3 toPoint, Constraint constraint, Graph graph, TMod pathModifier, int threadIndex = 0,
                               bool burstEnabled = true, bool cacheEnabled = false) where TMod : struct, IPathModifier
        {
            var path         = new Path();
            var pathResult   = new PathInternal();
            var navMeshGraph = (NavMeshGraph)graph;

            var areas = -1;

            if (constraint.checkArea == true)
            {
                areas = (int)constraint.areaMask;
            }

            System.Diagnostics.Stopwatch swPath = null;
            if ((pathfindingLogLevel & LogLevel.Path) != 0)
            {
                swPath = System.Diagnostics.Stopwatch.StartNew();
            }

            var statLength  = 0;
            var statVisited = 0;

            var query = new UnityEngine.Experimental.AI.NavMeshQuery(UnityEngine.Experimental.AI.NavMeshWorld.GetDefaultWorld(), Unity.Collections.Allocator.TempJob, PathfindingNavMeshProcessor.POOL_SIZE);

            if (burstEnabled == true)
            {
                var results     = new Unity.Collections.NativeArray <UnityEngine.Experimental.AI.NavMeshLocation>(PathfindingNavMeshProcessor.MAX_PATH_SIZE, Unity.Collections.Allocator.TempJob);
                var pathResults = new Unity.Collections.NativeArray <int>(2, Unity.Collections.Allocator.TempJob);
                var job         = new BuildPathJob()
                {
                    query       = query,
                    fromPoint   = fromPoint,
                    toPoint     = toPoint,
                    agentTypeId = navMeshGraph.agentTypeId,
                    areas       = areas,
                    pathResults = pathResults,
                    results     = results,
                };
                job.Schedule().Complete();
                var pathStatus  = (UnityEngine.Experimental.AI.PathQueryStatus)pathResults[0];
                var cornerCount = pathResults[1];
                pathResults.Dispose();

                if ((pathStatus & UnityEngine.Experimental.AI.PathQueryStatus.Success) != 0)
                {
                    if (cornerCount >= 2)
                    {
                        path.navMeshPoints = PoolListCopyable <Vector3> .Spawn(cornerCount);

                        for (var i = 0; i < cornerCount; ++i)
                        {
                            path.navMeshPoints.Add(results[i].position);
                        }

                        if ((pathfindingLogLevel & LogLevel.Path) != 0)
                        {
                            var hash = 0;
                            for (var i = 0; i < cornerCount; ++i)
                            {
                                hash ^= (int)(results[i].position.x * 1000000f);
                            }

                            UnityEngine.Debug.Log("Path hash X: " + hash);

                            hash = 0;
                            for (var i = 0; i < cornerCount; ++i)
                            {
                                hash ^= (int)(results[i].position.y * 1000000f);
                            }

                            UnityEngine.Debug.Log("Path hash Y: " + hash);

                            hash = 0;
                            for (var i = 0; i < cornerCount; ++i)
                            {
                                hash ^= (int)(results[i].position.z * 1000000f);
                            }

                            UnityEngine.Debug.Log("Path hash Z: " + hash);
                        }

                        if ((pathStatus & UnityEngine.Experimental.AI.PathQueryStatus.PartialResult) != 0)
                        {
                            path.result = PathCompleteState.CompletePartial;
                        }
                        else
                        {
                            path.result = PathCompleteState.Complete;
                        }
                    }
                    else
                    {
                        path.result = PathCompleteState.NotExist;
                    }
                }
                results.Dispose();
                query.Dispose();
                return(path);
            }

            UnityEngine.AI.NavMesh.SamplePosition(fromPoint, out var hitFrom, 1000f, new UnityEngine.AI.NavMeshQueryFilter()
            {
                agentTypeID = navMeshGraph.agentTypeId,
                areaMask    = areas,
            });
            fromPoint = hitFrom.position;
            var from = query.MapLocation(fromPoint, Vector3.one * 10f, navMeshGraph.agentTypeId, areas);

            if (from.polygon.IsNull() == true)
            {
                return(path);
            }

            UnityEngine.AI.NavMesh.SamplePosition(toPoint, out var hitTo, 1000f, new UnityEngine.AI.NavMeshQueryFilter()
            {
                agentTypeID = navMeshGraph.agentTypeId,
                areaMask    = areas,
            });
            toPoint = hitTo.position;
            var to = query.MapLocation(toPoint, Vector3.one * 10f, navMeshGraph.agentTypeId, areas);

            if (to.polygon.IsNull() == true)
            {
                return(path);
            }

            var marker = new Unity.Profiling.ProfilerMarker("PathfindingNavMeshProcessor::Query::BuildPath");

            marker.Begin();
            query.BeginFindPath(from, to, areas);
            query.UpdateFindPath(PathfindingNavMeshProcessor.MAX_ITERATIONS, out var performed);
            marker.End();
            statVisited = performed;

            var result = query.EndFindPath(out var pathSize);

            if ((result & UnityEngine.Experimental.AI.PathQueryStatus.Success) != 0)
            {
                var pathInternal = new Unity.Collections.NativeArray <UnityEngine.Experimental.AI.PolygonId>(pathSize, Unity.Collections.Allocator.Persistent);
                query.GetPathResult(pathInternal);

                var markerFindStraight = new Unity.Profiling.ProfilerMarker("PathfindingNavMeshProcessor::Query::FindStraightPath");
                markerFindStraight.Begin();

                var straightPathFlags = new Unity.Collections.NativeArray <StraightPathFlags>(PathfindingNavMeshProcessor.MAX_PATH_SIZE, Unity.Collections.Allocator.Persistent);
                var vertexSide        = new Unity.Collections.NativeArray <float>(PathfindingNavMeshProcessor.MAX_PATH_SIZE, Unity.Collections.Allocator.Persistent);
                var results           = new Unity.Collections.NativeArray <UnityEngine.Experimental.AI.NavMeshLocation>(PathfindingNavMeshProcessor.MAX_PATH_SIZE, Unity.Collections.Allocator.Persistent);
                var resultStatus      = new Unity.Collections.NativeArray <int>(2, Unity.Collections.Allocator.TempJob);
                var job = new FindStraightPathJob()
                {
                    query             = query,
                    from              = from,
                    to                = to,
                    pathInternal      = pathInternal,
                    pathSize          = pathSize,
                    results           = results,
                    straightPathFlags = straightPathFlags,
                    vertexSide        = vertexSide,
                    resultStatus      = resultStatus,
                };
                job.Schedule().Complete();

                var pathStatus  = (UnityEngine.Experimental.AI.PathQueryStatus)job.resultStatus[0];
                var cornerCount = job.resultStatus[1];
                resultStatus.Dispose();

                statLength = cornerCount;

                markerFindStraight.End();

                if (pathStatus == UnityEngine.Experimental.AI.PathQueryStatus.Success)
                {
                    /*for (int i = 1; i < cornerCount; ++i) {
                     *
                     *  Gizmos.color = Color.green;
                     *  Gizmos.DrawLine(results[i].position, results[i - 1].position);
                     *
                     * }*/
                    pathResult.pathStatus = pathStatus;
                    pathResult.results    = results;
                    pathResult.corners    = cornerCount;

                    if (cornerCount >= 2)
                    {
                        path.navMeshPoints = PoolListCopyable <Vector3> .Spawn(cornerCount);

                        for (var i = 0; i < cornerCount; ++i)
                        {
                            path.navMeshPoints.Add(results[i].position);
                        }

                        if ((pathfindingLogLevel & LogLevel.Path) != 0)
                        {
                            var hash = 0;
                            for (var i = 0; i < cornerCount; ++i)
                            {
                                hash ^= (int)(results[i].position.x * 1000000f);
                            }

                            UnityEngine.Debug.Log("Path hash X: " + hash);

                            hash = 0;
                            for (var i = 0; i < cornerCount; ++i)
                            {
                                hash ^= (int)(results[i].position.y * 1000000f);
                            }

                            UnityEngine.Debug.Log("Path hash Y: " + hash);

                            hash = 0;
                            for (var i = 0; i < cornerCount; ++i)
                            {
                                hash ^= (int)(results[i].position.z * 1000000f);
                            }

                            UnityEngine.Debug.Log("Path hash Z: " + hash);
                        }

                        path.result = PathCompleteState.Complete;
                    }
                    else
                    {
                        path.result = PathCompleteState.NotExist;
                    }

                    pathResult.Dispose();
                }
                else
                {
                    path.result = PathCompleteState.NotExist;
                    results.Dispose();
                }

                vertexSide.Dispose();
                straightPathFlags.Dispose();
                pathInternal.Dispose();
            }
            else
            {
                path.result = PathCompleteState.NotExist;
                //Debug.LogWarning("Path result: " + result + ", performed: " + performed);
            }

            System.Diagnostics.Stopwatch swModifier = null;
            if ((pathfindingLogLevel & LogLevel.PathMods) != 0)
            {
                swModifier = System.Diagnostics.Stopwatch.StartNew();
            }

            if ((path.result & PathCompleteState.Complete) != 0)
            {
                path = pathModifier.Run(path, constraint);
            }

            if ((pathfindingLogLevel & LogLevel.Path) != 0)
            {
                Logger.Log(
                    $"Path result {path.result}, built in {(swPath.ElapsedTicks / (double)System.TimeSpan.TicksPerMillisecond).ToString("0.##")}ms. Path length: {statLength} (Visited: {statVisited})\nThread Index: {threadIndex}");
            }

            if ((pathfindingLogLevel & LogLevel.PathMods) != 0)
            {
                Logger.Log($"Path Mods: {swModifier.ElapsedMilliseconds}ms");
            }

            query.Dispose();

            return(path);
        }