< Summary

Information
Class: Trailblazer.Navigation.NavigatorPathRequestFactory
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Navigation/Navigator/Guidance/NavigatorPathRequestFactory.cs
Line coverage
99%
Covered lines: 191
Uncovered lines: 1
Coverable lines: 192
Total lines: 363
Line coverage: 99.4%
Branch coverage
90%
Covered branches: 56
Total branches: 62
Branch coverage: 90.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
TryCreate(...)100%1212100%
TryCreateVolumeExitHandoff(...)100%66100%
TryCreateVolumeExitHandoffIfNeeded(...)91.66%1212100%
TryGetChartBackedTargetState(...)100%66100%
TryCreateGasLandingHandoff(...)78.57%141496.77%
TryCreateAStarRequest(...)100%22100%
TryCreateFlowFieldRequest(...)100%22100%
GetDirectVolumePathCost(...)75%88100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Navigation/Navigator/Guidance/NavigatorPathRequestFactory.cs

#LineLine coverage
 1using FixedMathSharp;
 2using GridForge.Grids;
 3using System.Diagnostics.CodeAnalysis;
 4using Trailblazer.Pathing;
 5
 6namespace Trailblazer.Navigation;
 7
 8/// <summary>
 9/// Creates built-in path requests for navigators from host-facing guided travel commands.
 10/// </summary>
 11public static class NavigatorPathRequestFactory
 12{
 13    internal static bool TryCreate(
 14        TrailblazerWorldContext context,
 15        Vector3d origin,
 16        Vector3d targetPosition,
 17        Fixed64 unitSize,
 18        SolidPathAlgorithm pathMode,
 19        bool allowUnwalkableEndpoints,
 20        bool allowTraversalTransitions,
 21        Fixed64 maxClimbHeight,
 22        TraversalMedium traversalMedium,
 23        HeuristicMethod aStarHeuristic,
 24        int flowFieldExtraFloodRange,
 25        [NotNullWhen(true)] out IPathRequest? request,
 26        out GuidedVolumeExitHandoff? handoff)
 27    {
 8028        PathRequestContextResolver.ThrowIfUnusable(context);
 8029        handoff = null;
 30
 31        // For gas and liquid traversal, we only support volume path requests,
 32        // so we bypass the path mode switch and go straight to trying to create a volume request.
 33        // If that fails and traversal transitions are allowed,
 34        // we attempt to create a guided volume exit handoff request which will plan a
 35        // volume path to an exit if needed before transitioning to a chart-based path for
 36        // the remainder of the journey.
 8037        if (traversalMedium == TraversalMedium.Gas || traversalMedium == TraversalMedium.Liquid)
 38        {
 4439            VolumePathRequest? volume = VolumePathRequest.Create(
 4440                context,
 4441                origin,
 4442                targetPosition,
 4443                unitSize,
 4444                aStarHeuristic,
 4445                allowUnwalkableEndpoints,
 4446                traversalMedium);
 4447            if (volume == null)
 1948                return TryCreateVolumeExitHandoff(
 1949                    context,
 1950                    origin,
 1951                    targetPosition,
 1952                    unitSize,
 1953                    traversalMedium,
 1954                    pathMode,
 1955                    allowUnwalkableEndpoints,
 1956                    allowTraversalTransitions,
 1957                    maxClimbHeight,
 1958                    aStarHeuristic,
 1959                    flowFieldExtraFloodRange,
 1960                    out request,
 1961                    out handoff,
 1962                    out _);
 63
 2564            if (TryCreateVolumeExitHandoffIfNeeded(
 2565                context,
 2566                targetPosition,
 2567                traversalMedium,
 2568                volume,
 2569                pathMode,
 2570                allowUnwalkableEndpoints,
 2571                allowTraversalTransitions,
 2572                maxClimbHeight,
 2573                aStarHeuristic,
 2574                flowFieldExtraFloodRange,
 2575                out request,
 2576                out handoff))
 77            {
 478                return true;
 79            }
 80
 2181            request = volume;
 2182            return true;
 83        }
 84
 85        switch (pathMode)
 86        {
 87            case SolidPathAlgorithm.AStar:
 2788                return TryCreateAStarRequest(
 2789                    context,
 2790                    origin, targetPosition, unitSize,
 2791                    aStarHeuristic, allowUnwalkableEndpoints, allowTraversalTransitions,
 2792                    maxClimbHeight, out request);
 93
 94            case SolidPathAlgorithm.FlowField:
 895                return TryCreateFlowFieldRequest(
 896                    context,
 897                    origin, targetPosition, unitSize,
 898                    allowUnwalkableEndpoints, allowTraversalTransitions,
 899                    maxClimbHeight, flowFieldExtraFloodRange, out request);
 100
 101            default:
 1102                request = null;
 1103                return false;
 104        }
 105    }
 106
 107    private static bool TryCreateVolumeExitHandoff(
 108        TrailblazerWorldContext context,
 109        Vector3d origin,
 110        Vector3d targetPosition,
 111        Fixed64 unitSize,
 112        TraversalMedium medium,
 113        SolidPathAlgorithm chartPathMode,
 114        bool allowUnwalkableEndpoints,
 115        bool allowTraversalTransitions,
 116        Fixed64 maxClimbHeight,
 117        HeuristicMethod aStarHeuristic,
 118        int flowFieldExtraFloodRange,
 119        [NotNullWhen(true)] out IPathRequest? request,
 120        out GuidedVolumeExitHandoff? handoff,
 121        out int totalPathCost)
 122    {
 26123        request = null;
 26124        handoff = null;
 26125        totalPathCost = 0;
 126
 26127        if (!allowTraversalTransitions)
 4128            return false;
 129
 22130        return GuidedVolumeExitPlanner.TryPlan(
 22131            context,
 22132            origin,
 22133            targetPosition,
 22134            unitSize,
 22135            medium,
 22136            chartPathMode,
 22137            allowUnwalkableEndpoints,
 22138            allowTraversalTransitions,
 22139            maxClimbHeight,
 22140            aStarHeuristic,
 22141            flowFieldExtraFloodRange,
 22142            out VolumePathRequest? volumeRequest,
 22143            out handoff,
 22144            out totalPathCost)
 22145            && volumeRequest != null
 22146            && (request = volumeRequest) != null;
 147    }
 148
 149    private static bool TryCreateVolumeExitHandoffIfNeeded(
 150        TrailblazerWorldContext context,
 151        Vector3d targetPosition,
 152        TraversalMedium medium,
 153        VolumePathRequest directRequest,
 154        SolidPathAlgorithm chartPathMode,
 155        bool allowUnwalkableEndpoints,
 156        bool allowTraversalTransitions,
 157        Fixed64 maxClimbHeight,
 158        HeuristicMethod aStarHeuristic,
 159        int flowFieldExtraFloodRange,
 160        [NotNullWhen(true)] out IPathRequest? request,
 161        out GuidedVolumeExitHandoff? handoff)
 162    {
 25163        request = null;
 25164        handoff = null;
 165
 25166        if (directRequest == null
 25167            || !allowTraversalTransitions
 25168            || !TryGetChartBackedTargetState(
 25169                context,
 25170                targetPosition,
 25171                medium,
 25172                out bool targetRequiresConstrainedExitHandoff))
 173        {
 16174            return false;
 175        }
 176
 9177        if (!targetRequiresConstrainedExitHandoff
 9178            && !TryCreateGasLandingHandoff(
 9179                directRequest,
 9180                context,
 9181                targetPosition,
 9182                medium,
 9183                chartPathMode,
 9184                allowUnwalkableEndpoints,
 9185                allowTraversalTransitions,
 9186                maxClimbHeight,
 9187                aStarHeuristic,
 9188                flowFieldExtraFloodRange,
 9189                out request,
 9190                out handoff))
 191        {
 5192            return false;
 193        }
 194
 4195        if (request != null)
 2196            return true;
 197
 2198        return TryCreateVolumeExitHandoff(
 2199            context,
 2200            directRequest.Origin,
 2201            targetPosition,
 2202            directRequest.UnitSize,
 2203            medium,
 2204            chartPathMode,
 2205            allowUnwalkableEndpoints,
 2206            allowTraversalTransitions,
 2207            maxClimbHeight,
 2208            aStarHeuristic,
 2209            flowFieldExtraFloodRange,
 2210            out request,
 2211            out handoff,
 2212            out _);
 213    }
 214
 215    private static bool TryGetChartBackedTargetState(
 216        TrailblazerWorldContext context,
 217        Vector3d targetPosition,
 218        TraversalMedium medium,
 219        out bool targetRequiresConstrainedExitHandoff)
 220    {
 17221        targetRequiresConstrainedExitHandoff = false;
 222
 17223        if (!context.World.TryGetVoxel(targetPosition, out Voxel? targetVoxel)
 17224            || targetVoxel == null)
 1225            return false;
 226
 16227        if (targetVoxel.TryGetPartition(out SolidChartPartition? _) != true)
 7228            return false;
 229
 9230        targetRequiresConstrainedExitHandoff = !VolumeMediumRules.Matches(context.Pathing.State, targetVoxel, medium);
 9231        return true;
 232    }
 233
 234    private static bool TryCreateGasLandingHandoff(
 235        VolumePathRequest directRequest,
 236        TrailblazerWorldContext context,
 237        Vector3d targetPosition,
 238        TraversalMedium medium,
 239        SolidPathAlgorithm chartPathMode,
 240        bool allowUnwalkableEndpoints,
 241        bool allowTraversalTransitions,
 242        Fixed64 maxClimbHeight,
 243        HeuristicMethod aStarHeuristic,
 244        int flowFieldExtraFloodRange,
 245        [NotNullWhen(true)] out IPathRequest? request,
 246        out GuidedVolumeExitHandoff? handoff)
 247    {
 7248        request = null;
 7249        handoff = null;
 250
 7251        if (medium != TraversalMedium.Gas)
 2252            return false;
 253
 5254        if (!TryCreateVolumeExitHandoff(
 5255            context,
 5256            directRequest.Origin,
 5257            targetPosition,
 5258            directRequest.UnitSize,
 5259            medium,
 5260            chartPathMode,
 5261            allowUnwalkableEndpoints,
 5262            allowTraversalTransitions,
 5263            maxClimbHeight,
 5264            aStarHeuristic,
 5265            flowFieldExtraFloodRange,
 5266            out IPathRequest? plannedRequest,
 5267            out GuidedVolumeExitHandoff? plannedHandoff,
 5268            out int handoffPathCost))
 269        {
 1270            return false;
 271        }
 272
 4273        if (plannedRequest == null || plannedHandoff == null || directRequest.EndNode == null)
 0274            return false;
 275
 4276        if (directRequest.EndNode.WorldPosition != targetPosition)
 277        {
 1278            request = plannedRequest;
 1279            handoff = plannedHandoff;
 1280            return true;
 281        }
 282
 3283        if (handoffPathCost < GetDirectVolumePathCost(directRequest))
 284        {
 1285            request = plannedRequest;
 1286            handoff = plannedHandoff;
 1287            return true;
 288        }
 289
 2290        return false;
 291    }
 292
 293    private static bool TryCreateAStarRequest(
 294        TrailblazerWorldContext context,
 295        Vector3d origin,
 296        Vector3d targetPosition,
 297        Fixed64 unitSize,
 298        HeuristicMethod heuristic,
 299        bool allowUnwalkableEndpoints,
 300        bool allowTraversalTransitions,
 301        Fixed64 maxClimbHeight,
 302        [NotNullWhen(true)] out IPathRequest? request)
 303    {
 27304        AStarPathRequest? aStar = AStarPathRequest.Create(
 27305            context,
 27306            origin,
 27307            targetPosition,
 27308            unitSize,
 27309            heuristic,
 27310            allowUnwalkableEndpoints,
 27311            allowTraversalTransitions);
 27312        if (aStar == null)
 313        {
 3314            request = null;
 3315            return false;
 316        }
 317
 24318        aStar.MaxClimbHeight = maxClimbHeight;
 24319        request = aStar;
 24320        return true;
 321    }
 322
 323    private static bool TryCreateFlowFieldRequest(
 324        TrailblazerWorldContext context,
 325        Vector3d origin,
 326        Vector3d targetPosition,
 327        Fixed64 unitSize,
 328        bool allowUnwalkableEndpoints,
 329        bool allowTraversalTransitions,
 330        Fixed64 maxClimbHeight,
 331        int flowFieldExtraFloodRange,
 332        [NotNullWhen(true)] out IPathRequest? request)
 333    {
 8334        FlowFieldPathRequest? flowField = FlowFieldPathRequest.Create(
 8335            context,
 8336            origin,
 8337            targetPosition,
 8338            unitSize,
 8339            allowUnwalkableEndpoints,
 8340            allowTraversalTransitions);
 8341        if (flowField == null)
 342        {
 2343            request = null;
 2344            return false;
 345        }
 346
 6347        flowField.MaxClimbHeight = maxClimbHeight;
 6348        flowField.ExtraFloodRange = flowFieldExtraFloodRange;
 6349        request = flowField;
 6350        return true;
 351    }
 352
 353    private static int GetDirectVolumePathCost(VolumePathRequest request)
 354    {
 3355        if (request.HasZeroDisplacement)
 1356            return 0;
 357
 2358        VolumeSurveyResult result = request.Context.Pathing.State.GuideState.VolumeSurveyor.FindPath(request);
 2359        return result.HasPath && result.Waypoints != null && result.Waypoints.Length > 0
 2360            ? result.Waypoints[^1].PathCost
 2361            : int.MaxValue;
 362    }
 363}

