< Summary

Information
Class: Trailblazer.Pathing.NavigationStructuralCompositionWork
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Graph/NavigationStructuralCompositionWork.cs
Line coverage
100%
Covered lines: 557
Uncovered lines: 0
Coverable lines: 557
Total lines: 868
Line coverage: 100%
Branch coverage
100%
Covered branches: 300
Total branches: 300
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/Graph/NavigationStructuralCompositionWork.cs

#LineLine coverage
 1//=======================================================================
 2// NavigationStructuralCompositionWork.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/// Retains the pre-change structural root and a canonical cursor while explicit dependency and
 16/// affected-component work is debited across fixed-step maintenance boundaries.
 17/// </summary>
 18internal sealed class NavigationStructuralCompositionWork
 19{
 20    private const long BaseRetainedBytes = 112L;
 21
 22    private readonly GridWorld _world;
 23    private readonly int _batchChangeCount;
 24    private readonly NavigationWorldGraph _sourceGraph;
 25    private readonly NavigationOperationCandidate _candidate;
 26    private readonly NavigationOperationFrameChange[] _changes;
 112127    private PersistentStringMap<bool> _changedMapIds = PersistentStringMap<bool>.Empty;
 112128    private NavigationSurfaceComponentKeySet _affectedComponents =
 112129        NavigationSurfaceComponentKeySet.Empty;
 112130    private NavigationSurfaceComponentKeySet _publishedAffectedComponents =
 112131        NavigationSurfaceComponentKeySet.Empty;
 112132    private NavigationCellAddressSet _affectedAddresses = NavigationCellAddressSet.Empty;
 112133    private NavigationSurfaceComponentKeySet _affectedMediumStates =
 112134        NavigationSurfaceComponentKeySet.Empty;
 35    private int _affectedMemberCount;
 112136    private PersistentStringMap<bool> _wholeMapIds = PersistentStringMap<bool>.Empty;
 37    private NavigationWorldGraph.StructuralPreparationWork? _preparation;
 38    private NavigationAutomaticSeamRefreshWork? _seamRefresh;
 39    private NavigationWorldGraph? _preparedGraph;
 40    private NavigationMaterializedComponentWork? _componentUpdate;
 41    private string? _pendingMapId;
 42    private NavigationSurfaceComponentKey? _pendingComponentKey;
 112143    private TraversalMedium _pendingMedium = TraversalMedium.Solid;
 44    private NavigationCellAddress? _pendingExactAddress;
 45    private int _pendingMapComponentOrdinal;
 46    private int _explicitSourceIndex;
 47    private int _changeIndex;
 48    private int _overlayIndex;
 49    private int _overlayCellIndex;
 50    private int _capturePhase;
 51    private int _seamSourceIndex;
 52    private int _seamCapturePhase;
 53    private string? _pendingSeamMapId;
 54    private bool _seamCaptureComplete;
 55    private bool _exactCaptureComplete;
 56    private bool _pendingWholeMap;
 57    private int _explicitOwnerIndex;
 58    private int _explicitEndpointStage;
 59    private int _seamEndpointIndex;
 60    private int _preparedMapOrdinal;
 61    private int _preparedMapAddressOrdinal;
 62    private int _addressBakedCursor;
 63    private int _addressDynamicCursor;
 112164    private readonly VoxelIndex[] _addressScratch = new VoxelIndex[1];
 65    private int _incidentAddressIndex;
 112166    private TraversalMedium _incidentMedium = TraversalMedium.Gas;
 67    private bool _incidentNodeActive;
 68    private bool _incidentOutgoingComplete;
 69    private NavigationSurfaceEdgeEnumerator _incidentOutgoing;
 70    private NavigationIncomingSurfaceEdgeEnumerator _incidentIncoming;
 71    private NavigationCellAddress? _pendingIncidentAddress;
 72    private bool _allClosePublished;
 73    private bool _affectedClosurePublished;
 74    private bool _allCloseRepublishRequired;
 75
 112176    internal NavigationStructuralCompositionWork(
 112177        GridWorld world,
 112178        NavigationWorldGraph sourceGraph,
 112179        NavigationOperationCandidate candidate,
 112180        NavigationOperationFrameChange[] changes,
 112181        int changeCount)
 82    {
 112183        _world = world;
 112184        _sourceGraph = sourceGraph;
 112185        _candidate = candidate;
 112186        _changes = changes;
 112187        _batchChangeCount = changeCount;
 112188    }
 89
 490    internal int CapturedChangedMapCount => _changedMapIds.Count;
 91
 1262692    internal bool IsChangedMapCaptureComplete => _capturePhase == 4
 1262693        && _seamCaptureComplete
 1262694        && _exactCaptureComplete;
 95
 52196    internal NavigationSurfaceComponentKeySet AffectedComponents => _affectedComponents;
 97
 1325098    internal bool RequiresAffectedClosurePublication => _allClosePublished
 1325099        && IsChangedMapCaptureComplete
 13250100        && !_affectedClosurePublished;
 101
 13076102    internal bool RequiresAllClosePublication => _allCloseRepublishRequired;
 103
 104    internal string GetCapturedChangedMapIdAt(int ordinal) =>
 4105        _changedMapIds.GetKeyAt(ordinal);
 106
 293860107    internal NavigationWorldGraph PreparedGraph => _preparedGraph!;
 108
 270469109    internal long RetainedBytes => checked(
 270469110        BaseRetainedBytes
 270469111        + _changedMapIds.RetainedBytes
 270469112        + _wholeMapIds.RetainedBytes
 270469113        + (_componentUpdate == null ? _affectedAddresses.RetainedBytes : 0L)
 270469114        + (_componentUpdate == null ? _affectedMediumStates.RetainedBytes : 0L)
 270469115        + (_componentUpdate == null
 270469116            && !ReferenceEquals(_publishedAffectedComponents, _affectedComponents)
 270469117                ? _affectedComponents.RetainedBytes
 270469118                : 0L)
 270469119        + (_preparation?.RetainedBytes ?? 0)
 270469120        + (_seamRefresh?.RetainedBytes ?? 0)
 270469121        + (_componentUpdate?.RetainedBytes ?? 0)
 270469122        );
 123
 270819124    internal int PersistentPageCount => checked(
 270819125        1
 270819126        + _changedMapIds.PersistentNodeCount
 270819127        + _wholeMapIds.PersistentNodeCount
 270819128        + (_componentUpdate == null ? _affectedAddresses.PersistentPageCount : 0)
 270819129        + (_componentUpdate == null ? _affectedMediumStates.PersistentPageCount : 0)
 270819130        + (_componentUpdate == null
 270819131            && !ReferenceEquals(_publishedAffectedComponents, _affectedComponents)
 270819132                ? _affectedComponents.PersistentPageCount
 270819133                : 0)
 270819134        + (_preparation?.PersistentPageCount ?? 0)
 270819135        + (_seamRefresh?.PersistentPageCount ?? 0)
 270819136        + (_componentUpdate?.PersistentPageCount ?? 0));
 137
 17138    internal bool IsComplete => IsLifecycleComplete(
 17139        IsChangedMapCaptureComplete,
 17140        _preparation?.IsComplete,
 17141        _seamRefresh?.IsComplete,
 17142        _affectedComponents.Count,
 17143        _affectedAddresses.Count,
 17144        _componentUpdate?.IsComplete);
 145
 146    internal static bool IsLifecycleComplete(
 147        bool captureComplete,
 148        bool? preparationComplete,
 149        bool? seamRefreshComplete,
 150        int affectedComponentCount,
 151        int affectedAddressCount,
 26152        bool? componentUpdateComplete) => captureComplete
 26153        && preparationComplete == true
 26154        && seamRefreshComplete == true
 26155        && (affectedComponentCount == 0 && affectedAddressCount == 0
 26156            || componentUpdateComplete == true);
 157
 1082158    internal NavigationWorldGraph Result => _componentUpdate?.Result
 1082159        ?? PreparedGraph.WithSurfaceComponents(_sourceGraph.SurfaceComponents);
 160
 161    internal bool Advance(MaintenanceWorkMeter meter)
 162    {
 37163        return Advance(
 37164            meter,
 37165            long.MaxValue,
 37166            int.MaxValue,
 37167            out _);
 168    }
 169
 170    internal bool Advance(
 171        MaintenanceWorkMeter meter,
 172        long maximumRetainedBytes,
 173        int maximumPersistentPages,
 174        out bool capacityExceeded)
 175    {
 11838176        capacityExceeded = false;
 11838177        if (_capturePhase != 4 && !AdvanceChangedMapCapture(meter))
 1612178            return false;
 10226179        _preparation ??= new NavigationWorldGraph.StructuralPreparationWork(
 10226180            _sourceGraph,
 10226181            _candidate,
 10226182            _changes,
 10226183            _batchChangeCount,
 10226184            _changedMapIds,
 10226185            _sourceGraph.GraphVersion + 1);
 186        // Topology-native edges, seams, cache invalidations, explicit edges, reverse dependencies,
 187        // and weak components all consume the same maintenance meter.
 10226188        if (!_preparation.IsComplete && !_preparation.Advance(meter))
 1443189            return false;
 8783190        _seamRefresh ??= new NavigationAutomaticSeamRefreshWork(
 8783191            _world,
 8783192            _sourceGraph,
 8783193            _preparation.Result,
 8783194            _changes,
 8783195            _batchChangeCount);
 8783196        if (ExceedsCapacity(maximumRetainedBytes, maximumPersistentPages))
 197        {
 2198            capacityExceeded = true;
 2199            return false;
 200        }
 236271201        while (!_seamRefresh.IsComplete)
 202        {
 232101203            long seamRevision = _seamRefresh.Revision;
 232101204            NavigationAutomaticSeamRefreshWork.SeamAdvanceStatus seamStatus =
 232101205                _seamRefresh.AdvanceOne(meter);
 232101206            if (_seamRefresh.Revision != seamRevision)
 207            {
 1208                ResetSeamState();
 1209                return false;
 210            }
 232100211            if (ExceedsCapacity(maximumRetainedBytes, maximumPersistentPages))
 212            {
 3213                capacityExceeded = true;
 3214                return false;
 215            }
 232097216            if (seamStatus == NavigationAutomaticSeamRefreshWork.SeamAdvanceStatus.Blocked)
 4607217                return false;
 218        }
 4170219        if (!_seamCaptureComplete && !AdvanceSeamChangedMapCapture(meter))
 52220            return false;
 4118221        _preparedGraph ??= _preparation.Result.WithAutomaticSeams(_seamRefresh.Result);
 4118222        if (!_exactCaptureComplete && !AdvanceExactAffectedCapture(meter))
 1728223            return false;
 2390224        if (RequiresAffectedClosurePublication || RequiresAllClosePublication)
 168225            return false;
 2222226        if (_affectedComponents.Count == 0 && _affectedAddresses.Count == 0)
 89227            return true;
 2133228        _componentUpdate ??= new NavigationMaterializedComponentWork(
 2133229            PreparedGraph,
 2133230            _affectedMediumStates,
 2133231            _affectedComponents,
 2133232            _affectedAddresses,
 2133233            checked(_affectedMemberCount + _affectedAddresses.Count),
 2133234            world: null,
 2133235            baselineCaptures: null,
 2133236            affectedMapOrdinals: null,
 2133237            affectedMapCount: 0,
 2133238            events: null,
 2133239            eventCount: 0);
 2133240        bool complete = _componentUpdate.Advance(meter);
 2133241        if (ExceedsCapacity(maximumRetainedBytes, maximumPersistentPages))
 242        {
 171243            capacityExceeded = true;
 171244            return false;
 245        }
 1962246        return complete;
 247    }
 248
 249    private bool ExceedsCapacity(long maximumRetainedBytes, int maximumPersistentPages) =>
 243016250        RetainedBytes > maximumRetainedBytes
 243016251        || PersistentPageCount > maximumPersistentPages;
 252
 253    internal void MarkAffectedClosurePublished()
 254    {
 177255        _publishedAffectedComponents = _affectedComponents;
 177256        _affectedClosurePublished = true;
 177257    }
 258
 259    internal void RecordAffectedClosurePublication(
 260        NavigationCandidatePublication publication)
 261    {
 170262        if (publication == NavigationCandidatePublication.Published)
 167263            MarkAffectedClosurePublished();
 170264    }
 265
 266    internal void MarkAllClosePublished()
 267    {
 167268        _allClosePublished = true;
 167269        _allCloseRepublishRequired = false;
 167270    }
 271
 272    internal void MarkInitialClosurePublished()
 273    {
 177274        if (IsChangedMapCaptureComplete)
 10275            MarkAffectedClosurePublished();
 276        else
 167277            MarkAllClosePublished();
 167278    }
 279
 280    internal void MarkAllCloseRepublished()
 281    {
 2282        _allClosePublished = true;
 2283        _allCloseRepublishRequired = false;
 2284        _affectedClosurePublished = false;
 2285        _publishedAffectedComponents = NavigationSurfaceComponentKeySet.Empty;
 2286    }
 287
 288    internal void RecordAllClosePublication(
 289        NavigationCandidatePublication publication)
 290    {
 4291        if (publication == NavigationCandidatePublication.Published)
 2292            MarkAllCloseRepublished();
 4293    }
 294
 295    internal bool RevalidateAutomaticSeamsForPublication()
 296    {
 485297        if (_seamRefresh == null || !_seamCaptureComplete)
 1298            return true;
 484299        long revision = _seamRefresh.Revision;
 484300        if (_seamRefresh.RevalidateForPublication())
 481301            return true;
 302        System.Diagnostics.Debug.Assert(_seamRefresh.Revision != revision,
 303            "Failed seam revalidation resets the refresh and advances its revision.");
 3304        ResetSeamState();
 3305        return false;
 306    }
 307
 308    private bool AdvanceChangedMapCapture(MaintenanceWorkMeter meter)
 309    {
 17868310        while (true)
 311        {
 20602312            if (_capturePhase == 0)
 313            {
 19253314                if (!HasNextRawMapId())
 315                {
 938316                    _capturePhase = 4;
 938317                    return true;
 318                }
 18315319                if (!meter.TryConsumeComponentNodes(1))
 262320                    return false;
 18053321                if (!TryTakeNextRawScope(
 18053322                        out _pendingMapId,
 18053323                        out _pendingExactAddress,
 18053324                        out _pendingWholeMap))
 325                {
 184326                    _capturePhase = 4;
 184327                    return true;
 328                }
 17869329                _pendingComponentKey = null;
 17869330                _pendingMedium = _pendingWholeMap
 17869331                    ? (TraversalMedium)((int)TraversalMedium.Liquid + 1)
 17869332                    : TraversalMedium.Solid;
 17869333                _pendingMapComponentOrdinal = 0;
 17869334                _addressBakedCursor = 0;
 17869335                _addressDynamicCursor = 0;
 17869336                _capturePhase = 1;
 337            }
 19218338            if (_capturePhase == 1)
 339            {
 17870340                if (!_changedMapIds.ContainsKey(_pendingMapId!))
 341                {
 1364342                    if (!meter.TryConsumeDependencyEntries(1))
 1343                        return false;
 1363344                    _changedMapIds = _changedMapIds.Set(_pendingMapId!, true);
 345                }
 17869346                _capturePhase = 2;
 347            }
 19217348            if (_capturePhase == 2)
 349            {
 68906350                while (_pendingExactAddress.HasValue
 68906351                    && _pendingMedium <= TraversalMedium.Liquid)
 352                {
 49690353                    TraversalMedium medium = _pendingMedium++;
 49690354                    if (!HasMediumStateChanged(_pendingExactAddress.Value, medium)
 49690355                        || !_sourceGraph.TryGetSurfaceComponent(
 49690356                            _pendingExactAddress.Value,
 49690357                            medium,
 49690358                            out NavigationSurfaceComponentKey componentKey,
 49690359                            out _)
 49690360                        || _affectedComponents.Contains(componentKey))
 361                    {
 362                        continue;
 363                    }
 93364                    if (!meter.TryConsumeDependencyEntries(1))
 365                    {
 1366                        _pendingMedium--;
 1367                        return false;
 368                    }
 92369                    AddAffectedComponent(componentKey);
 370                }
 19216371                if (_pendingExactAddress.HasValue)
 372                {
 16564373                    if (!_affectedAddresses.Contains(_pendingExactAddress.Value))
 374                    {
 16563375                        if (!meter.TryConsumeDependencyEntries(1))
 2376                            return false;
 16561377                        _affectedAddresses = _affectedAddresses.Add(
 16561378                            _pendingExactAddress.Value);
 379                    }
 380                }
 2652381                else if (_pendingWholeMap)
 382                {
 2489383                    if (_sourceGraph.TryGetMap(
 2489384                            _pendingMapId!,
 2489385                            out NavigationMapInstance? sourceInstance))
 386                    {
 1396387                        NavigationMapInstance instance = sourceInstance!;
 7908388                        while (_pendingComponentKey.HasValue
 7908389                            || _pendingMedium <= TraversalMedium.Liquid
 7908390                            || _pendingMapComponentOrdinal < instance.AddressCount)
 391                        {
 7857392                            if (_pendingComponentKey.HasValue)
 393                            {
 145394                                NavigationSurfaceComponentKey pendingKey =
 145395                                    _pendingComponentKey.Value;
 145396                                if (!_affectedComponents.Contains(pendingKey))
 397                                {
 14398                                    if (!meter.TryConsumeDependencyEntries(1))
 1399                                        return false;
 13400                                    AddAffectedComponent(pendingKey);
 401                                }
 144402                                _pendingComponentKey = null;
 144403                                continue;
 404                            }
 7712405                            if (_pendingMedium <= TraversalMedium.Liquid)
 406                            {
 4776407                                TraversalMedium medium = _pendingMedium++;
 4776408                                var currentAddress = new NavigationCellAddress(
 4776409                                    _pendingMapId!,
 4776410                                    _addressScratch[0]);
 4776411                                if (HasMediumStateChanged(currentAddress, medium)
 4776412                                    && _sourceGraph.TryGetSurfaceComponent(
 4776413                                        currentAddress,
 4776414                                        medium,
 4776415                                        out NavigationSurfaceComponentKey membershipKey,
 4776416                                        out _))
 417                                {
 144418                                    _pendingComponentKey = membershipKey;
 419                                }
 144420                                continue;
 421                            }
 2936422                            if (!meter.TryConsumeComponentNodes(1))
 1344423                                return false;
 1592424                            instance.CopyCanonicalAddressChunk(
 1592425                                ref _addressBakedCursor,
 1592426                                ref _addressDynamicCursor,
 1592427                                _addressScratch);
 1592428                            _pendingMapComponentOrdinal++;
 1592429                            _pendingMedium = TraversalMedium.Solid;
 430                        }
 431                    }
 1144432                    if (!_wholeMapIds.ContainsKey(_pendingMapId!))
 433                    {
 1141434                        if (!meter.TryConsumeDependencyEntries(1))
 1435                            return false;
 1140436                        _wholeMapIds = _wholeMapIds.Set(_pendingMapId!, true);
 437                    }
 438                }
 17868439                _pendingMapId = null;
 17868440                _pendingComponentKey = null;
 17868441                _pendingMedium = TraversalMedium.Solid;
 17868442                _pendingExactAddress = null;
 17868443                _pendingMapComponentOrdinal = 0;
 17868444                _addressBakedCursor = 0;
 17868445                _addressDynamicCursor = 0;
 17868446                _pendingWholeMap = false;
 17868447                _capturePhase = 0;
 448            }
 449        }
 450    }
 451
 452    private bool AdvanceSeamChangedMapCapture(MaintenanceWorkMeter meter)
 453    {
 1524454        while (_seamSourceIndex < _seamRefresh!.ChangedMapCount || _seamCapturePhase != 0)
 455        {
 404456            if (_seamCapturePhase == 0)
 457            {
 401458                if (!meter.TryConsumeComponentNodes(1))
 49459                    return false;
 352460                _pendingSeamMapId = _seamRefresh.GetChangedMapIdAt(_seamSourceIndex++);
 352461                _seamCapturePhase = 1;
 462            }
 463            System.Diagnostics.Debug.Assert(_seamCapturePhase == 1,
 464                "a metered seam-map read always advances directly into its ownership phase");
 355465            if (!_changedMapIds.ContainsKey(_pendingSeamMapId!))
 466            {
 35467                if (!meter.TryConsumeDependencyEntries(1))
 3468                    return false;
 32469                _changedMapIds = _changedMapIds.Set(_pendingSeamMapId!, true);
 470            }
 352471            _pendingSeamMapId = null;
 352472            _seamCapturePhase = 0;
 473        }
 1120474        _seamCaptureComplete = true;
 1120475        return true;
 476    }
 477
 478    private bool AdvanceExactAffectedCapture(MaintenanceWorkMeter meter)
 479    {
 19991480        while (_explicitOwnerIndex < _candidate.ExplicitChangedOwnerCount)
 481        {
 17160482            NavigationConnectionOwnerKey owner =
 17160483                _candidate.GetExplicitChangedOwnerAt(_explicitOwnerIndex);
 17160484            _sourceGraph.ExplicitConnections.TryGet(
 17160485                owner,
 17160486                out NavigationExplicitConnectionRecord prior);
 17160487            _candidate.ExplicitConnections.TryGet(
 17160488                owner,
 17160489                out NavigationExplicitConnectionRecord next);
 17160490            NavigationExplicitConnectionRecord? record = _explicitEndpointStage < 2
 17160491                ? prior
 17160492                : next;
 17160493            if (record != null && record.IsActive)
 494            {
 8600495                if (!meter.TryConsumeDependencyEntries(1))
 16496                    return false;
 8584497                CaptureAffectedAddress(
 8584498                    (_explicitEndpointStage & 1) == 0
 8584499                        ? record.Source
 8584500                        : record.Destination,
 8584501                    includeVolume: false);
 502            }
 17144503            _explicitEndpointStage++;
 17144504            if (_explicitEndpointStage == 4)
 505            {
 4286506                _explicitEndpointStage = 0;
 4286507                _explicitOwnerIndex++;
 508            }
 509        }
 510
 3215511        while (_seamEndpointIndex < _seamRefresh!.ChangedStructuralEndpointCount)
 512        {
 403513            if (!meter.TryConsumeDependencyEntries(1))
 19514                return false;
 384515            CaptureAffectedAddress(
 384516                _seamRefresh.GetChangedStructuralEndpointAt(_seamEndpointIndex++),
 384517                includeVolume: true);
 518        }
 519
 12918520        while (_preparedMapOrdinal < PreparedGraph.MapCount)
 521        {
 11723522            NavigationMapInstance instance = PreparedGraph.GetInstance(_preparedMapOrdinal);
 11723523            if (!_wholeMapIds.ContainsKey(instance.MapId))
 524            {
 8976525                _preparedMapOrdinal++;
 8976526                continue;
 527            }
 18886528            while (_preparedMapAddressOrdinal < instance.AddressCount)
 529            {
 17756530                if (!meter.TryConsumeComponentNodes(1))
 1617531                    return false;
 16139532                instance.CopyCanonicalAddressChunk(
 16139533                    ref _addressBakedCursor,
 16139534                    ref _addressDynamicCursor,
 16139535                    _addressScratch);
 16139536                _preparedMapAddressOrdinal++;
 16139537                var address = new NavigationCellAddress(
 16139538                    instance.MapId,
 16139539                    _addressScratch[0]);
 16139540                if (PreparedGraph.HasEffectiveCell(address)
 16139541                    && !HasSameStructuralMedia(address))
 14711542                    _affectedAddresses = _affectedAddresses.Add(address);
 543            }
 1130544            _preparedMapOrdinal++;
 1130545            _preparedMapAddressOrdinal = 0;
 1130546            _addressBakedCursor = 0;
 1130547            _addressDynamicCursor = 0;
 548        }
 729114549        while (_incidentAddressIndex < _affectedAddresses.Count
 729114550            || _incidentNodeActive
 729114551            || _pendingIncidentAddress.HasValue)
 552        {
 727995553            if (_pendingIncidentAddress.HasValue)
 554            {
 147183555                NavigationCellAddress address = _pendingIncidentAddress.Value;
 147183556                if (_sourceGraph.TryGetSurfaceComponent(
 147183557                        address,
 147183558                        TraversalMedium.Solid,
 147183559                        out NavigationSurfaceComponentKey component,
 147183560                        out _)
 147183561                    && !_affectedComponents.Contains(component))
 562                {
 47563                    if (!meter.TryConsumeDependencyEntries(1))
 5564                        return false;
 42565                    AddAffectedComponent(component);
 566                }
 147178567                _pendingIncidentAddress = null;
 147178568                continue;
 569            }
 580812570            if (!_incidentNodeActive)
 571            {
 35450572                NavigationCellAddress address =
 35450573                    _affectedAddresses.GetAt(_incidentAddressIndex);
 106346574                while (_incidentMedium <= TraversalMedium.Liquid)
 575                {
 70898576                    TraversalMedium medium = _incidentMedium++;
 70898577                    if (!HasMediumStateChanged(address, medium))
 578                        continue;
 796579                    var affectedState = new NavigationSurfaceComponentKey(address, medium);
 580                    System.Diagnostics.Debug.Assert(
 581                        !_affectedMediumStates.Contains(affectedState),
 582                        "the canonical affected-address cursor visits each exact medium once");
 796583                    if (!meter.TryConsumeDependencyEntries(1))
 584                    {
 2585                        _incidentMedium--;
 2586                        return false;
 587                    }
 794588                    _affectedMediumStates = _affectedMediumStates.Add(affectedState);
 589                }
 35448590                if (!PreparedGraph.TryGetStructuralMediumStateRef(
 35448591                        address,
 35448592                        TraversalMedium.Solid,
 35448593                        out NavigationMediumStateRef solidState))
 594                {
 790595                    _incidentMedium = TraversalMedium.Gas;
 790596                    _incidentAddressIndex++;
 790597                    continue;
 598                }
 34658599                NavigationNodeRef node = solidState.Node;
 34658600                _incidentOutgoing = PreparedGraph.EnumerateStructuralSurfaceEdges(node);
 34658601                _incidentIncoming =
 34658602                    PreparedGraph.EnumerateIncomingStructuralSurfaceEdges(node);
 34658603                _incidentOutgoingComplete = false;
 34658604                _incidentNodeActive = true;
 605            }
 580020606            int remainingEdges = meter.RemainingSurfaceComponentEdges;
 580020607            if (!_incidentOutgoingComplete)
 608            {
 220364609                NavigationSurfaceEdgeAdvanceStatus status =
 220364610                    _incidentOutgoing.AdvanceOne(meter, ref remainingEdges);
 220364611                if (status == NavigationSurfaceEdgeAdvanceStatus.Blocked)
 26612                    return false;
 220338613                if (status == NavigationSurfaceEdgeAdvanceStatus.Pending)
 614                    continue;
 108247615                if (status == NavigationSurfaceEdgeAdvanceStatus.Edge)
 616                {
 73589617                    bool found = PreparedGraph.TryGetNodeAddress(
 73589618                        _incidentOutgoing.Current.Target,
 73589619                        out NavigationCellAddress address);
 620                    System.Diagnostics.Debug.Assert(found,
 621                        "A structural outgoing edge targets a node in the prepared graph.");
 73589622                    _pendingIncidentAddress = address;
 73589623                    continue;
 624                }
 34658625                _incidentOutgoingComplete = true;
 626            }
 394314627            NavigationSurfaceEdgeAdvanceStatus incomingStatus =
 394314628                _incidentIncoming.AdvanceOne(meter, ref remainingEdges);
 394314629            if (incomingStatus == NavigationSurfaceEdgeAdvanceStatus.Blocked)
 43630                return false;
 394271631            if (incomingStatus == NavigationSurfaceEdgeAdvanceStatus.Pending)
 632                continue;
 108247633            if (incomingStatus == NavigationSurfaceEdgeAdvanceStatus.Edge)
 634            {
 73589635                bool found = PreparedGraph.TryGetNodeAddress(
 73589636                    _incidentIncoming.Current.Predecessor,
 73589637                    out NavigationCellAddress address);
 638                System.Diagnostics.Debug.Assert(found,
 639                    "A structural incoming edge originates at a node in the prepared graph.");
 73589640                _pendingIncidentAddress = address;
 73589641                continue;
 642            }
 34658643            _incidentOutgoing = default;
 34658644            _incidentIncoming = default;
 34658645            _incidentNodeActive = false;
 34658646            _incidentMedium = TraversalMedium.Gas;
 34658647            _incidentAddressIndex++;
 648        }
 1119649        _exactCaptureComplete = true;
 1119650        return true;
 651    }
 652
 653    private void CaptureAffectedAddress(
 654        NavigationCellAddress address,
 655        bool includeVolume)
 656    {
 8968657        _affectedAddresses = _affectedAddresses.Add(address);
 8968658        TraversalMedium maximum = includeVolume
 8968659            ? TraversalMedium.Liquid
 8968660            : TraversalMedium.Solid;
 8968661        for (TraversalMedium medium = TraversalMedium.Solid;
 18704662             medium <= maximum;
 9736663             medium++)
 664        {
 9736665            if (_sourceGraph.TryGetSurfaceComponent(
 9736666                    address,
 9736667                    medium,
 9736668                    out NavigationSurfaceComponentKey component,
 9736669                    out _))
 670            {
 8334671                AddAffectedComponent(component);
 672            }
 673        }
 8968674    }
 675
 676    private void AddAffectedComponent(NavigationSurfaceComponentKey key)
 677    {
 8481678        if (_affectedComponents.Contains(key))
 8301679            return;
 180680        _affectedComponents = _affectedComponents.Add(key);
 180681        _sourceGraph.SurfaceComponents.TryGet(key, out NavigationSurfaceComponent component);
 682        System.Diagnostics.Debug.Assert(
 683            component != null,
 684            "Affected keys originate from resolved source-graph components.");
 180685        _affectedMemberCount = checked(_affectedMemberCount + component.Members.Count);
 180686    }
 687
 688    private void ResetSeamState()
 689    {
 4690        _changedMapIds = PersistentStringMap<bool>.Empty;
 4691        _affectedComponents = NavigationSurfaceComponentKeySet.Empty;
 4692        _affectedAddresses = NavigationCellAddressSet.Empty;
 4693        _affectedMediumStates = NavigationSurfaceComponentKeySet.Empty;
 4694        _affectedMemberCount = 0;
 4695        _wholeMapIds = PersistentStringMap<bool>.Empty;
 4696        _pendingMapId = null;
 4697        _pendingComponentKey = null;
 4698        _pendingMedium = TraversalMedium.Solid;
 4699        _pendingExactAddress = null;
 4700        _pendingMapComponentOrdinal = 0;
 4701        _pendingWholeMap = false;
 4702        _explicitSourceIndex = 0;
 4703        _changeIndex = 0;
 4704        _overlayIndex = 0;
 4705        _overlayCellIndex = 0;
 4706        _capturePhase = 0;
 4707        _seamSourceIndex = 0;
 4708        _seamCapturePhase = 0;
 4709        _pendingSeamMapId = null;
 4710        _seamCaptureComplete = false;
 4711        _exactCaptureComplete = false;
 4712        _explicitOwnerIndex = 0;
 4713        _explicitEndpointStage = 0;
 4714        _seamEndpointIndex = 0;
 4715        _preparedMapOrdinal = 0;
 4716        _preparedMapAddressOrdinal = 0;
 4717        _addressBakedCursor = 0;
 4718        _addressDynamicCursor = 0;
 4719        _incidentAddressIndex = 0;
 4720        _incidentMedium = TraversalMedium.Gas;
 4721        _incidentNodeActive = false;
 4722        _incidentOutgoingComplete = false;
 4723        _incidentOutgoing = default;
 4724        _incidentIncoming = default;
 4725        _pendingIncidentAddress = null;
 4726        _preparation = null;
 4727        _seamRefresh = null;
 4728        _preparedGraph = null;
 4729        _componentUpdate = null;
 4730        if (_affectedClosurePublished)
 2731            _allCloseRepublishRequired = true;
 4732        _affectedClosurePublished = false;
 4733        _publishedAffectedComponents = NavigationSurfaceComponentKeySet.Empty;
 4734    }
 735
 736    private bool HasNextRawMapId() =>
 19253737        _explicitSourceIndex < _candidate.ExplicitChangedSourceCount
 19253738        || _changeIndex < _batchChangeCount;
 739
 740    private bool TryTakeNextRawScope(
 741        out string mapId,
 742        out NavigationCellAddress? exactAddress,
 743        out bool wholeMap)
 744    {
 18053745        if (_explicitSourceIndex < _candidate.ExplicitChangedSourceCount)
 746        {
 124747            mapId = _candidate.GetExplicitChangedSourceAt(_explicitSourceIndex++);
 124748            exactAddress = null;
 124749            wholeMap = false;
 124750            return true;
 751        }
 752        while (true)
 753        {
 17948754            NavigationOperationFrameChange change = _changes[_changeIndex];
 17948755            if (change.Kind != NavigationOperationFrameChangeKind.Overlay)
 756            {
 1143757                _changeIndex++;
 1143758                mapId = change.MapId!;
 1143759                exactAddress = null;
 1143760                wholeMap = true;
 1143761                return true;
 762            }
 16805763            ReadOnlySpan<NavigationMapOverlayDelta> maps =
 16805764                change.PreparedOverlay!.Transaction.MapSpan;
 16805765            NavigationMapOverlayDelta map = maps[_overlayIndex];
 16805766            if (_overlayCellIndex < map.CellSpan.Length)
 767            {
 16573768                mapId = map.MapId;
 16573769                var address = new NavigationCellAddress(
 16573770                    map.MapId,
 16573771                    map.CellSpan[_overlayCellIndex++].Index);
 16573772                exactAddress = HasSameStructuralMedia(address) ? null : address;
 16573773                wholeMap = false;
 16573774                return true;
 775            }
 232776            bool hasNonCellStructuralDelta = !map.ConnectionSpan.IsEmpty
 232777                || !map.TransitionSpan.IsEmpty;
 232778            if (hasNonCellStructuralDelta && _overlayCellIndex == map.CellSpan.Length)
 779            {
 29780                _overlayCellIndex++;
 29781                mapId = map.MapId;
 29782                exactAddress = null;
 29783                wholeMap = false;
 29784                return true;
 785            }
 203786            _overlayIndex++;
 203787            _overlayCellIndex = 0;
 203788            if (_overlayIndex == maps.Length)
 789            {
 188790                _overlayIndex = 0;
 188791                _changeIndex++;
 188792                if (_changeIndex == _batchChangeCount)
 793                {
 184794                    mapId = null!;
 184795                    exactAddress = null;
 184796                    wholeMap = false;
 184797                    return false;
 798                }
 799            }
 800        }
 801    }
 802
 803    private bool HasSameStructuralMedia(NavigationCellAddress address)
 804    {
 32711805        bool priorAddressed = _sourceGraph.TryGetSemanticState(
 32711806            address,
 32711807            out NavigationCellSemanticSource priorSource,
 32711808            out bool priorHasCell,
 32711809            out NavigationCell priorCell);
 32711810        bool nextAddressed = _candidate.TryGetSemanticState(
 32711811            address,
 32711812            out NavigationCellSemanticSource nextSource,
 32711813            out bool nextHasCell,
 32711814            out NavigationCell nextCell);
 32711815        TraversalMedia priorMedia = priorAddressed && priorHasCell
 32711816            ? priorCell.Media
 32711817            : TraversalMedia.None;
 32711818        TraversalMedia nextMedia = nextAddressed && nextHasCell
 32711819            ? nextCell.Media
 32711820            : TraversalMedia.None;
 32711821        return priorMedia == nextMedia;
 822    }
 823
 824    private bool HasMediumStateChanged(
 825        NavigationCellAddress address,
 826        TraversalMedium medium)
 827    {
 125364828        _sourceGraph.TryGetSemanticState(
 125364829            address,
 125364830            out _,
 125364831            out bool priorHasCell,
 125364832            out NavigationCell priorCell);
 125364833        _candidate.TryGetSemanticState(
 125364834            address,
 125364835            out _,
 125364836            out bool nextHasCell,
 125364837            out NavigationCell nextCell);
 125364838        bool prior = priorHasCell && priorCell.SupportsMedium(medium);
 125364839        bool next = nextHasCell && nextCell.SupportsMedium(medium);
 125364840        return prior != next;
 841    }
 842
 843    internal static long GetMinimumScratchBytes(
 844        int sourceMapCount,
 845        int candidateMapCount,
 846        int changedMapCount,
 847        long overlayCellCount)
 848    {
 1112849        long semanticPages = overlayCellCount == 0 ? 0 : ((overlayCellCount + 63) / 64) + 1;
 1112850        return checked(
 1112851            NavigationAutomaticSeamRefreshWork.FixedRetainedBytes
 1112852            + 256L
 1112853            + ((long)candidateMapCount * 256L)
 1112854            + (semanticPages * 4_504L));
 855    }
 856
 857    internal static int GetMinimumScratchPages(
 858        int candidateMapCount,
 859        long overlayCellCount)
 860    {
 1111861        long semanticPages = overlayCellCount == 0 ? 0 : ((overlayCellCount + 63) / 64) + 1;
 1111862        return checked(
 1111863            2 + 4
 1111864            + (candidateMapCount * 2)
 1111865            + checked((int)Math.Min(int.MaxValue, semanticPages * 2L)));
 866    }
 867
 868}

