/// <summary>
        /// Marks tiles that should be built according to how much their geometry affects the navigation mesh and the bounding boxes specified for building
        /// </summary>
        private void MarkTiles(NavigationMeshInputBuilder inputBuilder, ref NavigationMeshBuildSettings buildSettings, ref NavigationAgentSettings agentSettings, HashSet <Point> tilesToBuild)
        {
            // Extend bounding box for agent size
            BoundingBox boundingBoxToCheck = inputBuilder.BoundingBox;

            NavigationMeshBuildUtils.ExtendBoundingBox(ref boundingBoxToCheck, new Vector3(agentSettings.Radius));

            List <Point> newTileList = NavigationMeshBuildUtils.GetOverlappingTiles(buildSettings, boundingBoxToCheck);

            foreach (Point p in newTileList)
            {
                tilesToBuild.Add(p);
            }
        }
        private NavigationMeshTile BuildTile(Point tileCoordinate, NavigationMeshBuildSettings buildSettings, NavigationAgentSettings agentSettings,
                                             ICollection <BoundingBox> boundingBoxes, Vector3[] inputVertices, int[] inputIndices, long buildTimeStamp)
        {
            NavigationMeshTile meshTile = null;

            // Include bounding boxes in tile height range
            BoundingBox tileBoundingBox = NavigationMeshBuildUtils.CalculateTileBoundingBox(buildSettings, tileCoordinate);
            float       minimumHeight   = float.MaxValue;
            float       maximumHeight   = float.MinValue;
            bool        shouldBuildTile = false;

            foreach (var boundingBox in boundingBoxes)
            {
                if (boundingBox.Intersects(ref tileBoundingBox))
                {
                    maximumHeight   = Math.Max(maximumHeight, boundingBox.Maximum.Y);
                    minimumHeight   = Math.Min(minimumHeight, boundingBox.Minimum.Y);
                    shouldBuildTile = true;
                }
            }

            NavigationMeshBuildUtils.SnapBoundingBoxToCellHeight(buildSettings, ref tileBoundingBox);

            // Skip tiles that do not overlap with any bounding box
            if (shouldBuildTile)
            {
                // Set tile's minimum and maximum height
                tileBoundingBox.Minimum.Y = minimumHeight;
                tileBoundingBox.Maximum.Y = maximumHeight;

                unsafe
                {
                    IntPtr builder = Navigation.CreateBuilder();

                    // Turn build settings into native structure format
                    Navigation.BuildSettings internalBuildSettings = new Navigation.BuildSettings
                    {
                        // Tile settings
                        BoundingBox  = tileBoundingBox,
                        TilePosition = tileCoordinate,
                        TileSize     = buildSettings.TileSize,

                        // General build settings
                        CellHeight           = buildSettings.CellHeight,
                        CellSize             = buildSettings.CellSize,
                        RegionMinArea        = buildSettings.MinRegionArea,
                        RegionMergeArea      = buildSettings.RegionMergeArea,
                        EdgeMaxLen           = buildSettings.MaxEdgeLen,
                        EdgeMaxError         = buildSettings.MaxEdgeError,
                        DetailSampleDist     = buildSettings.DetailSamplingDistance,
                        DetailSampleMaxError = buildSettings.MaxDetailSamplingError,

                        // Agent settings
                        AgentHeight   = agentSettings.Height,
                        AgentRadius   = agentSettings.Radius,
                        AgentMaxClimb = agentSettings.MaxClimb,
                        AgentMaxSlope = agentSettings.MaxSlope.Degrees,
                    };

                    Navigation.SetSettings(builder, new IntPtr(&internalBuildSettings));
                    IntPtr buildResultPtr = Navigation.Build(builder, inputVertices, inputVertices.Length, inputIndices, inputIndices.Length);
                    Navigation.GeneratedData *generatedDataPtr = (Navigation.GeneratedData *)buildResultPtr;
                    if (generatedDataPtr->Success && generatedDataPtr->NavmeshDataLength > 0)
                    {
                        meshTile = new NavigationMeshTile();

                        // Copy the generated navigationMesh data
                        meshTile.Data = new byte[generatedDataPtr->NavmeshDataLength + sizeof(long)];
                        Marshal.Copy(generatedDataPtr->NavmeshData, meshTile.Data, 0, generatedDataPtr->NavmeshDataLength);

                        // Append time stamp
                        byte[] timeStamp = BitConverter.GetBytes(buildTimeStamp);
                        for (int i = 0; i < timeStamp.Length; i++)
                        {
                            meshTile.Data[meshTile.Data.Length - sizeof(long) + i] = timeStamp[i];
                        }

                        List <Vector3> outputVerts = new List <Vector3>();
                        if (generatedDataPtr->NumNavmeshVertices > 0)
                        {
                            Vector3 *navmeshVerts = (Vector3 *)generatedDataPtr->NavmeshVertices;
                            for (int j = 0; j < generatedDataPtr->NumNavmeshVertices; j++)
                            {
                                outputVerts.Add(navmeshVerts[j]);
                            }
                        }

                        Navigation.DestroyBuilder(builder);
                    }
                }
            }

            return(meshTile);
        }