Пример #1
0
        void buildMoveMapTile(uint mapID, uint tileX, uint tileY, MeshData meshData, float[] bmin, float[] bmax, dtNavMesh navMesh)
        {
            // console output
            string tileString = $"[Map {mapID:D4}] [{tileX:D2},{tileY:D2}]: ";

            Console.WriteLine($"{tileString} Building movemap tiles...");

            Tile iv = new Tile();

            float[] tVerts     = meshData.solidVerts.ToArray();
            int     tVertCount = meshData.solidVerts.Count / 3;

            int[] tTris     = meshData.solidTris.ToArray();
            int   tTriCount = meshData.solidTris.Count / 3;

            float[] lVerts     = meshData.liquidVerts.ToArray();
            int     lVertCount = meshData.liquidVerts.Count / 3;

            int[] lTris     = meshData.liquidTris.ToArray();
            int   lTriCount = meshData.liquidTris.Count / 3;

            byte[] lTriFlags = meshData.liquidType.ToArray();

            // these are WORLD UNIT based metrics
            // this are basic unit dimentions
            // value have to divide GRID_SIZE(533.3333f) ( aka: 0.5333, 0.2666, 0.3333, 0.1333, etc )
            float BASE_UNIT_DIM = 0.2666666f;// m_bigBaseUnit ? 0.5333333f : 0.2666666f;

            // All are in UNIT metrics!
            int VERTEX_PER_MAP  = (int)(SharedConst.GRID_SIZE / BASE_UNIT_DIM + 0.5f);
            int VERTEX_PER_TILE = 80;// m_bigBaseUnit ? 40 : 80; // must divide VERTEX_PER_MAP
            int TILES_PER_MAP   = VERTEX_PER_MAP / VERTEX_PER_TILE;

            rcConfig config = new rcConfig();

            rcVcopy(config.bmin, bmin);
            rcVcopy(config.bmax, bmax);

            config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
            config.cs = BASE_UNIT_DIM;
            config.ch = BASE_UNIT_DIM;
            config.walkableSlopeAngle = m_maxWalkableAngle;
            config.tileSize           = VERTEX_PER_TILE;
            config.walkableRadius     = 2;                   // m_bigBaseUnit ? 1 : 2;
            config.borderSize         = config.walkableRadius + 3;
            config.maxEdgeLen         = VERTEX_PER_TILE + 1; // anything bigger than tileSize
            config.walkableHeight     = 6;                   // m_bigBaseUnit ? 3 : 6;
            // a value >= 3|6 allows npcs to walk over some fences
            // a value >= 4|8 allows npcs to walk over all fences
            config.walkableClimb          = 8;// m_bigBaseUnit ? 4 : 8;
            config.minRegionArea          = dtSqr(60);
            config.mergeRegionArea        = dtSqr(50);
            config.maxSimplificationError = 1.8f;           // eliminates most jagged edges (tiny polygons)
            config.detailSampleDist       = config.cs * 64;
            config.detailSampleMaxError   = config.ch * 2;

            // this sets the dimensions of the heightfield - should maybe happen before border padding
            rcCalcGridSize(config.bmin, config.bmax, config.cs, out config.width, out config.height);

            // allocate subregions : tiles
            Tile[] tiles = new Tile[TILES_PER_MAP * TILES_PER_MAP];

            // Initialize per tile config.
            rcConfig tileCfg = new rcConfig(config);

            tileCfg.width  = config.tileSize + config.borderSize * 2;
            tileCfg.height = config.tileSize + config.borderSize * 2;

            // merge per tile poly and detail meshes
            rcPolyMesh[]       pmmerge = new rcPolyMesh[TILES_PER_MAP * TILES_PER_MAP];
            rcPolyMeshDetail[] dmmerge = new rcPolyMeshDetail[TILES_PER_MAP * TILES_PER_MAP];
            int nmerge = 0;

            // build all tiles
            for (int y = 0; y < TILES_PER_MAP; ++y)
            {
                for (int x = 0; x < TILES_PER_MAP; ++x)
                {
                    Tile tile = tiles[x + y * TILES_PER_MAP];

                    // Calculate the per tile bounding box.
                    tileCfg.bmin[0] = config.bmin[0] + (float)(x * config.tileSize - config.borderSize) * config.cs;
                    tileCfg.bmin[2] = config.bmin[2] + (float)(y * config.tileSize - config.borderSize) * config.cs;
                    tileCfg.bmax[0] = config.bmin[0] + (float)((x + 1) * config.tileSize + config.borderSize) * config.cs;
                    tileCfg.bmax[2] = config.bmin[2] + (float)((y + 1) * config.tileSize + config.borderSize) * config.cs;

                    // build heightfield
                    tile.solid = new rcHeightfield();
                    if (!rcCreateHeightfield(m_rcContext, tile.solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch))
                    {
                        Console.WriteLine($"{tileString} Failed building heightfield!            ");
                        continue;
                    }

                    // mark all walkable tiles, both liquids and solids
                    byte[] triFlags = new byte[tTriCount];
                    for (var i = 0; i < tTriCount; ++i)
                    {
                        triFlags[i] = (byte)NavArea.Ground;
                    }

                    rcClearUnwalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags);
                    rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, tile.solid, config.walkableClimb);

                    rcFilterLowHangingWalkableObstacles(m_rcContext, config.walkableClimb, tile.solid);
                    rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, tile.solid);
                    rcFilterWalkableLowHeightSpans(m_rcContext, tileCfg.walkableHeight, tile.solid);

                    rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, tile.solid, config.walkableClimb);

                    // compact heightfield spans
                    tile.chf = new rcCompactHeightfield();
                    if (!rcBuildCompactHeightfield(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, tile.solid, tile.chf))
                    {
                        Console.WriteLine($"{tileString} Failed compacting heightfield!");
                        continue;
                    }

                    // build polymesh intermediates
                    if (!rcErodeWalkableArea(m_rcContext, config.walkableRadius, tile.chf))
                    {
                        Console.WriteLine($"{tileString} Failed eroding area!");
                        continue;
                    }

                    if (!rcBuildDistanceField(m_rcContext, tile.chf))
                    {
                        Console.WriteLine($"{tileString} Failed building distance field!");
                        continue;
                    }

                    if (!rcBuildRegions(m_rcContext, tile.chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea))
                    {
                        Console.WriteLine($"{tileString} Failed building regions!");
                        continue;
                    }

                    tile.cset = new rcContourSet();
                    if (!rcBuildContours(m_rcContext, tile.chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, tile.cset, 1))
                    {
                        Console.WriteLine($"{tileString} Failed building contours!");
                        continue;
                    }

                    // build polymesh
                    tile.pmesh = new rcPolyMesh();
                    if (!rcBuildPolyMesh(m_rcContext, tile.cset, tileCfg.maxVertsPerPoly, tile.pmesh))
                    {
                        Console.WriteLine($"{tileString} Failed building polymesh!");
                        continue;
                    }

                    tile.dmesh = new rcPolyMeshDetail();
                    if (!rcBuildPolyMeshDetail(m_rcContext, tile.pmesh, tile.chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, tile.dmesh))
                    {
                        Console.WriteLine($"{tileString} Failed building polymesh detail!");
                        continue;
                    }

                    // free those up
                    // we may want to keep them in the future for debug
                    // but right now, we don't have the code to merge them
                    tile.solid = null;
                    tile.chf   = null;
                    tile.cset  = null;

                    pmmerge[nmerge] = tile.pmesh;
                    dmmerge[nmerge] = tile.dmesh;
                    nmerge++;
                }
            }

            iv.pmesh = new rcPolyMesh();
            rcMergePolyMeshes(m_rcContext, ref pmmerge, nmerge, iv.pmesh);

            iv.dmesh = new rcPolyMeshDetail();
            rcMergePolyMeshDetails(m_rcContext, dmmerge, nmerge, ref iv.dmesh);


            // set polygons as walkable
            // TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off
            for (int i = 0; i < iv.pmesh.npolys; ++i)
            {
                byte area = (byte)(iv.pmesh.areas[i] & RC_WALKABLE_AREA);
                if (area != 0)
                {
                    if (area >= (byte)NavArea.MagmaSlime)
                    {
                        iv.pmesh.flags[i] = (ushort)(1 << (63 - area));
                    }
                    else
                    {
                        iv.pmesh.flags[i] = (byte)NavTerrainFlag.Ground; // TODO: these will be dynamic in future
                    }
                }
            }

            // setup mesh parameters
            dtNavMeshCreateParams createParams = new dtNavMeshCreateParams();

            //memset(&createParams, 0, sizeof(createParams));
            createParams.verts            = iv.pmesh.verts;
            createParams.vertCount        = iv.pmesh.nverts;
            createParams.polys            = iv.pmesh.polys;
            createParams.polyAreas        = iv.pmesh.areas;
            createParams.polyFlags        = iv.pmesh.flags;
            createParams.polyCount        = iv.pmesh.npolys;
            createParams.nvp              = iv.pmesh.nvp;
            createParams.detailMeshes     = iv.dmesh.meshes;
            createParams.detailVerts      = iv.dmesh.verts;
            createParams.detailVertsCount = iv.dmesh.nverts;
            createParams.detailTris       = iv.dmesh.tris;
            createParams.detailTriCount   = iv.dmesh.ntris;

            createParams.offMeshConVerts = meshData.offMeshConnections.ToArray();
            createParams.offMeshConCount = meshData.offMeshConnections.Count / 6;
            createParams.offMeshConRad   = meshData.offMeshConnectionRads.ToArray();
            createParams.offMeshConDir   = meshData.offMeshConnectionDirs.ToArray();
            createParams.offMeshConAreas = meshData.offMeshConnectionsAreas.ToArray();
            createParams.offMeshConFlags = meshData.offMeshConnectionsFlags.ToArray();

            createParams.walkableHeight = BASE_UNIT_DIM * config.walkableHeight;    // agent height
            createParams.walkableRadius = BASE_UNIT_DIM * config.walkableRadius;    // agent radius
            createParams.walkableClimb  = BASE_UNIT_DIM * config.walkableClimb;     // keep less that walkableHeight (aka agent height)!
            createParams.tileX          = (int)((((bmin[0] + bmax[0]) / 2) - navMesh.getParams().orig[0]) / SharedConst.GRID_SIZE);
            createParams.tileY          = (int)((((bmin[2] + bmax[2]) / 2) - navMesh.getParams().orig[2]) / SharedConst.GRID_SIZE);
            rcVcopy(createParams.bmin, bmin);
            rcVcopy(createParams.bmax, bmax);
            createParams.cs          = config.cs;
            createParams.ch          = config.ch;
            createParams.tileLayer   = 0;
            createParams.buildBvTree = true;

            // will hold final navmesh
            dtRawTileData navData = null;

            do
            {
                // these values are checked within dtCreateNavMeshData - handle them here
                // so we have a clear error message
                if (createParams.nvp > DT_VERTS_PER_POLYGON)
                {
                    Console.WriteLine($"{tileString} Invalid verts-per-polygon value!");
                    break;
                }
                if (createParams.vertCount >= 0xffff)
                {
                    Console.WriteLine($"{tileString} Too many vertices!");
                    break;
                }
                if (createParams.vertCount == 0 || createParams.verts == null)
                {
                    // occurs mostly when adjacent tiles have models
                    // loaded but those models don't span into this tile

                    // message is an annoyance
                    break;
                }
                if (createParams.polyCount == 0 || createParams.polys == null ||
                    TILES_PER_MAP * TILES_PER_MAP == createParams.polyCount)
                {
                    // we have flat tiles with no actual geometry - don't build those, its useless
                    // keep in mind that we do output those into debug info
                    // drop tiles with only exact count - some tiles may have geometry while having less tiles
                    Console.WriteLine($"{tileString} No polygons to build on tile!              ");
                    break;
                }
                if (createParams.detailMeshes == null || createParams.detailVerts == null || createParams.detailTris == null)
                {
                    Console.WriteLine($"{tileString} No detail mesh to build tile!");
                    break;
                }

                Console.WriteLine($"{tileString} Building navmesh tile...");
                if (!dtCreateNavMeshData(createParams, out navData))
                {
                    Console.WriteLine($"{tileString} Failed building navmesh tile!");
                    break;
                }

                ulong tileRef = 0;
                Console.WriteLine($"{tileString} Adding tile to navmesh...");
                // DT_TILE_FREE_DATA tells detour to unallocate memory when the tile
                // is removed via removeTile()
                if (dtStatusFailed(navMesh.addTile(navData, (int)dtTileFlags.DT_TILE_FREE_DATA, 0, ref tileRef)) || tileRef == 0)
                {
                    Console.WriteLine($"{tileString} Failed adding tile to navmesh!");
                    break;
                }

                // file output
                string fileName = $"mmaps/{mapID:D4}{tileY:D2}{tileX:D2}.mmtile";
                using (BinaryWriter binaryWriter = new BinaryWriter(File.Open(fileName, FileMode.Create, FileAccess.Write)))
                {
                    Console.WriteLine($"{tileString} Writing to file...");

                    var navDataBytes = navData.ToBytes();

                    // write header
                    MmapTileHeader header = new MmapTileHeader();
                    header.mmapMagic   = SharedConst.MMAP_MAGIC;
                    header.dtVersion   = Detour.DT_NAVMESH_VERSION;
                    header.mmapVersion = SharedConst.MMAP_VERSION;
                    header.usesLiquids = m_terrainBuilder.usesLiquids();
                    header.size        = (uint)navDataBytes.Length;
                    binaryWriter.WriteStruct(header);

                    // write data
                    binaryWriter.Write(navDataBytes);
                }

                // now that tile is written to disk, we can unload it
                navMesh.removeTile(tileRef, out dtRawTileData dtRawTileData);
            }while (false);
        }
