< Summary

Information
Class: Trailblazer.Pathing.VolumePathRequest
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/Volume/VolumePathRequest.cs
Line coverage
96%
Covered lines: 128
Uncovered lines: 5
Coverable lines: 133
Total lines: 311
Line coverage: 96.2%
Branch coverage
75%
Covered branches: 57
Total branches: 76
Branch coverage: 75%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_HasOrigin()100%11100%
get_HasDestination()100%11100%
get_HasValidEndpoints()100%22100%
get_IsValid()100%22100%
get_HasZeroDisplacement()100%22100%
get_RequestCacheKey()100%11100%
.ctor()100%11100%
TryCreate(...)100%11100%
Create(...)62.5%8896.42%
UpdateRequest(...)71.42%1414100%
TrySetOrigin(...)72.22%181892%
TrySetDestination(...)72.22%181892%
TrySetUnitSize(...)100%44100%
Equals(...)100%22100%
Equals(...)100%22100%
GetHashCode()50%44100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/Volume/VolumePathRequest.cs

#LineLine coverage
 1using FixedMathSharp;
 2using GridForge.Grids;
 3using System;
 4using System.Diagnostics.CodeAnalysis;
 5using System.Runtime.CompilerServices;
 6
 7namespace Trailblazer.Pathing;
 8
 9/// <summary>
 10/// Represents a chart-optional guided travel request through raw voxel volume.
 11/// </summary>
 12/// <remarks>
 13/// Volume requests resolve directly against raw voxels instead of surface partitions. Traversal membership
 14/// can come from authored <see cref="VolumeChartPartition"/> data, host-configured <see cref="VolumeMediumRules"/>,
 15/// or both, depending on the requested <see cref="Medium"/>.
 16/// </remarks>
 17public sealed class VolumePathRequest : IPathRequest, IEquatable<VolumePathRequest>
 18{
 19    /// <inheritdoc/>
 20    public TrailblazerWorldContext Context { get; private set; } = null!;
 21
 22    /// <inheritdoc/>
 23    public Vector3d Origin { get; private set; }
 24
 25    /// <inheritdoc/>
 26    public Voxel? StartNode { get; private set; }
 27
 28    /// <inheritdoc/>
 29    public Vector3d TargetPosition { get; private set; }
 30
 31    /// <inheritdoc/>
 32    public Voxel? EndNode { get; private set; }
 33
 34    /// <inheritdoc/>
 35    public Fixed64 UnitSize { get; private set; }
 36
 37    /// <inheritdoc/>
 38    public bool AllowUnwalkableEndpoints { get; set; }
 39
 40    /// <inheritdoc/>
 41    public int MaxPathSearchRange { get; set; }
 42
 43    /// <summary>
 44    /// Gets or sets the heuristic method used to guide the algorithm's decision-making process.
 45    /// </summary>
 46    /// <remarks>
 47    /// Selecting an appropriate heuristic can significantly impact the performance and accuracy of
 48    /// the algorithm. Refer to the documentation for HeuristicMethod for available options and their intended use
 49    /// cases.
 50    /// </remarks>
 51    public HeuristicMethod Heuristic { get; set; }
 52
 53    /// <summary>
 54    /// Gets the medium used for traversal operations.
 55    /// </summary>
 56    /// <remarks>
 57    /// The traversal medium determines the method or environment by which traversal is performed.
 58    /// The value is set internally and cannot be modified directly by consumers of the class.
 59    /// </remarks>
 60    public TraversalMedium Medium { get; private set; }
 61
 62    /// <inheritdoc/>
 74863    public bool HasOrigin => StartNode != null;
 64
 65    /// <inheritdoc/>
 74266    public bool HasDestination => EndNode != null;
 67
 68    /// <inheritdoc/>
 74769    public bool HasValidEndpoints => HasOrigin && HasDestination;
 70
 71    /// <inheritdoc/>
 55472    public bool IsValid => HasValidEndpoints && MaxPathSearchRange > 0;
 73
 74    /// <inheritdoc/>
 75    public bool HasZeroDisplacement =>
 25576        !IsValid
 25577        || StartNode == EndNode;
 78
 79    /// <inheritdoc/>
 251580    public int RequestCacheKey => GetHashCode();
 81
 37082    private VolumePathRequest() { }
 83
 84    /// <summary>
 85    /// Attempts to create a new context-bound volume pathfinding request.
 86    /// </summary>
 87    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 88    public static bool TryCreate(
 89        TrailblazerWorldContext context,
 90        Vector3d origin,
 91        Vector3d destination,
 92        Fixed64 unitSize,
 93        [NotNullWhen(true)] out VolumePathRequest? request,
 94        HeuristicMethod heuristic = HeuristicMethod.Euclidean,
 95        bool allowUnwalkableEndpoints = false,
 96        TraversalMedium medium = TraversalMedium.Gas)
 97    {
 898        request = Create(
 899            context,
 8100            origin,
 8101            destination,
 8102            unitSize,
 8103            heuristic,
 8104            allowUnwalkableEndpoints,
 8105            medium);
 106
 8107        return request != null;
 108    }
 109
 110    /// <summary>
 111    /// Creates a context-bound volume pathfinding request.
 112    /// </summary>
 113    public static VolumePathRequest? Create(
 114        TrailblazerWorldContext context,
 115        Vector3d origin,
 116        Vector3d destination,
 117        Fixed64 unitSize,
 118        HeuristicMethod heuristic = HeuristicMethod.Euclidean,
 119        bool allowUnwalkableEndpoints = false,
 120        TraversalMedium medium = TraversalMedium.Gas)
 121    {
 210122        PathRequestContextResolver.ThrowIfUnusable(context);
 210123        if (!VolumeVoxelFinder.TryGetPathEdgeVoxels(
 210124            context,
 210125            origin,
 210126            destination,
 210127            out Voxel? startNode,
 210128            out Voxel? endNode,
 210129            unitSize,
 210130            allowUnwalkableEndpoints,
 210131            medium))
 132        {
 25133            return null;
 134        }
 135
 185136        if (startNode == null || endNode == null)
 0137            return null;
 138
 185139        var request = new VolumePathRequest
 185140        {
 185141            Context = context,
 185142            Origin = origin,
 185143            StartNode = startNode,
 185144            TargetPosition = destination,
 185145            EndNode = endNode,
 185146            UnitSize = unitSize,
 185147            Heuristic = heuristic,
 185148            AllowUnwalkableEndpoints = allowUnwalkableEndpoints,
 185149            Medium = medium
 185150        };
 151
 185152        if (context.Pathing.TryGetMaxSearchSize(startNode, endNode, out int searchSize))
 185153            request.MaxPathSearchRange = searchSize;
 154
 185155        return request;
 156    }
 157
 158    /// <inheritdoc/>
 159    public bool UpdateRequest(
 160        Vector3d origin,
 161        Vector3d destination,
 162        Fixed64? unitSize)
 163    {
 5164        Fixed64 resolvedUnitSize = unitSize ?? Context.VoxelSize;
 5165        bool hasEndpoints = VolumeVoxelFinder.TryGetPathEdgeVoxels(
 5166            Context,
 5167            origin,
 5168            destination,
 5169            out Voxel? startNode,
 5170            out Voxel? endNode,
 5171            resolvedUnitSize,
 5172            AllowUnwalkableEndpoints,
 5173            Medium);
 174
 5175        Origin = origin;
 5176        TargetPosition = destination;
 5177        StartNode = hasEndpoints ? startNode : null;
 5178        EndNode = hasEndpoints ? endNode : null;
 5179        UnitSize = resolvedUnitSize;
 5180        MaxPathSearchRange = 0;
 181
 5182        if (hasEndpoints
 5183            && StartNode != null
 5184            && EndNode != null
 5185            && Context.Pathing.TryGetMaxSearchSize(StartNode, EndNode, out int searchSize))
 2186            MaxPathSearchRange = searchSize;
 187
 5188        return HasValidEndpoints;
 189    }
 190
 191    /// <inheritdoc/>
 192    public bool TrySetOrigin(Vector3d origin, bool resetSearchRange = false)
 193    {
 17194        if (EndNode == null)
 1195            return false;
 196
 16197        if (!VolumeVoxelFinder.GetStartVoxel(
 16198            Context,
 16199            origin,
 16200            TargetPosition,
 16201            out Voxel? startNode,
 16202            AllowUnwalkableEndpoints,
 16203            UnitSize,
 16204            Medium))
 205        {
 1206            return false;
 207        }
 208
 15209        if (startNode == null)
 0210            return false;
 211
 15212        Origin = origin;
 213
 15214        if (StartNode != null)
 215        {
 15216            if (startNode == StartNode)
 13217                return true;
 218
 2219            if (startNode.GridIndex != StartNode.GridIndex)
 0220                resetSearchRange = true;
 221        }
 222
 2223        StartNode = startNode;
 224
 2225        if (resetSearchRange)
 226        {
 1227            MaxPathSearchRange = 0;
 1228            if (HasDestination && Context.Pathing.TryGetMaxSearchSize(StartNode, EndNode, out int searchSize))
 1229                MaxPathSearchRange = searchSize;
 230        }
 231
 2232        return true;
 233    }
 234
 235    /// <inheritdoc/>
 236    public bool TrySetDestination(Vector3d destination, bool resetSearchRange = false)
 237    {
 5238        if (StartNode == null)
 1239            return false;
 240
 4241        if (!VolumeVoxelFinder.GetEndVoxel(
 4242            Context,
 4243            Origin,
 4244            destination,
 4245            out Voxel? endNode,
 4246            AllowUnwalkableEndpoints,
 4247            UnitSize,
 4248            Medium))
 249        {
 1250            return false;
 251        }
 252
 3253        if (endNode == null)
 0254            return false;
 255
 3256        TargetPosition = destination;
 257
 3258        if (EndNode != null)
 259        {
 3260            if (endNode == EndNode)
 1261                return true;
 262
 2263            if (endNode.GridIndex != EndNode.GridIndex)
 0264                resetSearchRange = true;
 265        }
 266
 2267        EndNode = endNode;
 268
 2269        if (resetSearchRange)
 270        {
 1271            MaxPathSearchRange = 0;
 1272            if (HasOrigin && Context.Pathing.TryGetMaxSearchSize(StartNode, EndNode, out int searchSize))
 1273                MaxPathSearchRange = searchSize;
 274        }
 275
 2276        return true;
 277    }
 278
 279    /// <inheritdoc/>
 280    public bool TrySetUnitSize(Fixed64 unitSize)
 281    {
 3282        if (UnitSize == unitSize || !HasValidEndpoints)
 1283            return false;
 284
 2285        return UpdateRequest(Origin, TargetPosition, unitSize);
 286    }
 287
 288    /// <inheritdoc/>
 289    public override bool Equals(object? obj) =>
 3290        obj is VolumePathRequest other && Equals(other);
 291
 292    /// <inheritdoc/>
 293    public bool Equals(VolumePathRequest? other) =>
 5294        other != null
 5295        && RequestCacheKey == other.RequestCacheKey;
 296
 297    /// <inheritdoc/>
 298    public override int GetHashCode()
 299    {
 2517300        PathRequestHashBuilder hash = PathRequestHashBuilder.Create();
 2517301        hash.Add(StartNode?.SpawnToken ?? 0);
 2517302        hash.Add(EndNode?.SpawnToken ?? 0);
 2517303        hash.Add(UnitSize.GetHashCode());
 2517304        hash.Add(AllowUnwalkableEndpoints);
 2517305        hash.Add((int)Heuristic);
 2517306        hash.Add((int)Medium);
 2517307        hash.Add(MaxPathSearchRange);
 2517308        hash.Add(Context.Pathing.State.VolumeRulesState.RegistryVersion);
 2517309        return hash.ToHashCode();
 310    }
 311}