Methods/Properties

.ctor(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationWorldGraph,Trailblazer.Pathing.NavigationOperationCandidate,Trailblazer.Pathing.NavigationOperationFrameChange[],System.Int32)
get_CapturedChangedMapCount()
get_IsChangedMapCaptureComplete()
get_AffectedComponents()
get_RequiresAffectedClosurePublication()
get_RequiresAllClosePublication()
GetCapturedChangedMapIdAt(System.Int32)
get_PreparedGraph()
get_RetainedBytes()
get_PersistentPageCount()
get_IsComplete()
IsLifecycleComplete(System.Boolean,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Int32,System.Int32,System.Nullable`1<System.Boolean>)
get_Result()
Advance(Trailblazer.Pathing.MaintenanceWorkMeter)
Advance(Trailblazer.Pathing.MaintenanceWorkMeter,System.Int64,System.Int32,System.Boolean&)
ExceedsCapacity(System.Int64,System.Int32)
MarkAffectedClosurePublished()
RecordAffectedClosurePublication(Trailblazer.Pathing.NavigationCandidatePublication)
MarkAllClosePublished()
MarkInitialClosurePublished()
MarkAllCloseRepublished()
RecordAllClosePublication(Trailblazer.Pathing.NavigationCandidatePublication)
RevalidateAutomaticSeamsForPublication()
AdvanceChangedMapCapture(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceSeamChangedMapCapture(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceExactAffectedCapture(Trailblazer.Pathing.MaintenanceWorkMeter)
CaptureAffectedAddress(Trailblazer.Pathing.NavigationCellAddress,System.Boolean)
AddAffectedComponent(Trailblazer.Pathing.NavigationSurfaceComponentKey)
ResetSeamState()
HasNextRawMapId()
TryTakeNextRawScope(System.String&,System.Nullable`1<Trailblazer.Pathing.NavigationCellAddress>&,System.Boolean&)
HasSameStructuralMedia(Trailblazer.Pathing.NavigationCellAddress)
HasMediumStateChanged(Trailblazer.Pathing.NavigationCellAddress,Trailblazer.TraversalMedium)
GetMinimumScratchBytes(System.Int32,System.Int32,System.Int32,System.Int64)
GetMinimumScratchPages(System.Int32,System.Int64)