Пример #2
0
        /// @par
        ///
        /// This function returns the data for the tile so that, if desired,
        /// it can be added back to the navigation mesh at a later point.
        ///
        /// @see #addTile
        /// Removes the specified tile from the navigation mesh.
        ///  @param[in]		ref			The reference of the tile to remove.
        ///  @param[out]	data		Data associated with deleted tile.
        ///  @param[out]	dataSize	Size of the data associated with deleted tile.
        /// @return The status flags for the operation.
        public dtStatus removeTile(dtTileRef tileRef, out dtRawTileData rawTileData)
        {
            rawTileData = null;

            if (tileRef == 0)
                return DT_FAILURE | DT_INVALID_PARAM;
            uint tileIndex = decodePolyIdTile((dtPolyRef)tileRef);
            uint tileSalt = decodePolyIdSalt((dtPolyRef)tileRef);
            if ((int)tileIndex >= m_maxTiles)
                return DT_FAILURE | DT_INVALID_PARAM;
            dtMeshTile tile = m_tiles[tileIndex];
            if (tile.salt != tileSalt)
                return DT_FAILURE | DT_INVALID_PARAM;

            // Remove tile from hash lookup.
            int h = computeTileHash(tile.header.x,tile.header.y,m_tileLutMask);
            dtMeshTile prev = null;
            dtMeshTile cur = m_posLookup[h];
            while (cur != null)
            {
                if (cur == tile)
                {
                    if (prev != null)
                        prev.next = cur.next;
                    else
                        m_posLookup[h] = cur.next;
                    break;
                }
                prev = cur;
                cur = cur.next;
            }

            // Remove connections to neighbour tiles.
            // Create connections with neighbour tiles.
            const int MAX_NEIS = 32;
            dtMeshTile[] neis = new dtMeshTile[MAX_NEIS];
            int nneis;

            // Connect with layers in current tile.
            nneis = getTilesAt(tile.header.x, tile.header.y, neis, MAX_NEIS);
            for (int j = 0; j < nneis; ++j)
            {
                if (neis[j] == tile) continue;
                unconnectExtLinks(neis[j], tile);
            }

            // Connect with neighbour tiles.
            for (int i = 0; i < 8; ++i)
            {
                nneis = getNeighbourTilesAt(tile.header.x, tile.header.y, i, neis, MAX_NEIS);
                for (int j = 0; j < nneis; ++j)
                    unconnectExtLinks(neis[j], tile);
            }

            // Reset tile.
            if ((tile.flags & (int)dtTileFlags.DT_TILE_FREE_DATA) != 0)
            {
                // Owns data
                //dtFree(tile.data);
                tile.data = null;
                //tile.dataSize = 0;
                //if (data) *data = 0;
                //if (dataSize) *dataSize = 0;
                rawTileData = null;

            }
            else
            {
                //if (data) *data = tile.data;
                //if (dataSize) *dataSize = tile.dataSize;
                rawTileData = tile.data;
            }

            tile.header = null;
            tile.flags = 0;
            tile.linksFreeList = 0;
            tile.polys = null;
            tile.verts = null;
            tile.links = null;
            tile.detailMeshes = null;
            tile.detailVerts = null;
            tile.detailTris = null;
            tile.bvTree = null;
            tile.offMeshCons = null;

            // Update salt, salt should never be zero.
            #if DT_POLYREF64
            tile.salt = (tile.salt+1) & ((1<<DT_SALT_BITS)-1);
            #else
            tile.salt = (dtTileRef)( (tile.salt+1) & ((1<<(int)m_saltBits)-1) );
            #endif
            if (tile.salt == 0)
                tile.salt++;

            // Add to free list.
            tile.next = m_nextFree;
            m_nextFree = tile;

            return DT_SUCCESS;
        }
