NavMeshPtr makeEmptyNavMesh(const Settings& settings) { // Max tiles and max polys affect how the tile IDs are caculated. // There are 22 bits available for identifying a tile and a polygon. const int polysAndTilesBits = 22; const auto polysBits = getMinValuableBitsNumber(settings.mMaxPolys); if (polysBits >= polysAndTilesBits) throw InvalidArgument("Too many polygons per tile"); const auto tilesBits = polysAndTilesBits - polysBits; dtNavMeshParams params; std::fill_n(params.orig, 3, 0.0f); params.tileWidth = settings.mTileSize * settings.mCellSize; params.tileHeight = settings.mTileSize * settings.mCellSize; params.maxTiles = 1 << tilesBits; params.maxPolys = 1 << polysBits; NavMeshPtr navMesh(dtAllocNavMesh(), &dtFreeNavMesh); const auto status = navMesh->init(¶ms); if (!dtStatusSucceed(status)) throw NavigatorException("Failed to init navmesh"); return navMesh; }
NavMeshLoader::LoadResult NavMeshLoader::LoadZoneMeshData(const std::shared_ptr<char>& data, DWORD length) { ReadCursor cursor{ data.get(), length }; //------------------------------------------------------------------------ // Read the header NavMeshSetHeader header; if (!FillStructure(cursor, header)) { DebugSpewAlways("Failed to read header from mesh file!"); return CORRUPT; } if (header.magic != NAVMESHSET_MAGIC) { DebugSpewAlways("Header Magic value mismatch!"); return CORRUPT; } if (header.version != NAVMESHSET_VERSION) { DebugSpewAlways("Header version mismatch!"); return VERSION_MISMATCH; } std::unique_ptr<dtNavMesh> navMesh(new dtNavMesh); if (!navMesh->init(&header.params)) { DebugSpewAlways("Header params are bad!"); return CORRUPT; } //------------------------------------------------------------------------ // Read the tiles int passtile = 0, failtile = 0; for (int i = 0; i < header.numTiles; ++i) { NavMeshTileHeader tileHeader; if (!FillStructure(cursor, tileHeader)) { DebugSpewAlways("Failed to read tile header for tile %d!", i); return CORRUPT; } if (!tileHeader.tileRef || !tileHeader.dataSize) { continue; } // validate the size. For sure it should not exceed the remainder of the // file size. if (tileHeader.dataSize < 0 || tileHeader.dataSize > cursor.length) { DebugSpewAlways("tileHeader's dataSize has invalid size %d for tile %d", tileHeader.dataSize, i); return CORRUPT; } unsigned char* tileData = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM); memcpy(tileData, cursor.data, tileHeader.dataSize); cursor.length -= tileHeader.dataSize; cursor.data += tileHeader.dataSize; if (navMesh->addTile(tileData, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0)) passtile++; else { DebugSpewAlways("Failed to load tile %d", i); failtile++; } } // these values shouldn't be set until we have a successful load m_loadedTiles = passtile; m_mesh = std::move(navMesh); OnNavMeshChanged(m_mesh.get()); return SUCCESS; }