Methods/Properties

TryCreate(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Trailblazer.Navigation.SolidPathAlgorithm,System.Boolean,System.Boolean,FixedMathSharp.Fixed64,Trailblazer.TraversalMedium,Trailblazer.Pathing.HeuristicMethod,System.Int32,Trailblazer.Pathing.IPathRequest&,Trailblazer.Navigation.GuidedVolumeExitHandoff&)
TryCreateVolumeExitHandoff(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Trailblazer.TraversalMedium,Trailblazer.Navigation.SolidPathAlgorithm,System.Boolean,System.Boolean,FixedMathSharp.Fixed64,Trailblazer.Pathing.HeuristicMethod,System.Int32,Trailblazer.Pathing.IPathRequest&,Trailblazer.Navigation.GuidedVolumeExitHandoff&,System.Int32&)
TryCreateVolumeExitHandoffIfNeeded(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,Trailblazer.TraversalMedium,Trailblazer.Pathing.VolumePathRequest,Trailblazer.Navigation.SolidPathAlgorithm,System.Boolean,System.Boolean,FixedMathSharp.Fixed64,Trailblazer.Pathing.HeuristicMethod,System.Int32,Trailblazer.Pathing.IPathRequest&,Trailblazer.Navigation.GuidedVolumeExitHandoff&)
TryGetChartBackedTargetState(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,Trailblazer.TraversalMedium,System.Boolean&)
TryCreateGasLandingHandoff(Trailblazer.Pathing.VolumePathRequest,Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,Trailblazer.TraversalMedium,Trailblazer.Navigation.SolidPathAlgorithm,System.Boolean,System.Boolean,FixedMathSharp.Fixed64,Trailblazer.Pathing.HeuristicMethod,System.Int32,Trailblazer.Pathing.IPathRequest&,Trailblazer.Navigation.GuidedVolumeExitHandoff&)
TryCreateAStarRequest(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Trailblazer.Pathing.HeuristicMethod,System.Boolean,System.Boolean,FixedMathSharp.Fixed64,Trailblazer.Pathing.IPathRequest&)
TryCreateFlowFieldRequest(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Boolean,System.Boolean,FixedMathSharp.Fixed64,System.Int32,Trailblazer.Pathing.IPathRequest&)
GetDirectVolumePathCost(Trailblazer.Pathing.VolumePathRequest)