Ticket #4327: pathfinderFix.patch

File pathfinderFix.patch, 8.5 KB (added by wraitii, 7 years ago)
  • source/simulation2/components/CCmpPathfinder_Vertex.cpp

    diff --git a/source/simulation2/components/CCmpPathfinder_Vertex.cpp b/source/simulation2/components/CCmpPathfinder_Vertex.cpp
    index ab180b3..6e52e27 100644
    a b void CCmpPathfinder::ComputeShortPath(const IObstructionTestFilter& filter,  
    592592    entity_pos_t pathfindClearance = clearance;
    593593
    594594    // Convert each obstruction square into collision edges and search graph vertexes
     595    // We also expand our range if vertices fall outside of it, so that all required terrain edges are added.
    595596    for (size_t i = 0; i < squares.size(); ++i)
    596597    {
    597598        CFixedVector2D center(squares[i].x, squares[i].z);
  • source/simulation2/components/CCmpUnitMotion.cpp

    diff --git a/source/simulation2/components/CCmpUnitMotion.cpp b/source/simulation2/components/CCmpUnitMotion.cpp
    index 04a7a00..e526221 100644
    a b public:  
    217217         */
    218218        PATHSTATE_FOLLOWING_REQUESTING_SHORT,
    219219
     220        /*
     221         * We ran out of waypoints and were not really close to our final destination
     222         * There is a possibility the short-range pathfinder will find a better path
     223         * since the long-range rasterization is less permissive
     224         * So we'll request one final short path. If it fails, we fail.
     225         */
     226        PATHSTATE_ARRIVED_TRYING_SHORT,
     227
    220228        PATHSTATE_MAX
    221229    };
    222230    u8 m_PathState;
    private:  
    639647    void UpdateFinalGoal();
    640648
    641649    /**
    642      * Returns whether we are close enough to the target to assume it's a good enough
    643      * position to stop.
     650     * Returns if we are close enough to safely assume we've arrived.
     651     */
     652    bool IsAtDestination(const CFixedVector2D& from);
     653
     654    /**
     655     * If we are close enough to stop, succeed the move.
    644656     */
    645657    bool ShouldConsiderOurselvesAtDestination(const CFixedVector2D& from);
    646658
    void CCmpUnitMotion::PathResult(u32 ticket, const WaypointPath& path)  
    741753
    742754        m_Moving = true;
    743755    }
    744     else if (m_PathState == PATHSTATE_WAITING_REQUESTING_SHORT || m_PathState == PATHSTATE_FOLLOWING_REQUESTING_SHORT)
     756    else if (m_PathState == PATHSTATE_WAITING_REQUESTING_SHORT || m_PathState == PATHSTATE_FOLLOWING_REQUESTING_SHORT
     757             || m_PathState == PATHSTATE_ARRIVED_TRYING_SHORT)
    745758    {
    746759        m_ShortPath = path;
    747 
    748760        // If there's no waypoints then we couldn't get near the target
    749761        if (m_ShortPath.m_Waypoints.empty())
    750762        {
     763            CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
     764
     765            if (!cmpPosition || !cmpPosition->IsInWorld())
     766                return;
     767
     768            CFixedVector2D pos = cmpPosition->GetPosition2D();
     769
     770            // we failed to improve on our path
     771            if (m_PathState == PATHSTATE_ARRIVED_TRYING_SHORT)
     772            {
     773                StopMoving();
     774                m_State = STATE_IDLE;
     775                // two options: if we were just moving there, succeed: we got as close as we could.
     776                // if we were targeting an entity, only succeed if we're in range
     777                if (!m_TargetEntity || IsInTargetRange(m_TargetEntity, m_TargetMinRange, m_TargetMaxRange))
     778                {
     779                    MoveSucceeded();
     780
     781                    if (m_FacePointAfterMove)
     782                        FaceTowardsPointFromPos(pos, m_FinalGoal.x, m_FinalGoal.z);
     783                    return;
     784                }
     785                // we actually failed.
     786                MoveFailed();
     787                return;
     788            }
     789
    751790            // If we're globally following a long path, try to remove the next waypoint, it might be obstructed
    752791            // If not, and we are not in a formation, retry
    753792            // unless we are close to our target and we don't have a target entity.
    void CCmpUnitMotion::PathResult(u32 ticket, const WaypointPath& path)  
    765804            CMessageMotionChanged msg(false, false);
    766805            GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);
    767806
    768             CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
    769             if (!cmpPosition || !cmpPosition->IsInWorld())
    770                 return;
    771 
    772             CFixedVector2D pos = cmpPosition->GetPosition2D();
    773 
    774807            if (ShouldConsiderOurselvesAtDestination(pos))
    775808                return;
    776809
    void CCmpUnitMotion::Move(fixed dt)  
    10111044
    10121045        if (m_PathState == PATHSTATE_FOLLOWING)
    10131046        {
    1014             // If we're not currently computing any new paths:
    1015             if (m_LongPath.m_Waypoints.empty() && m_ShortPath.m_Waypoints.empty())
    1016             {
    1017                 if (IsFormationMember())
    1018                 {
    1019                     // We've reached our assigned position. If the controller
    1020                     // is idle, send a notification in case it should disband,
    1021                     // otherwise continue following the formation next turn.
    1022                     CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), m_TargetEntity);
    1023                     if (cmpUnitMotion && !cmpUnitMotion->IsMoving())
    1024                     {
    1025                         CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle());
    1026                         if (cmpObstruction)
    1027                             cmpObstruction->SetMovingFlag(false);
    1028 
    1029                         m_Moving = false;
    1030                         CMessageMotionChanged msg(false, false);
    1031                         GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);
    1032                     }
    1033                 }
    1034                 else
    1035                 {
    1036                     // check if target was reached in case of a moving target
    1037                     CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), m_TargetEntity);
    1038                     if (cmpUnitMotion && cmpUnitMotion->IsMoving() &&
    1039                         MoveToTargetRange(m_TargetEntity, m_TargetMinRange, m_TargetMaxRange))
    1040                         return;
    1041 
    1042                     // Not in formation, so just finish moving
    1043                     StopMoving();
    1044                     m_State = STATE_IDLE;
    1045                     MoveSucceeded();
    1046 
    1047                     if (m_FacePointAfterMove)
    1048                         FaceTowardsPointFromPos(pos, m_FinalGoal.x, m_FinalGoal.z);
    1049                     // TODO: if the goal was a square building, we ought to point towards the
    1050                     // nearest point on the square, not towards its center
    1051                 }
    1052             }
    1053 
    10541047            // If we have a target entity, and we're not miles away from the end of
    10551048            // our current path, and the target moved enough, then recompute our
    10561049            // whole path
     1050            bool followingTarget = false;
    10571051            if (IsFormationMember())
    1058                 CheckTargetMovement(pos, CHECK_TARGET_MOVEMENT_MIN_DELTA_FORMATION);
     1052                followingTarget = CheckTargetMovement(pos, CHECK_TARGET_MOVEMENT_MIN_DELTA_FORMATION);
    10591053            else
    1060                 CheckTargetMovement(pos, CHECK_TARGET_MOVEMENT_MIN_DELTA);
     1054                followingTarget = CheckTargetMovement(pos, CHECK_TARGET_MOVEMENT_MIN_DELTA);
     1055
     1056            if (followingTarget)
     1057                return;
     1058
     1059            // If we are still going to compute a path, return.
     1060            if (!m_LongPath.m_Waypoints.empty() || !m_ShortPath.m_Waypoints.empty())
     1061             return;
     1062
     1063            // if we dont believe we're actually arrived, presumably the long-range pathfinder's path was a little bad
     1064            // probably because it over-rasterized. Retry a new long path, which will pop us in recovery mode if necessary.
     1065            if (!ShouldConsiderOurselvesAtDestination(pos))
     1066            {
     1067                m_PathState = PATHSTATE_ARRIVED_TRYING_SHORT;
     1068                RequestShortPath(pos, m_FinalGoal, true);
     1069                return;
     1070            }
    10611071        }
    10621072    }
    10631073    }
    void CCmpUnitMotion::UpdateFinalGoal()  
    12131223    m_FinalGoal.z = targetPos.Y;
    12141224}
    12151225
     1226bool CCmpUnitMotion::IsAtDestination(const CFixedVector2D& from)
     1227{
     1228    return ((m_TargetEntity != INVALID_ENTITY && IsInTargetRange(m_TargetEntity, m_TargetMinRange, m_TargetMaxRange))
     1229            || m_FinalGoal.DistanceToPoint(from) <= SHORT_PATH_GOAL_RADIUS);
     1230}
     1231
    12161232bool CCmpUnitMotion::ShouldConsiderOurselvesAtDestination(const CFixedVector2D& from)
    12171233{
    1218     if (m_TargetEntity != INVALID_ENTITY || m_FinalGoal.DistanceToPoint(from) > SHORT_PATH_GOAL_RADIUS)
     1234    if (!IsAtDestination(from))
    12191235        return false;
    12201236
    1221     StopMoving();
    1222     MoveSucceeded();
     1237    if (IsFormationMember())
     1238    {
     1239        // We've reached our assigned position. If the controller
     1240        // is idle, send a notification in case it should disband,
     1241        // otherwise continue following the formation next turn.
     1242        CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), m_TargetEntity);
     1243        if (cmpUnitMotion && !cmpUnitMotion->IsMoving())
     1244        {
     1245            CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle());
     1246            if (cmpObstruction)
     1247                cmpObstruction->SetMovingFlag(false);
     1248
     1249            m_Moving = false;
     1250            CMessageMotionChanged msg(false, false);
     1251            GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg);
     1252        }
     1253    }
     1254    else
     1255    {
     1256        // check if target was reached in case of a moving target
     1257        CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), m_TargetEntity);
     1258        if (cmpUnitMotion && cmpUnitMotion->IsMoving() &&
     1259            MoveToTargetRange(m_TargetEntity, m_TargetMinRange, m_TargetMaxRange))
     1260            return true;
    12231261
    1224     if (m_FacePointAfterMove)
    1225         FaceTowardsPointFromPos(from, m_FinalGoal.x, m_FinalGoal.z);
     1262        // Not in formation, so just finish moving
     1263        StopMoving();
     1264        m_State = STATE_IDLE;
     1265        MoveSucceeded();
     1266
     1267        if (m_FacePointAfterMove)
     1268            FaceTowardsPointFromPos(from, m_FinalGoal.x, m_FinalGoal.z);
     1269        // TODO: if the goal was a square building, we ought to point towards the
     1270        // nearest point on the square, not towards its center
     1271    }
    12261272    return true;
    12271273}
    12281274