void PathInfo::Build() { float x, y, z; // set start and a default next position m_sourceObject->GetPosition(x, y, z); setStartPosition(x, y, z); setNextPosition(x, y, z); // get nav mesh m_navMesh = m_sourceObject->GetMap()->GetNavMesh(); if(!m_navMesh) { // if there is no navmesh, just move to destination shortcut(); return; } float extents[3] = {2.0f, 4.0f, 2.0f}; // defines bounds of box for search area dtQueryFilter filter = dtQueryFilter(); // use general filter so we know if we are near navmesh // get start and end positions getStartPosition(x, y, z); float startPos[3] = {y, z, x}; getEndPosition(x, y, z); float endPos[3] = {y, z, x}; // find start and end poly dtPolyRef startPoly = m_navMesh->findNearestPoly(startPos, extents, &filter, 0); dtPolyRef endPoly = m_navMesh->findNearestPoly(endPos, extents, &filter, 0); Build(startPoly, endPoly); }
static bool HandleMmapLocCommand(ChatHandler* handler, const char* /*args*/) { handler->PSendSysMessage("mmap tileloc:"); // grid tile location Player* player = handler->GetSession()->GetPlayer(); int32 gx = 32 - player->GetPositionX() / SIZE_OF_GRIDS; int32 gy = 32 - player->GetPositionY() / SIZE_OF_GRIDS; handler->PSendSysMessage("%03u%02i%02i.mmtile", player->GetMapId(), gy, gx); handler->PSendSysMessage("gridloc [%i,%i]", gx, gy); // calculate navmesh tile location const dtNavMesh* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(player->GetMapId()); const dtNavMeshQuery* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(player->GetMapId(), player->GetInstanceId()); if (!navmesh || !navmeshquery) { handler->PSendSysMessage("NavMesh not loaded for current map."); return true; } const float* min = navmesh->getParams()->orig; float x, y, z; player->GetPosition(x, y, z); float location[VERTEX_SIZE] = {y, z, x}; float extents[VERTEX_SIZE] = {2.f,4.f,2.f}; int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS); int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS); handler->PSendSysMessage("Calc [%02i,%02i]", tilex, tiley); // navmesh poly -> navmesh tile location dtQueryFilter filter = dtQueryFilter(); dtPolyRef polyRef = INVALID_POLYREF; navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL); if (polyRef == INVALID_POLYREF) handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)"); else { const dtMeshTile* tile; const dtPoly* poly; navmesh->getTileAndPolyByRef(polyRef, &tile, &poly); if (tile) handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y); else handler->PSendSysMessage("Dt [??,??] (no tile loaded)"); } return true; }
void Sample_Debug::setHighlightedTile(const float* pos) { if (!pos || !m_navMesh) { m_highLightedTileX = -1; m_highLightedTileY = -1; return; } float extents[3] = {2.f, 4.f, 2.f}; dtPolyRef polyRef = m_navMesh->findNearestPoly(pos, extents, &dtQueryFilter(), 0); unsigned char area = m_navMesh->getPolyArea(polyRef); unsigned short flags = m_navMesh->getPolyFlags(polyRef); const dtMeshTile* tile = m_navMesh->getTileByPolyRef(polyRef, 0); if(!tile) { m_highLightedTileX = -1; m_highLightedTileY = -1; return; } m_highLightedTileX = tile->header->x; m_highLightedTileY = tile->header->y; }
static bool HandleMmapLocCommand(ChatHandler* handler, char const* /*args*/) { handler->PSendSysMessage("mmap tileloc:"); // grid tile location Player* player = handler->GetSession()->GetPlayer(); int32 gx = 32 - player->GetPositionX() / SIZE_OF_GRIDS; int32 gy = 32 - player->GetPositionY() / SIZE_OF_GRIDS; float x, y, z; player->GetPosition(x, y, z); handler->PSendSysMessage("%04u%02i%02i.mmtile", player->GetMapId(), gx, gy); handler->PSendSysMessage("gridloc [%i, %i]", gy, gx); // calculate navmesh tile location uint32 terrainMapId = PhasingHandler::GetTerrainMapId(player->GetPhaseShift(), player->GetMap(), x, y); dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(terrainMapId); dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(terrainMapId, player->GetInstanceId()); if (!navmesh || !navmeshquery) { handler->PSendSysMessage("NavMesh not loaded for current map."); return true; } float const* min = navmesh->getParams()->orig; float location[VERTEX_SIZE] = { y, z, x }; float extents[VERTEX_SIZE] = { 3.0f, 5.0f, 3.0f }; int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS); int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS); handler->PSendSysMessage("Calc [%02i, %02i]", tilex, tiley); // navmesh poly -> navmesh tile location dtQueryFilter filter = dtQueryFilter(); dtPolyRef polyRef = INVALID_POLYREF; if (dtStatusFailed(navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL))) { handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)"); return true; } if (polyRef == INVALID_POLYREF) handler->PSendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)"); else { dtMeshTile const* tile; dtPoly const* poly; if (dtStatusSucceed(navmesh->getTileAndPolyByRef(polyRef, &tile, &poly))) { if (tile) { handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y); return false; } } handler->PSendSysMessage("Dt [??,??] (no tile loaded)"); } return true; }
void PathInfo::Update(const float destX, const float destY, const float destZ) { float x, y, z; // update start and end m_sourceObject->GetPosition(x, y, z); setStartPosition(x, y, z); setEndPosition(destX, destY, destZ); // make sure navMesh works if(!m_navMesh) { m_sourceObject->GetPosition(x, y, z); m_navMesh = m_sourceObject->GetMap()->GetNavMesh(); if(!m_navMesh) { // can't pathfind if navmesh doesn't exist shortcut(); return; } } if(!m_pathPolyRefs) { // path was not built before, most likely because navmesh wasn't working // start from scratch, then return Build(); return; } // should be safe to update path now bool startOffPath = false; bool endOffPath = false; // find start and end poly // navMesh.findNearestPoly is expensive, so first we check just the current path getStartPosition(x, y, z); dtPolyRef startPoly = getPathPolyByPosition(x, y, z); getEndPosition(x, y, z); dtPolyRef endPoly = getPathPolyByPosition(x, y, z); if(startPoly != 0 && endPoly != 0) trim(startPoly, endPoly); else { // start or end is off the path, need to find the polygon float extents[3] = {2.f, 4.f, 2.f}; // bounds of poly search area dtQueryFilter filter = dtQueryFilter(); // filter for poly search if(!startPoly) { getStartPosition(x, y, z); float startPos[3] = {y, z, x}; startOffPath = true; startPoly = m_navMesh->findNearestPoly(startPos, extents, &filter, 0); } if(!endPoly) { getEndPosition(x, y, z); float endPos[3] = {y, z, x}; endOffPath = true; endPoly = m_navMesh->findNearestPoly(endPos, extents, &filter, 0); } if(startPoly == 0 || endPoly == 0) { // source or dest not near navmesh polygons: // flying, falling, swimming, or navmesh has a hole // ignore obstacles/terrain is better than giving up // PATHFIND TODO: prevent walking/swimming mobs from flying into the air shortcut(); return; } } if(startPoly == endPoly) { // start and end are on same polygon // just need to move in straight line // PATHFIND TODO: prevent walking/swimming mobs from flying into the air clear(); m_pathPolyRefs = new dtPolyRef[1]; m_pathPolyRefs[0] = startPoly; m_length = 1; getEndPosition(x, y, z); setNextPosition(x, y, z); m_type = PathType(m_type | PATHFIND_NORMAL); return; } if(startOffPath) { bool adjacent = false; int i; for(i = 0; i < DT_VERTS_PER_POLYGON; ++i) if(startPoly == m_navMesh->getPolyByRef(m_pathPolyRefs[0])->neis[i]) { adjacent = true; break; } if(adjacent) { // startPoly is adjacent to the path, we can add it to the start of the path // 50th poly will fall off of path, shouldn't be an issue because most paths aren't that long m_length = m_length < MAX_PATH_LENGTH ? m_length + 1 : m_length; dtPolyRef* temp = new dtPolyRef[m_length]; temp[0] = startPoly; for(i = 1; i < m_length; ++i) temp[i] = m_pathPolyRefs[i - 1]; delete [] m_pathPolyRefs; m_pathPolyRefs = temp; } else { // waste of time to optimize, just find brand new path Build(startPoly, endPoly); return; } } if(endOffPath) { bool adjacent = false; int i; for(i = 0; i < DT_VERTS_PER_POLYGON; ++i) if(startPoly == m_navMesh->getPolyByRef(m_pathPolyRefs[0])->neis[i]) { adjacent = true; break; } if(adjacent) { if(m_length < MAX_PATH_LENGTH) { // endPoly is adjacent to the path, and we have enough room to add it to the end dtPolyRef* temp = new dtPolyRef[m_length + 1]; for(i = 0; i < m_length; ++i) temp[i] = m_pathPolyRefs[i]; temp[i] = endPoly; delete [] m_pathPolyRefs; m_pathPolyRefs = temp; } //else // ; // endPoly is adjacent to the path, we just don't have room to store it } else { // waste of time to optimize, just find brand new path Build(startPoly, endPoly); return; } } updateNextPosition(); }