void buildNavMesh(uint mapID, out dtNavMesh navMesh) { // if map has a parent we use that to generate dtNavMeshParams - worldserver will load all missing tiles from that map int navMeshParamsMapId = _vmapManager.GetParentMapId(mapID); if (navMeshParamsMapId == -1) { navMeshParamsMapId = (int)mapID; } SortedSet <uint> tiles = getTileList((uint)navMeshParamsMapId); // old code for non-statically assigned bitmask sizes: ///*** calculate number of bits needed to store tiles & polys ***/ //int tileBits = dtIlog2(dtNextPow2(tiles.size())); //if (tileBits < 1) tileBits = 1; // need at least one bit! //int polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits; int polyBits = SharedConst.DT_POLY_BITS; int maxTiles = tiles.Count; int maxPolysPerTile = 1 << polyBits; /*** calculate bounds of map ***/ uint tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0; foreach (var it in tiles) { StaticMapTree.UnpackTileID(it, out uint tileX, out uint tileY); if (tileX > tileXMax) { tileXMax = tileX; } else if (tileX < tileXMin) { tileXMin = tileX; } if (tileY > tileYMax) { tileYMax = tileY; } else if (tileY < tileYMin) { tileYMin = tileY; } } // use Max because '32 - tileX' is negative for values over 32 float[] bmin; float[] bmax; getTileBounds(tileXMax, tileYMax, null, 0, out bmin, out bmax); /*** now create the navmesh ***/ // navmesh creation params dtNavMeshParams navMeshParams = new dtNavMeshParams(); navMeshParams.tileWidth = SharedConst.GRID_SIZE; navMeshParams.tileHeight = SharedConst.GRID_SIZE; rcVcopy(navMeshParams.orig, bmin); navMeshParams.maxTiles = maxTiles; navMeshParams.maxPolys = maxPolysPerTile; navMesh = new dtNavMesh(); if (dtStatusFailed(navMesh.init(navMeshParams))) { Console.WriteLine($"[Map: {mapID:D4}] Failed creating navmesh!"); return; } string fileName = $"mmaps/{mapID:D4}.mmap"; using (BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create, FileAccess.Write))) { // now that we know navMesh params are valid, we can write them to file writer.Write(bmin[0]); writer.Write(bmin[1]); writer.Write(bmin[2]); writer.Write(SharedConst.GRID_SIZE); writer.Write(SharedConst.GRID_SIZE); writer.Write(maxTiles); writer.Write(maxPolysPerTile); } }
/// 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); }
uint m_polyBits; //< Number of poly bits in the tile ID. #endif #region Constructors public dtNavMesh() { #if DT_POLYREF64 m_saltBits = 0; m_tileBits = 0; m_polyBits = 0; #endif m_params = new dtNavMeshParams(); m_orig[0] = 0; m_orig[1] = 0; m_orig[2] = 0; }
/// @{ /// @name Initialization and Tile Management /// Initializes the navigation mesh for tiled use. /// @param[in] params Initialization parameters. /// @return The status flags for the operation. public dtStatus init(dtNavMeshParams navMeshParams) { //memcpy(&m_params, params, sizeof(dtNavMeshParams)); m_params = navMeshParams.Clone(); dtVcopy(m_orig, navMeshParams.orig); m_tileWidth = navMeshParams.tileWidth; m_tileHeight = navMeshParams.tileHeight; // Init tiles m_maxTiles = navMeshParams.maxTiles; m_tileLutSize = (int)dtNextPow2((uint)(navMeshParams.maxTiles/4)); if (m_tileLutSize == 0) m_tileLutSize = 1; m_tileLutMask = m_tileLutSize-1; //m_tiles = (dtMeshTile*)dtAlloc(sizeof(dtMeshTile)*m_maxTiles, DT_ALLOC_PERM); m_tiles = new dtMeshTile[m_maxTiles]; dtcsArrayItemsCreate(m_tiles); if (m_tiles == null) return (DT_FAILURE | DT_OUT_OF_MEMORY); //m_posLookup = (dtMeshTile**)dtAlloc(sizeof(dtMeshTile*)*m_tileLutSize, DT_ALLOC_PERM); m_posLookup = new dtMeshTile[m_tileLutSize]; dtcsArrayItemsCreate(m_posLookup); if (m_posLookup == null) return DT_FAILURE | DT_OUT_OF_MEMORY; //memset(m_tiles, 0, sizeof(dtMeshTile)*m_maxTiles); //memset(m_posLookup, 0, sizeof(dtMeshTile*)*m_tileLutSize); m_nextFree = null; for (int i = m_maxTiles-1; i >= 0; --i) { m_tiles[i].salt = 1; m_tiles[i].next = m_nextFree; m_nextFree = m_tiles[i]; } // Init ID generator values. #if DT_POLYREF64 #else m_tileBits = (dtStatus)dtIlog2(dtNextPow2((uint)navMeshParams.maxTiles)); m_polyBits = (dtStatus)dtIlog2(dtNextPow2((uint)navMeshParams.maxPolys)); // Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow. m_saltBits = Math.Min((uint)31, 32 - m_tileBits - m_polyBits); if (m_saltBits < 10) return DT_FAILURE | DT_INVALID_PARAM; #endif return DT_SUCCESS; }