< Summary

Information
Class: Trailblazer.Pathing.TraversalEvaluator
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Graph/TraversalEvaluator.cs
Line coverage
100%
Covered lines: 341
Uncovered lines: 0
Coverable lines: 341
Total lines: 645
Line coverage: 100%
Branch coverage
100%
Covered branches: 108
Total branches: 108
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Profile()100%11100%
get_AreaPolicy()100%11100%
get_Graph()100%11100%
TryGetPassableNodeState(...)100%11100%
EvaluateEdge(...)100%44100%
BeginExplicitEdge(...)100%88100%
AdvanceExplicitEdge(...)100%1616100%
EvaluateNative(...)100%1010100%
EvaluateExplicitEdge(...)100%88100%
EvaluateAutomaticSeam(...)100%1212100%
TryGetExplicitConnectionCost(...)100%1212100%
TryGetPortalTraversalCost(...)100%1010100%
EvaluateVerticalDelta(...)100%88100%
TryGetPassableNode(...)100%2020100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Graph/TraversalEvaluator.cs

#LineLine coverage
 1//=======================================================================
 2// TraversalEvaluator.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using GridForge.Grids.Topology;
 10
 11namespace Trailblazer.Pathing;
 12
 13/// <summary>Reports the allocation-free result of one traversal evaluation.</summary>
 14internal enum TraversalEvaluationStatus : byte
 15{
 16    Passable = 0,
 17    Impassable = 1,
 18    CostOverflow = 2
 19}
 20
 21/// <summary>Reports progress through one bounded explicit-connection evaluation.</summary>
 22internal enum TraversalExplicitEdgeStatus : byte
 23{
 24    Pending = 0,
 25    Passable = 1,
 26    Impassable = 2,
 27    CostOverflow = 3
 28}
 29
 30/// <summary>Returns one evaluated edge's exact cost and resolved portal evidence.</summary>
 31internal readonly struct TraversalEdgeEvidence
 32{
 33    internal TraversalEdgeEvidence(NavigationNodeRef dependencyNode)
 34    {
 35        this = default;
 36        DependencyNode = dependencyNode;
 37    }
 38
 39    internal TraversalEdgeEvidence(
 40        Fixed64 cost,
 41        GridNavigationPortal portal,
 42        Vector3d sourcePortalAnchor,
 43        Vector3d targetPortalAnchor,
 44        NavigationCellAddress sourceAddress,
 45        NavigationCellAddress targetAddress,
 46        Vector3d sourceFootAnchor,
 47        Vector3d targetFootAnchor,
 48        in GridCellPrism sourcePrism,
 49        in GridCellPrism targetPrism,
 50        NavigationNodeRef dependencyNode)
 51    {
 52        Cost = cost;
 53        Portal = portal;
 54        SourcePortalAnchor = sourcePortalAnchor;
 55        TargetPortalAnchor = targetPortalAnchor;
 56        SourceAddress = sourceAddress;
 57        TargetAddress = targetAddress;
 58        SourceFootAnchor = sourceFootAnchor;
 59        TargetFootAnchor = targetFootAnchor;
 60        SourcePrism = sourcePrism;
 61        TargetPrism = targetPrism;
 62        DependencyNode = dependencyNode;
 63    }
 64
 65    internal Fixed64 Cost { get; }
 66
 67    internal GridNavigationPortal Portal { get; }
 68
 69    internal Vector3d SourcePortalAnchor { get; }
 70
 71    internal Vector3d TargetPortalAnchor { get; }
 72
 73    internal NavigationCellAddress SourceAddress { get; }
 74
 75    internal NavigationCellAddress TargetAddress { get; }
 76
 77    internal Vector3d SourceFootAnchor { get; }
 78
 79    internal Vector3d TargetFootAnchor { get; }
 80
 81    internal GridCellPrism SourcePrism { get; }
 82
 83    internal GridCellPrism TargetPrism { get; }
 84
 85    internal NavigationNodeRef DependencyNode { get; }
 86}
 87
 88/// <summary>Retains scalar state while explicit corridor legs are evaluated.</summary>
 89internal struct TraversalExplicitEdgeWork
 90{
 91    internal NavigationExplicitConnectionRecord Record;
 92    internal NavigationNodeRef Target;
 93    internal NavigationPagedSequence<GridNavigationPortal>.Enumerator Portals;
 94    internal NavigationCellAddress PreviousAddress;
 95    internal GridCellPrism PreviousPrism;
 96    internal Vector3d SourceFootAnchor;
 97    internal Vector3d TargetFootAnchor;
 98    internal Vector3d PreviousFootAnchor;
 99    internal Fixed64 TargetEnterCost;
 100    internal Fixed64 TargetAreaEnterCost;
 101    internal int WitnessIndex;
 102}
 103
 104/// <summary>Evaluates nodes and native edges against one resolved immutable query profile.</summary>
 105internal readonly struct TraversalEvaluator
 106{
 107    private readonly NavigationWorldGraph _graph;
 108    private readonly NavigationAgentProfile _profile;
 109    private readonly NavigationAreaPolicy _areaPolicy;
 110    private readonly TraversalMedia _medium;
 111    private readonly TraversalMedium _exactMedium;
 112
 113    internal TraversalEvaluator(
 114        NavigationWorldGraph graph,
 115        NavigationAgentProfile profile,
 116        NavigationAreaPolicy areaPolicy,
 117        TraversalMedium medium)
 118    {
 22871119        SwiftThrowHelper.ThrowIfNull(graph, nameof(graph));
 22871120        SwiftThrowHelper.ThrowIfNull(areaPolicy, nameof(areaPolicy));
 22871121        profile.Validate(nameof(profile));
 22871122        TraversalMedia resolvedMedium = NavigationCell.ToMedia(medium);
 22871123        SwiftThrowHelper.ThrowIfArgument(
 22871124            resolvedMedium == TraversalMedia.None,
 22871125            nameof(medium),
 22871126            "Traversal medium must resolve to one exact authored medium.");
 127
 22871128        _graph = graph;
 22871129        _profile = profile;
 22871130        _areaPolicy = areaPolicy;
 22871131        _medium = resolvedMedium;
 22871132        _exactMedium = medium;
 22871133    }
 134
 78755135    internal NavigationAgentProfile Profile => _profile;
 136
 2885137    internal NavigationAreaPolicy AreaPolicy => _areaPolicy;
 138
 4773139    internal NavigationWorldGraph Graph => _graph;
 140
 141    internal bool TryGetPassableNodeState(
 142        NavigationNodeRef node,
 143        out NavigationNodeState state) =>
 15417144        TryGetPassableNode(node, out state, out _);
 145
 146    internal TraversalEvaluationStatus EvaluateEdge(
 147        NavigationNodeRef source,
 148        in NavigationGraphEdge edge,
 149        out TraversalEdgeEvidence evidence)
 150    {
 102895151        return edge.Kind switch
 102895152        {
 20029153            NavigationGraphEdgeKind.Explicit => EvaluateExplicitEdge(
 20029154                source,
 20029155                edge,
 20029156                out evidence),
 40057157            NavigationGraphEdgeKind.Seam => EvaluateAutomaticSeam(
 40057158                source,
 40057159                edge,
 40057160                out evidence),
 42809161            _ => EvaluateNative(source, edge, out evidence)
 102895162        };
 163    }
 164
 165    internal TraversalExplicitEdgeStatus BeginExplicitEdge(
 166        NavigationNodeRef source,
 167        in NavigationGraphEdge edge,
 168        out TraversalExplicitEdgeWork work)
 169    {
 20211170        work = default;
 20211171        NavigationExplicitConnectionRecord record = edge.ExplicitConnection;
 20211172        bool hasSourceAddress = _graph.TryGetNodeAddress(
 20211173            source,
 20211174            out NavigationCellAddress sourceAddress);
 20211175        bool hasTargetAddress = _graph.TryGetNodeAddress(
 20211176            edge.Target,
 20211177            out NavigationCellAddress targetAddress);
 20211178        bool hasSourcePrism = _graph.TryGetSeamPrism(
 20211179            sourceAddress,
 20211180            out GridCellPrism sourcePrism);
 181        System.Diagnostics.Debug.Assert(
 182            record != null
 183            && record.IsActive
 184            && edge.Kind == NavigationGraphEdgeKind.Explicit
 185            && hasSourceAddress
 186            && hasTargetAddress
 187            && record.NavigationPortals.Count == record.Definition.Witnesses.Count + 1
 188            && hasSourcePrism
 189            && sourceAddress.Equals(record.Source)
 190            && targetAddress.Equals(record.Destination));
 20211191        if (!TryGetPassableNode(source, out NavigationNodeState sourceState, out _)
 20211192            || !TryGetPassableNode(
 20211193                edge.Target,
 20211194                out NavigationNodeState targetState,
 20211195                out NavigationAreaRule targetRule))
 196        {
 1197            return TraversalExplicitEdgeStatus.Impassable;
 198        }
 199
 20210200        KinematicBodyShape shape = _profile.Shape;
 20210201        NavigationConnection connection = record.Definition;
 20210202        if (shape.Radius > connection.PortalRadiusClearance
 20210203            || shape.Height > connection.PortalHeightClearance)
 204        {
 7205            return TraversalExplicitEdgeStatus.Impassable;
 206        }
 207
 20203208        work = new TraversalExplicitEdgeWork
 20203209        {
 20203210            Record = record,
 20203211            Target = edge.Target,
 20203212            Portals = record.NavigationPortals.GetEnumerator(),
 20203213            PreviousAddress = sourceAddress,
 20203214            PreviousPrism = sourcePrism,
 20203215            SourceFootAnchor = sourceState.FootAnchor,
 20203216            TargetFootAnchor = targetState.FootAnchor,
 20203217            PreviousFootAnchor = sourceState.FootAnchor,
 20203218            TargetEnterCost = targetState.Cell.EnterCost,
 20203219            TargetAreaEnterCost = targetRule.AdditionalEnterCost
 20203220        };
 20203221        return TraversalExplicitEdgeStatus.Pending;
 222    }
 223
 224    internal TraversalExplicitEdgeStatus AdvanceExplicitEdge(
 225        ref TraversalExplicitEdgeWork work,
 226        out TraversalEdgeEvidence evidence)
 227    {
 20557228        evidence = default;
 20557229        NavigationExplicitConnectionRecord record = work.Record;
 20557230        NavigationConnection connection = record.Definition;
 20557231        bool final = work.WitnessIndex >= connection.Witnesses.Count;
 20557232        NavigationCellAddress nextAddress = final
 20557233            ? record.Destination
 20557234            : connection.Witnesses[work.WitnessIndex];
 235        NavigationNodeRef dependencyNode;
 236        Vector3d nextFootAnchor;
 20557237        if (final)
 238        {
 20186239            dependencyNode = work.Target;
 20186240            evidence = new TraversalEdgeEvidence(dependencyNode);
 20186241            nextFootAnchor = work.TargetFootAnchor;
 242        }
 243        else
 244        {
 371245            bool hasDependencyNode = _graph.TryGetNodeRef(nextAddress, out dependencyNode);
 246            System.Diagnostics.Debug.Assert(hasDependencyNode);
 371247            evidence = new TraversalEdgeEvidence(dependencyNode);
 371248            if (!TryGetPassableNode(
 371249                    dependencyNode,
 371250                    out NavigationNodeState nextState,
 371251                    out _))
 252            {
 5253                return TraversalExplicitEdgeStatus.Impassable;
 254            }
 366255            nextFootAnchor = nextState.FootAnchor;
 256        }
 257
 20552258        bool hasNextPrism = _graph.TryGetSeamPrism(nextAddress, out GridCellPrism nextPrism);
 20552259        bool hasPortal = work.Portals.MoveNext();
 260        System.Diagnostics.Debug.Assert(hasNextPrism && hasPortal);
 20552261        GridNavigationPortal portal = work.Portals.Current;
 20552262        KinematicBodyShape shape = _profile.Shape;
 263        System.Diagnostics.Debug.Assert(portal.IsValid);
 20552264        bool resolvedProfile = portal.TryResolveProfile(
 20552265            shape.Radius,
 20552266            shape.Height,
 20552267            out Vector3d sourcePortalAnchor,
 20552268            out Vector3d targetPortalAnchor);
 269        System.Diagnostics.Debug.Assert(resolvedProfile);
 270        System.Diagnostics.Debug.Assert(
 271            portal.FaceKind != VoxelContactFaceKind.Horizontal
 272            || (GridCellGeometry.TryGetNavigationPortalTraversalParameters(
 273                    work.PreviousPrism,
 274                    nextPrism,
 275                    portal,
 276                    sourcePortalAnchor,
 277                    targetPortalAnchor,
 278                    shape.Radius,
 279                    shape.Height,
 280                    out Fixed64 sourceParameter,
 281                    out Fixed64 targetParameter)
 282                && sourceParameter == Fixed64.Zero
 283                && targetParameter == Fixed64.One),
 284            "published explicit corridors retain the exact validated profile crossing");
 285
 20552286        TraversalEvaluationStatus vertical = EvaluateVerticalDelta(
 20552287            work.PreviousFootAnchor,
 20552288            nextFootAnchor);
 20552289        if (vertical != TraversalEvaluationStatus.Passable)
 2290            return TraversalExplicitEdgeStatus.Impassable;
 291
 20550292        Fixed64 cost = Fixed64.Zero;
 20550293        if (final
 20550294            && !TryGetExplicitConnectionCost(
 20550295                work.SourceFootAnchor,
 20550296                connection.EntryAnchor,
 20550297                record.CorridorCost,
 20550298                connection.ExitAnchor,
 20550299                work.TargetFootAnchor,
 20550300                connection.AdditionalCost,
 20550301                work.TargetEnterCost,
 20550302                work.TargetAreaEnterCost,
 20550303                out cost))
 304        {
 3305            return TraversalExplicitEdgeStatus.CostOverflow;
 306        }
 307
 20547308        evidence = new TraversalEdgeEvidence(
 20547309            cost,
 20547310            portal,
 20547311            sourcePortalAnchor,
 20547312            targetPortalAnchor,
 20547313            work.PreviousAddress,
 20547314            nextAddress,
 20547315            work.PreviousFootAnchor,
 20547316            nextFootAnchor,
 20547317            work.PreviousPrism,
 20547318            nextPrism,
 20547319            dependencyNode);
 20547320        work.PreviousAddress = nextAddress;
 20547321        work.PreviousPrism = nextPrism;
 20547322        work.PreviousFootAnchor = nextFootAnchor;
 20547323        if (!final)
 364324            work.WitnessIndex++;
 20547325        return final
 20547326            ? TraversalExplicitEdgeStatus.Passable
 20547327            : TraversalExplicitEdgeStatus.Pending;
 328    }
 329
 330    private TraversalEvaluationStatus EvaluateNative(
 331        NavigationNodeRef source,
 332        in NavigationGraphEdge edge,
 333        out TraversalEdgeEvidence evidence)
 334    {
 42809335        evidence = default;
 42809336        if (!TryGetPassableNode(source, out NavigationNodeState sourceState, out _)
 42809337            || !TryGetPassableNode(
 42809338                edge.Target,
 42809339                out NavigationNodeState targetState,
 42809340                out NavigationAreaRule targetRule))
 341        {
 34342            return TraversalEvaluationStatus.Impassable;
 343        }
 344
 42775345        KinematicBodyShape shape = _profile.Shape;
 42775346        GridNavigationPortal template = edge.NativePortal;
 347        System.Diagnostics.Debug.Assert(template.IsValid);
 42775348        if (shape.Radius > template.MaximumHorizontalRadius
 42775349            || shape.Height > template.MaximumBodyHeight)
 350        {
 3351            return TraversalEvaluationStatus.Impassable;
 352        }
 353
 42772354        bool hasSourceAddress = _graph.TryGetNodeAddress(
 42772355            source,
 42772356            out NavigationCellAddress sourceAddress);
 42772357        bool hasTargetAddress = _graph.TryGetNodeAddress(
 42772358            edge.Target,
 42772359            out NavigationCellAddress targetAddress);
 42772360        bool hasSourcePrism = _graph.TryGetSeamPrism(
 42772361            sourceAddress,
 42772362            out GridCellPrism sourcePrism);
 42772363        bool hasTargetPrism = _graph.TryGetSeamPrism(
 42772364            targetAddress,
 42772365            out GridCellPrism targetPrism);
 366        System.Diagnostics.Debug.Assert(
 367            hasSourceAddress && hasTargetAddress && hasSourcePrism && hasTargetPrism);
 42772368        bool translated = template.TryTranslate(
 42772369            sourceState.Center,
 42772370            out GridNavigationPortal retainedPortal);
 371        System.Diagnostics.Debug.Assert(translated);
 42772372        bool createdPortal = GridCellGeometry.TryCreateNavigationPortal(
 42772373            sourcePrism,
 42772374            targetPrism,
 42772375            out GridNavigationPortal portal);
 376        System.Diagnostics.Debug.Assert(createdPortal && retainedPortal.IsValid);
 42772377        bool resolvedProfile = portal.TryResolveProfile(
 42772378            shape.Radius,
 42772379            shape.Height,
 42772380            out Vector3d sourcePortalFoot,
 42772381            out Vector3d targetPortalFoot);
 382        System.Diagnostics.Debug.Assert(resolvedProfile);
 383
 42772384        if (!TryGetPortalTraversalCost(
 42772385                useCeilingDistance: true,
 42772386                sourceState.FootAnchor,
 42772387                sourcePortalFoot,
 42772388                targetPortalFoot,
 42772389                targetState.FootAnchor,
 42772390                targetState.Cell.EnterCost,
 42772391                targetRule.AdditionalEnterCost,
 42772392                out Fixed64 total))
 393        {
 5394            return TraversalEvaluationStatus.CostOverflow;
 395        }
 396
 42767397        evidence = new TraversalEdgeEvidence(
 42767398            total,
 42767399            portal,
 42767400            sourcePortalFoot,
 42767401            targetPortalFoot,
 42767402            sourceAddress,
 42767403            targetAddress,
 42767404            sourceState.FootAnchor,
 42767405            targetState.FootAnchor,
 42767406            sourcePrism,
 42767407            targetPrism,
 42767408            default);
 42767409        return TraversalEvaluationStatus.Passable;
 410    }
 411
 412    private TraversalEvaluationStatus EvaluateExplicitEdge(
 413        NavigationNodeRef source,
 414        in NavigationGraphEdge edge,
 415        out TraversalEdgeEvidence evidence)
 416    {
 20029417        evidence = default;
 20029418        Fixed64 cost = Fixed64.Zero;
 20029419        TraversalExplicitEdgeStatus status = BeginExplicitEdge(source, edge, out TraversalExplicitEdgeWork work);
 40128420        while (status == TraversalExplicitEdgeStatus.Pending)
 421        {
 20099422            status = AdvanceExplicitEdge(ref work, out TraversalEdgeEvidence step);
 20099423            cost = step.Cost;
 424        }
 20029425        TraversalEvaluationStatus result = status switch
 20029426        {
 20022427            TraversalExplicitEdgeStatus.Passable => TraversalEvaluationStatus.Passable,
 1428            TraversalExplicitEdgeStatus.CostOverflow => TraversalEvaluationStatus.CostOverflow,
 6429            _ => TraversalEvaluationStatus.Impassable
 20029430        };
 20029431        if (result == TraversalEvaluationStatus.Passable)
 20022432            evidence = new TraversalEdgeEvidence(
 20022433                cost,
 20022434                default,
 20022435                default,
 20022436                default,
 20022437                default,
 20022438                default,
 20022439                default,
 20022440                default,
 20022441                default,
 20022442                default,
 20022443                default);
 20029444        return result;
 445    }
 446
 447    private TraversalEvaluationStatus EvaluateAutomaticSeam(
 448        NavigationNodeRef source,
 449        in NavigationGraphEdge edge,
 450        out TraversalEdgeEvidence evidence)
 451    {
 40057452        evidence = default;
 40057453        NavigationAutomaticSeamRef seam = edge.AutomaticSeam;
 40057454        bool hasSourceAddress = _graph.TryGetNodeAddress(
 40057455            source,
 40057456            out NavigationCellAddress sourceAddress);
 40057457        bool hasTargetAddress = _graph.TryGetNodeAddress(
 40057458            edge.Target,
 40057459            out NavigationCellAddress targetAddress);
 460        System.Diagnostics.Debug.Assert(
 461            edge.Kind == NavigationGraphEdgeKind.Seam
 462            && seam.Pair != null
 463            && _graph.AutomaticSeams.IsActive(seam)
 464            && hasSourceAddress
 465            && sourceAddress.Equals(seam.Source)
 466            && hasTargetAddress
 467            && targetAddress.Equals(seam.Destination));
 40057468        if (!TryGetPassableNode(source, out NavigationNodeState sourceState, out _)
 40057469            || !TryGetPassableNode(
 40057470                edge.Target,
 40057471                out NavigationNodeState targetState,
 40057472                out NavigationAreaRule targetRule))
 473        {
 2474            return TraversalEvaluationStatus.Impassable;
 475        }
 476
 40055477        KinematicBodyShape shape = _profile.Shape;
 40055478        GridNavigationPortal retainedPortal = seam.Portal;
 479        System.Diagnostics.Debug.Assert(retainedPortal.IsValid);
 40055480        if (shape.Radius > retainedPortal.MaximumHorizontalRadius
 40055481            || shape.Height > retainedPortal.MaximumBodyHeight)
 482        {
 1483            return TraversalEvaluationStatus.Impassable;
 484        }
 40054485        bool hasSourcePrism = _graph.TryGetSeamPrism(
 40054486            sourceAddress,
 40054487            out GridCellPrism sourcePrism);
 40054488        bool hasTargetPrism = _graph.TryGetSeamPrism(
 40054489            targetAddress,
 40054490            out GridCellPrism targetPrism);
 40054491        bool createdPortal = GridCellGeometry.TryCreateNavigationPortal(
 40054492            sourcePrism,
 40054493            targetPrism,
 40054494            out GridNavigationPortal portal);
 495        System.Diagnostics.Debug.Assert(
 496            hasSourcePrism
 497            && hasTargetPrism
 498            && createdPortal
 499            && retainedPortal.IsValid);
 40054500        bool resolvedProfile = portal.TryResolveProfile(
 40054501            shape.Radius,
 40054502            shape.Height,
 40054503            out Vector3d sourcePortalFoot,
 40054504            out Vector3d targetPortalFoot);
 505        System.Diagnostics.Debug.Assert(resolvedProfile);
 40054506        TraversalEvaluationStatus vertical = EvaluateVerticalDelta(
 40054507            sourceState.FootAnchor,
 40054508            targetState.FootAnchor);
 40054509        if (vertical != TraversalEvaluationStatus.Passable)
 1510            return vertical;
 40053511        if (!TryGetPortalTraversalCost(
 40053512                portal.FaceKind == VoxelContactFaceKind.Vertical,
 40053513                sourceState.FootAnchor,
 40053514                sourcePortalFoot,
 40053515                targetPortalFoot,
 40053516                targetState.FootAnchor,
 40053517                targetState.Cell.EnterCost,
 40053518                targetRule.AdditionalEnterCost,
 40053519                out Fixed64 total))
 520        {
 1521            return TraversalEvaluationStatus.CostOverflow;
 522        }
 523
 40052524        evidence = new TraversalEdgeEvidence(
 40052525            total,
 40052526            portal,
 40052527            sourcePortalFoot,
 40052528            targetPortalFoot,
 40052529            sourceAddress,
 40052530            targetAddress,
 40052531            sourceState.FootAnchor,
 40052532            targetState.FootAnchor,
 40052533            sourcePrism,
 40052534            targetPrism,
 40052535            default);
 40052536        return TraversalEvaluationStatus.Passable;
 537    }
 538
 539    internal static bool TryGetExplicitConnectionCost(
 540        Vector3d sourceFootAnchor,
 541        Vector3d entryAnchor,
 542        Fixed64 corridorCost,
 543        Vector3d exitAnchor,
 544        Vector3d targetFootAnchor,
 545        Fixed64 additionalCost,
 546        Fixed64 targetEnterCost,
 547        Fixed64 targetAreaEnterCost,
 548        out Fixed64 total)
 549    {
 20194550        total = Fixed64.Zero;
 20194551        return Vector3d.TryGetDistance(sourceFootAnchor, entryAnchor, out Fixed64 sourceDistance)
 20194552            && Vector3d.TryGetDistance(exitAnchor, targetFootAnchor, out Fixed64 targetDistance)
 20194553            && Fixed64.TryAdd(sourceDistance, corridorCost, out total)
 20194554            && Fixed64.TryAdd(total, targetDistance, out total)
 20194555            && Fixed64.TryAdd(total, additionalCost, out total)
 20194556            && Fixed64.TryAdd(total, targetEnterCost, out total)
 20194557            && Fixed64.TryAdd(total, targetAreaEnterCost, out total);
 558    }
 559
 560    internal static bool TryGetPortalTraversalCost(
 561        bool useCeilingDistance,
 562        Vector3d sourceFootAnchor,
 563        Vector3d sourcePortalFoot,
 564        Vector3d targetPortalFoot,
 565        Vector3d targetFootAnchor,
 566        Fixed64 targetEnterCost,
 567        Fixed64 targetAreaEnterCost,
 568        out Fixed64 total)
 569    {
 82832570        total = Fixed64.Zero;
 82832571        bool hasSourceDistance = useCeilingDistance
 82832572            ? NavigationDistanceMath.TryCeiling(
 82832573                sourceFootAnchor,
 82832574                sourcePortalFoot,
 82832575                out Fixed64 sourceDistance)
 82832576            : Vector3d.TryGetDistance(
 82832577                sourceFootAnchor,
 82832578                sourcePortalFoot,
 82832579                out sourceDistance);
 82832580        bool hasTargetDistance = useCeilingDistance
 82832581            ? NavigationDistanceMath.TryCeiling(
 82832582                targetPortalFoot,
 82832583                targetFootAnchor,
 82832584                out Fixed64 targetDistance)
 82832585            : Vector3d.TryGetDistance(
 82832586                targetPortalFoot,
 82832587                targetFootAnchor,
 82832588                out targetDistance);
 82832589        return hasSourceDistance
 82832590            && hasTargetDistance
 82832591            && Fixed64.TryAdd(sourceDistance, targetDistance, out total)
 82832592            && Fixed64.TryAdd(total, targetEnterCost, out total)
 82832593            && Fixed64.TryAdd(total, targetAreaEnterCost, out total);
 594    }
 595
 596    private TraversalEvaluationStatus EvaluateVerticalDelta(
 597        Vector3d sourceFootAnchor,
 598        Vector3d targetFootAnchor)
 599    {
 60606600        bool hasVerticalDelta = Fixed64.TrySubtract(
 60606601            targetFootAnchor.Y,
 60606602            sourceFootAnchor.Y,
 60606603            out Fixed64 verticalDelta);
 604        System.Diagnostics.Debug.Assert(hasVerticalDelta);
 60606605        if (verticalDelta > Fixed64.Zero)
 606        {
 21607            return verticalDelta <= _profile.MaxStepUp
 21608                ? TraversalEvaluationStatus.Passable
 21609                : TraversalEvaluationStatus.Impassable;
 610        }
 60585611        if (verticalDelta >= Fixed64.Zero)
 60574612            return TraversalEvaluationStatus.Passable;
 11613        bool hasDrop = Fixed64.TrySubtract(Fixed64.Zero, verticalDelta, out Fixed64 drop);
 614        System.Diagnostics.Debug.Assert(hasDrop);
 11615        return drop <= _profile.MaxDropDown
 11616            ? TraversalEvaluationStatus.Passable
 11617            : TraversalEvaluationStatus.Impassable;
 618    }
 619
 620    internal bool TryGetPassableNode(
 621        NavigationNodeRef node,
 622        out NavigationNodeState state,
 623        out NavigationAreaRule areaRule)
 624    {
 228676625        areaRule = default;
 228676626        if (!_graph.TryGetNodeState(node, _exactMedium, out state)
 228676627            || !state.IsPresent
 228676628            || state.ObstacleCount != 0
 228676629            || (_profile.AllowedMedia & _medium) != _medium
 228676630            || (state.Cell.Media & _medium) != _medium
 228676631            || (_profile.Capabilities & state.Cell.RequiredCapabilities)
 228676632                != state.Cell.RequiredCapabilities
 228676633            || !_areaPolicy.TryGetRule(state.Cell.Area, out areaRule)
 228676634            || !areaRule.IsAllowed
 228676635            || _profile.Shape.Radius > state.Cell.RadiusClearance
 228676636            || _profile.Shape.Height > state.Cell.HeightClearance)
 637        {
 233638            state = default;
 233639            areaRule = default;
 233640            return false;
 641        }
 642
 228443643        return true;
 644    }
 645}