Пример #3
0
        /// @par
        ///
        /// The add operation will fail if the data is in the wrong format, the allocated tile
        /// space is full, or there is a tile already at the specified reference.
        ///
        /// The lastRef parameter is used to restore a tile with the same tile
        /// reference it had previously used.  In this case the #dtPolyRef's for the
        /// tile will be restored to the same values they were before the tile was 
        /// removed.
        ///
        /// @see dtCreateNavMeshData, #removeTile
        /// Adds a tile to the navigation mesh.
        ///  @param[in]		data		Data for the new tile mesh. (See: #dtCreateNavMeshData)
        ///  @param[in]		dataSize	Data size of the new tile mesh.
        ///  @param[in]		flags		Tile flags. (See: #dtTileFlags)
        ///  @param[in]		lastRef		The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
        ///  @param[out]	result		The tile reference. (If the tile was succesfully added.) [opt]
        /// @return The status flags for the operation.
        public dtStatus addTile(dtRawTileData rawTileData, int flags, dtTileRef lastRef, ref dtTileRef result)
        {
            //C#: Using an intermediate class dtRawTileData because Cpp uses a binary buffer.

            // Make sure the data is in right format.
            dtMeshHeader header = rawTileData.header;
            if (header.magic != DT_NAVMESH_MAGIC)
                return DT_FAILURE | DT_WRONG_MAGIC;
            if (header.version != DT_NAVMESH_VERSION)
                return DT_FAILURE | DT_WRONG_VERSION;

            // Make sure the location is free.
            if (getTileAt(header.x, header.y, header.layer) != null)
                return DT_FAILURE;

            // Allocate a tile.
            dtMeshTile tile = null;
            if (lastRef == 0)
            {
                if (m_nextFree != null)
                {
                    tile = m_nextFree;
                    m_nextFree = tile.next;
                    tile.next = null;
                }
            }
            else
            {
                // Try to relocate the tile to specific index with same salt.
                int tileIndex = (int)decodePolyIdTile((dtPolyRef)lastRef);
                if (tileIndex >= m_maxTiles)
                    return DT_FAILURE | DT_OUT_OF_MEMORY;
                // Try to find the specific tile id from the free list.
                dtMeshTile target = m_tiles[tileIndex];
                dtMeshTile prev = null;
                tile = m_nextFree;
                while (tile != null && tile != target)
                {
                    prev = tile;
                    tile = tile.next;
                }
                // Could not find the correct location.
                if (tile != target)
                    return DT_FAILURE | DT_OUT_OF_MEMORY;
                // Remove from freelist
                if (prev == null)
                    m_nextFree = tile.next;
                else
                    prev.next = tile.next;

                // Restore salt.
                tile.salt = decodePolyIdSalt((dtPolyRef)lastRef);
            }

            // Make sure we could allocate a tile.
            if (tile == null)
                return DT_FAILURE | DT_OUT_OF_MEMORY;

            // Insert tile into the position lut.
            int h = computeTileHash(header.x, header.y, m_tileLutMask);
            tile.next = m_posLookup[h];
            m_posLookup[h] = tile;

            // Patch header pointers.

            //int vertsCount = 3*header.vertCount;
            //int polysSize = header.polyCount;
            //int linksSize = header.maxLinkCount;
            //int detailMeshesSize = header.detailMeshCount;
            //int detailVertsSize = 3*header.detailVertCount;
            //int detailTrisSize = 4*header.detailTriCount;
            //int bvtreeSize = header.bvNodeCount;
            //int offMeshLinksSize = header.offMeshConCount;

            //byte* d = data + headerSize;
            tile.verts = rawTileData.verts;
            tile.polys = rawTileData.polys;
            tile.links = rawTileData.links;
            tile.detailMeshes = rawTileData.detailMeshes;
            tile.detailVerts = rawTileData.detailVerts;
            tile.detailTris = rawTileData.detailTris;
            tile.bvTree = rawTileData.bvTree;
            tile.offMeshCons = rawTileData.offMeshCons;

            // If there are no items in the bvtree, reset the tree pointer.
            //c#: unnecessary, Cpp is afraid to point to whatever data ends up here
            //if (bvtreeSize == 0)
            //	tile.bvTree = null;

            // Build links freelist
            tile.linksFreeList = 0;
            tile.links[header.maxLinkCount-1].next = DT_NULL_LINK;
            for (int i = 0; i < header.maxLinkCount-1; ++i){
                tile.links[i].next = (dtTileRef) (i+1);
            }

            // Init tile.
            tile.header = header;
            tile.data = rawTileData;
            //tile.dataSize = dataSize;
            tile.flags = flags;

            connectIntLinks(tile);
            baseOffMeshLinks(tile);

            // Create connections with neighbour tiles.
            const int MAX_NEIS = 32;
            dtMeshTile[] neis = new dtMeshTile[MAX_NEIS];
            int nneis;

            // Connect with layers in current tile.
            nneis = getTilesAt(header.x, header.y, neis, MAX_NEIS);
            for (int j = 0; j < nneis; ++j)
            {
                if (neis[j] != tile)
                {
                    connectExtLinks(tile, neis[j], -1);
                    connectExtLinks(neis[j], tile, -1);
                }
                connectExtOffMeshLinks(tile, neis[j], -1);
                connectExtOffMeshLinks(neis[j], tile, -1);
            }

            // Connect with neighbour tiles.
            for (int i = 0; i < 8; ++i)
            {
                nneis = getNeighbourTilesAt(header.x, header.y, i, neis, MAX_NEIS);
                for (int j = 0; j < nneis; ++j)
                {
                    connectExtLinks(tile, neis[j], i);
                    connectExtLinks(neis[j], tile, dtOppositeTile(i));
                    connectExtOffMeshLinks(tile, neis[j], i);
                    connectExtOffMeshLinks(neis[j], tile, dtOppositeTile(i));
                }
            }

            result = getTileRef(tile);

            return DT_SUCCESS;
        }
