Esempio n. 1
0
/*
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;
}
Esempio n. 2
0
/*
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);
}
Esempio n. 3
0
/*
Request a new multipath, store the result and return a handle-id to it.
*/
unsigned int CPathManager::RequestPath(
	const MoveData* md,
	const float3& startPos,
	const float3& goalPos,
	CPathFinderDef* pfDef,
	CSolidObject* caller,
	bool synced
) {
	SCOPED_TIMER("PFS");

	MoveData* moveData = moveinfo->moveData[md->pathType];
	moveData->tempOwner = caller;

	// Creates a new multipath.
	MultiPath* newPath = new MultiPath(startPos, pfDef, moveData);
	newPath->finalGoal = goalPos;
	newPath->caller = caller;

	if (caller) {
		caller->UnBlock();
	}

	const int ownerId = caller? caller->id: 0;
	unsigned int retValue = 0;

	// choose the PF or the PE depending on the goal-distance
	const float distanceToGoal = pfDef->Heuristic(int(startPos.x / SQUARE_SIZE), int(startPos.z / SQUARE_SIZE));

	if (distanceToGoal < DETAILED_DISTANCE) {
		// Get a detailed path.
		IPath::SearchResult result =
			maxResPF->GetPath(*moveData, startPos, *pfDef, newPath->maxResPath, true, false, MAX_SEARCHED_NODES_PF, true, ownerId, synced);
		newPath->searchResult = result;

		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 = medResPE->GetPath(*moveData, startPos, *pfDef, newPath->medResPath, MAX_SEARCHED_NODES_PE, synced);
		newPath->searchResult = result;

		if (result == IPath::Ok || result == IPath::GoalOutOfRange) {
			// Turn a part of it into detailed path.
			MedRes2MaxRes(*newPath, startPos, ownerId, synced);
			// Store the path.
			retValue = Store(newPath);
		} else {
			// if we fail see if it can work find a better block to start from
			float3 sp = medResPE->FindBestBlockCenter(moveData, startPos, synced);

			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 = medResPE->GetPath(*moveData, sp, *pfDef, newPath->medResPath, MAX_SEARCHED_NODES_PE, synced);
				newPath->searchResult = result;

				if (result == IPath::Ok || result == IPath::GoalOutOfRange) {
					MedRes2MaxRes(*newPath, startPos, ownerId, synced);
					retValue = Store(newPath);
				} else {
					delete newPath;
				}
			} else {
				delete newPath;
			}
		}
	} else {
		// Get a low-res. estimate path.
		IPath::SearchResult result = lowResPE->GetPath(*moveData, startPos, *pfDef, newPath->lowResPath, MAX_SEARCHED_NODES_PE, synced);
		newPath->searchResult = result;

		if (result == IPath::Ok || result == IPath::GoalOutOfRange) {
			// Turn a part of it into hi-res. estimate path.
			LowRes2MedRes(*newPath, startPos, ownerId, synced);
			// And estimate into detailed.
			MedRes2MaxRes(*newPath, startPos, ownerId, synced);

			// Store the path.
			retValue = Store(newPath);
		} else {
			// sometimes the 32*32 squares can be wrong (admissibility...) so if it fails to get a path also try with 8*8 squares
			IPath::SearchResult result = medResPE->GetPath(*moveData, startPos, *pfDef, newPath->medResPath, MAX_SEARCHED_NODES_PE, synced);
			newPath->searchResult = result;

			if (result == IPath::Ok || result == IPath::GoalOutOfRange) {
				MedRes2MaxRes(*newPath, startPos, ownerId, synced);
				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 = medResPE->FindBestBlockCenter(moveData, startPos, synced);

				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 = medResPE->GetPath(*moveData, sp, *pfDef, newPath->medResPath, MAX_SEARCHED_NODES_PE, synced);

					if (result == IPath::Ok || result == IPath::GoalOutOfRange) {
						MedRes2MaxRes(*newPath, startPos, ownerId, synced);
						retValue = Store(newPath);
					} else {
						delete newPath;
					}
				} else {
					delete newPath;
				}
			}
		}
	}

	if (caller) {
		caller->Block();
	}

	moveData->tempOwner = NULL;
	return retValue;
}
Esempio n. 4
0
/*
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.
	const 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->maxResPath.path.empty())
			callerPos = multiPath->maxResPath.path.back();
	}

	// check if detailed path needs bettering
	if (!multiPath->medResPath.path.empty() &&
		(multiPath->medResPath.path.back().SqDistance2D(callerPos) < Square(MIN_DETAILED_DISTANCE * SQUARE_SIZE) ||
		multiPath->maxResPath.path.size() <= 2)) {

		if (!multiPath->lowResPath.path.empty() &&  // if so, check if estimated path also needs bettering
			(multiPath->lowResPath.path.back().SqDistance2D(callerPos) < Square(MIN_ESTIMATE_DISTANCE * SQUARE_SIZE) ||
			multiPath->medResPath.path.size() <= 2)) {

			LowRes2MedRes(*multiPath, callerPos, ownerId, synced);
		}

		if (multiPath->caller) {
			multiPath->caller->UnBlock();
		}

		MedRes2MaxRes(*multiPath, callerPos, ownerId, synced);

		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->maxResPath.path.empty()) {
			if (multiPath->lowResPath.path.empty() && multiPath->medResPath.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->maxResPath.path.back();
			multiPath->maxResPath.path.pop_back();
		}
	} while (callerPos.SqDistance2D(waypoint) < Square(minDistance) && waypoint != multiPath->maxResPath.pathGoal);

	return waypoint;
}