/// <summary>
        /// Returns the configuration parameters used to initialize the navigation mesh.
        /// </summary>
        /// <returns>The configuration parameters used to initialize the navigation mesh.</returns>
        public NavmeshParams GetConfig()
        {
            NavmeshParams result = new NavmeshParams();

            NavmeshEx.dtnmGetParams(root, result);
            return(result);
        }
        /// <summary>
        /// Creates an empty navigation mesh ready for tiles to be added.
        /// </summary>
        /// <remarks>
        /// This is the method used when creating new multi-tile meshes.
        /// Tiles are added using the <see cref="AddTile"/> method.
        /// </remarks>
        /// <param name="config">The mesh configuration.</param>
        /// <param name="resultMesh">The result mesh.</param>
        /// <returns>The <see cref="NavStatus"/> flags for the operation.
        /// </returns>
        public static NavStatus Create(NavmeshParams config
                                       , out Navmesh resultMesh)
        {
            if (config == null || config.maxTiles < 1)
            {
                resultMesh = null;
                return(NavStatus.Failure | NavStatus.InvalidParam);
            }

            IntPtr root = IntPtr.Zero;

            NavStatus status = NavmeshEx.dtnmInitTiledNavMesh(config, ref root);

            if (NavUtil.Succeeded(status))
            {
                resultMesh = new Navmesh(root);
            }
            else
            {
                resultMesh = null;
            }

            return(status);
        }
        internal bool GetMeshBuildData(Vector3 origin, float tileWorldSize, TileZone zone
            , out NavmeshParams config
            , out NavmeshTileData[] tiles)
        {
            // Is there anything to bake?

            config = null;
            tiles = null;

            int maxPolyCount;

            int tileCount;
            BakeableCount(out tileCount, out maxPolyCount);

            if (tileCount == 0)
                return false;

            config = new NavmeshParams(origin
                , tileWorldSize, tileWorldSize
                , Mathf.Max(1, tileCount)
                , Mathf.Max(1, maxPolyCount));

            // Add the tiles.

            List<NavmeshTileData> ltiles = new List<NavmeshTileData>();

            for (int tx = zone.xmin; tx <= zone.xmax; tx++)
            {
                for (int tz = zone.zmin; tz <= zone.zmax; tz++)
                {
                    int trash;
                    NavmeshTileData td = GetTileData(tx, tz, out trash);
                    if (td == null)
                        // Tile is not available.
                        continue;

                    ltiles.Add(td);
                }
            }

            tiles = ltiles.ToArray();

            return true;
        }
 internal bool GetMeshBuildData(Vector3 origin, float tileWorldSize
     , out NavmeshParams config
     , out NavmeshTileData[] tiles)
 {
     return GetMeshBuildData(origin, tileWorldSize, new TileZone(0, 0, Width - 1, Depth - 1)
         , out config, out tiles);
 }
        /// <summary>
        /// Extracts the tile data from a serialized navigation mesh.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Tile data is normally preserved by serializing
        /// the the content of the <see cref="NavmeshTileData"/> objects used to
        /// create the navigation mesh.  That is the most efficient method
        /// and should be used whenever possible.
        /// </para>
        /// <para>
        /// This method can be used to extract the tile data when
        /// the original data is not available.  It should only be used as
        /// a backup to the normal method since this method is not efficient.
        /// </para>
        /// <para>
        /// Always check the header polygon count
        /// of the resulting <see cref="NavmeshTileExtract"/> objects before use since some tiles
        /// in the navigation mesh may be empty.  The <see cref="NavmeshTileExtract.data"/> 
        /// field will be null for empty tiles.
        /// </para>
        /// </remarks>
        /// <param name="serializedMesh">A valid serialized navigation mesh.</param>
        /// <param name="tileData">
        /// The extracted tile data. [Length: <see cref="Navmesh.GetMaxTiles()"/>]
        /// </param>
        /// <param name="config">The navigation mesh's configuration.</param>
        /// <returns>The <see cref="NavStatus"/> flags for the operation.</returns>
        public static NavStatus ExtractTileData(byte[] serializedMesh
            , out NavmeshTileExtract[] tileData
            , out NavmeshParams config)
        {
            /*
             * Design notes:
             * 
             * Normally, the only way to get tile data out of a navigation mesh
             * is when the tile data is NOT owned by the mesh.  This is not
             * permitted for normal mesh objects, which is why the RemoveTile() method
             * never returns the tile data.
             * 
             * The most efficient way to extract the data is to get it directly
             * from the serialized data.  But that would be a code maintenance issue.
             * (Duplicating the mesh creation process.) So I'm using this rather 
             * convoluted method instead.
             * 
             */

            if (serializedMesh == null)
            {
                tileData = null;
                config = null;
                return NavStatus.Failure | NavStatus.InvalidParam;
            }

            Navmesh mesh;
            NavStatus status = Navmesh.UnsafeCreate(serializedMesh, false, out mesh);

            if ((status & NavStatus.Failure) != 0)
            {
                tileData = null;
                config = null;
                return status;
            }

            config = mesh.GetConfig();

            int count = mesh.GetMaxTiles();

            tileData = new NavmeshTileExtract[count];

            if (count == 0)
                return NavStatus.Sucess;

            for (int i = 0; i < count; i++)
            {
                NavmeshTile tile = mesh.GetTile(i);

                tileData[i].header = tile.GetHeader();

                if (tileData[i].header.polyCount == 0)
                    // Tile not in use.
                    continue;

                tileData[i].tileRef = tile.GetTileRef();

                IntPtr tdata = new IntPtr();
                int tsize = 0;

                NavmeshEx.dtnmRemoveTile(mesh.root, tileData[i].tileRef, ref tdata, ref tsize);

                tileData[i].data = UtilEx.ExtractArrayByte(tdata, tsize);

                NavmeshEx.dtnmFreeBytes(ref tdata);
            }

            return NavStatus.Sucess;
        }
        /// <summary>
        /// Creates an empty navigation mesh ready for tiles to be added.
        /// </summary>
        /// <remarks>
        /// This is the method used when creating new multi-tile meshes.
        /// Tiles are added using the <see cref="AddTile"/> method.
        /// </remarks>
        /// <param name="config">The mesh configuration.</param>
        /// <param name="resultMesh">The result mesh.</param>
        /// <returns>The <see cref="NavStatus"/> flags for the operation.
        /// </returns>
        public static NavStatus Create(NavmeshParams config
            , out Navmesh resultMesh)
        {
            if (config == null || config.maxTiles < 1)
            {
                resultMesh = null;
                return NavStatus.Failure | NavStatus.InvalidParam;
            }

            IntPtr root = IntPtr.Zero;

            NavStatus status = NavmeshEx.dtnmInitTiledNavMesh(config, ref root);

            if (NavUtil.Succeeded(status))
                resultMesh = new Navmesh(root);
            else
                resultMesh = null;

            return status;
        }
 /// <summary>
 /// Returns the configuration parameters used to initialize the navigation mesh.
 /// </summary>
 /// <returns>The configuration parameters used to initialize the navigation mesh.</returns>
 public NavmeshParams GetConfig()
 {
     NavmeshParams result = new NavmeshParams();
     NavmeshEx.dtnmGetParams(root, result);
     return result;
 }
    /// <summary>
    /// Loads a navigation mesh.
    /// </summary>
    /// <param name="config">The mesh configuration.</param>
    /// <param name="tiles">The tiles to add to the mesh.</param>
    /// <param name="buildConfig">The build information. (Optional)</param>
    /// <returns>The <see cref="NavStatus"/> flags for the operation.</returns>
    public NavStatus Load(NavmeshParams config
        , NavmeshTileData[] tiles
        , NavmeshBuildInfo buildConfig)
    {
        if (config == null || tiles == null || tiles.Length > config.maxTiles)
            return NavStatus.Failure | NavStatus.InvalidParam;

        Navmesh navmesh;
        NavStatus status = Navmesh.Create(config, out navmesh);

        if ((status & NavStatus.Sucess) == 0)
            return status;

        foreach (NavmeshTileData tile in tiles)
        {
            if (tile == null)
                continue;

            uint trash;
            status = navmesh.AddTile(tile, Navmesh.NullTile, out trash);

            if ((status & NavStatus.Sucess) == 0)
                return status | NavStatus.InvalidParam;
        }

        mDataPack = navmesh.GetSerializedMesh();

        if (mDataPack == null)
            return NavStatus.Failure;

        mBuildInfo = buildConfig;

        mVersion++;

        return NavStatus.Sucess;
    }
        /// <summary>
        /// Extracts the tile data from a serialized navigation mesh.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Tile data is normally preserved by serializing
        /// the the content of the <see cref="NavmeshTileData"/> objects used to
        /// create the navigation mesh.  That is the most efficient method
        /// and should be used whenever possible.
        /// </para>
        /// <para>
        /// This method can be used to extract the tile data when
        /// the original data is not available.  It should only be used as
        /// a backup to the normal method since this method is not efficient.
        /// </para>
        /// <para>
        /// Always check the header polygon count
        /// of the resulting <see cref="NavmeshTileExtract"/> objects before use since some tiles
        /// in the navigation mesh may be empty.  The <see cref="NavmeshTileExtract.data"/>
        /// field will be null for empty tiles.
        /// </para>
        /// </remarks>
        /// <param name="serializedMesh">A valid serialized navigation mesh.</param>
        /// <param name="tileData">
        /// The extracted tile data. [Length: <see cref="Navmesh.GetMaxTiles()"/>]
        /// </param>
        /// <param name="config">The navigation mesh's configuration.</param>
        /// <returns>The <see cref="NavStatus"/> flags for the operation.</returns>
        public static NavStatus ExtractTileData(byte[] serializedMesh
                                                , out NavmeshTileExtract[] tileData
                                                , out NavmeshParams config)
        {
            /*
             * Design notes:
             *
             * Normally, the only way to get tile data out of a navigation mesh
             * is when the tile data is NOT owned by the mesh.  This is not
             * permitted for normal mesh objects, which is why the RemoveTile() method
             * never returns the tile data.
             *
             * The most efficient way to extract the data is to get it directly
             * from the serialized data.  But that would be a code maintenance issue.
             * (Duplicating the mesh creation process.) So I'm using this rather
             * convoluted method instead.
             *
             */

            if (serializedMesh == null)
            {
                tileData = null;
                config   = null;
                return(NavStatus.Failure | NavStatus.InvalidParam);
            }

            Navmesh   mesh;
            NavStatus status = Navmesh.UnsafeCreate(serializedMesh, false, out mesh);

            if ((status & NavStatus.Failure) != 0)
            {
                tileData = null;
                config   = null;
                return(status);
            }

            config = mesh.GetConfig();

            int count = mesh.GetMaxTiles();

            tileData = new NavmeshTileExtract[count];

            if (count == 0)
            {
                return(NavStatus.Sucess);
            }

            for (int i = 0; i < count; i++)
            {
                NavmeshTile tile = mesh.GetTile(i);

                tileData[i].header = tile.GetHeader();

                if (tileData[i].header.polyCount == 0)
                {
                    // Tile not in use.
                    continue;
                }

                tileData[i].tileRef = tile.GetTileRef();

                IntPtr tdata = new IntPtr();
                int    tsize = 0;

                NavmeshEx.dtnmRemoveTile(mesh.root, tileData[i].tileRef, ref tdata, ref tsize);

                tileData[i].data = UtilEx.ExtractArrayByte(tdata, tsize);

                NavmeshEx.dtnmFreeBytes(ref tdata);
            }

            return(NavStatus.Sucess);
        }