Пример #4
0
        /// Initializes the navigation mesh for single tile use.
        ///  @param[in]	data		Data of the new tile. (See: #dtCreateNavMeshData)
        ///  @param[in]	dataSize	The data size of the new tile.
        ///  @param[in]	flags		The tile flags. (See: #dtTileFlags)
        /// @return The status flags for the operation.
        ///  @see dtCreateNavMeshData
        public dtStatus init(dtRawTileData rawTile, int flags)
        {
            //C#: Using an intermediate class dtRawTileData because Cpp uses a binary buffer.

            // Make sure the data is in right format.
            //dtMeshHeader header = (dtMeshHeader*)data;
            dtMeshHeader header = rawTile.header;
            if (header.magic != DT_NAVMESH_MAGIC)
                return DT_FAILURE | DT_WRONG_MAGIC;
            if (header.version != DT_NAVMESH_VERSION)
                return DT_FAILURE | DT_WRONG_VERSION;

            dtNavMeshParams navMeshParams = new dtNavMeshParams();
            dtVcopy(navMeshParams.orig, header.bmin);
            navMeshParams.tileWidth = header.bmax[0] - header.bmin[0];
            navMeshParams.tileHeight = header.bmax[2] - header.bmin[2];
            navMeshParams.maxTiles = 1;
            navMeshParams.maxPolys = header.polyCount;

            dtStatus status = init(navMeshParams);
            if (dtStatusFailed(status))
                return status;

            //return addTile(data, dataSize, flags, 0, 0);
            dtTileRef dummyResult = 0;
            return addTile(rawTile, flags, 0,ref dummyResult);
        }