< Summary

Information
Class: Trailblazer.Pathing.TrailblazerPathingService
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/TrailblazerPathingService.cs
Line coverage
100%
Covered lines: 107
Uncovered lines: 0
Coverable lines: 107
Total lines: 239
Line coverage: 100%
Branch coverage
100%
Covered branches: 10
Total branches: 10
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/TrailblazerPathingService.cs

#LineLine coverage
 1//=======================================================================
 2// TrailblazerPathingService.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 System;
 9using GridForge.Grids;
 10using GridForge.Spatial;
 11
 12namespace Trailblazer.Pathing;
 13
 14/// <summary>
 15/// Context-owned admission, query, maintenance, and diagnostic API for unified navigation maps.
 16/// </summary>
 17public sealed class TrailblazerPathingService
 18{
 19    private readonly TrailblazerWorldContext _context;
 20
 21    private bool _disposed;
 22
 23    private readonly NavigationGraphRuntime _navigationGraph;
 24    private readonly NavigationImmediateRayWorkspace _immediateRayWorkspace;
 25    private readonly NavigationAStarAdmissionGate _navigationAStarAdmissionGate;
 26    private readonly NavigationFlowAdmissionGate _navigationFlowAdmissionGate;
 27
 98928    internal TrailblazerPathingService(TrailblazerWorldContext context)
 29    {
 98930        _context = context;
 98931        _navigationGraph = new NavigationGraphRuntime(context.World, context.Settings);
 98932        NavigationQueryLimits queryLimits = context.Settings.QueryLimits;
 98933        _immediateRayWorkspace = new NavigationImmediateRayWorkspace(
 98934            Math.Max(
 98935                queryLimits.AStarWorkspaceMapCapacity,
 98936                queryLimits.FlowWorkspaceMapCapacity),
 98937            Math.Max(
 98938                queryLimits.AStarWorkspaceEndpointPageCapacity,
 98939                queryLimits.FlowWorkspaceEndpointPageCapacity),
 98940            Math.Max(
 98941                queryLimits.AStarWorkspaceComponentCapacity,
 98942                queryLimits.FlowWorkspaceComponentCapacity),
 98943            queryLimits.RayWorkspaceCoveredAddressCapacity,
 98944            queryLimits.RayWorkspaceTraceIntervalCapacity);
 98945        var admissionCoordinator = new NavigationQueryAdmissionCoordinator(
 98946            queryLimits.MaxConcurrentNavigationQueries);
 98947        _navigationAStarAdmissionGate = new NavigationAStarAdmissionGate(
 98948            context.World,
 98949            _navigationGraph.Store,
 98950            context.Settings.QueryLimits,
 98951            admissionCoordinator);
 98952        _navigationFlowAdmissionGate = new NavigationFlowAdmissionGate(
 98953            context.World,
 98954            _navigationGraph.Store,
 98955            context.Settings.QueryLimits,
 98956            admissionCoordinator,
 98957            _immediateRayWorkspace);
 98958        context.World.OnChangeCommitted += HandleCommittedChange;
 98959    }
 60
 61    internal int RetainedBaselineCaptureCount =>
 2162        _navigationGraph.RetainedBaselineCaptureCount;
 63
 64    internal NavigationWorldGraphStore NavigationGraphStore =>
 103465        _navigationGraph.Store;
 66
 67    internal NavigationAStarAdmissionGate NavigationAStarAdmissionGate =>
 40468        _navigationAStarAdmissionGate;
 69
 70    internal NavigationFlowAdmissionGate NavigationFlowAdmissionGate =>
 6971        _navigationFlowAdmissionGate;
 72
 73    internal NavigationImmediateRayWorkspace ImmediateRayWorkspace =>
 57774        _immediateRayWorkspace;
 75
 76    internal int RetainedCompositionWorkCount =>
 34177        _navigationGraph.RetainedCompositionWorkCount;
 78
 79    internal int RetainedOperationWorkCount =>
 4480        _navigationGraph.RetainedOperationWorkCount;
 81
 82    internal MaintenanceWorkMeter NavigationMaintenanceMeter =>
 32183        _navigationGraph.MaintenanceMeter;
 84
 85    internal int LastAffectedMapCollectionCount =>
 186        _navigationGraph.LastAffectedMapCollectionCount;
 87
 88    /// <summary>Admits one prepared map commit for deterministic fixed-step publication.</summary>
 89    public bool Admit(NavigationMapCommitOperation operation)
 90    {
 93191        EnsureUsable();
 93192        return _navigationGraph.Admit(operation);
 93    }
 94
 95    /// <summary>Admits one map removal for deterministic fixed-step publication.</summary>
 96    public bool Admit(NavigationMapRemoveOperation operation)
 97    {
 998        EnsureUsable();
 999        return _navigationGraph.Admit(operation);
 100    }
 101
 102    /// <summary>Admits one atomic semantic overlay transaction for deterministic fixed-step publication.</summary>
 103    public bool Admit(NavigationOverlayCommitOperation operation)
 104    {
 191105        EnsureUsable();
 191106        return _navigationGraph.Admit(operation);
 107    }
 108
 109    /// <summary>Admits one immutable navigation-area policy revision for fixed-step publication.</summary>
 110    public bool Admit(NavigationAreaPolicyCommitOperation operation)
 111    {
 172112        EnsureUsable();
 172113        return _navigationGraph.Admit(operation);
 114    }
 115
 116    internal void MaintainNavigationGraph(int frame)
 117    {
 12185118        EnsureUsable();
 12185119        _navigationGraph.Maintain(frame);
 12185120    }
 121
 122    internal NavigationWorldGraphLease? TryAcquireNavigationGraph() =>
 888123        _navigationGraph.TryAcquire();
 124
 125    internal bool TryGetNavigationGraphCellState(
 126        string mapId,
 127        VoxelIndex index,
 128        out NavigationGraphCellState state)
 129    {
 378130        EnsureUsable();
 378131        return _navigationGraph.TryGetCellState(mapId, index, out state);
 132    }
 133
 134    internal NavigationCommittedCellResolveStatus TryResolveCommittedCell(
 135        GridForge.Configuration.GridConfigurationKey gridKey,
 136        WorldVoxelIndex worldIndex,
 137        out NavigationCellAddress address,
 138        out NavigationAreaId area,
 139        out long graphVersion)
 140    {
 64141        EnsureUsable();
 64142        NavigationWorldGraph graph = _navigationGraph.Current;
 64143        graphVersion = graph.GraphVersion;
 64144        if (!graph.TryGetMapId(gridKey, out string mapId))
 145        {
 25146            address = default;
 25147            area = default;
 25148            return NavigationCommittedCellResolveStatus.NoCell;
 149        }
 39150        graph.TryGetMap(mapId, out NavigationMapInstance? instance);
 151        System.Diagnostics.Debug.Assert(instance != null);
 39152        if (!instance.GridIdentity.Matches(
 39153                worldIndex.WorldSpawnToken,
 39154                worldIndex.GridIndex,
 39155                worldIndex.GridSpawnToken))
 156        {
 3157            address = default;
 3158            area = default;
 3159            return NavigationCommittedCellResolveStatus.Unavailable;
 160        }
 161        NavigationCell cell;
 36162        if (!instance.TryGetSlot(worldIndex.VoxelIndex, out int slot))
 163        {
 1164            address = default;
 1165            area = default;
 1166            return NavigationCommittedCellResolveStatus.NoCell;
 167        }
 35168        bool foundPhysicalState = instance.TryGetPhysicalState(slot, out bool isPresent, out _);
 169        System.Diagnostics.Debug.Assert(foundPhysicalState);
 35170        if (!isPresent
 35171            || !instance.TryGetEffectiveCell(slot, out cell))
 172        {
 2173            address = default;
 2174            area = default;
 2175            return NavigationCommittedCellResolveStatus.NoCell;
 176        }
 177
 33178        address = new NavigationCellAddress(mapId, worldIndex.VoxelIndex);
 33179        area = cell.Area;
 33180        return NavigationCommittedCellResolveStatus.Resolved;
 181    }
 182
 183    internal bool TryResolveNavigationAreaPolicy(
 184        NavigationAreaPolicyKey key,
 185        out NavigationAreaPolicy? policy)
 186    {
 7187        EnsureUsable();
 7188        return _navigationGraph.TryResolveAreaPolicy(key, out policy);
 189    }
 190
 191    /// <summary>Copies a bounded immutable diagnostic view of the context navigation graph.</summary>
 192    public NavigationGraphDiagnosticsSnapshot GetNavigationGraphDiagnostics()
 193    {
 1641194        EnsureUsable();
 1640195        return _navigationGraph.GetDiagnostics(
 1640196            _context.Settings.MaintenanceBudget.MaxBaselineAddresses);
 197    }
 198
 199    /// <summary>
 200    /// Cancels active graph queries and clears this context's unified navigation graph.
 201    /// </summary>
 202    public void Reset()
 203    {
 23204        EnsureUsable();
 23205        _navigationAStarAdmissionGate.CancelActive();
 23206        _navigationFlowAdmissionGate.CancelActive();
 23207        _navigationGraph.Reset();
 23208    }
 209
 210    internal void Dispose()
 211    {
 988212        _context.World.OnChangeCommitted -= HandleCommittedChange;
 988213        _navigationAStarAdmissionGate.Dispose();
 988214        _navigationFlowAdmissionGate.Dispose();
 988215        _navigationGraph.Dispose();
 988216        _disposed = true;
 988217    }
 218
 219    private void HandleCommittedChange(GridEventInfo eventInfo) =>
 1186220        _navigationGraph.EnqueueCommittedChange(eventInfo);
 221
 222    private void EnsureUsable()
 223    {
 15601224        SwiftThrowHelper.ThrowIfDisposed(
 15601225            _disposed,
 15601226            nameof(TrailblazerWorldContext));
 15601227        SwiftThrowHelper.ThrowIfTrue(
 15601228            !_context.World.IsActive,
 15601229            nameof(TrailblazerPathingService),
 15601230            "TrailblazerPathingService is bound to an inactive GridWorld.");
 15600231    }
 232}
 233
 234internal enum NavigationCommittedCellResolveStatus : byte
 235{
 236    NoCell,
 237    Resolved,
 238    Unavailable
 239}