Index: source/simulation2/components/CCmpUnitMotion.cpp =================================================================== --- source/simulation2/components/CCmpUnitMotion.cpp +++ source/simulation2/components/CCmpUnitMotion.cpp @@ -94,7 +94,7 @@ * this could probably be lowered. * TODO: when unit pushing is implemented, this number can probably be lowered. */ -static const u8 MAX_FAILED_PATH_COMPUTATIONS = 15; +static const u8 MAX_FAILED_PATH_COMPUTATIONS = 20; /** * If we have failed path computations this many times and ComputePathToGoal is called, @@ -700,6 +700,13 @@ */ void RequestShortPath(const CFixedVector2D& from, const PathGoal& goal, bool avoidMovingUnits); + /** + * Request a short path to the next long path waypoint. + * NB: this will pop() the last long waypoint, to avoid getting stuck + * if the next long waypoint is within other unit obstruction shapes (i.e. unreachable). + */ + bool ShortPathToNextWaypoint(const CFixedVector2D& pos); + /** * General handler for MoveTo interface functions. */ @@ -824,21 +831,11 @@ IncrementFailedPathComputationAndMaybeNotify(); - // If there's no waypoints then we couldn't get near the target - // If we're globally following a long path, try to remove the next waypoint, + // If there's no waypoints then we couldn't get near the target. + // If we're globally following a long path, try to remove the next waypoint if it's close, // it might be obstructed (e.g. by idle entities which the long-range pathfinder doesn't see). - if (!m_LongPath.m_Waypoints.empty()) - { - m_LongPath.m_Waypoints.pop_back(); - if (!m_LongPath.m_Waypoints.empty()) - { - // Get close enough - this will likely help the short path efficiency, and if we end up taking a wrong way - // we'll easily be able to revert it using a long path. - goal = { PathGoal::CIRCLE, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z, ShortPathWaypointRange(m_LongPath) }; - RequestShortPath(pos, goal, true); - return; - } - } + if (ShortPathToNextWaypoint(pos)) + return; ComputePathToGoal(pos, goal); } @@ -1081,16 +1078,8 @@ // If we still have long waypoints, try and compute a short path to our next long waypoint. // Assume the next waypoint is impassable and pop it. This helps unstuck entities in some cases, and we'll just // end up recomputing a long path if we pop all of them, so it's safe. - if (m_LongPath.m_Waypoints.size() >= 1) - m_LongPath.m_Waypoints.pop_back(); - if (!m_LongPath.m_Waypoints.empty()) - { - // Get close enough - this will likely help the short path efficiency, and if we end up taking a wrong way - // we'll easily be able to revert it using a long path. - goal = { PathGoal::CIRCLE, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z, ShortPathWaypointRange(m_LongPath) }; - RequestShortPath(pos, goal, true); + if (ShortPathToNextWaypoint(pos)) return true; - } } // Else, just entirely recompute. This will ensure we occasionally run a long path so avoid getting stuck @@ -1492,11 +1481,33 @@ fixed searchRange = SHORT_PATH_MIN_SEARCH_RANGE + SHORT_PATH_SEARCH_RANGE_INCREMENT * m_FailedPathComputations; if (searchRange > SHORT_PATH_MAX_SEARCH_RANGE) searchRange = SHORT_PATH_MAX_SEARCH_RANGE; + else if ((from - CFixedVector2D(goal.x, goal.z)).CompareLength(searchRange) >= 0) + searchRange = (from - CFixedVector2D(goal.x, goal.z)).Length(); m_ExpectedPathTicket.m_Type = Ticket::SHORT_PATH; m_ExpectedPathTicket.m_Ticket = cmpPathfinder->ComputeShortPathAsync(from.X, from.Y, m_Clearance, searchRange, goal, m_PassClass, avoidMovingUnits, GetGroup(), GetEntityId()); } +bool CCmpUnitMotion::ShortPathToNextWaypoint(const CFixedVector2D& pos) +{ + if (m_LongPath.m_Waypoints.size() < 2) + return false; + + // If the next waypoint is too far away, it's probably that we've already popped several waypoints. + // At this point, it's more likely that we're _actually_ stuck because of other units, + // so popping more waypoints won't do any good - let the rest of the code handle it. + if ((pos-CFixedVector2D(m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z)).CompareLength(LONG_PATH_MIN_DIST) >= 0) + return false; + + m_LongPath.m_Waypoints.pop_back(); + + // Get close enough - this will likely help the short path efficiency, and if we end up taking a wrong way + // we'll easily be able to revert it using a long path. + PathGoal goal = { PathGoal::CIRCLE, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z, ShortPathWaypointRange(m_LongPath) }; + RequestShortPath(pos, goal, true); + return true; +} + bool CCmpUnitMotion::MoveTo(MoveRequest request) { PROFILE("MoveTo");