< Summary

Information
Class: Trailblazer.Pathing.AStarGuide
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/AStar/AStarGuide.cs
Line coverage
100%
Covered lines: 58
Uncovered lines: 0
Coverable lines: 58
Total lines: 185
Line coverage: 100%
Branch coverage
90%
Covered branches: 36
Total branches: 40
Branch coverage: 90%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Initialize(...)100%22100%
get_ActiveWaypoints()100%88100%
HasArrived()100%22100%
GetIndex(...)83.33%66100%
AdvanceWaypoint()100%11100%
TryGetMovementDirection(...)100%22100%
GetCurrentWaypointDirection(...)75%88100%
TryGetFallbackDirection(...)100%66100%
TryGetWaypointAt(...)83.33%66100%
ResetForReuse()100%11100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/AStar/AStarGuide.cs

#LineLine coverage
 1using FixedMathSharp;
 2
 3namespace Trailblazer.Pathing;
 4
 5/// <summary>
 6/// Provides steering direction based on a sequence of waypoints generated from an A* pathfinding survey.
 7/// Suitable for direct point-to-point navigation along a computed path.
 8/// </summary>
 9public class AStarGuide : IWaypointGuide
 10{
 11    /// <summary>
 12    /// The result of the A* survey, containing the waypoints and path information needed to guide an agent along the pa
 13    /// </summary>
 14    public AStarSurveyResult TrailMap { get; private set; } = AStarSurveyResult.Empty;
 15
 16    /// <summary>
 17    /// Cached smoothed waypoints generated from the original TrailMap waypoints.
 18    /// This allows for optional smoothing (e.g. Catmull-Rom interpolation) without modifying the original path data.
 19    /// </summary>
 20    private AStarWaypoint[]? _smoothedWaypoints;
 21
 22    /// <inheritdoc/>
 23    public int CurrentWaypointIndex { get; private set; }
 24
 25    /// <summary>
 26    /// Indicates whether a smoothing algorithm like spline interpolation should be applied to the final path.
 27    /// </summary>
 28    public bool UseSplineSmoothing { get; set; }
 29
 30    /// <summary>
 31    /// Tracks the last waypoint index that was used to provide a fallback direction.
 32    /// This helps ensure that fallback directions are provided in a forward progression along the path,
 33    /// rather than repeatedly returning the same fallback when the agent is stuck.
 34    /// </summary>
 35    private int _lastTriedIndex;
 36
 37    /// <summary>
 38    /// Initializes the guide with the given A* survey result.
 39    /// </summary>
 40    /// <param name="surveyResult">The result of the A* survey containing the waypoints and path information.</param>
 41    /// <returns>True if the guide is successfully initialized with a valid path; otherwise, false.</returns>
 42    public bool Initialize(AStarSurveyResult surveyResult)
 43    {
 59044        if (!surveyResult.HasPath)
 145            return false;
 46
 58947        TrailMap = surveyResult;
 58948        CurrentWaypointIndex = 0;
 49
 58950        return true;
 51    }
 52
 53    /// <summary>
 54    /// Gets the active waypoints for this guide, applying optional smoothing if enabled.
 55    /// </summary>
 56    public AStarWaypoint[] ActiveWaypoints
 57    {
 58        get
 59        {
 18160            if (UseSplineSmoothing)
 61            {
 1062                if (_smoothedWaypoints == null && TrailMap.Waypoints.Length >= 4)
 463                    _smoothedWaypoints = AStarSurveyor.CatmullSmooth(TrailMap.Waypoints);
 1064                return _smoothedWaypoints ?? TrailMap.Waypoints;
 65            }
 66
 17167            return TrailMap.Waypoints;
 68        }
 69    }
 70
 71    /// <summary>
 72    /// Determines whether the guide has reached the final waypoint.
 73    /// </summary>
 74    /// <returns>True if the guide has arrived at the final waypoint; otherwise, false.</returns>
 75    public bool HasArrived()
 76    {
 577        return TrailMap.HasPath && CurrentWaypointIndex == ActiveWaypoints.Length - 1;
 78    }
 79
 80    /// <inheritdoc/>
 81    public int GetIndex(Vector3d from)
 82    {
 283        Fixed64 minDistSq = Fixed64.MAX_VALUE;
 284        int bestIndex = -1;
 1285        for (int i = 0; i < ActiveWaypoints.Length; i++)
 86        {
 587            Fixed64 distSq = (from - ActiveWaypoints[i].Position).SqrMagnitude;
 588            if (distSq < minDistSq)
 89            {
 590                minDistSq = distSq;
 591                bestIndex = i;
 92            }
 93
 594            if (minDistSq <= Fixed64.Epsilon)
 95                break;
 96        }
 97
 298        return bestIndex;
 99    }
 100
 101    /// <inheritdoc/>
 29102    public void AdvanceWaypoint() => CurrentWaypointIndex++;
 103
 104    /// <inheritdoc/>
 105    public bool TryGetMovementDirection(Vector3d origin, out Vector3d direction)
 106    {
 2107        direction = Vector3d.Zero;
 108
 2109        if (!TrailMap.HasPath)
 1110            return false;
 111
 1112        int closestIndex = GetIndex(origin);
 1113        direction = (ActiveWaypoints[closestIndex].Position - origin).Normalize();
 1114        return true;
 115    }
 116
 117    /// <inheritdoc/>
 118    public Vector3d GetCurrentWaypointDirection(Vector3d origin)
 119    {
 34120        if (!TrailMap.HasPath || CurrentWaypointIndex < 0 || CurrentWaypointIndex >= ActiveWaypoints.Length)
 1121            return Vector3d.Zero;
 122
 33123        Vector3d movementDirection = ActiveWaypoints[CurrentWaypointIndex].Position;
 33124        if (movementDirection == Vector3d.Zero)
 18125            return Vector3d.Zero;
 126
 15127        return (movementDirection - origin).Normal;
 128    }
 129
 130    /// <inheritdoc/>
 131    public bool TryGetFallbackDirection(Vector3d from, out Vector3d fallbackDirection)
 132    {
 3133        fallbackDirection = Vector3d.Zero;
 134
 3135        if (ActiveWaypoints.Length == 0)
 1136            return false;
 137
 138        // Start from CurrentIndex + 1 and search forward
 2139        int searchStart = FixedMath.Clamp(_lastTriedIndex, 0, ActiveWaypoints.Length - 1);
 140
 2141        Fixed64 minDistSq = Fixed64.MAX_VALUE;
 2142        int bestIndex = searchStart;
 143
 16144        for (int i = searchStart; i < ActiveWaypoints.Length; i++)
 145        {
 6146            Fixed64 distSq = (from - ActiveWaypoints[i].Position).SqrMagnitude;
 6147            if (distSq < minDistSq)
 148            {
 4149                minDistSq = distSq;
 4150                bestIndex = i;
 151            }
 152        }
 153
 2154        fallbackDirection = (ActiveWaypoints[bestIndex].Position - from).Normal;
 2155        _lastTriedIndex = bestIndex;
 2156        return true;
 157    }
 158
 159    /// <summary>
 160    /// Attempts to get the waypoint at the specified index.
 161    /// </summary>
 162    /// <param name="index">The index of the waypoint to retrieve.</param>
 163    /// <param name="waypoint">The waypoint at the specified index, if found.</param>
 164    /// <returns>True if the waypoint was successfully retrieved; otherwise, false.</returns>
 165    public bool TryGetWaypointAt(int index, out AStarWaypoint waypoint)
 166    {
 15167        if (!TrailMap.HasPath || index < 0 || index >= ActiveWaypoints.Length)
 168        {
 3169            waypoint = default;
 3170            return false;
 171        }
 172
 12173        waypoint = ActiveWaypoints[index];
 12174        return true;
 175    }
 176
 177    internal void ResetForReuse()
 178    {
 559179        TrailMap = AStarSurveyResult.Empty;
 559180        _smoothedWaypoints = null;
 559181        CurrentWaypointIndex = 0;
 559182        UseSplineSmoothing = false;
 559183        _lastTriedIndex = 0;
 559184    }
 185}