/* Removes and return the next waypoint in the multipath corresponding to given id. */ float3 CPathManager::NextWaypoint(unsigned int pathId, float3 callerPos, float minDistance, int numRetries, int ownerId) const { SCOPED_TIMER("PFS"); //0 indicate a no-path id. if(pathId == 0) return float3(-1,-1,-1); if(numRetries>4) return float3(-1,-1,-1); //Find corresponding multipath. std::map<unsigned int, MultiPath*>::const_iterator pi = pathMap.find(pathId); if(pi == pathMap.end()) return float3(-1,-1,-1); MultiPath* multiPath = pi->second; if(callerPos==ZeroVector){ if(!multiPath->detailedPath.path.empty()) callerPos=multiPath->detailedPath.path.back(); } //check if detailed path need bettering if(!multiPath->estimatedPath.path.empty() && (multiPath->estimatedPath.path.back().SqDistance2D(callerPos) < Square(MIN_DETAILED_DISTANCE * SQUARE_SIZE) || multiPath->detailedPath.path.size() <= 2)){ if(!multiPath->estimatedPath2.path.empty() //if so check if estimated path also need bettering && (multiPath->estimatedPath2.path.back().SqDistance2D(callerPos) < Square(MIN_ESTIMATE_DISTANCE * SQUARE_SIZE) || multiPath->estimatedPath.path.size() <= 2)){ Estimate2ToEstimate(*multiPath, callerPos, ownerId); } if(multiPath->caller) multiPath->caller->UnBlock(); EstimateToDetailed(*multiPath, callerPos, ownerId); if(multiPath->caller) multiPath->caller->Block(); } //Repeat until a waypoint distant enought are found. float3 waypoint; do { //Get next waypoint. if(multiPath->detailedPath.path.empty()) { if(multiPath->estimatedPath2.path.empty() && multiPath->estimatedPath.path.empty()) return multiPath->finalGoal; else return NextWaypoint(pathId,callerPos,minDistance,numRetries+1,ownerId); } else { waypoint = multiPath->detailedPath.path.back(); multiPath->detailedPath.path.pop_back(); } } while(callerPos.SqDistance2D(waypoint) < Square(minDistance) && waypoint != multiPath->detailedPath.pathGoal); return waypoint; }
/* Request a new multipath, store the result and return an handle-id to it. */ unsigned int CPathManager::RequestPath(const MoveData* moveData, float3 startPos, CPathFinderDef* peDef, float3 goalPos, CSolidObject* caller) { SCOPED_TIMER("AI:PFS"); // Creates a new multipath. MultiPath* newPath = SAFE_NEW MultiPath(startPos, peDef, moveData); newPath->finalGoal = goalPos; newPath->caller = caller; if (caller) { caller->UnBlock(); } unsigned int retValue = 0; // Choose finder dependent on distance to goal. float distanceToGoal = peDef->Heuristic(int(startPos.x / SQUARE_SIZE), int(startPos.z / SQUARE_SIZE)); if (distanceToGoal < DETAILED_DISTANCE) { // Get a detailed path. IPath::SearchResult result = pf->GetPath(*moveData, startPos, *peDef, newPath->detailedPath, true); if (result == IPath::Ok || result == IPath::GoalOutOfRange) { retValue = Store(newPath); } else { delete newPath; } } else if (distanceToGoal < ESTIMATE_DISTANCE) { // Get an estimate path. IPath::SearchResult result = pe->GetPath(*moveData, startPos, *peDef, newPath->estimatedPath); if (result == IPath::Ok || result == IPath::GoalOutOfRange) { // Turn a part of it into detailed path. EstimateToDetailed(*newPath, startPos); // Store the path. retValue = Store(newPath); } else { // if we fail see if it can work find a better block to start from float3 sp = pe->FindBestBlockCenter(moveData, startPos); if (sp.x != 0 && (((int) sp.x) / (SQUARE_SIZE * 8) != ((int) startPos.x) / (SQUARE_SIZE * 8) || ((int) sp.z) / (SQUARE_SIZE * 8) != ((int) startPos.z) / (SQUARE_SIZE * 8))) { IPath::SearchResult result = pe->GetPath(*moveData, sp, *peDef, newPath->estimatedPath); if (result == IPath::Ok || result == IPath::GoalOutOfRange) { EstimateToDetailed(*newPath, startPos); retValue = Store(newPath); } else { delete newPath; } } else { delete newPath; } } } else { // Get a low-res. estimate path. IPath::SearchResult result = pe2->GetPath(*moveData, startPos, *peDef, newPath->estimatedPath2); if (result == IPath::Ok || result == IPath::GoalOutOfRange) { // Turn a part of it into hi-res. estimate path. Estimate2ToEstimate(*newPath, startPos); // And estimate into detailed. EstimateToDetailed(*newPath, startPos); // Store the path. retValue = Store(newPath); } else { // sometimes the 32*32 squares can be wrong so if it fails to get a path also try with 8*8 squares IPath::SearchResult result = pe->GetPath(*moveData, startPos, *peDef, newPath->estimatedPath); if (result == IPath::Ok || result == IPath::GoalOutOfRange) { EstimateToDetailed(*newPath, startPos); retValue = Store(newPath); } else { // 8*8 can also fail rarely, so see if we can find a better 8*8 to start from float3 sp = pe->FindBestBlockCenter(moveData, startPos); if (sp.x != 0 && (((int) sp.x) / (SQUARE_SIZE * 8) != ((int) startPos.x) / (SQUARE_SIZE * 8) || ((int) sp.z) / (SQUARE_SIZE * 8) != ((int) startPos.z) / (SQUARE_SIZE * 8))) { IPath::SearchResult result = pe->GetPath(*moveData, sp, *peDef, newPath->estimatedPath); if (result == IPath::Ok || result == IPath::GoalOutOfRange) { EstimateToDetailed(*newPath, startPos); retValue = Store(newPath); } else { delete newPath; } } else { delete newPath; } } } } if (caller) { caller->Block(); } return retValue; }
/* Removes and return the next waypoint in the multipath corresponding to given id. */ float3 CPathManager::NextWaypoint(unsigned int pathId, float3 callerPos, float minDistance, int numRetries, int ownerId, bool synced) const { SCOPED_TIMER("PFS"); // 0 indicates a no-path id if (pathId == 0) return float3(-1.0f, -1.0f, -1.0f); if (numRetries > 4) return float3(-1.0f, -1.0f, -1.0f); //Find corresponding multipath. std::map<unsigned int, MultiPath*>::const_iterator pi = pathMap.find(pathId); if (pi == pathMap.end()) return float3(-1.0f, -1.0f, -1.0f); MultiPath* multiPath = pi->second; if (callerPos == ZeroVector) { if (!multiPath->detailedPath.path.empty()) callerPos = multiPath->detailedPath.path.back(); } // check if detailed path needs bettering if (!multiPath->estimatedPath.path.empty() && (multiPath->estimatedPath.path.back().SqDistance2D(callerPos) < Square(MIN_DETAILED_DISTANCE * SQUARE_SIZE) || multiPath->detailedPath.path.size() <= 2)) { if (!multiPath->estimatedPath2.path.empty() && // if so, check if estimated path also needs bettering (multiPath->estimatedPath2.path.back().SqDistance2D(callerPos) < Square(MIN_ESTIMATE_DISTANCE * SQUARE_SIZE) || multiPath->estimatedPath.path.size() <= 2)) { Estimate2ToEstimate(*multiPath, callerPos, ownerId, synced); } if (multiPath->caller) { multiPath->caller->UnBlock(); } EstimateToDetailed(*multiPath, callerPos, ownerId); if (multiPath->caller) { multiPath->caller->Block(); } } float3 waypoint; do { // get the next waypoint from the high-res path // // if this is not possible, then either we are // at the goal OR the path could not reach all // the way to it (ie. a GoalOutOfRange result) if (multiPath->detailedPath.path.empty()) { if (multiPath->estimatedPath2.path.empty() && multiPath->estimatedPath.path.empty()) { if (multiPath->searchResult == IPath::Ok) { return multiPath->finalGoal; } else { return float3(-1.0f, -1.0f, -1.0f); } } else { return NextWaypoint(pathId, callerPos, minDistance, numRetries + 1, ownerId, synced); } } else { waypoint = multiPath->detailedPath.path.back(); multiPath->detailedPath.path.pop_back(); } } while (callerPos.SqDistance2D(waypoint) < Square(minDistance) && waypoint != multiPath->detailedPath.pathGoal); return waypoint; }
/* Removes and return the next waypoint in the multipath corresponding to given id. */ float3 CPathManager::NextWaypoint(unsigned int pathId, float3 callerPos, float minDistance, int numRetries) { #ifdef PROFILE_TIME LARGE_INTEGER starttime; QueryPerformanceCounter(&starttime); #endif //0 indicate a no-path id. if(pathId == 0) return float3(-1,-1,-1); if(numRetries>4) return float3(-1,-1,-1); //Find corresponding multipath. map<unsigned int, MultiPath*>::iterator pi = pathMap.find(pathId); if(pi == pathMap.end()) return float3(-1,-1,-1); MultiPath* multiPath = pi->second; if(callerPos==ZeroVector){ if(!multiPath->detailedPath.path.empty()) callerPos=multiPath->detailedPath.path.back(); } //check if detailed path need bettering if(!multiPath->estimatedPath.path.empty() && (multiPath->estimatedPath.path.back().distance2D(callerPos) < MIN_DETAILED_DISTANCE * SQUARE_SIZE || multiPath->detailedPath.path.size() <= 2)){ if(!multiPath->estimatedPath2.path.empty() //if so check if estimated path also need bettering && (multiPath->estimatedPath2.path.back().distance2D(callerPos) < MIN_ESTIMATE_DISTANCE * SQUARE_SIZE || multiPath->estimatedPath.path.size() <= 2)){ Estimate2ToEstimate(*multiPath, callerPos); } if(multiPath->caller) multiPath->caller->UnBlock(); EstimateToDetailed(*multiPath, callerPos); if(multiPath->caller) multiPath->caller->Block(); } //Repeat until a waypoint distant enought are found. float3 waypoint; do { //Get next waypoint. if(multiPath->detailedPath.path.empty()) { if(multiPath->estimatedPath2.path.empty() && multiPath->estimatedPath.path.empty()) return multiPath->finalGoal; else return NextWaypoint(pathId,callerPos,minDistance,numRetries+1); } else { waypoint = multiPath->detailedPath.path.back(); multiPath->detailedPath.path.pop_back(); } } while(callerPos.distance2D(waypoint) < minDistance && waypoint != multiPath->detailedPath.pathGoal); //Return the result. #ifdef PROFILE_TIME LARGE_INTEGER stop; QueryPerformanceCounter(&stop); profiler.AddTime("AI:PFS",stop.QuadPart - starttime.QuadPart); #endif return waypoint; }