/* Request a new multipath, store the result and return a handle-id to it. */ unsigned int CPathManager::RequestPath( CSolidObject* caller, const MoveDef* moveDef, float3 startPos, float3 goalPos, float goalRadius, bool synced ) { if (!IsFinalized()) return 0; // in misc since it is called from many points SCOPED_TIMER("Misc::Path::RequestPath"); startPos.ClampInBounds(); goalPos.ClampInBounds(); // Create an estimator definition. goalRadius = std::max<float>(goalRadius, PATH_NODE_SPACING * SQUARE_SIZE); //FIXME do on a per PE & PF level? assert(moveDef == moveDefHandler->GetMoveDefByPathType(moveDef->pathType)); MultiPath newPath = MultiPath(moveDef, startPos, goalPos, goalRadius); newPath.finalGoal = goalPos; newPath.caller = caller; newPath.peDef.synced = synced; if (caller != nullptr) caller->UnBlock(); const IPath::SearchResult result = ArrangePath(&newPath, moveDef, startPos, goalPos, caller); unsigned int pathID = 0; if (result != IPath::Error) { if (newPath.maxResPath.path.empty()) { if (result != IPath::CantGetCloser) { LowRes2MedRes(newPath, startPos, caller, synced); MedRes2MaxRes(newPath, startPos, caller, synced); } else { // add one dummy waypoint so that the calling MoveType // does not consider this request a failure, which can // happen when startPos is very close to goalPos // // otherwise, code relying on MoveType::progressState // (eg. BuilderCAI::MoveInBuildRange) would misbehave // (eg. reject build orders) newPath.maxResPath.path.push_back(startPos); newPath.maxResPath.squares.push_back(int2(startPos.x / SQUARE_SIZE, startPos.z / SQUARE_SIZE)); } } FinalizePath(&newPath, startPos, goalPos, result == IPath::CantGetCloser); newPath.searchResult = result; pathID = Store(newPath); } if (caller != nullptr) caller->Block(); return pathID; }
bool JPSPlus::GetPath(void *data, xyLocJPS& s, xyLocJPS& g, std::vector<xyLocJPS> &path) { JPSPlus* Search = (JPSPlus*)data; if (path.size() > 0) { path.push_back(g); return true; } { // Initialize map int startRow = s.y; int startCol = s.x; m_goalRow = g.y; m_goalCol = g.x; path.clear(); m_goalNode = &m_mapNodes[m_goalRow][m_goalCol]; m_currentIteration++; m_openList.reset(); m_openList.reserve(3000); // Push the starting node onto the Open list PathfindingNode* startNode = &m_mapNodes[startRow][startCol]; startNode->m_parent = NULL; startNode->m_givenCost = 0; startNode->m_finalCost = 0; startNode->m_listStatus = PathfindingNode::OnOpen; startNode->m_iteration = m_currentIteration; m_openList.add(&m_mapNodes[startRow][startCol]); } PathStatus status = SearchLoop(); if (status == PathFound) { FinalizePath(path); if (path.size() > 0) { path.pop_back(); return false; } return true; } else { // No path return true; } }
/* Removes and return the next waypoint in the multipath corresponding to given id. */ float3 CPathManager::NextWayPoint( const CSolidObject* owner, unsigned int pathID, unsigned int numRetries, float3 callerPos, float radius, bool synced ) { // in misc since it is called from many points SCOPED_TIMER("Misc::Path::NextWayPoint"); const float3 noPathPoint = -XZVector; if (!IsFinalized()) return noPathPoint; // 0 indicates the null-path ID if (pathID == 0) return noPathPoint; // find corresponding multipath entry MultiPath* multiPath = GetMultiPath(pathID); if (multiPath == nullptr) return noPathPoint; if (numRetries > MAX_PATH_REFINEMENT_DEPTH) return (multiPath->finalGoal); IPath::Path& maxResPath = multiPath->maxResPath; IPath::Path& medResPath = multiPath->medResPath; IPath::Path& lowResPath = multiPath->lowResPath; if ((callerPos == ZeroVector) && !maxResPath.path.empty()) callerPos = maxResPath.path.back(); assert(multiPath->peDef.synced == synced); #define EXTEND_PATH_POINTS(curResPts, nxtResPts, dist) ((!curResPts.empty() && (curResPts.back()).SqDistance2D(callerPos) < Square((dist))) || nxtResPts.size() <= 2) const bool extendMaxResPath = EXTEND_PATH_POINTS(medResPath.path, maxResPath.path, MAXRES_SEARCH_DISTANCE_EXT); const bool extendMedResPath = EXTEND_PATH_POINTS(lowResPath.path, medResPath.path, MEDRES_SEARCH_DISTANCE_EXT); #undef EXTEND_PATH_POINTS // check whether the max-res path needs extending through // recursive refinement of its lower-resolution segments // if so, check if the med-res path also needs extending if (extendMaxResPath) { if (multiPath->caller != nullptr) multiPath->caller->UnBlock(); if (extendMedResPath) LowRes2MedRes(*multiPath, callerPos, owner, synced); MedRes2MaxRes(*multiPath, callerPos, owner, synced); if (multiPath->caller != nullptr) multiPath->caller->Block(); FinalizePath(multiPath, callerPos, multiPath->finalGoal, multiPath->searchResult == IPath::CantGetCloser); } float3 waypoint = noPathPoint; do { // eat waypoints from the max-res path until we // find one that lies outside the search-radius // or equals the goal // // 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) // OR we are stuck on an impassable square if (maxResPath.path.empty()) { if (lowResPath.path.empty() && medResPath.path.empty()) { if (multiPath->searchResult == IPath::Ok) { waypoint = multiPath->finalGoal; break; } else { // reached in the CantGetCloser case for any max-res searches // that start within their goal radius (ie. have no waypoints) // RequestPath always puts startPos into maxResPath to handle // this so waypoint will have been set to it (during previous // iteration) if we end up here break; } } else { waypoint = NextWayPoint(owner, pathID, numRetries + 1, callerPos, radius, synced); break; } } else { waypoint = maxResPath.path.back(); maxResPath.path.pop_back(); } } while ((callerPos.SqDistance2D(waypoint) < Square(radius)) && (waypoint != maxResPath.pathGoal)); // y=0 indicates this is not a temporary waypoint // (the default PFS does not queue path-requests) return (waypoint * XZVector); }