Methods/Properties

.ctor(Trailblazer.Pathing.NavigationWorldGraph,Trailblazer.Pathing.NavigationAgentProfile,Trailblazer.Pathing.NavigationAreaPolicy,Trailblazer.TraversalMedium)
get_Profile()
get_AreaPolicy()
get_Graph()
TryGetPassableNodeState(Trailblazer.Pathing.NavigationNodeRef,Trailblazer.Pathing.NavigationNodeState&)
EvaluateEdge(Trailblazer.Pathing.NavigationNodeRef,Trailblazer.Pathing.NavigationGraphEdge&,Trailblazer.Pathing.TraversalEdgeEvidence&)
BeginExplicitEdge(Trailblazer.Pathing.NavigationNodeRef,Trailblazer.Pathing.NavigationGraphEdge&,Trailblazer.Pathing.TraversalExplicitEdgeWork&)
AdvanceExplicitEdge(Trailblazer.Pathing.TraversalExplicitEdgeWork&,Trailblazer.Pathing.TraversalEdgeEvidence&)
EvaluateNative(Trailblazer.Pathing.NavigationNodeRef,Trailblazer.Pathing.NavigationGraphEdge&,Trailblazer.Pathing.TraversalEdgeEvidence&)
EvaluateExplicitEdge(Trailblazer.Pathing.NavigationNodeRef,Trailblazer.Pathing.NavigationGraphEdge&,Trailblazer.Pathing.TraversalEdgeEvidence&)
EvaluateAutomaticSeam(Trailblazer.Pathing.NavigationNodeRef,Trailblazer.Pathing.NavigationGraphEdge&,Trailblazer.Pathing.TraversalEdgeEvidence&)
TryGetExplicitConnectionCost(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
TryGetPortalTraversalCost(System.Boolean,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64&)
EvaluateVerticalDelta(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
TryGetPassableNode(Trailblazer.Pathing.NavigationNodeRef,Trailblazer.Pathing.NavigationNodeState&,Trailblazer.Pathing.NavigationAreaRule&)