< Summary

Information
Class: Trailblazer.Pathing.VolumeVoxelFinder
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/VoxelResolution/VolumeVoxelFinder.cs
Line coverage
98%
Covered lines: 105
Uncovered lines: 2
Coverable lines: 107
Total lines: 325
Line coverage: 98.1%
Branch coverage
90%
Covered branches: 76
Total branches: 84
Branch coverage: 90.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
TryGetPathEdgeVoxels(...)100%44100%
GetStartVoxel(...)100%22100%
GetEndVoxel(...)100%22100%
IsDirectPathClear(...)95%2020100%
IsTraversable(...)100%11100%
IsTraversable(...)100%22100%
TryGetClosestTraversableVoxel(...)100%11100%
IsBaseTraversable(...)91.66%1212100%
TryGetEndpointVoxel(...)100%11100%
PassesMedium(...)100%11100%
RequiresSizeFallback(...)75%1616100%
HasClearance(...)90.9%232288.23%
.ctor(...)100%11100%
CanResolve()100%11100%
TryAcceptDirectVoxel(...)100%44100%
RequiresSizeFallback(...)100%11100%
IsTraversable(...)100%11100%
TryGetFinalFallbackVoxel(...)100%11100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/VoxelResolution/VolumeVoxelFinder.cs

#LineLine coverage
 1using FixedMathSharp;
 2using GridForge;
 3using GridForge.Grids;
 4using GridForge.Utility;
 5using System.Diagnostics.CodeAnalysis;
 6using System.Runtime.CompilerServices;
 7
 8namespace Trailblazer.Pathing;
 9
 10/// <summary>
 11/// Resolves and validates raw voxel volumes without requiring navigation chart partitions.
 12/// </summary>
 13public static class VolumeVoxelFinder
 14{
 15    /// <summary>
 16    /// Attempts to determine the voxels at the origin and target endpoints in one explicit context.
 17    /// </summary>
 18    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 19    public static bool TryGetPathEdgeVoxels(
 20        TrailblazerWorldContext context,
 21        Vector3d origin,
 22        Vector3d target,
 23        [MaybeNullWhen(false)] out Voxel originVoxel,
 24        [MaybeNullWhen(false)] out Voxel targetVoxel,
 25        Fixed64 unitSize,
 26        bool allowUnwalkableEndpoints = false,
 27        TraversalMedium medium = TraversalMedium.Gas)
 28    {
 21929        targetVoxel = null;
 21930        if (!GetStartVoxel(context, origin, target, out originVoxel, allowUnwalkableEndpoints, unitSize, medium))
 1331            return false;
 32
 20633        if (!GetEndVoxel(context, origin, target, out targetVoxel, allowUnwalkableEndpoints, unitSize, medium))
 1734            return false;
 35
 18936        return true;
 37    }
 38
 39    /// <summary>
 40    /// Attempts to determine the start voxel in one explicit context.
 41    /// </summary>
 42    public static bool GetStartVoxel(
 43        TrailblazerWorldContext context,
 44        Vector3d origin,
 45        Vector3d target,
 46        [MaybeNullWhen(false)] out Voxel originVoxel,
 47        bool allowUnwalkableEndpoints = false,
 48        Fixed64? unitSize = null,
 49        TraversalMedium medium = TraversalMedium.Gas)
 50    {
 23851        return TryGetEndpointVoxel(
 23852            context,
 23853            origin,
 23854            target,
 23855            out originVoxel,
 23856            allowUnwalkableEndpoints,
 23857            unitSize ?? context.VoxelSize,
 23858            medium);
 59    }
 60
 61    /// <summary>
 62    /// Attempts to determine the end voxel in one explicit context.
 63    /// </summary>
 64    public static bool GetEndVoxel(
 65        TrailblazerWorldContext context,
 66        Vector3d origin,
 67        Vector3d target,
 68        [MaybeNullWhen(false)] out Voxel targetVoxel,
 69        bool allowUnwalkableEndpoints = false,
 70        Fixed64? unitSize = null,
 71        TraversalMedium medium = TraversalMedium.Gas)
 72    {
 21173        return TryGetEndpointVoxel(
 21174            context,
 21175            target,
 21176            origin,
 21177            out targetVoxel,
 21178            allowUnwalkableEndpoints,
 21179            unitSize ?? context.VoxelSize,
 21180            medium);
 81    }
 82
 83    /// <summary>
 84    /// Determines whether a direct, traversable path exists in one explicit context.
 85    /// </summary>
 86    public static bool IsDirectPathClear(
 87        TrailblazerWorldContext context,
 88        Vector3d start,
 89        Vector3d end,
 90        Fixed64 unitSize,
 91        bool allowUnwalkableEndpoints,
 92        TraversalMedium medium = TraversalMedium.Gas,
 93        Voxel? startNode = null,
 94        Voxel? endNode = null)
 95    {
 2096        PathRequestContextResolver.ThrowIfUnusable(context);
 2097        PathingWorldState state = context.Pathing.State;
 2098        if (!VolumeMediumRules.IsConfigured(state, medium))
 199            return false;
 100
 19101        bool foundAny = false;
 102
 65103        foreach (GridVoxelSet gridVoxelSet in GridTracer.TraceLine(context.World, start, end))
 104        {
 125105            foreach (Voxel voxel in gridVoxelSet.Voxels)
 106            {
 49107                foundAny = true;
 108
 49109                bool isRelaxedEndpoint = allowUnwalkableEndpoints
 49110                    && ((startNode != null && voxel.WorldIndex == startNode.WorldIndex)
 49111                    || (endNode != null && voxel.WorldIndex == endNode.WorldIndex));
 49112                if (isRelaxedEndpoint)
 113                {
 4114                    if (!PassesMedium(state, voxel, medium))
 1115                        return false;
 116
 117                    continue;
 118                }
 119
 45120                if (!IsTraversable(state, voxel, unitSize, medium))
 10121                    return false;
 122            }
 123        }
 124
 8125        return foundAny;
 11126    }
 127
 128    /// <summary>
 129    /// Determines whether the specified voxel can be traversed in one explicit context.
 130    /// </summary>
 131    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 132    public static bool IsTraversable(
 133        TrailblazerWorldContext context,
 134        Voxel voxel,
 135        Fixed64 unitSize,
 136        TraversalMedium medium = TraversalMedium.Gas)
 137    {
 8361138        PathRequestContextResolver.ThrowIfUnusable(context);
 8361139        return IsTraversable(context.Pathing.State, voxel, unitSize, medium);
 140    }
 141
 142    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 143    internal static bool IsTraversable(
 144        PathingWorldState state,
 145        Voxel voxel,
 146        Fixed64 unitSize,
 147        TraversalMedium medium = TraversalMedium.Gas)
 148    {
 8628149        return IsBaseTraversable(voxel, unitSize)
 8628150            && PassesMedium(state, voxel, medium);
 151    }
 152
 153    /// <summary>
 154    /// Attempts to find the closest traversable neighboring voxel in one explicit context.
 155    /// </summary>
 156    public static bool TryGetClosestTraversableVoxel(
 157        TrailblazerWorldContext context,
 158        Voxel voxel,
 159        [MaybeNullWhen(false)] out Voxel closestNeighbor,
 160        Fixed64 unitSize,
 161        TraversalMedium medium = TraversalMedium.Gas)
 162    {
 2163        return EndpointVoxelResolver.TryGetClosestTraversableVoxel(
 2164            context,
 2165            voxel,
 2166            out closestNeighbor,
 2167            unitSize,
 2168            new VolumeEndpointPolicy(context, medium));
 169    }
 170
 171    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 172    private static bool IsBaseTraversable(Voxel voxel, Fixed64 unitSize)
 173    {
 8984174        if (voxel == null || voxel.IsBlocked)
 149175            return false;
 176
 8835177        if (voxel.TryGetPartition(out VolumeChartPartition? volumePartition)
 8835178            && volumePartition != null)
 3533179            return !volumePartition.IsImpassable(unitSize);
 180
 5302181        if (voxel.TryGetPartition(out SolidChartPartition? partition)
 5302182            && partition != null)
 671183            return !partition.IsImpassable(unitSize);
 184
 4631185        return false;
 186    }
 187
 188    private static bool TryGetEndpointVoxel(
 189        TrailblazerWorldContext context,
 190        Vector3d position,
 191        Vector3d traceToward,
 192        [MaybeNullWhen(false)] out Voxel voxel,
 193        bool allowUnwalkableEndpoints,
 194        Fixed64 unitSize,
 195        TraversalMedium medium)
 196    {
 449197        return EndpointVoxelResolver.TryGetEndpointVoxel(
 449198            context,
 449199            position,
 449200            traceToward,
 449201            out voxel,
 449202            allowUnwalkableEndpoints,
 449203            unitSize,
 449204            new VolumeEndpointPolicy(context, medium));
 205    }
 206
 207    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 208    private static bool PassesMedium(PathingWorldState state, Voxel voxel, TraversalMedium medium)
 209    {
 4289210        return VolumeMediumRules.Matches(state, voxel, medium);
 211    }
 212
 213    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 214    private static bool RequiresSizeFallback(
 215        PathingWorldState state,
 216        Voxel voxel,
 217        Fixed64 unitSize,
 218        Fixed64 voxelSize,
 219        TraversalMedium medium)
 220    {
 23221        if (unitSize == voxelSize
 23222            || voxel == null
 23223            || voxel.IsBlocked
 23224            || !PassesMedium(state, voxel, medium))
 225        {
 19226            return false;
 227        }
 228
 4229        if (voxel.TryGetPartition(out VolumeChartPartition? volumePartition)
 4230            && volumePartition != null)
 3231            return volumePartition.IsImpassable(unitSize);
 232
 1233        return voxel.TryGetPartition(out SolidChartPartition? partition)
 1234            && partition != null
 1235            && partition.IsImpassable(unitSize);
 236    }
 237
 238    internal static bool HasClearance(TrailblazerWorldContext context, Voxel origin, Fixed64 unitSize)
 239    {
 3536240        PathRequestContextResolver.ThrowIfUnusable(context);
 3536241        Fixed64 voxelSize = context.VoxelSize;
 3536242        if (unitSize <= voxelSize)
 3519243            return true;
 244
 17245        int requiredRadius = (unitSize / voxelSize).CeilToInt() - 1;
 17246        if (requiredRadius <= 0)
 0247            return true;
 248
 17249        if (!context.World.TryGetGrid(origin.GridIndex, out VoxelGrid? grid))
 0250            return false;
 251
 82252        for (int x = -requiredRadius; x <= requiredRadius; x++)
 253        {
 210254            for (int y = -requiredRadius; y <= requiredRadius; y++)
 255            {
 594256                for (int z = -requiredRadius; z <= requiredRadius; z++)
 257                {
 225258                    if (x == 0 && y == 0 && z == 0)
 259                        continue;
 260
 217261                    if (!origin.TryGetNeighborFromOffset(grid!, (x, y, z), out Voxel? neighbor)
 217262                        || neighbor!.IsBlocked)
 263                    {
 9264                        return false;
 265                    }
 266                }
 267            }
 268        }
 269
 8270        return true;
 271    }
 272
 273    private readonly struct VolumeEndpointPolicy : IVoxelEndpointResolutionPolicy
 274    {
 275        private readonly PathingWorldState _state;
 276        private readonly Fixed64 _voxelSize;
 277        private readonly TraversalMedium _medium;
 278
 279        public VolumeEndpointPolicy(TrailblazerWorldContext context, TraversalMedium medium)
 280        {
 451281            _state = context.Pathing.State;
 451282            _voxelSize = context.VoxelSize;
 451283            _medium = medium;
 451284        }
 285
 286        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 287        public bool CanResolve()
 288        {
 449289            return VolumeMediumRules.IsConfigured(_state, _medium);
 290        }
 291
 292        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 293        public bool TryAcceptDirectVoxel(
 294            Voxel voxel,
 295            Fixed64 unitSize,
 296            bool allowUnwalkableEndpoints)
 297        {
 438298            return PassesMedium(_state, voxel, _medium)
 438299                && (allowUnwalkableEndpoints || IsBaseTraversable(voxel, unitSize));
 300        }
 301
 302        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 303        public bool RequiresSizeFallback(Voxel voxel, Fixed64 unitSize)
 304        {
 23305            return VolumeVoxelFinder.RequiresSizeFallback(_state, voxel, unitSize, _voxelSize, _medium);
 306        }
 307
 308        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 309        public bool IsTraversable(Voxel voxel, Fixed64 unitSize)
 310        {
 222311            return VolumeVoxelFinder.IsTraversable(_state, voxel, unitSize, _medium);
 312        }
 313
 314        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 315        public bool TryGetFinalFallbackVoxel(
 316            Vector3d position,
 317            Voxel directVoxel,
 318            Fixed64 unitSize,
 319            [MaybeNullWhen(false)] out Voxel voxel)
 320        {
 3321            voxel = null;
 3322            return false;
 323        }
 324    }
 325}

Methods/Properties

TryGetPathEdgeVoxels(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,GridForge.Grids.Voxel&,GridForge.Grids.Voxel&,FixedMathSharp.Fixed64,System.Boolean,Trailblazer.TraversalMedium)
GetStartVoxel(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,GridForge.Grids.Voxel&,System.Boolean,System.Nullable`1<FixedMathSharp.Fixed64>,Trailblazer.TraversalMedium)
GetEndVoxel(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,GridForge.Grids.Voxel&,System.Boolean,System.Nullable`1<FixedMathSharp.Fixed64>,Trailblazer.TraversalMedium)
IsDirectPathClear(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Boolean,Trailblazer.TraversalMedium,GridForge.Grids.Voxel,GridForge.Grids.Voxel)
IsTraversable(Trailblazer.TrailblazerWorldContext,GridForge.Grids.Voxel,FixedMathSharp.Fixed64,Trailblazer.TraversalMedium)
IsTraversable(Trailblazer.Pathing.PathingWorldState,GridForge.Grids.Voxel,FixedMathSharp.Fixed64,Trailblazer.TraversalMedium)
TryGetClosestTraversableVoxel(Trailblazer.TrailblazerWorldContext,GridForge.Grids.Voxel,GridForge.Grids.Voxel&,FixedMathSharp.Fixed64,Trailblazer.TraversalMedium)
IsBaseTraversable(GridForge.Grids.Voxel,FixedMathSharp.Fixed64)
TryGetEndpointVoxel(Trailblazer.TrailblazerWorldContext,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,GridForge.Grids.Voxel&,System.Boolean,FixedMathSharp.Fixed64,Trailblazer.TraversalMedium)
PassesMedium(Trailblazer.Pathing.PathingWorldState,GridForge.Grids.Voxel,Trailblazer.TraversalMedium)
RequiresSizeFallback(Trailblazer.Pathing.PathingWorldState,GridForge.Grids.Voxel,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Trailblazer.TraversalMedium)
HasClearance(Trailblazer.TrailblazerWorldContext,GridForge.Grids.Voxel,FixedMathSharp.Fixed64)
.ctor(Trailblazer.TrailblazerWorldContext,Trailblazer.TraversalMedium)
CanResolve()
TryAcceptDirectVoxel(GridForge.Grids.Voxel,FixedMathSharp.Fixed64,System.Boolean)
RequiresSizeFallback(GridForge.Grids.Voxel,FixedMathSharp.Fixed64)
IsTraversable(GridForge.Grids.Voxel,FixedMathSharp.Fixed64)
TryGetFinalFallbackVoxel(FixedMathSharp.Vector3d,GridForge.Grids.Voxel,FixedMathSharp.Fixed64,GridForge.Grids.Voxel&)