< Summary

Line coverage
100%
Covered lines: 1738
Uncovered lines: 0
Coverable lines: 1738
Total lines: 2844
Line coverage: 100%
Branch coverage
100%
Covered branches: 782
Total branches: 782
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: .ctor(...)100%11100%
File 1: get_MapCount()100%11100%
File 1: get_OverlayCellCount()100%11100%
File 1: get_OverlayConnectionCount()100%11100%
File 1: get_TransitionRuleCount()100%11100%
File 1: get_NavigationAreaCount()100%11100%
File 1: get_RetainedBytes()100%22100%
File 1: get_PersistentPageCount()100%22100%
File 1: get_WorkCopiedPersistentBytes()100%11100%
File 1: get_WorkCopiedPersistentPages()100%11100%
File 1: get_WorkOwnedExplicitPayloadBytes()100%11100%
File 1: get_WorkOwnedExplicitPayloadPages()100%11100%
File 1: get_WorkOwnedMapStatePayloadBytes()100%11100%
File 1: get_WorkOwnedMapStatePayloadPages()100%11100%
File 1: get_NonPayloadRetainedBytes()100%11100%
File 1: get_NonPayloadPersistentPageCount()100%11100%
File 1: ResetWorkCopiedPersistentOwnership()100%11100%
File 1: RecordPersistentCopies(...)100%11100%
File 1: RecordExplicitRecordOwnership(...)100%11100%
File 1: RecordExplicitIncidenceOwnership(...)100%11100%
File 1: RecordExplicitEndpointOwnership(...)100%11100%
File 1: ReplaceCurrentPayloadOwnership(...)100%11100%
File 1: ReplaceDisplacedPayloadOwnership(...)100%44100%
File 1: GetPayloadOwnership(...)100%44100%
File 1: GetPayloadSize(...)100%22100%
File 1: RecordMapStateOwnership(...)100%11100%
File 1: GetAdditionalMapStatePayload(...)100%1818100%
File 1: ReplaceDisplacedMapStateOwnership(...)100%1818100%
File 1: ReplaceDisplacedMapStateComponent(...)100%44100%
File 1: ReplaceOverlayState(...)100%1212100%
File 1: Clone()100%11100%
File 1: GetIncomingSourceCount(...)100%22100%
File 1: GetIncomingSource(...)100%11100%
File 1: UpdateIncomingSourceForWork(...)100%11100%
File 1: ValidateTransitionForWork(...)100%66100%
File 1: TryGetMap(...)100%22100%
File 1: TryGetState(...)100%11100%
File 1: TryGetSemanticState(...)100%2020100%
File 1: TryGetOverlay(...)100%22100%
File 1: SetMapState(...)100%22100%
File 1: AddMapStateTotals(...)100%11100%
File 1: RemoveMapStateTotals(...)100%11100%
File 1: ReplaceTotals(...)100%44100%
File 1: UpdateIncomingSource(...)100%1818100%
File 1: ValidateTransition(...)100%1818100%
File 1: TryGetEffectiveCell(...)100%66100%
File 1: HasDefinitionMedium(...)100%1010100%
File 1: SupportsMedium(...)100%44100%
File 1: FindChangedState(...)100%66100%
File 1: TryFindCellOverlay(...)100%11100%
File 1: .ctor(...)100%44100%
File 2: get_ExplicitConnections()100%11100%
File 2: get_ExplicitChangedSourceCount()100%11100%
File 2: get_ExplicitChangedOwnerCount()100%11100%
File 2: GetExplicitChangedSourceAt(...)100%11100%
File 2: GetExplicitChangedOwnerAt(...)100%11100%
File 2: BeginExplicitConnectionRefresh(...)100%11100%
File 2: BeginExplicitConnectionRefresh(...)100%11100%
File 2: TrySelectConnection(...)100%1414100%
File 2: TryGetSemanticPrism(...)100%1414100%
File 2: ValidateLowerBound(...)100%1010100%
File 2: Dormant(...)100%11100%
File 2: IsKnownSuppressed(...)100%22100%
File 2: .ctor(...)100%11100%
File 2: get_DisplacedSourcePayloadBytes()100%11100%
File 2: get_DisplacedSourcePayloadPages()100%11100%
File 2: get_RetainedBytes()100%1010100%
File 2: get_PersistentPageCount()100%1010100%
File 2: Advance(...)100%4242100%
File 2: InitializeCurrent(...)100%22100%
File 2: AdvanceCompilation(...)100%3232100%
File 2: CaptureSemanticPrism(...)100%2222100%
File 2: AdvanceDistinctAddresses(...)100%88100%
File 2: AdvanceOldIncidenceTouches(...)100%88100%
File 2: UpdateOwner()100%22100%
File 2: AdvanceFinalAdditions(...)100%1212100%
File 2: AdvanceIncidenceRows(...)100%2626100%
File 2: InitializeRow(...)100%11100%
File 2: AdvancePriorRowFilter(...)100%88100%
File 2: AdvanceRowMerge(...)100%4242100%
File 2: IsIncidenceChanged(...)100%66100%
File 2: GetOrCreateRowDelta(...)100%88100%
File 2: ReleaseCurrentRow()100%11100%
File 2: IsEndpoint(...)100%22100%
File 2: GetRawAddress(...)100%44100%
File 2: ResetCurrent()100%11100%
File 2: HasComponentEdgeChanged(...)100%1818100%
File 2: PortalsEqual(...)100%44100%
File 2: PortalEquals(...)100%11100%
File 2: AdvanceGather(...)100%2424100%
File 2: AdvanceOverlayGather(...)100%1212100%
File 2: AddOwner(...)100%88100%
File 2: AdvanceIncidentOwners(...)100%88100%
File 2: get_RetainedBytes()100%44100%
File 2: get_PersistentPageCount()100%44100%
File 2: AppendAddition(...)100%22100%
File 2: MarkEndpointTouched()100%11100%
File 2: SealAdditions()100%44100%
File 2: ReleaseAdditions()100%11100%
File 2: get_RetainedBytes()100%11100%
File 2: get_PersistentPageCount()100%11100%
File 2: Add(...)100%88100%
File 2: GetSuccessor(...)100%88100%
File 2: Clear()100%11100%
File 2: Minimum(...)100%44100%
File 2: Rebalance(...)100%1010100%
File 2: RotateLeft(...)100%22100%
File 2: RotateRight(...)100%22100%
File 2: ReplaceParentLink(...)100%44100%
File 2: Height(...)100%22100%
File 2: UpdateHeight(...)100%11100%
File 2: .ctor(...)100%11100%
File 3: BeginMapFold(...)100%11100%
File 3: BeginMapRemovalFold(...)100%11100%
File 3: .ctor(...)100%11100%
File 3: .ctor(...)100%22100%
File 3: get_Candidate()100%11100%
File 3: get_DisplacedExplicitPayloadBytes()100%22100%
File 3: get_DisplacedExplicitPayloadPages()100%22100%
File 3: get_DisplacedMapStatePayloadBytes()100%11100%
File 3: get_DisplacedMapStatePayloadPages()100%11100%
File 3: get_RetainedBytes()100%22100%
File 3: get_PersistentPageCount()100%22100%
File 3: GetPendingStateGrowthBytes()100%44100%
File 3: GetPendingStateGrowthPages()100%44100%
File 3: Advance(...)100%3030100%
File 3: PrepareCommit()100%4242100%
File 3: AdvanceCells(...)100%2020100%
File 3: AdvanceDynamic(...)100%66100%
File 3: AdvanceAuthoredValidation(...)100%1010100%
File 3: AdvanceRuleOwnershipValidation(...)100%2020100%
File 3: AdvanceValidation(...)100%66100%
File 3: GetValidationState()100%66100%
File 3: AdvanceStateValidation(...)100%1010100%
File 3: AdvanceDependencies(...)100%1010100%
File 3: AdvanceStateDependencies(...)100%1616100%
File 3: Commit()100%66100%
File 3: ResetDependencyCursor()100%11100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Map/Operations/NavigationOperationCandidate.cs

#LineLine coverage
 1//=======================================================================
 2// NavigationOperationCandidate.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 FixedMathSharp;
 10using GridForge.Grids.Topology;
 11
 12namespace Trailblazer.Pathing;
 13
 14internal sealed partial class NavigationOperationCandidate
 15{
 16    private readonly int _navigationAreaCount;
 447117    private PersistentStringMap<MapState> _maps = PersistentStringMap<MapState>.Empty;
 447118    private PersistentStringMap<long> _bakeVersionHighWater = PersistentStringMap<long>.Empty;
 447119    private PersistentStringMap<PersistentStringMap<bool>> _incomingSources =
 447120        PersistentStringMap<PersistentStringMap<bool>>.Empty;
 447121    private PersistentGridConfigurationMap<string> _gridBindings = PersistentGridConfigurationMap<string>.Empty;
 447122    private NavigationExplicitConnectionIndex _explicitConnections =
 447123        NavigationExplicitConnectionIndex.Empty;
 447124    private PersistentStringMap<bool> _explicitChangedSources =
 447125        PersistentStringMap<bool>.Empty;
 447126    private NavigationConnectionOwnerKeySet _explicitChangedOwners =
 447127        NavigationConnectionOwnerKeySet.Empty;
 28    private long _overlaySlotCount;
 29    private long _overlayConnectionCount;
 30    private long _overlayTransitionCount;
 31    private long _transitionRuleCount;
 32    private long _seamCandidateCount;
 33    private long _explicitEdgeCount;
 34    private int _dynamicCellCount;
 35    private long _mapStateRetainedBytes;
 36    private int _mapStatePersistentPages;
 37    private long _incomingSetRetainedBytes;
 38    private int _incomingSetPersistentPages;
 39    private long _workCopiedPersistentBytes;
 40    private int _workCopiedPersistentPages;
 447141    private NavigationExplicitConnectionIndex _workPublishedExplicitConnections =
 447142        NavigationExplicitConnectionIndex.Empty;
 447143    private PersistentStringMap<MapState> _workPublishedMaps = PersistentStringMap<MapState>.Empty;
 44    private long _workOwnedExplicitPayloadBytes;
 45    private int _workOwnedExplicitPayloadPages;
 46    private long _workOwnedMapStatePayloadBytes;
 47    private int _workOwnedMapStatePayloadPages;
 48
 447149    internal NavigationOperationCandidate(int navigationAreaCount = ushort.MaxValue + 1)
 50    {
 447151        _navigationAreaCount = navigationAreaCount;
 447152    }
 53
 223954    internal int MapCount => _maps.Count;
 55
 222356    internal long OverlayCellCount => _overlaySlotCount;
 57
 258    internal long OverlayConnectionCount => _overlayConnectionCount;
 59
 140160    internal long TransitionRuleCount => _transitionRuleCount;
 61
 1707662    internal int NavigationAreaCount => _navigationAreaCount;
 63
 12676164    internal long RetainedBytes => checked(
 12676165        112L
 12676166        + _maps.RetainedBytes
 12676167        + _bakeVersionHighWater.RetainedBytes
 12676168        + _incomingSources.RetainedBytes
 12676169        + _gridBindings.RetainedBytes
 12676170        + _explicitConnections.RetainedBytes
 12676171        + _explicitChangedSources.RetainedBytes
 12676172        + (ReferenceEquals(_explicitChangedOwners, NavigationConnectionOwnerKeySet.Empty)
 12676173            ? 0L
 12676174            : _explicitChangedOwners.RetainedBytes)
 12676175        + _mapStateRetainedBytes
 12676176        + _incomingSetRetainedBytes);
 77
 12748478    internal int PersistentPageCount => checked(
 12748479        4
 12748480        + _maps.PersistentNodeCount
 12748481        + _bakeVersionHighWater.PersistentNodeCount
 12748482        + _incomingSources.PersistentNodeCount
 12748483        + _gridBindings.Count
 12748484        + _explicitConnections.PersistentPageCount
 12748485        + _explicitChangedSources.PersistentNodeCount
 12748486        + (ReferenceEquals(_explicitChangedOwners, NavigationConnectionOwnerKeySet.Empty)
 12748487            ? 0
 12748488            : _explicitChangedOwners.PersistentPageCount)
 12748489        + _mapStatePersistentPages
 12748490        + _incomingSetPersistentPages);
 91
 6282292    internal long WorkCopiedPersistentBytes => _workCopiedPersistentBytes;
 93
 6318794    internal int WorkCopiedPersistentPages => _workCopiedPersistentPages;
 95
 12564196    internal long WorkOwnedExplicitPayloadBytes => _workOwnedExplicitPayloadBytes;
 97
 12637698    internal int WorkOwnedExplicitPayloadPages => _workOwnedExplicitPayloadPages;
 99
 125636100    internal long WorkOwnedMapStatePayloadBytes => _workOwnedMapStatePayloadBytes;
 101
 126372102    internal int WorkOwnedMapStatePayloadPages => _workOwnedMapStatePayloadPages;
 103
 125634104    internal long NonPayloadRetainedBytes => checked(
 125634105        RetainedBytes
 125634106        - _explicitConnections.PayloadRetainedBytes
 125634107        - _mapStateRetainedBytes);
 108
 126370109    internal int NonPayloadPersistentPageCount => checked(
 126370110        PersistentPageCount
 126370111        - _explicitConnections.PayloadPersistentPageCount
 126370112        - _mapStatePersistentPages);
 113
 114    internal void ResetWorkCopiedPersistentOwnership()
 115    {
 3542116        _workCopiedPersistentBytes = 0;
 3542117        _workCopiedPersistentPages = 0;
 3542118        _workOwnedExplicitPayloadBytes = 0;
 3542119        _workOwnedExplicitPayloadPages = 0;
 3542120        _workOwnedMapStatePayloadBytes = 0;
 3542121        _workOwnedMapStatePayloadPages = 0;
 3542122        _workPublishedExplicitConnections = _explicitConnections;
 3542123        _workPublishedMaps = _maps;
 3542124        _explicitChangedSources = PersistentStringMap<bool>.Empty;
 3542125        _explicitChangedOwners = NavigationConnectionOwnerKeySet.Empty;
 3542126    }
 127
 128    internal void RecordPersistentCopies(int copiedNodes, long bytesPerNode = 64L)
 129    {
 60757130        _workCopiedPersistentPages = checked(_workCopiedPersistentPages + copiedNodes);
 60757131        _workCopiedPersistentBytes = checked(
 60757132            _workCopiedPersistentBytes + (copiedNodes * bytesPerNode));
 60757133    }
 134
 135    internal void RecordExplicitRecordOwnership(
 136        NavigationConnectionOwnerKey owner,
 137        NavigationExplicitConnectionRecord? next,
 138        NavigationExplicitConnectionIndex foldSource,
 139        ref long displacedBytes,
 140        ref int displacedPages)
 141    {
 4481142        _explicitConnections.TryGet(owner, out NavigationExplicitConnectionRecord prior);
 4481143        _workPublishedExplicitConnections.TryGet(owner, out NavigationExplicitConnectionRecord published);
 4481144        foldSource.TryGet(owner, out NavigationExplicitConnectionRecord source);
 4481145        ReplaceCurrentPayloadOwnership(
 4481146            prior,
 4481147            next,
 4481148            published,
 4481149            ref _workOwnedExplicitPayloadBytes,
 4481150            ref _workOwnedExplicitPayloadPages);
 4481151        ReplaceDisplacedPayloadOwnership(
 4481152            next,
 4481153            published,
 4481154            source,
 4481155            ref displacedBytes,
 4481156            ref displacedPages);
 4481157    }
 158
 159    internal void RecordExplicitIncidenceOwnership(
 160        NavigationCellAddress address,
 161        NavigationPagedSequence<NavigationConnectionOwnerKey> next,
 162        NavigationExplicitConnectionIndex foldSource,
 163        ref long displacedBytes,
 164        ref int displacedPages)
 165    {
 4578166        NavigationPagedSequence<NavigationConnectionOwnerKey> prior =
 4578167            _explicitConnections.GetIncidentOwnerRow(address);
 4578168        NavigationPagedSequence<NavigationConnectionOwnerKey> published =
 4578169            _workPublishedExplicitConnections.GetIncidentOwnerRow(address);
 4578170        NavigationPagedSequence<NavigationConnectionOwnerKey> source =
 4578171            foldSource.GetIncidentOwnerRow(address);
 4578172        ReplaceCurrentPayloadOwnership(
 4578173            prior,
 4578174            next,
 4578175            published,
 4578176            ref _workOwnedExplicitPayloadBytes,
 4578177            ref _workOwnedExplicitPayloadPages);
 4578178        ReplaceDisplacedPayloadOwnership(
 4578179            next,
 4578180            published,
 4578181            source,
 4578182            ref displacedBytes,
 4578183            ref displacedPages);
 4578184    }
 185
 186    internal void RecordExplicitEndpointOwnership(
 187        NavigationCellAddress address,
 188        NavigationPagedSequence<NavigationConnectionOwnerKey> next,
 189        NavigationExplicitConnectionIndex foldSource,
 190        ref long displacedBytes,
 191        ref int displacedPages)
 192    {
 4458193        NavigationPagedSequence<NavigationConnectionOwnerKey> prior =
 4458194            _explicitConnections.GetEndpointOwnerRow(address);
 4458195        NavigationPagedSequence<NavigationConnectionOwnerKey> published =
 4458196            _workPublishedExplicitConnections.GetEndpointOwnerRow(address);
 4458197        NavigationPagedSequence<NavigationConnectionOwnerKey> source =
 4458198            foldSource.GetEndpointOwnerRow(address);
 4458199        ReplaceCurrentPayloadOwnership(
 4458200            prior,
 4458201            next,
 4458202            published,
 4458203            ref _workOwnedExplicitPayloadBytes,
 4458204            ref _workOwnedExplicitPayloadPages);
 4458205        ReplaceDisplacedPayloadOwnership(
 4458206            next,
 4458207            published,
 4458208            source,
 4458209            ref displacedBytes,
 4458210            ref displacedPages);
 4458211    }
 212
 213    private static void ReplaceCurrentPayloadOwnership<T>(
 214        T? prior,
 215        T? next,
 216        T? published,
 217        ref long bytes,
 218        ref int pages)
 219        where T : class
 220    {
 13517221        GetPayloadOwnership(prior, published, out long priorBytes, out int priorPages);
 13517222        GetPayloadOwnership(next, published, out long nextBytes, out int nextPages);
 13517223        bytes = checked(bytes - priorBytes + nextBytes);
 13517224        pages = checked(pages - priorPages + nextPages);
 13517225    }
 226
 227    private static void ReplaceDisplacedPayloadOwnership<T>(
 228        T? next,
 229        T? published,
 230        T? source,
 231        ref long bytes,
 232        ref int pages)
 233        where T : class
 234    {
 235        // A fold commits each canonical key once, so its prior payload is the fold source.
 13517236        if (source == null || ReferenceEquals(source, published))
 13323237            return;
 238        // Owner and row folds materialize a replacement payload before committing a key.
 239        System.Diagnostics.Debug.Assert(!ReferenceEquals(next, source));
 194240        GetPayloadSize(source, out long sourceBytes, out int sourcePages);
 194241        bytes = checked(bytes + sourceBytes);
 194242        pages = checked(pages + sourcePages);
 194243    }
 244
 245    private static void GetPayloadOwnership<T>(
 246        T? value,
 247        T? published,
 248        out long bytes,
 249        out int pages)
 250        where T : class
 251    {
 27034252        if (value == null || ReferenceEquals(value, published))
 253        {
 13340254            bytes = 0;
 13340255            pages = 0;
 13340256            return;
 257        }
 13694258        GetPayloadSize(value, out bytes, out pages);
 13694259    }
 260
 261    private static void GetPayloadSize<T>(T value, out long bytes, out int pages)
 262        where T : class
 263    {
 13888264        if (value is NavigationExplicitConnectionRecord record)
 265        {
 4615266            bytes = record.RetainedBytes;
 4615267            pages = record.PersistentPageCount;
 4615268            return;
 269        }
 9273270        var row = (NavigationPagedSequence<NavigationConnectionOwnerKey>)(object)value;
 9273271        bytes = row.RetainedBytes;
 9273272        pages = row.PersistentPageCount;
 9273273    }
 274
 275    internal void RecordMapStateOwnership(
 276        string mapId,
 277        MapState? next,
 278        NavigationOperationCandidate foldSource,
 279        ref long displacedBytes,
 280        ref int displacedPages)
 281    {
 1741282        _maps.TryGetValue(mapId, out MapState prior);
 1741283        _workPublishedMaps.TryGetValue(mapId, out MapState published);
 1741284        foldSource._maps.TryGetValue(mapId, out MapState source);
 1741285        GetAdditionalMapStatePayload(prior, published, out long priorBytes, out int priorPages);
 1741286        GetAdditionalMapStatePayload(next, published, out long nextBytes, out int nextPages);
 1741287        _workOwnedMapStatePayloadBytes = checked(
 1741288            _workOwnedMapStatePayloadBytes - priorBytes + nextBytes);
 1741289        _workOwnedMapStatePayloadPages = checked(
 1741290            _workOwnedMapStatePayloadPages - priorPages + nextPages);
 1741291        ReplaceDisplacedMapStateOwnership(
 1741292            next,
 1741293            published,
 1741294            source,
 1741295            ref displacedBytes,
 1741296            ref displacedPages);
 1741297    }
 298
 299    internal static void GetAdditionalMapStatePayload(
 300        MapState? value,
 301        MapState? shared,
 302        out long bytes,
 303        out int pages)
 304    {
 19696305        bytes = 0;
 19696306        pages = 0;
 19696307        if (value == null)
 1350308            return;
 18346309        if (shared == null || !ReferenceEquals(value.Map, shared.Map))
 310        {
 17627311            bytes = checked(
 17627312                bytes + value.PreparedMapRetainedBytes - value.BakedCellLookup.RetainedBytes);
 313        }
 18346314        if (shared == null || !ReferenceEquals(value.BakedCellLookup, shared.BakedCellLookup))
 17630315            bytes = checked(bytes + value.BakedCellLookup.RetainedBytes);
 18346316        if (shared == null || !ReferenceEquals(value.Overlay, shared.Overlay))
 317        {
 17818318            bytes = checked(bytes + value.Overlay.RetainedBytes);
 17818319            pages = checked(pages + value.Overlay.PersistentNodeCount);
 320        }
 18346321        if (shared == null || !ReferenceEquals(value.DynamicAddresses, shared.DynamicAddresses))
 322        {
 17601323            bytes = checked(bytes + value.DynamicAddresses.RetainedBytes);
 17601324            pages = checked(pages + value.DynamicAddresses.PersistentNodeCount);
 325        }
 18346326    }
 327
 328    private static void ReplaceDisplacedMapStateOwnership(
 329        MapState? next,
 330        MapState? published,
 331        MapState? source,
 332        ref long bytes,
 333        ref int pages)
 334    {
 335        // Map ids are canonical within a fold; each source component is displaced at most once.
 1741336        if (source == null)
 1333337            return;
 408338        ReplaceDisplacedMapStateComponent(
 408339            next?.Map,
 408340            published?.Map,
 408341            source.Map,
 408342            source.PreparedMapRetainedBytes - source.BakedCellLookup.RetainedBytes,
 408343            0,
 408344            ref bytes,
 408345            ref pages);
 408346        ReplaceDisplacedMapStateComponent(
 408347            next?.BakedCellLookup,
 408348            published?.BakedCellLookup,
 408349            source.BakedCellLookup,
 408350            source.BakedCellLookup.RetainedBytes,
 408351            0,
 408352            ref bytes,
 408353            ref pages);
 408354        ReplaceDisplacedMapStateComponent(
 408355            next?.Overlay,
 408356            published?.Overlay,
 408357            source.Overlay,
 408358            source.Overlay.RetainedBytes,
 408359            source.Overlay.PersistentNodeCount,
 408360            ref bytes,
 408361            ref pages);
 408362        ReplaceDisplacedMapStateComponent(
 408363            next?.DynamicAddresses,
 408364            published?.DynamicAddresses,
 408365            source.DynamicAddresses,
 408366            source.DynamicAddresses.RetainedBytes,
 408367            source.DynamicAddresses.PersistentNodeCount,
 408368            ref bytes,
 408369            ref pages);
 408370    }
 371
 372    private static void ReplaceDisplacedMapStateComponent(
 373        object? next,
 374        object? published,
 375        object source,
 376        long sourceBytes,
 377        int sourcePages,
 378        ref long bytes,
 379        ref int pages)
 380    {
 1632381        if (ReferenceEquals(source, published))
 1508382            return;
 124383        if (!ReferenceEquals(next, source))
 384        {
 68385            bytes = checked(bytes + sourceBytes);
 68386            pages = checked(pages + sourcePages);
 387        }
 124388    }
 389
 390    internal NavigationOperationRejection ReplaceOverlayState(
 391        MapState current,
 392        MapState next,
 393        NavigationOperationLimits limits)
 394    {
 348395        if (next.Overlay.CellCount > limits.MaxOverlayCellsPerMap
 348396            || next.Overlay.ConnectionCount > limits.MaxOverlayConnectionsPerMap
 348397            || next.Overlay.TransitionCount > limits.MaxOverlayTransitionsPerMap)
 398        {
 2399            return NavigationOperationRejection.CapacityExceeded;
 400        }
 346401        long candidateCells = _overlaySlotCount
 346402            - current.Overlay.CellCount + next.Overlay.CellCount;
 346403        long candidateConnections = _overlayConnectionCount
 346404            - current.Overlay.ConnectionCount + next.Overlay.ConnectionCount;
 346405        long candidateTransitions = _overlayTransitionCount
 346406            - current.Overlay.TransitionCount + next.Overlay.TransitionCount;
 346407        if (candidateCells > limits.MaxOverlayCells
 346408            || candidateConnections > limits.MaxOverlayConnections
 346409            || candidateTransitions > limits.MaxOverlayTransitions)
 410        {
 2411            return NavigationOperationRejection.CapacityExceeded;
 412        }
 344413        ReplaceTotals(current, next);
 344414        SetMapState(current, next);
 344415        return NavigationOperationRejection.None;
 416    }
 417
 418    internal NavigationOperationCandidate Clone()
 419    {
 3074420        return new NavigationOperationCandidate(_navigationAreaCount)
 3074421        {
 3074422            _maps = _maps,
 3074423            _bakeVersionHighWater = _bakeVersionHighWater,
 3074424            _incomingSources = _incomingSources,
 3074425            _gridBindings = _gridBindings,
 3074426            _explicitConnections = _explicitConnections,
 3074427            _explicitChangedSources = _explicitChangedSources,
 3074428            _explicitChangedOwners = _explicitChangedOwners,
 3074429            _overlaySlotCount = _overlaySlotCount,
 3074430            _overlayConnectionCount = _overlayConnectionCount,
 3074431            _overlayTransitionCount = _overlayTransitionCount,
 3074432            _transitionRuleCount = _transitionRuleCount,
 3074433            _seamCandidateCount = _seamCandidateCount,
 3074434            _explicitEdgeCount = _explicitEdgeCount,
 3074435            _dynamicCellCount = _dynamicCellCount,
 3074436            _mapStateRetainedBytes = _mapStateRetainedBytes,
 3074437            _mapStatePersistentPages = _mapStatePersistentPages,
 3074438            _incomingSetRetainedBytes = _incomingSetRetainedBytes,
 3074439            _incomingSetPersistentPages = _incomingSetPersistentPages,
 3074440            _workCopiedPersistentBytes = _workCopiedPersistentBytes,
 3074441            _workCopiedPersistentPages = _workCopiedPersistentPages,
 3074442            _workPublishedExplicitConnections = _workPublishedExplicitConnections,
 3074443            _workOwnedExplicitPayloadBytes = _workOwnedExplicitPayloadBytes,
 3074444            _workOwnedExplicitPayloadPages = _workOwnedExplicitPayloadPages,
 3074445            _workPublishedMaps = _workPublishedMaps,
 3074446            _workOwnedMapStatePayloadBytes = _workOwnedMapStatePayloadBytes,
 3074447            _workOwnedMapStatePayloadPages = _workOwnedMapStatePayloadPages
 3074448        };
 449    }
 450
 451    internal int GetIncomingSourceCount(string mapId) =>
 4503452        _incomingSources.TryGetValue(mapId, out PersistentStringMap<bool> sources)
 4503453            ? sources.Count
 4503454            : 0;
 455
 456    internal string GetIncomingSource(string mapId, int ordinal)
 457    {
 166458        _incomingSources.TryGetValue(mapId, out PersistentStringMap<bool> sources);
 166459        return sources.GetKeyAt(ordinal);
 460    }
 461
 462    internal void UpdateIncomingSourceForWork(
 463        string destinationMapId,
 464        string sourceMapId,
 4132465        bool remove) => UpdateIncomingSource(destinationMapId, sourceMapId, remove);
 466
 467    internal bool ValidateTransitionForWork(
 468        MapState state,
 469        bool overlay,
 470        int index,
 471        string[] changedMapIds,
 472        MapState[] changedStates)
 473    {
 8338474        if (!overlay)
 475        {
 105476            TraversalTransitionDefinition transition = state.Map.TransitionSpan[index];
 105477            return state.Overlay.TryGetTransition(transition.Id, out _)
 105478                || ValidateTransition(
 105479                    state,
 105480                    transition,
 105481                    changedMapIds,
 105482                    changedStates);
 483        }
 8233484        TraversalTransitionOverlayOperation operation = state.Overlay.GetTransitionAt(index);
 8233485        return operation.Kind != TraversalTransitionOverlayOperationKind.Upsert
 8233486            || ValidateTransition(
 8233487                state,
 8233488                operation.Transition,
 8233489                changedMapIds,
 8233490                changedStates);
 491    }
 492
 493    internal bool TryGetMap(string mapId, out NavigationMap map)
 494    {
 27495        if (_maps.TryGetValue(mapId, out MapState? state))
 496        {
 17497            map = state.Map;
 17498            return true;
 499        }
 500
 10501        map = null!;
 10502        return false;
 503    }
 504
 505    internal bool TryGetState(string mapId, out MapState? state) =>
 2053506        _maps.TryGetValue(mapId, out state);
 507
 508    internal bool TryGetSemanticState(
 509        NavigationCellAddress address,
 510        out NavigationCellSemanticSource source,
 511        out bool hasCell,
 512        out NavigationCell cell)
 513    {
 158095514        if (!_maps.TryGetValue(address.MapId, out MapState? state) || state == null)
 515        {
 426516            source = default;
 426517            hasCell = false;
 426518            cell = default;
 426519            return false;
 520        }
 157669521        int bakedSlot = state.BakedCellLookup.Find(address.Index);
 157669522        bool dynamic = bakedSlot < 0
 157669523            && state.DynamicAddresses.TryGetValue(address.Index, out _);
 157669524        if (bakedSlot < 0 && !dynamic)
 525        {
 74526            source = default;
 74527            hasCell = false;
 74528            cell = default;
 74529            return false;
 530        }
 157595531        if (state.Overlay.TryGetCell(
 157595532                address.Index,
 157595533                out NavigationCellOverlayOperation operation))
 534        {
 107352535            if (operation.Kind == NavigationCellOverlayOperationKind.Set)
 536            {
 107090537                source = dynamic
 107090538                    ? NavigationCellSemanticSource.DynamicOverlaySet
 107090539                    : NavigationCellSemanticSource.OverlaySet;
 107090540                hasCell = true;
 107090541                cell = operation.Cell;
 107090542                return true;
 543            }
 262544            source = NavigationCellSemanticSource.OverlaySuppressed;
 262545            hasCell = false;
 262546            cell = default;
 262547            return true;
 548        }
 50243549        if (dynamic)
 550        {
 222551            NavigationCell? defaultCell = state.Map.DefaultCell;
 222552            source = defaultCell.HasValue
 222553                ? NavigationCellSemanticSource.Baked
 222554                : NavigationCellSemanticSource.DynamicInactive;
 222555            hasCell = defaultCell.HasValue;
 222556            cell = defaultCell.GetValueOrDefault();
 222557            return true;
 558        }
 50021559        source = NavigationCellSemanticSource.Baked;
 50021560        hasCell = true;
 50021561        cell = state.Map.CellSpan[bakedSlot].Cell;
 50021562        return true;
 563    }
 564
 565    internal bool TryGetOverlay(string mapId, out NavigationMapOverlayState overlay)
 566    {
 49567        if (_maps.TryGetValue(mapId, out MapState? state))
 568        {
 48569            overlay = state.Overlay;
 48570            return true;
 571        }
 572
 1573        overlay = NavigationMapOverlayState.Empty;
 1574        return false;
 575    }
 576
 577    private void SetMapState(MapState? previous, MapState next)
 578    {
 1720579        if (previous != null)
 387580            RemoveMapStateTotals(previous);
 1720581        AddMapStateTotals(next);
 1720582        _maps = _maps.Set(next.Map.MapId, next, out int copiedNodes);
 1720583        RecordPersistentCopies(copiedNodes);
 1720584    }
 585
 586    private void AddMapStateTotals(MapState state)
 587    {
 1720588        _mapStateRetainedBytes = checked(
 1720589            _mapStateRetainedBytes
 1720590            + state.PreparedMapRetainedBytes
 1720591            + state.Overlay.RetainedBytes
 1720592            + state.DynamicAddresses.RetainedBytes);
 1720593        _mapStatePersistentPages = checked(
 1720594            _mapStatePersistentPages
 1720595            + state.Overlay.PersistentNodeCount
 1720596            + state.DynamicAddresses.PersistentNodeCount);
 1720597    }
 598
 599    private void RemoveMapStateTotals(MapState state)
 600    {
 404601        _mapStateRetainedBytes = checked(
 404602            _mapStateRetainedBytes
 404603            - state.PreparedMapRetainedBytes
 404604            - state.Overlay.RetainedBytes
 404605            - state.DynamicAddresses.RetainedBytes);
 404606        _mapStatePersistentPages = checked(
 404607            _mapStatePersistentPages
 404608            - state.Overlay.PersistentNodeCount
 404609            - state.DynamicAddresses.PersistentNodeCount);
 404610    }
 611
 612    private void ReplaceTotals(MapState? previous, MapState? next)
 613    {
 1737614        if (previous != null)
 615        {
 404616            _overlaySlotCount -= previous.Overlay.CellCount;
 404617            _overlayConnectionCount -= previous.Overlay.ConnectionCount;
 404618            _overlayTransitionCount -= previous.Overlay.TransitionCount;
 404619            _transitionRuleCount = checked(
 404620                _transitionRuleCount - previous.Map.TransitionRuleSpan.Length);
 404621            long previousConnections = previous.Map.ConnectionSpan.Length
 404622                + previous.Overlay.ConnectionCount;
 404623            _seamCandidateCount -= previousConnections;
 404624            _explicitEdgeCount -= previousConnections
 404625                + previous.Map.TransitionSpan.Length
 404626                + previous.Overlay.TransitionCount;
 404627            _dynamicCellCount = checked(_dynamicCellCount - previous.DynamicAddresses.Count);
 628        }
 629
 1737630        if (next != null)
 631        {
 1720632            _overlaySlotCount += next.Overlay.CellCount;
 1720633            _overlayConnectionCount += next.Overlay.ConnectionCount;
 1720634            _overlayTransitionCount += next.Overlay.TransitionCount;
 1720635            _transitionRuleCount = checked(
 1720636                _transitionRuleCount + next.Map.TransitionRuleSpan.Length);
 1720637            long nextConnections = next.Map.ConnectionSpan.Length
 1720638                + next.Overlay.ConnectionCount;
 1720639            _seamCandidateCount += nextConnections;
 1720640            _explicitEdgeCount += nextConnections
 1720641                + next.Map.TransitionSpan.Length
 1720642                + next.Overlay.TransitionCount;
 1720643            _dynamicCellCount = checked(_dynamicCellCount + next.DynamicAddresses.Count);
 644        }
 1737645    }
 646
 647    private void UpdateIncomingSource(string destinationMapId, string sourceMapId, bool remove)
 648    {
 4218649        bool hadSources = _incomingSources.TryGetValue(
 4218650            destinationMapId,
 4218651            out PersistentStringMap<bool> sources);
 4218652        sources ??= PersistentStringMap<bool>.Empty;
 4218653        long previousBytes = hadSources ? sources.RetainedBytes : 0;
 4218654        int previousPages = hadSources ? sources.PersistentNodeCount : 0;
 4218655        if (remove)
 656        {
 20657            sources = sources.Remove(sourceMapId, out bool removed, out int copiedNodes);
 20658            if (!removed)
 7659                return;
 13660            RecordPersistentCopies(copiedNodes);
 13661            if (sources.Count == 0)
 662            {
 12663                _incomingSources = _incomingSources.Remove(
 12664                    destinationMapId,
 12665                    out _,
 12666                    out copiedNodes);
 667            }
 668            else
 669            {
 1670                _incomingSources = _incomingSources.Set(
 1671                    destinationMapId,
 1672                    sources,
 1673                    out copiedNodes);
 674            }
 13675            RecordPersistentCopies(copiedNodes);
 676        }
 677        else
 678        {
 4198679            if (sources.ContainsKey(sourceMapId))
 4109680                return;
 89681            sources = sources.Set(sourceMapId, true, out int copiedNodes);
 89682            RecordPersistentCopies(copiedNodes);
 89683            _incomingSources = _incomingSources.Set(
 89684                destinationMapId,
 89685                sources,
 89686                out copiedNodes);
 89687            RecordPersistentCopies(copiedNodes);
 688        }
 102689        long nextBytes = sources.Count == 0 ? 0 : sources.RetainedBytes;
 102690        int nextPages = sources.Count == 0 ? 0 : sources.PersistentNodeCount;
 102691        _incomingSetRetainedBytes = checked(
 102692            _incomingSetRetainedBytes - previousBytes + nextBytes);
 102693        _incomingSetPersistentPages = checked(
 102694            _incomingSetPersistentPages - previousPages + nextPages);
 102695    }
 696
 697    private bool ValidateTransition(
 698        MapState source,
 699        TraversalTransitionDefinition transition,
 700        string[] changedMapIds,
 701        MapState[] changedStates)
 702    {
 8316703        if (!source.Map.GridBinding.IsValidIndex(transition.SourceIndex))
 1704            return false;
 705
 706        // NavigationMapBuilder validates authored source media. Once a map identity is
 707        // admitted, overlay and cross-map endpoints may deliberately remain dormant
 708        // until later publication supplies their requested medium.
 709
 8315710        if (transition.HasSourcePointOverride)
 711        {
 9712            bool hasSourcePrism = source.Map.GridBinding.TryGetCellPrism(
 9713                transition.SourceIndex,
 9714                out GridForge.Grids.Topology.GridCellPrism sourcePrism);
 715            System.Diagnostics.Debug.Assert(hasSourcePrism);
 9716            if (!sourcePrism.Contains(transition.SourcePointOverride))
 2717                return false;
 718        }
 719
 8313720        MapState? destination = FindChangedState(transition.Destination.MapId, changedMapIds, changedStates);
 8313721        if (destination == null && !_maps.TryGetValue(transition.Destination.MapId, out destination))
 11722            return true;
 8302723        if (!destination.Map.GridBinding.IsValidIndex(transition.Destination.Index))
 1724            return false;
 8301725        if (!HasDefinitionMedium(
 8301726                destination,
 8301727                transition.Destination.Index,
 8301728                transition.DestinationMedium)
 8301729            && !_bakeVersionHighWater.ContainsKey(destination.Map.MapId))
 3730            return false;
 731
 8298732        if (!transition.HasDestinationPointOverride)
 8291733            return true;
 734
 7735        bool hasDestinationPrism = destination.Map.GridBinding.TryGetCellPrism(
 7736            transition.Destination.Index,
 7737            out GridForge.Grids.Topology.GridCellPrism destinationPrism);
 738        System.Diagnostics.Debug.Assert(hasDestinationPrism);
 7739        return destinationPrism.Contains(transition.DestinationPointOverride);
 740    }
 741
 742    private static bool TryGetEffectiveCell(
 743        MapState state,
 744        GridForge.Spatial.VoxelIndex index,
 745        out NavigationCell cell)
 746    {
 9127747        if (TryFindCellOverlay(state.Overlay, index, out NavigationCellOverlayOperation operation))
 748        {
 8224749            cell = operation.Cell;
 8224750            return operation.Kind == NavigationCellOverlayOperationKind.Set;
 751        }
 903752        int baked = state.BakedCellLookup.Find(index);
 903753        if (baked >= 0)
 754        {
 896755            cell = state.Map.CellSpan[baked].Cell;
 896756            return true;
 757        }
 7758        NavigationCell? defaultCell = state.Map.GridBinding.IsValidIndex(index)
 7759            ? state.Map.DefaultCell
 7760            : null;
 7761        cell = defaultCell.GetValueOrDefault();
 7762        return defaultCell.HasValue;
 763    }
 764
 765    private static bool HasDefinitionMedium(
 766        MapState state,
 767        GridForge.Spatial.VoxelIndex index,
 768        TraversalMedium medium)
 769    {
 8301770        if (TryFindCellOverlay(
 8301771                state.Overlay,
 8301772                index,
 8301773                out NavigationCellOverlayOperation operation)
 8301774            && operation.Kind == NavigationCellOverlayOperationKind.Set
 8301775            && SupportsMedium(operation.Cell, medium))
 776        {
 8192777            return true;
 778        }
 109779        int baked = state.BakedCellLookup.Find(index);
 109780        if (baked >= 0)
 103781            return SupportsMedium(state.Map.CellSpan[baked].Cell, medium);
 6782        return state.Map.DefaultCell.HasValue
 6783            && SupportsMedium(state.Map.DefaultCell.Value, medium);
 784    }
 785
 786    private static bool SupportsMedium(NavigationCell cell, TraversalMedium medium)
 787    {
 788        System.Diagnostics.Debug.Assert(TraversalTransitionDefinition.IsKnownMedium(medium));
 8302789        TraversalMedia requested = medium == TraversalMedium.Solid
 8302790            ? TraversalMedia.Solid
 8302791            : medium == TraversalMedium.Gas
 8302792                ? TraversalMedia.Gas
 8302793                : TraversalMedia.Liquid;
 8302794        return (cell.Media & requested) != 0;
 795    }
 796
 797    private static MapState? FindChangedState(
 798        string mapId,
 799        string[] changedMapIds,
 800        MapState[] changedStates)
 801    {
 8313802        int low = 0;
 8313803        int high = changedMapIds.Length - 1;
 8328804        while (low <= high)
 805        {
 8313806            int middle = low + ((high - low) >> 1);
 8313807            int comparison = string.CompareOrdinal(changedMapIds[middle], mapId);
 8313808            if (comparison == 0)
 8298809                return changedStates[middle];
 15810            if (comparison < 0)
 11811                low = middle + 1;
 812            else
 4813                high = middle - 1;
 814        }
 815
 15816        return null;
 817    }
 818
 819    private static bool TryFindCellOverlay(
 820        NavigationMapOverlayState overlay,
 821        GridForge.Spatial.VoxelIndex index,
 822        out NavigationCellOverlayOperation operation)
 17428823        => overlay.TryGetCell(index, out operation);
 824
 825    internal sealed class MapState
 826    {
 2357827        internal MapState(
 2357828            NavigationMap map,
 2357829            long bakeVersion,
 2357830            long preparedMapRetainedBytes,
 2357831            NavigationMapOverlayState overlay,
 2357832            long dynamicSlotGeneration,
 2357833            PersistentVoxelIndexMap<byte>? dynamicAddresses = null,
 2357834            NavigationBakedCellLookup? bakedCellLookup = null)
 835        {
 2357836            Map = map;
 2357837            BakeVersion = bakeVersion;
 2357838            PreparedMapRetainedBytes = preparedMapRetainedBytes;
 2357839            Overlay = overlay;
 2357840            DynamicSlotGeneration = dynamicSlotGeneration;
 2357841            DynamicAddresses = dynamicAddresses ?? PersistentVoxelIndexMap<byte>.Empty;
 2357842            BakedCellLookup = bakedCellLookup ?? NavigationBakedCellLookup.Create(map);
 2357843        }
 844
 845        internal NavigationMap Map { get; }
 846
 847        internal long BakeVersion { get; }
 848
 849        internal long PreparedMapRetainedBytes { get; }
 850
 851        internal NavigationMapOverlayState Overlay { get; }
 852
 853        internal long DynamicSlotGeneration { get; }
 854
 855        internal PersistentVoxelIndexMap<byte> DynamicAddresses { get; }
 856
 857        internal NavigationBakedCellLookup BakedCellLookup { get; }
 858    }
 859}

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Map/Operations/NavigationOperationCandidate.ExplicitConnections.cs

#LineLine coverage
 1//=======================================================================
 2// NavigationOperationCandidate.ExplicitConnections.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 FixedMathSharp;
 10using GridForge.Grids.Topology;
 11
 12namespace Trailblazer.Pathing;
 13
 14internal sealed partial class NavigationOperationCandidate
 15{
 2263716    internal NavigationExplicitConnectionIndex ExplicitConnections => _explicitConnections;
 17
 3730618    internal int ExplicitChangedSourceCount => _explicitChangedSources.Count;
 19
 1999120    internal int ExplicitChangedOwnerCount => _explicitChangedOwners.Count;
 21
 22    internal string GetExplicitChangedSourceAt(int ordinal) =>
 12423        _explicitChangedSources.GetKeyAt(ordinal);
 24
 25    internal NavigationConnectionOwnerKey GetExplicitChangedOwnerAt(int ordinal) =>
 1716026        _explicitChangedOwners.GetAt(ordinal);
 27
 28    internal ExplicitConnectionRefreshWork BeginExplicitConnectionRefresh(
 29        string mapId,
 30        NavigationExplicitConnectionIndex foldSource,
 31        GridCellPrism[] corridorPrisms,
 32        Vector3d[] corridorWaypoints,
 33        NavigationCellAddress[] corridorAddresses,
 165034        NavigationAddressStampSet corridorAddressSet) => new(
 165035            this,
 165036            foldSource,
 165037            mapId,
 165038            transaction: null,
 165039            corridorPrisms,
 165040            corridorWaypoints,
 165041            corridorAddresses,
 165042            corridorAddressSet);
 43
 44    internal ExplicitConnectionRefreshWork BeginExplicitConnectionRefresh(
 45        NavigationOverlayTransaction transaction,
 46        NavigationExplicitConnectionIndex foldSource,
 47        GridCellPrism[] corridorPrisms,
 48        Vector3d[] corridorWaypoints,
 49        NavigationCellAddress[] corridorAddresses,
 29250        NavigationAddressStampSet corridorAddressSet) => new(
 29251            this,
 29252            foldSource,
 29253            mapId: null,
 29254            transaction,
 29255            corridorPrisms,
 29256            corridorWaypoints,
 29257            corridorAddresses,
 29258            corridorAddressSet);
 59
 60    private bool TrySelectConnection(
 61        NavigationConnectionOwnerKey owner,
 62        out MapState source,
 63        out NavigationConnection definition)
 64    {
 449765        if (!_maps.TryGetValue(owner.MapId, out source!))
 66        {
 167            definition = null!;
 168            return false;
 69        }
 449670        if (source.Overlay.TryGetConnection(
 449671                owner.ConnectionId,
 449672                out NavigationConnectionOverlayOperation overlay))
 73        {
 415874            if (overlay.Kind == NavigationConnectionOverlayOperationKind.Upsert)
 75            {
 414476                definition = overlay.Connection!;
 414477                return true;
 78            }
 1479            if (overlay.Kind == NavigationConnectionOverlayOperationKind.Suppress)
 80            {
 1481                definition = null!;
 1482                return false;
 83            }
 84        }
 33885        ReadOnlySpan<NavigationConnection> baked = source.Map.ConnectionSpan;
 33886        int low = 0;
 33887        int high = baked.Length - 1;
 86488        while (low <= high)
 89        {
 86290            int middle = low + ((high - low) >> 1);
 86291            int comparison = string.CompareOrdinal(baked[middle].Id, owner.ConnectionId);
 86292            if (comparison == 0)
 93            {
 33694                definition = baked[middle];
 33695                return true;
 96            }
 52697            if (comparison < 0)
 28398                low = middle + 1;
 99            else
 243100                high = middle - 1;
 101        }
 2102        definition = null!;
 2103        return false;
 104    }
 105
 106    private bool TryGetSemanticPrism(
 107        NavigationCellAddress address,
 108        NavigationConnection connection,
 109        bool validateAnchor,
 110        Vector3d anchor,
 111        out GridCellPrism prism,
 112        out NavigationCell cell,
 113        out bool dormant)
 114    {
 4709115        dormant = false;
 4709116        if (!_maps.TryGetValue(address.MapId, out MapState target))
 117        {
 62118            prism = default;
 62119            cell = default;
 62120            dormant = true;
 62121            return true;
 122        }
 4647123        if (!TryGetEffectiveCell(target, address.Index, out cell))
 124        {
 21125            prism = default;
 21126            if (IsKnownSuppressed(target, address.Index))
 127            {
 17128                dormant = true;
 17129                return true;
 130            }
 4131            return false;
 132        }
 4626133        if (connection.PortalRadiusClearance > cell.RadiusClearance
 4626134            || connection.PortalHeightClearance > cell.HeightClearance)
 135        {
 2136            prism = default;
 2137            return false;
 138        }
 4624139        bool hasPrism = target.Map.GridBinding.TryGetCellPrism(address.Index, out prism);
 140        System.Diagnostics.Debug.Assert(hasPrism);
 4624141        if (validateAnchor && !prism.Contains(anchor))
 142        {
 1143            prism = default;
 1144            return false;
 145        }
 4623146        return true;
 147    }
 148
 149    private static bool ValidateLowerBound(
 150        in GridCellPrism source,
 151        in GridCellPrism destination,
 152        NavigationCell destinationCell,
 153        NavigationConnection connection,
 154        Fixed64 corridorCost)
 155    {
 3156        Vector3d sourceFoot = new(source.Center.X, source.VerticalMin, source.Center.Z);
 3157        Vector3d destinationFoot = new(
 3158            destination.Center.X,
 3159            destination.VerticalMin,
 3160            destination.Center.Z);
 3161        bool hasApproach = Vector3d.TryGetDistance(
 3162            sourceFoot,
 3163            connection.EntryAnchor,
 3164            out Fixed64 approach);
 3165        bool hasDeparture = Vector3d.TryGetDistance(
 3166            connection.ExitAnchor,
 3167            destinationFoot,
 3168            out Fixed64 departure);
 169        System.Diagnostics.Debug.Assert(hasApproach && hasDeparture);
 3170        return Fixed64.TryAdd(approach, corridorCost, out Fixed64 total)
 3171            && Fixed64.TryAdd(total, departure, out total)
 3172            && Fixed64.TryAdd(total, connection.AdditionalCost, out total)
 3173            && Fixed64.TryAdd(total, destinationCell.EnterCost, out total)
 3174            && NavigationDistanceMath.TryCeiling(
 3175                sourceFoot,
 3176                destinationFoot,
 3177                out Fixed64 direct)
 3178            && total >= direct;
 179    }
 180
 181    private static NavigationExplicitConnectionRecord Dormant(
 182        NavigationConnectionOwnerKey owner,
 59183        NavigationConnection connection) => new(
 59184            owner,
 59185            connection,
 59186            isActive: false,
 59187            Fixed64.Zero,
 59188            NavigationPagedSequence<GridNavigationPortal>.Empty);
 189
 190    private static bool IsKnownSuppressed(MapState state, GridForge.Spatial.VoxelIndex index) =>
 26191        state.Overlay.TryGetCell(index, out NavigationCellOverlayOperation operation)
 26192        && operation.Kind == NavigationCellOverlayOperationKind.Suppress;
 193
 194    internal sealed class ExplicitConnectionRefreshWork
 195    {
 196        private const long BaseRetainedBytes = 792L;
 197
 198        private readonly NavigationOperationCandidate _candidate;
 199        private readonly NavigationExplicitConnectionIndex _foldSource;
 200        private readonly string? _mapId;
 201        private readonly NavigationOverlayTransaction? _transaction;
 202        private readonly GridCellPrism[] _corridorPrisms;
 203        private readonly Vector3d[] _corridorWaypoints;
 204        private readonly NavigationCellAddress[] _corridorAddresses;
 205        private readonly NavigationAddressStampSet _corridorAddressSet;
 1942206        private PersistentStringMap<PersistentStringMap<bool>> _owners =
 1942207            PersistentStringMap<PersistentStringMap<bool>>.Empty;
 208        private int _stage;
 209        private int _mapIndex;
 210        private int _itemIndex;
 211        private NavigationPagedSequence<NavigationConnectionOwnerKey>.Enumerator
 212            _incidentOwnerEnumerator;
 213        private NavigationConnectionOwnerKey _pendingIncidentOwner;
 214        private bool _incidentOwnerEnumerationStarted;
 215        private bool _hasPendingIncidentOwner;
 216        private int _compileMapIndex;
 217        private int _compileOwnerIndex;
 218        private NavigationConnectionOwnerKey _currentOwner;
 219        private MapState? _currentSource;
 220        private NavigationConnection? _currentDefinition;
 221        private NavigationExplicitConnectionRecord? _priorRecord;
 222        private NavigationExplicitConnectionRecord? _preparedRecord;
 223        private NavigationCell _destinationCell;
 224        private int _semanticIndex;
 225        private int _rawAddressIndex;
 226        private int _distinctAddressCount;
 227        private int _touchAddressIndex;
 228        private bool _currentInitialized;
 229        private bool _selectionCharged;
 230        private bool _isDormant;
 231        private bool _incidenceUnchanged;
 232        private bool _ownerUpdated;
 233        private bool _componentOwnerJournaled;
 234        private bool _corridorStarted;
 235        private GridNavigationCorridorValidationCursor _corridorCursor;
 236        private NavigationPagedSequence<GridNavigationPortal>.Builder? _portalBuilder;
 237        private int _portalCopyIndex;
 1942238        private PersistentStringMap<PersistentVoxelIndexMap<IncidenceRowDelta>> _rowDeltas =
 1942239            PersistentStringMap<PersistentVoxelIndexMap<IncidenceRowDelta>>.Empty;
 240        private IncidenceOwnerTree _finalOwners;
 241        private IncidenceOwnerTree.Node? _additionOwner;
 242        private NavigationConnection? _additionDefinition;
 243        private int _additionAddressIndex;
 244        private bool _additionOwnerInitialized;
 245        private int _rowMapIndex;
 246        private int _rowAddressIndex;
 247        private NavigationCellAddress _rowAddress;
 248        private IncidenceRowDelta? _rowDelta;
 249        private NavigationPagedSequence<NavigationConnectionOwnerKey>.Enumerator _priorRowOwners;
 250        private NavigationPagedSequence<NavigationConnectionOwnerKey>.Enumerator _additionRowOwners;
 251        private NavigationConnectionOwnerKey _priorRowOwner;
 252        private NavigationConnectionOwnerKey _additionRowOwner;
 253        private int _priorRowRemaining;
 254        private int _additionRowRemaining;
 255        private bool _priorRowOwnerReady;
 256        private bool _additionRowOwnerReady;
 257        private NavigationPagedSequence<NavigationConnectionOwnerKey>.Builder? _finalRowBuilder;
 258        private NavigationPagedSequence<NavigationConnectionOwnerKey>.Builder? _endpointRowBuilder;
 259        private NavigationConnectionOwnerKey _pendingEndpointOwner;
 260        private bool _endpointOwnerPending;
 261        private bool _incidentRowCommitted;
 262        private bool _rowInitialized;
 263        private long _rowDeltaInnerBytes;
 264        private int _rowDeltaInnerPages;
 265        private long _rowDeltaValueBytes;
 266        private int _rowDeltaValuePages;
 267        private long _innerOwnerBytes;
 268        private int _innerOwnerPages;
 269        private long _displacedSourcePayloadBytes;
 270        private int _displacedSourcePayloadPages;
 271
 1942272        internal ExplicitConnectionRefreshWork(
 1942273            NavigationOperationCandidate candidate,
 1942274            NavigationExplicitConnectionIndex foldSource,
 1942275            string? mapId,
 1942276            NavigationOverlayTransaction? transaction,
 1942277            GridCellPrism[] corridorPrisms,
 1942278            Vector3d[] corridorWaypoints,
 1942279            NavigationCellAddress[] corridorAddresses,
 1942280            NavigationAddressStampSet corridorAddressSet)
 281        {
 1942282            _candidate = candidate;
 1942283            _foldSource = foldSource;
 1942284            _mapId = mapId;
 1942285            _transaction = transaction;
 1942286            _corridorPrisms = corridorPrisms;
 1942287            _corridorWaypoints = corridorWaypoints;
 1942288            _corridorAddresses = corridorAddresses;
 1942289            _corridorAddressSet = corridorAddressSet;
 1942290        }
 291
 292        internal bool IsValid { get; private set; } = true;
 293
 2558294        internal long DisplacedSourcePayloadBytes => _displacedSourcePayloadBytes;
 295
 2557296        internal int DisplacedSourcePayloadPages => _displacedSourcePayloadPages;
 297
 2813298        internal long RetainedBytes => checked(
 2813299            BaseRetainedBytes
 2813300            + _owners.RetainedBytes
 2813301            + _innerOwnerBytes
 2813302            + _rowDeltas.RetainedBytes
 2813303            + _rowDeltaInnerBytes
 2813304            + _rowDeltaValueBytes
 2813305            + _finalOwners.RetainedBytes
 2813306            + (_finalRowBuilder?.RetainedBytes ?? 0)
 2813307            + (_endpointRowBuilder?.RetainedBytes ?? 0)
 2813308            + (_portalBuilder?.RetainedBytes ?? 0)
 2813309            + (_ownerUpdated ? 0 : _preparedRecord?.RetainedBytes ?? 0));
 310
 2556311        internal int PersistentPageCount => checked(
 2556312            1
 2556313            + _owners.PersistentNodeCount
 2556314            + _innerOwnerPages
 2556315            + _rowDeltas.PersistentNodeCount
 2556316            + _rowDeltaInnerPages
 2556317            + _rowDeltaValuePages
 2556318            + _finalOwners.PersistentPageCount
 2556319            + (_finalRowBuilder?.PersistentPageCount ?? 0)
 2556320            + (_endpointRowBuilder?.PersistentPageCount ?? 0)
 2556321            + (_portalBuilder?.PersistentPageCount ?? 0)
 2556322            + (_ownerUpdated ? 0 : _preparedRecord?.PersistentPageCount ?? 0));
 323
 324        internal bool Advance(MaintenanceWorkMeter meter)
 325        {
 2936326            if (_stage < 4 && !AdvanceGather(meter))
 164327                return false;
 2996328            while (_compileMapIndex < _owners.Count)
 329            {
 723330                PersistentStringMap<bool> map = _owners.GetValueAt(_compileMapIndex);
 5203331                while (_compileOwnerIndex < map.Count)
 332                {
 4979333                    if (!_currentInitialized)
 4497334                        InitializeCurrent(map);
 4979335                    if (!AdvanceCompilation(meter))
 256336                        return false;
 4723337                    if (!IsValid)
 15338                        return true;
 4708339                    if (!_componentOwnerJournaled
 4708340                        && HasComponentEdgeChanged(_priorRecord, _preparedRecord))
 341                    {
 4394342                        if (!meter.TryConsumeDependencyEntries(1))
 2343                            return false;
 4392344                        _candidate._explicitChangedOwners =
 4392345                            _candidate._explicitChangedOwners.Add(_currentOwner);
 4392346                        _componentOwnerJournaled = true;
 347                    }
 4706348                    _incidenceUnchanged = _priorRecord != null
 4706349                        && _preparedRecord != null
 4706350                        && ReferenceEquals(
 4706351                            _priorRecord.Definition,
 4706352                            _preparedRecord.Definition);
 4706353                    if (_incidenceUnchanged)
 50354                        UpdateOwner();
 4706355                    if (!_ownerUpdated)
 356                    {
 4611357                        if (!AdvanceDistinctAddresses(_priorRecord?.Definition, meter))
 91358                            return false;
 4520359                        if (!AdvanceOldIncidenceTouches(meter))
 89360                            return false;
 4431361                        UpdateOwner();
 362                    }
 4526363                    if (!_incidenceUnchanged)
 364                    {
 4476365                        if (_preparedRecord != null)
 366                        {
 4460367                            if (!meter.TryConsumeDependencyEntries(1))
 46368                                return false;
 4414369                            _finalOwners.Add(
 4414370                                _currentOwner,
 4414371                                _candidate._explicitConnections);
 372                        }
 373                    }
 4480374                    _compileOwnerIndex++;
 4480375                    ResetCurrent();
 376                }
 224377                _compileMapIndex++;
 224378                _compileOwnerIndex = 0;
 379            }
 2273380            if (!AdvanceFinalAdditions(meter))
 212381                return false;
 2061382            return AdvanceIncidenceRows(meter);
 383        }
 384
 385        private void InitializeCurrent(PersistentStringMap<bool> map)
 386        {
 4497387            _corridorAddressSet.Reset();
 4497388            _currentOwner = new NavigationConnectionOwnerKey(
 4497389                _owners.GetKeyAt(_compileMapIndex),
 4497390                map.GetKeyAt(_compileOwnerIndex));
 4497391            if (_candidate.TrySelectConnection(
 4497392                    _currentOwner,
 4497393                    out MapState source,
 4497394                    out NavigationConnection definition))
 395            {
 4480396                _currentSource = source;
 4480397                _currentDefinition = definition;
 398            }
 4497399            _candidate._explicitConnections.TryGet(_currentOwner, out _priorRecord!);
 4497400            _currentInitialized = true;
 4497401        }
 402
 403        private bool AdvanceCompilation(MaintenanceWorkMeter meter)
 404        {
 4979405            if (_preparedRecord != null)
 212406                return true;
 4767407            if (_currentDefinition == null)
 408            {
 32409                if (_selectionCharged)
 14410                    return true;
 18411                if (!meter.TryConsumeExplicitEdges(1))
 1412                    return false;
 17413                _selectionCharged = true;
 17414                return true;
 415            }
 416
 4735417            int semanticCount = _currentDefinition.Witnesses.Count + 2;
 418            System.Diagnostics.Debug.Assert(
 419                _corridorWaypoints.Length / 2 == _corridorPrisms.Length - 1);
 420            System.Diagnostics.Debug.Assert(semanticCount <= _corridorPrisms.Length);
 13913421            while (_semanticIndex < semanticCount)
 422            {
 9288423                if (!meter.TryConsumeExplicitEdges(1))
 99424                    return false;
 9189425                if (!CaptureSemanticPrism(_semanticIndex))
 426                {
 11427                    IsValid = false;
 11428                    return true;
 429                }
 9178430                _semanticIndex++;
 431            }
 4625432            if (_isDormant)
 433            {
 59434                _preparedRecord = Dormant(_currentOwner, _currentDefinition);
 59435                return true;
 436            }
 437
 4566438            int prismCount = semanticCount;
 4566439            if (!_corridorStarted)
 440            {
 4410441                _corridorCursor = new GridNavigationCorridorValidationCursor(
 4410442                    prismCount,
 4410443                    _currentDefinition.EntryAnchor,
 4410444                    _currentDefinition.ExitAnchor,
 4410445                    _currentDefinition.PortalRadiusClearance,
 4410446                    _currentDefinition.PortalHeightClearance);
 4410447                _corridorStarted = true;
 448            }
 26911449            while (_corridorCursor.Status == GridNavigationCorridorValidationStatus.InProgress)
 450            {
 22501451                if (!meter.TryConsumeExplicitEdges(1))
 156452                    return false;
 22345453                _corridorCursor.Advance(
 22345454                    _corridorPrisms.AsSpan(0, prismCount),
 22345455                    _corridorWaypoints.AsSpan(0, (prismCount - 1) * 2),
 22345456                    maxWork: 1);
 22345457                if (_corridorCursor.TryGetCurrentPortal(out GridNavigationPortal portal))
 458                {
 4556459                    _portalBuilder ??= new NavigationPagedSequence<GridNavigationPortal>.Builder(
 4556460                        elementBytes: GridNavigationPortal.SizeInBytes);
 4556461                    _portalBuilder.Append(portal);
 4556462                    _portalCopyIndex++;
 463                }
 464            }
 4410465            if (_corridorCursor.Status != GridNavigationCorridorValidationStatus.Complete)
 466            {
 2467                IsValid = false;
 2468                return true;
 469            }
 470            System.Diagnostics.Debug.Assert(_portalCopyIndex == prismCount - 1);
 4408471            if (_currentDefinition.IsLowerBoundCertified
 4408472                && !ValidateLowerBound(
 4408473                    _corridorPrisms[0],
 4408474                    _corridorPrisms[prismCount - 1],
 4408475                    _destinationCell,
 4408476                    _currentDefinition,
 4408477                    _corridorCursor.GeometricCost))
 478            {
 2479                IsValid = false;
 2480                return true;
 481            }
 482            // Every valid connection corridor contains source and destination prisms,
 483            // so successful validation always emits at least one portal.
 484            System.Diagnostics.Debug.Assert(_portalBuilder != null);
 4406485            NavigationPagedSequence<GridNavigationPortal> portals = _portalBuilder!.Seal();
 4406486            _portalBuilder = null;
 4406487            _preparedRecord = new NavigationExplicitConnectionRecord(
 4406488                _currentOwner,
 4406489                _currentDefinition,
 4406490                isActive: true,
 4406491                _corridorCursor.GeometricCost,
 4406492                portals,
 4406493                isLowerBoundCertified: _currentDefinition.IsLowerBoundCertified);
 4406494            return true;
 495        }
 496
 497        private bool CaptureSemanticPrism(int semanticIndex)
 498        {
 9189499            NavigationConnection connection = _currentDefinition!;
 9189500            if (semanticIndex == 0)
 501            {
 4480502                if (!TryGetEffectiveCell(
 4480503                        _currentSource!,
 4480504                        connection.SourceIndex,
 4480505                        out NavigationCell sourceCell))
 506                {
 5507                    if (IsKnownSuppressed(_currentSource!, connection.SourceIndex))
 508                    {
 4509                        _isDormant = true;
 4510                        _corridorPrisms[0] = default;
 4511                        return true;
 512                    }
 1513                    return false;
 514                }
 4475515                if (connection.PortalRadiusClearance > sourceCell.RadiusClearance
 4475516                    || connection.PortalHeightClearance > sourceCell.HeightClearance)
 517                {
 2518                    return false;
 519                }
 4473520                bool hasPrism = _currentSource!.Map.GridBinding.TryGetCellPrism(
 4473521                    connection.SourceIndex,
 4473522                    out _corridorPrisms[0]);
 523                System.Diagnostics.Debug.Assert(hasPrism);
 4473524                if (!_corridorPrisms[0].Contains(connection.EntryAnchor))
 1525                    return false;
 4472526                return true;
 527            }
 528
 4709529            bool isDestination = semanticIndex == connection.Witnesses.Count + 1;
 4709530            NavigationCellAddress address = isDestination
 4709531                ? connection.Destination
 4709532                : connection.Witnesses[semanticIndex - 1];
 4709533            if (!_candidate.TryGetSemanticPrism(
 4709534                    address,
 4709535                    connection,
 4709536                    validateAnchor: isDestination,
 4709537                    isDestination ? connection.ExitAnchor : default,
 4709538                    out _corridorPrisms[semanticIndex],
 4709539                    out NavigationCell cell,
 4709540                    out bool dormant))
 541            {
 7542                return false;
 543            }
 4702544            _isDormant |= dormant;
 4702545            if (isDestination && !dormant)
 4428546                _destinationCell = cell;
 4702547            return true;
 548        }
 549
 550        private bool AdvanceDistinctAddresses(
 551            NavigationConnection? definition,
 552            MaintenanceWorkMeter meter)
 553        {
 9236554            if (definition == null)
 4344555                return true;
 4892556            int rawCount = definition.Witnesses.Count + 2;
 14083557            while (_rawAddressIndex < rawCount)
 558            {
 9395559                if (!meter.TryConsumeDependencyEntries(1))
 204560                    return false;
 9191561                NavigationCellAddress address = GetRawAddress(
 9191562                    _currentOwner,
 9191563                    definition,
 9191564                    _rawAddressIndex++);
 9191565                if (_corridorAddressSet.Add(address))
 9190566                    _corridorAddresses[_distinctAddressCount++] = address;
 567            }
 4688568            return true;
 569        }
 570
 571        private bool AdvanceOldIncidenceTouches(MaintenanceWorkMeter meter)
 572        {
 4520573            if (_priorRecord == null)
 4344574                return true;
 372575            while (_touchAddressIndex < _distinctAddressCount)
 576            {
 285577                if (!meter.TryConsumeDependencyEntries(1))
 89578                    return false;
 196579                NavigationCellAddress address = _corridorAddresses[_touchAddressIndex++];
 196580                IncidenceRowDelta row = GetOrCreateRowDelta(address);
 196581                if (IsEndpoint(address, _currentOwner, _priorRecord.Definition))
 174582                    row.MarkEndpointTouched();
 583            }
 87584            return true;
 585        }
 586
 587        private void UpdateOwner()
 588        {
 4481589            if (_preparedRecord != null)
 590            {
 4465591                _candidate.RecordExplicitRecordOwnership(
 4465592                    _currentOwner,
 4465593                    _preparedRecord,
 4465594                    _foldSource,
 4465595                    ref _displacedSourcePayloadBytes,
 4465596                    ref _displacedSourcePayloadPages);
 4465597                _candidate._explicitConnections = _candidate._explicitConnections.SetOwner(
 4465598                    _preparedRecord,
 4465599                    out int copiedNodes);
 4465600                _candidate.RecordPersistentCopies(copiedNodes);
 601            }
 602            else
 603            {
 16604                _candidate.RecordExplicitRecordOwnership(
 16605                    _currentOwner,
 16606                    next: null,
 16607                    _foldSource,
 16608                    ref _displacedSourcePayloadBytes,
 16609                    ref _displacedSourcePayloadPages);
 16610                _candidate._explicitConnections = _candidate._explicitConnections.RemoveOwner(
 16611                    _currentOwner,
 16612                    out _,
 16613                    out int copiedNodes);
 16614                _candidate.RecordPersistentCopies(copiedNodes);
 615            }
 4481616            _ownerUpdated = true;
 4481617        }
 618
 619        private bool AdvanceFinalAdditions(MaintenanceWorkMeter meter)
 620        {
 4413621            while (true)
 622            {
 6686623                if (!_additionOwnerInitialized)
 624                {
 6475625                    _additionOwner = _finalOwners.GetSuccessor(_additionOwner);
 6475626                    if (_additionOwner == null)
 627                    {
 2061628                        _finalOwners.Clear();
 2061629                        return true;
 630                    }
 4414631                    _currentOwner = _additionOwner.Owner;
 4414632                    _candidate._explicitConnections.TryGet(
 4414633                        _currentOwner,
 4414634                        out NavigationExplicitConnectionRecord record);
 4414635                    _additionDefinition = record.Definition;
 4414636                    _corridorAddressSet.Reset();
 4414637                    _rawAddressIndex = 0;
 4414638                    _distinctAddressCount = 0;
 4414639                    _additionAddressIndex = 0;
 4414640                    _additionOwnerInitialized = true;
 641                }
 4625642                if (!AdvanceDistinctAddresses(_additionDefinition, meter))
 113643                    return false;
 13506644                while (_additionAddressIndex < _distinctAddressCount)
 645                {
 9093646                    if (!meter.TryConsumeDependencyEntries(1))
 99647                        return false;
 8994648                    IncidenceRowDelta row = GetOrCreateRowDelta(
 8994649                        _corridorAddresses[_additionAddressIndex++]);
 8994650                    long priorBytes = row.RetainedBytes;
 8994651                    int priorPages = row.PersistentPageCount;
 8994652                    row.AppendAddition(_currentOwner);
 8994653                    NavigationCellAddress address =
 8994654                        _corridorAddresses[_additionAddressIndex - 1];
 8994655                    if (IsEndpoint(address, _currentOwner, _additionDefinition!))
 8826656                        row.MarkEndpointTouched();
 8994657                    _rowDeltaValueBytes = checked(
 8994658                        _rowDeltaValueBytes - priorBytes + row.RetainedBytes);
 8994659                    _rowDeltaValuePages = checked(
 8994660                        _rowDeltaValuePages - priorPages + row.PersistentPageCount);
 661                }
 4413662                _additionOwnerInitialized = false;
 663            }
 664        }
 665
 666        private bool AdvanceIncidenceRows(MaintenanceWorkMeter meter)
 667        {
 2410668            while (_rowMapIndex < _rowDeltas.Count)
 669            {
 743670                PersistentVoxelIndexMap<IncidenceRowDelta> map =
 743671                    _rowDeltas.GetValueAt(_rowMapIndex);
 5321672                while (_rowAddressIndex < map.Count)
 673                {
 4972674                    if (!_rowInitialized)
 4578675                        InitializeRow(map);
 4972676                    if (!AdvancePriorRowFilter(meter))
 86677                        return false;
 4886678                    if (!AdvanceRowMerge(meter))
 222679                        return false;
 4664680                    if (!_incidentRowCommitted)
 681                    {
 4623682                        if (!meter.TryConsumeDependencyEntries(1))
 45683                            return false;
 4578684                        NavigationPagedSequence<NavigationConnectionOwnerKey> next =
 4578685                            _finalRowBuilder?.Seal()
 4578686                                ?? NavigationPagedSequence<NavigationConnectionOwnerKey>.Empty;
 4578687                        _finalRowBuilder = null;
 4578688                        NavigationPagedSequence<NavigationConnectionOwnerKey> prior =
 4578689                            _candidate._explicitConnections.GetIncidentOwnerRow(_rowAddress);
 4578690                        _candidate.RecordExplicitIncidenceOwnership(
 4578691                            _rowAddress,
 4578692                            next,
 4578693                            _foldSource,
 4578694                            ref _displacedSourcePayloadBytes,
 4578695                            ref _displacedSourcePayloadPages);
 4578696                        _candidate._explicitConnections =
 4578697                            _candidate._explicitConnections.SetIncidentRow(
 4578698                                _rowAddress,
 4578699                                prior,
 4578700                                next,
 4578701                                out int copiedNodes);
 4578702                        _candidate.RecordPersistentCopies(copiedNodes);
 4578703                        _incidentRowCommitted = true;
 704                    }
 4619705                    if (_rowDelta!.EndpointTouched)
 706                    {
 4499707                        if (!meter.TryConsumeDependencyEntries(1))
 41708                            return false;
 4458709                        NavigationPagedSequence<NavigationConnectionOwnerKey> next =
 4458710                            _endpointRowBuilder?.Seal()
 4458711                                ?? NavigationPagedSequence<NavigationConnectionOwnerKey>.Empty;
 4458712                        _endpointRowBuilder = null;
 4458713                        NavigationPagedSequence<NavigationConnectionOwnerKey> prior =
 4458714                            _candidate._explicitConnections.GetEndpointOwnerRow(_rowAddress);
 4458715                        _candidate.RecordExplicitEndpointOwnership(
 4458716                            _rowAddress,
 4458717                            next,
 4458718                            _foldSource,
 4458719                            ref _displacedSourcePayloadBytes,
 4458720                            ref _displacedSourcePayloadPages);
 4458721                        _candidate._explicitConnections =
 4458722                            _candidate._explicitConnections.SetEndpointRow(
 4458723                                _rowAddress,
 4458724                                prior,
 4458725                                next,
 4458726                                out int copiedNodes);
 4458727                        _candidate.RecordPersistentCopies(copiedNodes);
 728                    }
 4578729                    ReleaseCurrentRow();
 4578730                    _rowAddressIndex++;
 731                }
 349732                _rowMapIndex++;
 349733                _rowAddressIndex = 0;
 734            }
 1667735            _rowDeltas =
 1667736                PersistentStringMap<PersistentVoxelIndexMap<IncidenceRowDelta>>.Empty;
 1667737            _rowDeltaInnerBytes = 0;
 1667738            _rowDeltaInnerPages = 0;
 1667739            _rowDeltaValueBytes = 0;
 1667740            _rowDeltaValuePages = 0;
 1667741            return true;
 742        }
 743
 744        private void InitializeRow(PersistentVoxelIndexMap<IncidenceRowDelta> map)
 745        {
 4578746            _rowAddress = new NavigationCellAddress(
 4578747                _rowDeltas.GetKeyAt(_rowMapIndex),
 4578748                map.GetKeyAt(_rowAddressIndex));
 4578749            _rowDelta = map.GetValueAt(_rowAddressIndex);
 4578750            long priorBytes = _rowDelta.RetainedBytes;
 4578751            int priorPages = _rowDelta.PersistentPageCount;
 4578752            NavigationPagedSequence<NavigationConnectionOwnerKey> additions =
 4578753                _rowDelta.SealAdditions();
 4578754            _rowDeltaValueBytes = checked(
 4578755                _rowDeltaValueBytes - priorBytes + _rowDelta.RetainedBytes);
 4578756            _rowDeltaValuePages = checked(
 4578757                _rowDeltaValuePages - priorPages + _rowDelta.PersistentPageCount);
 4578758            NavigationPagedSequence<NavigationConnectionOwnerKey> prior =
 4578759                _candidate._explicitConnections.GetIncidentOwnerRow(_rowAddress);
 4578760            _priorRowOwners = prior.GetEnumerator();
 4578761            _priorRowRemaining = prior.Count;
 4578762            _additionRowOwners = additions.GetEnumerator();
 4578763            _additionRowRemaining = additions.Count;
 4578764            _rowInitialized = true;
 4578765        }
 766
 767        private bool AdvancePriorRowFilter(MaintenanceWorkMeter meter)
 768        {
 14568769            while (!_priorRowOwnerReady && _priorRowRemaining != 0)
 770            {
 464771                if (!meter.TryConsumeDependencyEntries(1))
 92772                    return false;
 372773                _priorRowOwners.MoveNext();
 372774                _priorRowOwner = _priorRowOwners.Current;
 372775                _priorRowRemaining--;
 372776                if (!IsIncidenceChanged(_priorRowOwner))
 180777                    _priorRowOwnerReady = true;
 778            }
 14104779            return true;
 780        }
 781
 782        private bool AdvanceRowMerge(MaintenanceWorkMeter meter)
 783        {
 22929784            while (_priorRowOwnerReady || _priorRowRemaining != 0
 22929785                || _additionRowOwnerReady || _additionRowRemaining != 0
 22929786                || _endpointOwnerPending)
 787            {
 18267788                if (_endpointOwnerPending)
 789                {
 8962790                    if (!meter.TryConsumeDependencyEntries(1))
 93791                        return false;
 8869792                    _endpointRowBuilder ??=
 8869793                        new NavigationPagedSequence<NavigationConnectionOwnerKey>.Builder(16);
 8869794                    _endpointRowBuilder.Append(_pendingEndpointOwner);
 8869795                    _endpointOwnerPending = false;
 8869796                    continue;
 797                }
 9305798                if (!_priorRowOwnerReady && !AdvancePriorRowFilter(meter))
 6799                    return false;
 9299800                if (!_additionRowOwnerReady && _additionRowRemaining != 0)
 801                {
 8994802                    _additionRowOwners.MoveNext();
 8994803                    _additionRowOwner = _additionRowOwners.Current;
 8994804                    _additionRowRemaining--;
 8994805                    _additionRowOwnerReady = true;
 806                }
 9299807                if (!_priorRowOwnerReady && !_additionRowOwnerReady)
 2808                    return true;
 9297809                if (!meter.TryConsumeDependencyEntries(1))
 123810                    return false;
 811                NavigationConnectionOwnerKey next;
 9174812                if (!_priorRowOwnerReady)
 813                {
 8988814                    next = _additionRowOwner;
 8988815                    _additionRowOwnerReady = false;
 816                }
 186817                else if (!_additionRowOwnerReady)
 818                {
 9819                    next = _priorRowOwner;
 9820                    _priorRowOwnerReady = false;
 821                }
 177822                else if (_candidate._explicitConnections.CompareOwners(
 177823                             _priorRowOwner,
 177824                             _additionRowOwner) <= 0)
 825                {
 171826                    next = _priorRowOwner;
 171827                    _priorRowOwnerReady = false;
 828                }
 829                else
 830                {
 6831                    next = _additionRowOwner;
 6832                    _additionRowOwnerReady = false;
 833                }
 9174834                _finalRowBuilder ??=
 9174835                    new NavigationPagedSequence<NavigationConnectionOwnerKey>.Builder(16);
 9174836                _finalRowBuilder.Append(next);
 9174837                bool hasFinalRecord = _candidate._explicitConnections.TryGet(
 9174838                    next,
 9174839                    out NavigationExplicitConnectionRecord record);
 840                System.Diagnostics.Debug.Assert(hasFinalRecord);
 9174841                if (_rowDelta!.EndpointTouched
 9174842                    && IsEndpoint(_rowAddress, next, record.Definition))
 843                {
 8869844                    _pendingEndpointOwner = next;
 8869845                    _endpointOwnerPending = true;
 846                }
 847            }
 4662848            return true;
 849        }
 850
 851        private bool IsIncidenceChanged(NavigationConnectionOwnerKey owner)
 852        {
 372853            if (!_owners.TryGetValue(owner.MapId, out PersistentStringMap<bool> map)
 372854                || !map.ContainsKey(owner.ConnectionId))
 855            {
 171856                return false;
 857            }
 201858            bool hadPrior = _foldSource.TryGet(
 201859                owner,
 201860                out NavigationExplicitConnectionRecord prior);
 201861            bool hasFinal = _candidate._explicitConnections.TryGet(
 201862                owner,
 201863                out NavigationExplicitConnectionRecord final);
 864            System.Diagnostics.Debug.Assert(hadPrior);
 201865            return !hasFinal || !ReferenceEquals(prior.Definition, final.Definition);
 866        }
 867
 868        private IncidenceRowDelta GetOrCreateRowDelta(NavigationCellAddress address)
 869        {
 9190870            bool hadMap = _rowDeltas.TryGetValue(
 9190871                address.MapId,
 9190872                out PersistentVoxelIndexMap<IncidenceRowDelta> existing);
 9190873            PersistentVoxelIndexMap<IncidenceRowDelta> map = hadMap
 9190874                ? existing
 9190875                : PersistentVoxelIndexMap<IncidenceRowDelta>.Empty;
 9190876            if (map.TryGetValue(address.Index, out IncidenceRowDelta delta))
 4608877                return delta;
 4582878            delta = new IncidenceRowDelta();
 4582879            long priorMapBytes = hadMap ? map.RetainedBytes : 0;
 4582880            int priorMapPages = hadMap ? map.PersistentNodeCount : 0;
 4582881            map = map.Set(address.Index, delta);
 4582882            _rowDeltas = _rowDeltas.Set(address.MapId, map);
 4582883            _rowDeltaInnerBytes = checked(
 4582884                _rowDeltaInnerBytes - priorMapBytes + map.RetainedBytes);
 4582885            _rowDeltaInnerPages = checked(
 4582886                _rowDeltaInnerPages - priorMapPages + map.PersistentNodeCount);
 4582887            _rowDeltaValueBytes = checked(_rowDeltaValueBytes + delta.RetainedBytes);
 4582888            _rowDeltaValuePages = checked(
 4582889                _rowDeltaValuePages + delta.PersistentPageCount);
 4582890            return delta;
 891        }
 892
 893        private void ReleaseCurrentRow()
 894        {
 4578895            long priorBytes = _rowDelta!.RetainedBytes;
 4578896            int priorPages = _rowDelta.PersistentPageCount;
 4578897            _rowDelta.ReleaseAdditions();
 4578898            _rowDeltaValueBytes = checked(
 4578899                _rowDeltaValueBytes - priorBytes + _rowDelta.RetainedBytes);
 4578900            _rowDeltaValuePages = checked(
 4578901                _rowDeltaValuePages - priorPages + _rowDelta.PersistentPageCount);
 4578902            _rowDelta = null;
 4578903            _priorRowOwners = default;
 4578904            _additionRowOwners = default;
 4578905            _priorRowRemaining = 0;
 4578906            _additionRowRemaining = 0;
 4578907            _priorRowOwnerReady = false;
 4578908            _additionRowOwnerReady = false;
 4578909            _endpointRowBuilder = null;
 4578910            _pendingEndpointOwner = default;
 4578911            _endpointOwnerPending = false;
 4578912            _incidentRowCommitted = false;
 4578913            _rowInitialized = false;
 4578914        }
 915
 916        private static bool IsEndpoint(
 917            NavigationCellAddress address,
 918            NavigationConnectionOwnerKey owner,
 919            NavigationConnection definition) =>
 18064920                address.Equals(new NavigationCellAddress(owner.MapId, definition.SourceIndex))
 18064921                || address.Equals(definition.Destination);
 922
 923        private static NavigationCellAddress GetRawAddress(
 924            NavigationConnectionOwnerKey owner,
 925            NavigationConnection connection,
 926            int rawIndex)
 927        {
 9191928            if (rawIndex == 0)
 4500929                return new NavigationCellAddress(owner.MapId, connection.SourceIndex);
 4691930            if (rawIndex == connection.Witnesses.Count + 1)
 4500931                return connection.Destination;
 191932            return connection.Witnesses[rawIndex - 1];
 933        }
 934
 935        private void ResetCurrent()
 936        {
 4480937            _currentOwner = default;
 4480938            _currentSource = null;
 4480939            _currentDefinition = null;
 4480940            _priorRecord = null;
 4480941            _preparedRecord = null;
 4480942            _destinationCell = default;
 4480943            _semanticIndex = 0;
 4480944            _rawAddressIndex = 0;
 4480945            _distinctAddressCount = 0;
 4480946            _touchAddressIndex = 0;
 4480947            _currentInitialized = false;
 4480948            _selectionCharged = false;
 4480949            _isDormant = false;
 4480950            _incidenceUnchanged = false;
 4480951            _ownerUpdated = false;
 4480952            _componentOwnerJournaled = false;
 4480953            _corridorStarted = false;
 4480954            _corridorCursor = default;
 4480955            _portalBuilder = null;
 4480956            _portalCopyIndex = 0;
 4480957        }
 958
 959        private static bool HasComponentEdgeChanged(
 960            NavigationExplicitConnectionRecord? prior,
 961            NavigationExplicitConnectionRecord? next)
 962        {
 4688963            bool priorActive = prior?.IsActive ?? false;
 4688964            bool nextActive = next?.IsActive ?? false;
 4688965            if (priorActive != nextActive)
 4368966                return true;
 320967            if (!priorActive)
 47968                return false;
 273969            return prior!.Source != next!.Source
 273970                || prior.Destination != next.Destination
 273971                || prior.IsLowerBoundCertified != next.IsLowerBoundCertified
 273972                || prior.CorridorCost != next.CorridorCost
 273973                || !prior.Definition.Equals(next.Definition)
 273974                || !PortalsEqual(prior.NavigationPortals, next.NavigationPortals);
 975        }
 976
 977        private static bool PortalsEqual(
 978            NavigationPagedSequence<GridNavigationPortal> left,
 979            NavigationPagedSequence<GridNavigationPortal> right)
 980        {
 981            System.Diagnostics.Debug.Assert(left.Count == right.Count);
 248982            NavigationPagedSequence<GridNavigationPortal>.Enumerator leftValues =
 248983                left.GetEnumerator();
 248984            NavigationPagedSequence<GridNavigationPortal>.Enumerator rightValues =
 248985                right.GetEnumerator();
 496986            while (leftValues.MoveNext())
 987            {
 249988                rightValues.MoveNext();
 249989                if (!PortalEquals(leftValues.Current, rightValues.Current))
 1990                    return false;
 991            }
 247992            return true;
 993        }
 994
 995        private static bool PortalEquals(
 996            GridNavigationPortal left,
 997            GridNavigationPortal right) =>
 249998            left.FaceKind == right.FaceKind
 249999            & left.SourceToTarget == right.SourceToTarget
 2491000            & left.CanonicalFacePoint == right.CanonicalFacePoint
 2491001            & left.MaximumHorizontalRadius == right.MaximumHorizontalRadius
 2491002            & left.MaximumBodyHeight == right.MaximumBodyHeight
 2491003            & left.VerticalFaceSegmentStart == right.VerticalFaceSegmentStart
 2491004            & left.VerticalFaceSegmentEnd == right.VerticalFaceSegmentEnd;
 1005
 1006        private bool AdvanceGather(MaintenanceWorkMeter meter)
 1007        {
 18491008            if (_transaction != null)
 2961009                return AdvanceOverlayGather(meter);
 71251010            while (_stage < 4)
 1011            {
 57321012                _candidate._maps.TryGetValue(_mapId!, out MapState state);
 57321013                int count = _stage switch
 57321014                {
 14311015                    0 => _candidate._explicitConnections.GetSourceOwnerCount(_mapId!),
 14731016                    1 => _candidate._explicitConnections.GetIncidentAddressCount(_mapId!),
 14351017                    2 => state == null ? 0 : state.Map.ConnectionSpan.Length,
 13931018                    _ => state == null ? 0 : state.Overlay.ConnectionCount
 57321019                };
 61241020                while (_itemIndex < count)
 1021                {
 5521022                    if (_stage == 1)
 1023                    {
 1341024                        NavigationCellAddress address = _candidate._explicitConnections
 1341025                            .GetIncidentAddressAt(_mapId!, _itemIndex);
 1341026                        if (!AdvanceIncidentOwners(address, meter))
 801027                            return false;
 541028                        _itemIndex++;
 541029                        continue;
 1030                    }
 4181031                    NavigationConnectionOwnerKey owner = _stage switch
 4181032                    {
 931033                        0 => _candidate._explicitConnections
 931034                            .GetSourceOwnerAt(_mapId!, _itemIndex).Owner,
 3221035                        2 => new NavigationConnectionOwnerKey(
 3221036                            _mapId!,
 3221037                            state!.Map.ConnectionSpan[_itemIndex].Id),
 31038                        _ => new NavigationConnectionOwnerKey(
 31039                            _mapId!,
 31040                            state!.Overlay.GetConnectionAt(_itemIndex).Id)
 4181041                    };
 4181042                    if (!AddOwner(owner, meter))
 801043                        return false;
 3381044                    _itemIndex++;
 1045                }
 55721046                _stage++;
 55721047                _itemIndex = 0;
 1048            }
 13931049            return true;
 1050        }
 1051
 1052        private bool AdvanceOverlayGather(MaintenanceWorkMeter meter)
 1053        {
 2961054            ReadOnlySpan<NavigationMapOverlayDelta> maps = _transaction!.MapSpan;
 6351055            while (_mapIndex < maps.Length)
 1056            {
 3431057                NavigationMapOverlayDelta map = maps[_mapIndex];
 3431058                if (_stage == 0)
 1059                {
 3421060                    ReadOnlySpan<NavigationCellOverlayOperation> cells = map.CellSpan;
 175261061                    while (_itemIndex < cells.Length)
 1062                    {
 171871063                        if (!AdvanceIncidentOwners(
 171871064                                new NavigationCellAddress(map.MapId, cells[_itemIndex].Index),
 171871065                                meter))
 1066                        {
 31067                            return false;
 1068                        }
 171841069                        _itemIndex++;
 1070                    }
 3391071                    _stage = 1;
 3391072                    _itemIndex = 0;
 1073                }
 3401074                ReadOnlySpan<NavigationConnectionOverlayOperation> connections = map.ConnectionSpan;
 44961075                while (_itemIndex < connections.Length)
 1076                {
 41571077                    if (!AddOwner(
 41571078                            new NavigationConnectionOwnerKey(map.MapId, connections[_itemIndex].Id),
 41571079                            meter))
 11080                        return false;
 41561081                    _itemIndex++;
 1082                }
 3391083                _mapIndex++;
 3391084                _stage = 0;
 3391085                _itemIndex = 0;
 1086            }
 2921087            _stage = 4;
 2921088            return true;
 1089        }
 1090
 1091        private bool AddOwner(NavigationConnectionOwnerKey owner, MaintenanceWorkMeter meter)
 1092        {
 48351093            if (!meter.TryConsumeDependencyEntries(1))
 1641094                return false;
 46711095            PersistentStringMap<bool> map = _owners.TryGetValue(
 46711096                owner.MapId,
 46711097                out PersistentStringMap<bool> existing)
 46711098                    ? existing
 46711099                    : PersistentStringMap<bool>.Empty;
 46711100            if (!map.ContainsKey(owner.ConnectionId))
 1101            {
 44971102                long priorBytes = map.RetainedBytes;
 44971103                int priorPages = map.PersistentNodeCount;
 44971104                map = map.Set(owner.ConnectionId, true);
 44971105                _owners = _owners.Set(owner.MapId, map);
 44971106                _innerOwnerBytes = checked(
 44971107                    _innerOwnerBytes - priorBytes + map.RetainedBytes);
 44971108                _innerOwnerPages = checked(
 44971109                    _innerOwnerPages - priorPages + map.PersistentNodeCount);
 1110            }
 46711111            if (!_candidate._explicitChangedSources.ContainsKey(owner.MapId))
 1112            {
 2021113                _candidate._explicitChangedSources =
 2021114                    _candidate._explicitChangedSources.Set(owner.MapId, true);
 1115            }
 46711116            return true;
 1117        }
 1118
 1119        private bool AdvanceIncidentOwners(
 1120            NavigationCellAddress address,
 1121            MaintenanceWorkMeter meter)
 1122        {
 173211123            if (!_incidentOwnerEnumerationStarted)
 1124            {
 172381125                _incidentOwnerEnumerator =
 172381126                    _candidate._explicitConnections.GetIncidentOwnerEnumerator(address);
 172381127                _incidentOwnerEnumerationStarted = true;
 1128            }
 1771129            while (true)
 1130            {
 174981131                if (!_hasPendingIncidentOwner)
 1132                {
 174151133                    if (!_incidentOwnerEnumerator.MoveNext())
 1134                    {
 172381135                        _incidentOwnerEnumerationStarted = false;
 172381136                        return true;
 1137                    }
 1771138                    _pendingIncidentOwner = _incidentOwnerEnumerator.Current;
 1771139                    _hasPendingIncidentOwner = true;
 1140                }
 2601141                if (!AddOwner(_pendingIncidentOwner, meter))
 831142                    return false;
 1771143                _hasPendingIncidentOwner = false;
 1144            }
 1145        }
 1146
 1147        private sealed class IncidenceRowDelta
 1148        {
 1149            private NavigationPagedSequence<NavigationConnectionOwnerKey>.Builder?
 1150                _additionBuilder;
 1151            private NavigationPagedSequence<NavigationConnectionOwnerKey>? _additions;
 1152
 408821153            internal long RetainedBytes => checked(
 408821154                40L
 408821155                + (_additionBuilder?.RetainedBytes ?? _additions?.RetainedBytes ?? 0));
 1156
 408821157            internal int PersistentPageCount => checked(
 408821158                1
 408821159                + (_additionBuilder?.PersistentPageCount
 408821160                    ?? _additions?.PersistentPageCount
 408821161                    ?? 0));
 1162
 1163            internal void AppendAddition(NavigationConnectionOwnerKey owner)
 1164            {
 89941165                _additionBuilder ??=
 89941166                    new NavigationPagedSequence<NavigationConnectionOwnerKey>.Builder(16);
 89941167                _additionBuilder.Append(owner);
 89941168            }
 1169
 1170            internal bool EndpointTouched { get; private set; }
 1171
 90001172            internal void MarkEndpointTouched() => EndpointTouched = true;
 1173
 1174            internal NavigationPagedSequence<NavigationConnectionOwnerKey> SealAdditions()
 1175            {
 45781176                _additions = _additionBuilder?.Seal()
 45781177                    ?? NavigationPagedSequence<NavigationConnectionOwnerKey>.Empty;
 45781178                _additionBuilder = null;
 45781179                return _additions;
 1180            }
 1181
 1182            internal void ReleaseAdditions()
 1183            {
 45781184                _additionBuilder = null;
 45781185                _additions = null;
 45781186            }
 1187        }
 1188
 1189        private struct IncidenceOwnerTree
 1190        {
 1191            private Node? _root;
 1192            private int _count;
 1193
 28131194            internal long RetainedBytes => checked((long)_count * 64L);
 1195
 25561196            internal int PersistentPageCount => _count;
 1197
 1198            internal void Add(
 1199                NavigationConnectionOwnerKey owner,
 1200                NavigationExplicitConnectionIndex index)
 1201            {
 44141202                if (_root == null)
 1203                {
 1611204                    _root = new Node(owner, null);
 1611205                    _count = 1;
 1611206                    return;
 1207                }
 42531208                Node current = _root;
 1209                while (true)
 1210                {
 375101211                    int comparison = index.CompareOwners(owner, current.Owner);
 1212                    System.Diagnostics.Debug.Assert(comparison != 0);
 375101213                    if (comparison < 0)
 1214                    {
 161215                        if (current.Left != null)
 1216                        {
 51217                            current = current.Left;
 51218                            continue;
 1219                        }
 111220                        current.Left = new Node(owner, current);
 111221                        _count++;
 111222                        Rebalance(current);
 111223                        return;
 1224                    }
 374941225                    if (current.Right != null)
 1226                    {
 332521227                        current = current.Right;
 332521228                        continue;
 1229                    }
 42421230                    current.Right = new Node(owner, current);
 42421231                    _count++;
 42421232                    Rebalance(current);
 42421233                    return;
 1234                }
 1235            }
 1236
 1237            internal Node? GetSuccessor(Node? current)
 1238            {
 64751239                if (current == null)
 20621240                    return Minimum(_root);
 44131241                if (current.Right != null)
 21301242                    return Minimum(current.Right);
 22831243                Node child = current;
 22831244                Node? parent = current.Parent;
 44131245                while (parent != null && ReferenceEquals(parent.Right, child))
 1246                {
 21301247                    child = parent;
 21301248                    parent = parent.Parent;
 1249                }
 22831250                return parent;
 1251            }
 1252
 1253            internal void Clear()
 1254            {
 20611255                _root = null;
 20611256                _count = 0;
 20611257            }
 1258
 1259            private static Node? Minimum(Node? node)
 1260            {
 63151261                while (node?.Left != null)
 21231262                    node = node.Left;
 41921263                return node;
 1264            }
 1265
 1266            private void Rebalance(Node? node)
 1267            {
 417631268                while (node != null)
 1269                {
 375101270                    UpdateHeight(node);
 375101271                    int balance = Height(node.Left) - Height(node.Right);
 375101272                    if (balance > 1)
 1273                    {
 21274                        if (Height(node.Left!.Left) < Height(node.Left.Right))
 11275                            RotateLeft(node.Left);
 21276                        node = RotateRight(node);
 1277                    }
 375081278                    else if (balance < -1)
 1279                    {
 41711280                        if (Height(node.Right!.Right) < Height(node.Right.Left))
 11281                            RotateRight(node.Right);
 41711282                        node = RotateLeft(node);
 1283                    }
 375101284                    node = node.Parent;
 1285                }
 42531286            }
 1287
 1288            private Node RotateLeft(Node node)
 1289            {
 41721290                Node pivot = node.Right!;
 41721291                ReplaceParentLink(node, pivot);
 41721292                node.Right = pivot.Left;
 41721293                if (node.Right != null)
 20581294                    node.Right.Parent = node;
 41721295                pivot.Left = node;
 41721296                node.Parent = pivot;
 41721297                UpdateHeight(node);
 41721298                UpdateHeight(pivot);
 41721299                return pivot;
 1300            }
 1301
 1302            private Node RotateRight(Node node)
 1303            {
 31304                Node pivot = node.Left!;
 31305                ReplaceParentLink(node, pivot);
 31306                node.Left = pivot.Right;
 31307                if (node.Left != null)
 11308                    node.Left.Parent = node;
 31309                pivot.Right = node;
 31310                node.Parent = pivot;
 31311                UpdateHeight(node);
 31312                UpdateHeight(pivot);
 31313                return pivot;
 1314            }
 1315
 1316            private void ReplaceParentLink(Node node, Node replacement)
 1317            {
 41751318                Node? parent = node.Parent;
 41751319                replacement.Parent = parent;
 41751320                if (parent == null)
 571321                    _root = replacement;
 41181322                else if (ReferenceEquals(parent.Left, node))
 11323                    parent.Left = replacement;
 1324                else
 41171325                    parent.Right = replacement;
 41171326            }
 1327
 1750861328            private static int Height(Node? node) => node?.Height ?? 0;
 1329
 1330            private static void UpdateHeight(Node node) =>
 458601331                node.Height = 1 + Math.Max(Height(node.Left), Height(node.Right));
 1332
 1333            internal sealed class Node
 1334            {
 44141335                internal Node(NavigationConnectionOwnerKey owner, Node? parent)
 1336                {
 44141337                    Owner = owner;
 44141338                    Parent = parent;
 44141339                }
 1340
 1341                internal NavigationConnectionOwnerKey Owner { get; }
 1342
 1343                internal Node? Parent { get; set; }
 1344
 1345                internal Node? Left { get; set; }
 1346
 1347                internal Node? Right { get; set; }
 1348
 1349                internal int Height { get; set; } = 1;
 1350            }
 1351        }
 1352    }
 1353}

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Map/Operations/NavigationOperationCandidate.MapFold.cs

#LineLine coverage
 1//=======================================================================
 2// NavigationOperationCandidate.MapFold.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 FixedMathSharp;
 10using GridForge.Grids.Topology;
 11
 12namespace Trailblazer.Pathing;
 13
 14internal sealed partial class NavigationOperationCandidate
 15{
 16    internal MapFoldCursor BeginMapFold(
 17        PreparedNavigationMap prepared,
 18        OverlayReplacementPolicy replacementPolicy,
 19        NavigationOperationLimits limits,
 20        GridCellPrism[] corridorPrisms,
 21        Vector3d[] corridorWaypoints,
 22        NavigationCellAddress[] corridorAddresses,
 139723        NavigationAddressStampSet corridorAddressSet) => new(
 139724            this,
 139725            prepared,
 139726            replacementPolicy,
 139727            limits,
 139728            corridorPrisms,
 139729            corridorWaypoints,
 139730            corridorAddresses,
 139731            corridorAddressSet);
 32
 33    internal MapFoldCursor BeginMapRemovalFold(
 34        string mapId,
 35        GridCellPrism[] corridorPrisms,
 36        Vector3d[] corridorWaypoints,
 37        NavigationCellAddress[] corridorAddresses,
 1838        NavigationAddressStampSet corridorAddressSet) => new(
 1839            this,
 1840            mapId,
 1841            corridorPrisms,
 1842            corridorWaypoints,
 1843            corridorAddresses,
 1844            corridorAddressSet);
 45
 46    internal sealed class MapFoldCursor
 47    {
 48        private readonly NavigationOperationCandidate _working;
 49        private readonly NavigationOperationCandidate _foldSource;
 50        private readonly PreparedNavigationMap? _prepared;
 51        private readonly OverlayReplacementPolicy _replacementPolicy;
 52        private readonly NavigationOperationLimits _limits;
 53        private readonly GridCellPrism[]? _corridorPrisms;
 54        private readonly Vector3d[]? _corridorWaypoints;
 55        private readonly NavigationCellAddress[] _corridorAddresses;
 56        private readonly NavigationAddressStampSet _corridorAddressSet;
 57        private readonly string _mapId;
 58        private readonly MapState? _current;
 59        private readonly NavigationExplicitConnectionIndex _sourceExplicitConnections;
 60        private MapState? _next;
 141561        private readonly string[] _changedMapIds = new string[1];
 141562        private readonly MapState[] _changedStates = new MapState[1];
 63        private NavigationOperationRejection _rejection;
 64        private bool _defaultCellValidated;
 65        private int _cellIndex;
 66        private int _overlayCellIndex;
 67        private int _dynamicIndex;
 68        private int _authoredIndex;
 69        private int _ruleValidationMapIndex;
 70        private int _ruleValidationSourceIndex;
 71        private int _ruleValidationTargetIndex;
 72        private bool _ruleValidationMapDebited;
 141573        private int _validationSourceIndex = -1;
 74        private int _validationStage;
 75        private int _validationIndex;
 76        private int _dependencyStage;
 77        private int _dependencyIndex;
 141578        private bool _removeDependencies = true;
 79        private ExplicitConnectionRefreshWork? _explicitRefresh;
 80        private long _displacedMapStatePayloadBytes;
 81        private int _displacedMapStatePayloadPages;
 82        private Stage _stage;
 83
 139784        internal MapFoldCursor(
 139785            NavigationOperationCandidate source,
 139786            PreparedNavigationMap prepared,
 139787            OverlayReplacementPolicy replacementPolicy,
 139788            NavigationOperationLimits limits,
 139789            GridCellPrism[] corridorPrisms,
 139790            Vector3d[] corridorWaypoints,
 139791            NavigationCellAddress[] corridorAddresses,
 139792            NavigationAddressStampSet corridorAddressSet)
 93        {
 139794            _working = source.Clone();
 139795            _foldSource = source;
 139796            _sourceExplicitConnections = source.ExplicitConnections;
 139797            _prepared = prepared;
 139798            _replacementPolicy = replacementPolicy;
 139799            _limits = limits;
 1397100            _corridorPrisms = corridorPrisms;
 1397101            _corridorWaypoints = corridorWaypoints;
 1397102            _corridorAddresses = corridorAddresses;
 1397103            _corridorAddressSet = corridorAddressSet;
 1397104            _mapId = prepared.Map.MapId;
 1397105            _working._maps.TryGetValue(_mapId, out _current);
 1397106            _changedMapIds[0] = _mapId;
 1397107            PrepareCommit();
 1397108        }
 109
 18110        internal MapFoldCursor(
 18111            NavigationOperationCandidate source,
 18112            string mapId,
 18113            GridCellPrism[] corridorPrisms,
 18114            Vector3d[] corridorWaypoints,
 18115            NavigationCellAddress[] corridorAddresses,
 18116            NavigationAddressStampSet corridorAddressSet)
 117        {
 18118            _working = source.Clone();
 18119            _foldSource = source;
 18120            _sourceExplicitConnections = source.ExplicitConnections;
 18121            _prepared = null;
 18122            _replacementPolicy = OverlayReplacementPolicy.Clear;
 18123            _limits = default;
 18124            _mapId = mapId;
 18125            _corridorPrisms = corridorPrisms;
 18126            _corridorWaypoints = corridorWaypoints;
 18127            _corridorAddresses = corridorAddresses;
 18128            _corridorAddressSet = corridorAddressSet;
 18129            _working._maps.TryGetValue(mapId, out _current);
 18130            _changedMapIds[0] = mapId;
 18131            if (_current == null)
 132            {
 1133                _stage = Stage.Complete;
 1134                _rejection = NavigationOperationRejection.MissingMap;
 135            }
 136            else
 137            {
 17138                _stage = Stage.Dependencies;
 17139                _rejection = NavigationOperationRejection.None;
 140            }
 17141        }
 142
 61656143        internal NavigationOperationCandidate Candidate => _working;
 144
 145        internal long DisplacedExplicitPayloadBytes =>
 9258146            _explicitRefresh?.DisplacedSourcePayloadBytes ?? 0L;
 147
 148        internal int DisplacedExplicitPayloadPages =>
 9259149            _explicitRefresh?.DisplacedSourcePayloadPages ?? 0;
 150
 9261151        internal long DisplacedMapStatePayloadBytes => _displacedMapStatePayloadBytes;
 152
 9261153        internal int DisplacedMapStatePayloadPages => _displacedMapStatePayloadPages;
 154
 9260155        internal long RetainedBytes => checked(
 9260156            128L
 9260157            + ((long)(_changedMapIds.Length + _changedStates.Length) * System.IntPtr.Size)
 9260158            + _working.WorkCopiedPersistentBytes
 9260159            + (_explicitRefresh?.RetainedBytes ?? 0)
 9260160            + GetPendingStateGrowthBytes());
 161
 9261162        internal int PersistentPageCount => checked(
 9261163            1
 9261164            + _working.WorkCopiedPersistentPages
 9261165            + (_explicitRefresh?.PersistentPageCount ?? 0)
 9261166            + GetPendingStateGrowthPages());
 167
 168        private long GetPendingStateGrowthBytes()
 169        {
 9260170            if (_next == null || _stage == Stage.Complete)
 1154171                return 0;
 8106172            GetAdditionalMapStatePayload(_next, _current, out long bytes, out _);
 8106173            return bytes;
 174        }
 175
 176        private int GetPendingStateGrowthPages()
 177        {
 9261178            if (_next == null || _stage == Stage.Complete)
 1153179                return 0;
 8108180            GetAdditionalMapStatePayload(_next, _current, out _, out int pages);
 8108181            return pages;
 182        }
 183
 184        internal bool Advance(
 185            MaintenanceWorkMeter meter,
 186            out NavigationOperationRejection rejection)
 187        {
 4565188            if (_rejection != NavigationOperationRejection.None)
 189            {
 11190                rejection = _rejection;
 11191                return true;
 192            }
 4554193            if (_stage == Stage.Cells && !AdvanceCells(meter))
 194            {
 1987195                rejection = NavigationOperationRejection.None;
 1987196                return false;
 197            }
 2567198            if (_stage == Stage.Dynamic && !AdvanceDynamic(meter))
 199            {
 3200                rejection = NavigationOperationRejection.None;
 3201                return false;
 202            }
 2564203            if (_stage == Stage.AuthoredValidation && !AdvanceAuthoredValidation(meter))
 204            {
 12205                rejection = NavigationOperationRejection.None;
 12206                return false;
 207            }
 2552208            if (_stage == Stage.Validation && !AdvanceValidation(meter))
 209            {
 1210                rejection = NavigationOperationRejection.None;
 1211                return false;
 212            }
 2551213            if (_rejection != NavigationOperationRejection.None)
 214            {
 9215                rejection = _rejection;
 9216                return true;
 217            }
 2542218            if (_stage == Stage.Dependencies && !AdvanceDependencies(meter))
 219            {
 4220                rejection = NavigationOperationRejection.None;
 4221                return false;
 222            }
 2538223            if (_stage == Stage.Commit)
 1393224                Commit();
 225            System.Diagnostics.Debug.Assert(_stage == Stage.ExplicitConnections);
 2538226            if (!_explicitRefresh!.Advance(meter))
 227            {
 1147228                rejection = NavigationOperationRejection.None;
 1147229                return false;
 230            }
 1391231            if (!_explicitRefresh.IsValid)
 12232                _rejection = NavigationOperationRejection.ValidationFailed;
 1391233            _stage = Stage.Complete;
 1391234            rejection = _rejection;
 1391235            return true;
 236        }
 237
 238        private void PrepareCommit()
 239        {
 1397240            NavigationMap map = _prepared!.Map;
 1397241            bool replacing = _current != null;
 1397242            if (_working._bakeVersionHighWater.TryGetValue(_mapId, out long highWater)
 1397243                && _prepared.BakeVersion <= highWater)
 244            {
 2245                _rejection = NavigationOperationRejection.Stale;
 2246                _stage = Stage.Complete;
 2247                return;
 248            }
 1395249            if ((!_working._bakeVersionHighWater.ContainsKey(_mapId)
 1395250                    && _working._bakeVersionHighWater.Count >= _limits.MaxRetainedMapIdentities)
 1395251                || (!replacing && _working._maps.Count >= _limits.MaxMaps))
 252            {
 1253                _rejection = NavigationOperationRejection.CapacityExceeded;
 1254                _stage = Stage.Complete;
 1255                return;
 256            }
 1394257            long retainedRuleCount = checked(
 1394258                _working.TransitionRuleCount
 1394259                - (_current?.Map.TransitionRuleSpan.Length ?? 0));
 260            // Per-map rule capacity is rejected during admission before fold work exists.
 1394261            if (map.TransitionRuleSpan.Length > _limits.MaxTransitionRules - retainedRuleCount)
 262            {
 2263                _rejection = NavigationOperationRejection.CapacityExceeded;
 2264                _stage = Stage.Complete;
 2265                return;
 266            }
 1392267            if (_working._gridBindings.TryGetValue(map.GridBinding.Key, out string bound)
 1392268                && !string.Equals(bound, _mapId, System.StringComparison.Ordinal))
 269            {
 1270                _rejection = NavigationOperationRejection.ValidationFailed;
 1271                _stage = Stage.Complete;
 1272                return;
 273            }
 1391274            if (_prepared.CheckpointStamp.HasValue)
 275            {
 5276                NavigationMapCheckpointStamp stamp = _prepared.CheckpointStamp.Value;
 5277                if (!replacing
 5278                    || _current!.BakeVersion != stamp.BakeVersion
 5279                    || _current.Overlay.HighWaterSequence != stamp.OverlayHighWaterSequence)
 280                {
 4281                    _rejection = NavigationOperationRejection.Stale;
 4282                    _stage = Stage.Complete;
 4283                    return;
 284                }
 285            }
 1387286            NavigationMapOverlayState overlay = !replacing
 1387287                || _replacementPolicy == OverlayReplacementPolicy.Clear
 1387288                    ? NavigationMapOverlayState.Empty
 1387289                    : _current!.Overlay;
 1387290            PersistentVoxelIndexMap<byte> dynamicAddresses = replacing
 1387291                && _replacementPolicy == OverlayReplacementPolicy.PreserveAndRevalidate
 1387292                    ? _current!.DynamicAddresses
 1387293                    : PersistentVoxelIndexMap<byte>.Empty;
 1387294            _next = new MapState(
 1387295                map,
 1387296                _prepared.BakeVersion,
 1387297                _prepared.RetainedBytes,
 1387298                overlay,
 1387299                replacing && _replacementPolicy == OverlayReplacementPolicy.PreserveAndRevalidate
 1387300                    ? _current!.DynamicSlotGeneration
 1387301                    : replacing ? checked(_current!.DynamicSlotGeneration + 1) : 0,
 1387302                dynamicAddresses,
 1387303                _prepared.BakedCellLookup);
 1387304            _changedStates[0] = _next;
 1387305            _stage = Stage.Cells;
 1387306        }
 307
 308        private bool AdvanceCells(MaintenanceWorkMeter meter)
 309        {
 3372310            if (!_defaultCellValidated && _next!.Map.DefaultCell.HasValue)
 311            {
 35312                if (!meter.TryConsumeOverlaySlots(1))
 1313                    return false;
 34314                _defaultCellValidated = true;
 34315                if (_next.Map.DefaultCell.Value.Area.Value >= _working._navigationAreaCount)
 316                {
 1317                    _rejection = NavigationOperationRejection.ValidationFailed;
 1318                    _stage = Stage.Complete;
 1319                    return true;
 320                }
 321            }
 22583322            while (_cellIndex < _next!.Map.CellSpan.Length)
 323            {
 21196324                if (!meter.TryConsumeOverlaySlots(1))
 1982325                    return false;
 19214326                if (_next.Map.CellSpan[_cellIndex++].Cell.Area.Value >= _working._navigationAreaCount)
 327                {
 1328                    _rejection = NavigationOperationRejection.ValidationFailed;
 1329                    _stage = Stage.Complete;
 1330                    return true;
 331                }
 332            }
 1395333            while (_overlayCellIndex < _next!.Overlay.CellCount)
 334            {
 13335                if (!meter.TryConsumeOverlaySlots(1))
 4336                    return false;
 9337                if (!_next.Map.GridBinding.IsValidIndex(
 9338                        _next.Overlay.GetCellAt(_overlayCellIndex++).Index))
 339                {
 1340                    _rejection = NavigationOperationRejection.ValidationFailed;
 1341                    _stage = Stage.Complete;
 1342                    return true;
 343                }
 344            }
 1382345            _stage = Stage.Dynamic;
 1382346            return true;
 347        }
 348
 349        private bool AdvanceDynamic(MaintenanceWorkMeter meter)
 350        {
 1390351            while (_dynamicIndex < _next!.DynamicAddresses.Count)
 352            {
 9353                if (!meter.TryConsumeOverlaySlots(1))
 3354                    return false;
 6355                if (_next.Map.ContainsCell(_next.DynamicAddresses.GetKeyAt(_dynamicIndex++)))
 356                {
 1357                    _rejection = NavigationOperationRejection.ValidationFailed;
 1358                    _stage = Stage.Complete;
 1359                    return true;
 360                }
 361            }
 1381362            _stage = Stage.AuthoredValidation;
 1381363            return true;
 364        }
 365
 366        private bool AdvanceAuthoredValidation(MaintenanceWorkMeter meter)
 367        {
 1673368            while (_authoredIndex < _next!.Map.ConnectionSpan.Length)
 369            {
 282370                if (!meter.TryConsumeExplicitEdges(1))
 1371                    return false;
 281372                if (_next.Map.ConnectionSpan[_authoredIndex++].Witnesses.Count
 281373                    > _limits.MaxCorridorCells - 2)
 374                {
 1375                    _rejection = NavigationOperationRejection.CapacityExceeded;
 1376                    _stage = Stage.Complete;
 1377                    return true;
 378                }
 379            }
 1391380            if (!AdvanceRuleOwnershipValidation(meter))
 11381                return false;
 1380382            if (_rejection != NavigationOperationRejection.None)
 1383                return true;
 1379384            _stage = Stage.Validation;
 1379385            return true;
 386        }
 387
 388        private bool AdvanceRuleOwnershipValidation(MaintenanceWorkMeter meter)
 389        {
 1391390            ReadOnlySpan<TraversalTransitionRule> sourceRules = _next!.Map.TransitionRuleSpan;
 1391391            if (sourceRules.IsEmpty)
 1327392                return true;
 81393            while (_ruleValidationMapIndex < _working._maps.Count)
 394            {
 29395                if (!_ruleValidationMapDebited)
 396                {
 27397                    if (!meter.TryConsumeDependencyEntries(1))
 9398                        return false;
 18399                    _ruleValidationMapDebited = true;
 400                }
 20401                MapState target = _working._maps.GetValueAt(_ruleValidationMapIndex);
 20402                if (string.Equals(target.Map.MapId, _mapId, System.StringComparison.Ordinal))
 403                {
 3404                    _ruleValidationMapIndex++;
 3405                    _ruleValidationMapDebited = false;
 3406                    continue;
 407                }
 17408                ReadOnlySpan<TraversalTransitionRule> targetRules = target.Map.TransitionRuleSpan;
 20409                while (_ruleValidationSourceIndex < sourceRules.Length
 20410                    && _ruleValidationTargetIndex < targetRules.Length)
 411                {
 6412                    if (!meter.TryConsumeDependencyEntries(1))
 2413                        return false;
 4414                    int comparison = string.CompareOrdinal(
 4415                        sourceRules[_ruleValidationSourceIndex].Id,
 4416                        targetRules[_ruleValidationTargetIndex].Id);
 4417                    if (comparison == 0)
 418                    {
 1419                        _rejection = NavigationOperationRejection.ValidationFailed;
 1420                        _stage = Stage.Complete;
 1421                        return true;
 422                    }
 3423                    if (comparison < 0)
 2424                        _ruleValidationSourceIndex++;
 425                    else
 1426                        _ruleValidationTargetIndex++;
 427                }
 14428                _ruleValidationMapIndex++;
 14429                _ruleValidationSourceIndex = 0;
 14430                _ruleValidationTargetIndex = 0;
 14431                _ruleValidationMapDebited = false;
 432            }
 52433            return true;
 434        }
 435
 436        private bool AdvanceValidation(MaintenanceWorkMeter meter)
 437        {
 1386438            while (true)
 439            {
 2766440                MapState? state = GetValidationState();
 2766441                if (state == null)
 442                {
 1376443                    _stage = Stage.Dependencies;
 1376444                    return true;
 445                }
 1390446                if (!AdvanceStateValidation(state, meter))
 1447                    return false;
 1389448                if (_rejection != NavigationOperationRejection.None)
 3449                    return true;
 1386450                _validationSourceIndex++;
 1386451                _validationStage = 0;
 1386452                _validationIndex = 0;
 453            }
 454        }
 455
 456        private MapState? GetValidationState()
 457        {
 2766458            if (_validationSourceIndex < 0)
 1380459                return _next;
 1386460            int sourceCount = _working.GetIncomingSourceCount(_mapId);
 1387461            while (_validationSourceIndex < sourceCount)
 462            {
 11463                string sourceId = _working.GetIncomingSource(_mapId, _validationSourceIndex);
 11464                if (string.Equals(sourceId, _mapId, System.StringComparison.Ordinal))
 465                {
 1466                    _validationSourceIndex++;
 1467                    continue;
 468                }
 10469                bool hasSource = _working._maps.TryGetValue(sourceId, out MapState source);
 470                System.Diagnostics.Debug.Assert(hasSource);
 10471                return source;
 472            }
 1376473            return null;
 474        }
 475
 476        private bool AdvanceStateValidation(MapState state, MaintenanceWorkMeter meter)
 477        {
 4162478            while (_validationStage < 2)
 479            {
 2776480                int count = _validationStage == 0
 2776481                    ? state.Map.TransitionSpan.Length
 2776482                    : state.Overlay.TransitionCount;
 2870483                while (_validationIndex < count)
 484                {
 98485                    if (!meter.TryConsumeExplicitEdges(1))
 1486                        return false;
 97487                    if (!_working.ValidateTransitionForWork(
 97488                            state,
 97489                            overlay: _validationStage == 1,
 97490                            _validationIndex++,
 97491                            _changedMapIds,
 97492                            _changedStates))
 493                    {
 3494                        _rejection = NavigationOperationRejection.ValidationFailed;
 3495                        _stage = Stage.Complete;
 3496                        return true;
 497                    }
 498                }
 2772499                _validationStage++;
 2772500                _validationIndex = 0;
 501            }
 1386502            return true;
 503        }
 504
 505        private bool AdvanceDependencies(MaintenanceWorkMeter meter)
 506        {
 507            while (true)
 508            {
 2773509                MapState? state = _removeDependencies ? _current : _next;
 2773510                if (state != null && !AdvanceStateDependencies(state, _removeDependencies, meter))
 4511                    return false;
 2769512                if (_removeDependencies && _next != null)
 513                {
 1376514                    _removeDependencies = false;
 1376515                    ResetDependencyCursor();
 1376516                    continue;
 517                }
 1393518                _stage = Stage.Commit;
 1393519                return true;
 520            }
 521        }
 522
 523        private bool AdvanceStateDependencies(
 524            MapState state,
 525            bool remove,
 526            MaintenanceWorkMeter meter)
 527        {
 4312528            while (_dependencyStage < 2)
 529            {
 2876530                int count = _dependencyStage == 0
 2876531                    ? state.Map.TransitionSpan.Length
 2876532                    : state.Overlay.TransitionCount;
 2970533                while (_dependencyIndex < count)
 534                {
 98535                    TraversalTransitionOverlayOperation overlay = _dependencyStage == 1
 98536                        ? state.Overlay.GetTransitionAt(_dependencyIndex)
 98537                        : default;
 98538                    if (_dependencyStage == 1
 98539                        && overlay.Kind != TraversalTransitionOverlayOperationKind.Upsert)
 540                    {
 8541                        _dependencyIndex++;
 8542                        continue;
 543                    }
 90544                    if (!meter.TryConsumeDependencyEntries(1))
 4545                        return false;
 86546                    string destination = _dependencyStage == 0
 86547                        ? state.Map.TransitionSpan[_dependencyIndex].Destination.MapId
 86548                        : overlay.Transition.Destination.MapId;
 86549                    _working.UpdateIncomingSource(destination, state.Map.MapId, remove);
 86550                    _dependencyIndex++;
 551                }
 2872552                _dependencyStage++;
 2872553                _dependencyIndex = 0;
 554            }
 1436555            return true;
 556        }
 557
 558        private void Commit()
 559        {
 1393560            _working.RecordMapStateOwnership(
 1393561                _mapId,
 1393562                _next,
 1393563                _foldSource,
 1393564                ref _displacedMapStatePayloadBytes,
 1393565                ref _displacedMapStatePayloadPages);
 1393566            if (_next == null)
 567            {
 17568                _working._maps = _working._maps.Remove(
 17569                    _mapId,
 17570                    out _,
 17571                    out int copiedNodes);
 17572                _working.RecordPersistentCopies(copiedNodes);
 17573                _working.RemoveMapStateTotals(_current!);
 17574                _working._gridBindings = _working._gridBindings.Remove(
 17575                    _current!.Map.GridBinding.Key,
 17576                    out _,
 17577                    out copiedNodes);
 17578                _working.RecordPersistentCopies(copiedNodes, 144L);
 17579                _working.ReplaceTotals(_current, next: null);
 580            }
 581            else
 582            {
 1376583                _working.SetMapState(_current, _next);
 1376584                if (_current != null && !_current.Map.GridBinding.Key.Equals(_next.Map.GridBinding.Key))
 585                {
 10586                    _working._gridBindings = _working._gridBindings.Remove(
 10587                        _current.Map.GridBinding.Key,
 10588                        out _,
 10589                        out int removedCopies);
 10590                    _working.RecordPersistentCopies(removedCopies, 144L);
 591                }
 1376592                _working._gridBindings = _working._gridBindings.Set(
 1376593                    _next.Map.GridBinding.Key,
 1376594                    _mapId,
 1376595                    out int bindingCopies);
 1376596                _working.RecordPersistentCopies(bindingCopies, 144L);
 1376597                _working.ReplaceTotals(_current, _next);
 1376598                _working._bakeVersionHighWater = _working._bakeVersionHighWater.Set(
 1376599                    _mapId,
 1376600                    _prepared!.BakeVersion,
 1376601                    out int versionCopies);
 1376602                _working.RecordPersistentCopies(versionCopies);
 603            }
 1393604            _explicitRefresh = _working.BeginExplicitConnectionRefresh(
 1393605                _mapId,
 1393606                _sourceExplicitConnections,
 1393607                _corridorPrisms!,
 1393608                _corridorWaypoints!,
 1393609                _corridorAddresses,
 1393610                _corridorAddressSet);
 1393611            _stage = Stage.ExplicitConnections;
 1393612        }
 613
 614        private void ResetDependencyCursor()
 615        {
 1376616            _dependencyStage = 0;
 1376617            _dependencyIndex = 0;
 1376618        }
 619
 620        private enum Stage
 621        {
 622            Cells,
 623            Dynamic,
 624            AuthoredValidation,
 625            Validation,
 626            Dependencies,
 627            Commit,
 628            ExplicitConnections,
 629            Complete
 630        }
 631    }
 632}

Methods/Properties

.ctor(System.Int32)
get_MapCount()
get_OverlayCellCount()
get_OverlayConnectionCount()
get_TransitionRuleCount()
get_NavigationAreaCount()
get_RetainedBytes()
get_PersistentPageCount()
get_WorkCopiedPersistentBytes()
get_WorkCopiedPersistentPages()
get_WorkOwnedExplicitPayloadBytes()
get_WorkOwnedExplicitPayloadPages()
get_WorkOwnedMapStatePayloadBytes()
get_WorkOwnedMapStatePayloadPages()
get_NonPayloadRetainedBytes()
get_NonPayloadPersistentPageCount()
ResetWorkCopiedPersistentOwnership()
RecordPersistentCopies(System.Int32,System.Int64)
RecordExplicitRecordOwnership(Trailblazer.Pathing.NavigationConnectionOwnerKey,Trailblazer.Pathing.NavigationExplicitConnectionRecord,Trailblazer.Pathing.NavigationExplicitConnectionIndex,System.Int64&,System.Int32&)
RecordExplicitIncidenceOwnership(Trailblazer.Pathing.NavigationCellAddress,Trailblazer.Pathing.NavigationPagedSequence`1<Trailblazer.Pathing.NavigationConnectionOwnerKey>,Trailblazer.Pathing.NavigationExplicitConnectionIndex,System.Int64&,System.Int32&)
RecordExplicitEndpointOwnership(Trailblazer.Pathing.NavigationCellAddress,Trailblazer.Pathing.NavigationPagedSequence`1<Trailblazer.Pathing.NavigationConnectionOwnerKey>,Trailblazer.Pathing.NavigationExplicitConnectionIndex,System.Int64&,System.Int32&)
ReplaceCurrentPayloadOwnership(T,T,T,System.Int64&,System.Int32&)
ReplaceDisplacedPayloadOwnership(T,T,T,System.Int64&,System.Int32&)
GetPayloadOwnership(T,T,System.Int64&,System.Int32&)
GetPayloadSize(T,System.Int64&,System.Int32&)
RecordMapStateOwnership(System.String,Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.NavigationOperationCandidate,System.Int64&,System.Int32&)
GetAdditionalMapStatePayload(Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.NavigationOperationCandidate/MapState,System.Int64&,System.Int32&)
ReplaceDisplacedMapStateOwnership(Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.NavigationOperationCandidate/MapState,System.Int64&,System.Int32&)
ReplaceDisplacedMapStateComponent(System.Object,System.Object,System.Object,System.Int64,System.Int32,System.Int64&,System.Int32&)
ReplaceOverlayState(Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.NavigationOperationLimits)
Clone()
GetIncomingSourceCount(System.String)
GetIncomingSource(System.String,System.Int32)
UpdateIncomingSourceForWork(System.String,System.String,System.Boolean)
ValidateTransitionForWork(Trailblazer.Pathing.NavigationOperationCandidate/MapState,System.Boolean,System.Int32,System.String[],Trailblazer.Pathing.NavigationOperationCandidate/MapState[])
TryGetMap(System.String,Trailblazer.Pathing.NavigationMap&)
TryGetState(System.String,Trailblazer.Pathing.NavigationOperationCandidate/MapState&)
TryGetSemanticState(Trailblazer.Pathing.NavigationCellAddress,Trailblazer.Pathing.NavigationCellSemanticSource&,System.Boolean&,Trailblazer.Pathing.NavigationCell&)
TryGetOverlay(System.String,Trailblazer.Pathing.NavigationMapOverlayState&)
SetMapState(Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.NavigationOperationCandidate/MapState)
AddMapStateTotals(Trailblazer.Pathing.NavigationOperationCandidate/MapState)
RemoveMapStateTotals(Trailblazer.Pathing.NavigationOperationCandidate/MapState)
ReplaceTotals(Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.NavigationOperationCandidate/MapState)
UpdateIncomingSource(System.String,System.String,System.Boolean)
ValidateTransition(Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.TraversalTransitionDefinition,System.String[],Trailblazer.Pathing.NavigationOperationCandidate/MapState[])
TryGetEffectiveCell(Trailblazer.Pathing.NavigationOperationCandidate/MapState,GridForge.Spatial.VoxelIndex,Trailblazer.Pathing.NavigationCell&)
HasDefinitionMedium(Trailblazer.Pathing.NavigationOperationCandidate/MapState,GridForge.Spatial.VoxelIndex,Trailblazer.TraversalMedium)
SupportsMedium(Trailblazer.Pathing.NavigationCell,Trailblazer.TraversalMedium)
FindChangedState(System.String,System.String[],Trailblazer.Pathing.NavigationOperationCandidate/MapState[])
TryFindCellOverlay(Trailblazer.Pathing.NavigationMapOverlayState,GridForge.Spatial.VoxelIndex,Trailblazer.Pathing.NavigationCellOverlayOperation&)
.ctor(Trailblazer.Pathing.NavigationMap,System.Int64,System.Int64,Trailblazer.Pathing.NavigationMapOverlayState,System.Int64,Trailblazer.Pathing.PersistentVoxelIndexMap`1<System.Byte>,Trailblazer.Pathing.NavigationBakedCellLookup)
get_ExplicitConnections()
get_ExplicitChangedSourceCount()
get_ExplicitChangedOwnerCount()
GetExplicitChangedSourceAt(System.Int32)
GetExplicitChangedOwnerAt(System.Int32)
BeginExplicitConnectionRefresh(System.String,Trailblazer.Pathing.NavigationExplicitConnectionIndex,GridForge.Grids.Topology.GridCellPrism[],FixedMathSharp.Vector3d[],Trailblazer.Pathing.NavigationCellAddress[],Trailblazer.Pathing.NavigationAddressStampSet)
BeginExplicitConnectionRefresh(Trailblazer.Pathing.NavigationOverlayTransaction,Trailblazer.Pathing.NavigationExplicitConnectionIndex,GridForge.Grids.Topology.GridCellPrism[],FixedMathSharp.Vector3d[],Trailblazer.Pathing.NavigationCellAddress[],Trailblazer.Pathing.NavigationAddressStampSet)
TrySelectConnection(Trailblazer.Pathing.NavigationConnectionOwnerKey,Trailblazer.Pathing.NavigationOperationCandidate/MapState&,Trailblazer.Pathing.NavigationConnection&)
TryGetSemanticPrism(Trailblazer.Pathing.NavigationCellAddress,Trailblazer.Pathing.NavigationConnection,System.Boolean,FixedMathSharp.Vector3d,GridForge.Grids.Topology.GridCellPrism&,Trailblazer.Pathing.NavigationCell&,System.Boolean&)
ValidateLowerBound(GridForge.Grids.Topology.GridCellPrism&,GridForge.Grids.Topology.GridCellPrism&,Trailblazer.Pathing.NavigationCell,Trailblazer.Pathing.NavigationConnection,FixedMathSharp.Fixed64)
Dormant(Trailblazer.Pathing.NavigationConnectionOwnerKey,Trailblazer.Pathing.NavigationConnection)
IsKnownSuppressed(Trailblazer.Pathing.NavigationOperationCandidate/MapState,GridForge.Spatial.VoxelIndex)
.ctor(Trailblazer.Pathing.NavigationOperationCandidate,Trailblazer.Pathing.NavigationExplicitConnectionIndex,System.String,Trailblazer.Pathing.NavigationOverlayTransaction,GridForge.Grids.Topology.GridCellPrism[],FixedMathSharp.Vector3d[],Trailblazer.Pathing.NavigationCellAddress[],Trailblazer.Pathing.NavigationAddressStampSet)
get_DisplacedSourcePayloadBytes()
get_DisplacedSourcePayloadPages()
get_RetainedBytes()
get_PersistentPageCount()
Advance(Trailblazer.Pathing.MaintenanceWorkMeter)
InitializeCurrent(Trailblazer.Pathing.PersistentStringMap`1<System.Boolean>)
AdvanceCompilation(Trailblazer.Pathing.MaintenanceWorkMeter)
CaptureSemanticPrism(System.Int32)
AdvanceDistinctAddresses(Trailblazer.Pathing.NavigationConnection,Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceOldIncidenceTouches(Trailblazer.Pathing.MaintenanceWorkMeter)
UpdateOwner()
AdvanceFinalAdditions(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceIncidenceRows(Trailblazer.Pathing.MaintenanceWorkMeter)
InitializeRow(Trailblazer.Pathing.PersistentVoxelIndexMap`1<Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceRowDelta>)
AdvancePriorRowFilter(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceRowMerge(Trailblazer.Pathing.MaintenanceWorkMeter)
IsIncidenceChanged(Trailblazer.Pathing.NavigationConnectionOwnerKey)
GetOrCreateRowDelta(Trailblazer.Pathing.NavigationCellAddress)
ReleaseCurrentRow()
IsEndpoint(Trailblazer.Pathing.NavigationCellAddress,Trailblazer.Pathing.NavigationConnectionOwnerKey,Trailblazer.Pathing.NavigationConnection)
GetRawAddress(Trailblazer.Pathing.NavigationConnectionOwnerKey,Trailblazer.Pathing.NavigationConnection,System.Int32)
ResetCurrent()
HasComponentEdgeChanged(Trailblazer.Pathing.NavigationExplicitConnectionRecord,Trailblazer.Pathing.NavigationExplicitConnectionRecord)
PortalsEqual(Trailblazer.Pathing.NavigationPagedSequence`1<GridForge.Grids.Topology.GridNavigationPortal>,Trailblazer.Pathing.NavigationPagedSequence`1<GridForge.Grids.Topology.GridNavigationPortal>)
PortalEquals(GridForge.Grids.Topology.GridNavigationPortal,GridForge.Grids.Topology.GridNavigationPortal)
AdvanceGather(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceOverlayGather(Trailblazer.Pathing.MaintenanceWorkMeter)
AddOwner(Trailblazer.Pathing.NavigationConnectionOwnerKey,Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceIncidentOwners(Trailblazer.Pathing.NavigationCellAddress,Trailblazer.Pathing.MaintenanceWorkMeter)
get_RetainedBytes()
get_PersistentPageCount()
AppendAddition(Trailblazer.Pathing.NavigationConnectionOwnerKey)
MarkEndpointTouched()
SealAdditions()
ReleaseAdditions()
get_RetainedBytes()
get_PersistentPageCount()
Add(Trailblazer.Pathing.NavigationConnectionOwnerKey,Trailblazer.Pathing.NavigationExplicitConnectionIndex)
GetSuccessor(Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
Clear()
Minimum(Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
Rebalance(Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
RotateLeft(Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
RotateRight(Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
ReplaceParentLink(Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node,Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
Height(Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
UpdateHeight(Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
.ctor(Trailblazer.Pathing.NavigationConnectionOwnerKey,Trailblazer.Pathing.NavigationOperationCandidate/ExplicitConnectionRefreshWork/IncidenceOwnerTree/Node)
BeginMapFold(Trailblazer.Pathing.PreparedNavigationMap,Trailblazer.Pathing.OverlayReplacementPolicy,Trailblazer.Pathing.NavigationOperationLimits,GridForge.Grids.Topology.GridCellPrism[],FixedMathSharp.Vector3d[],Trailblazer.Pathing.NavigationCellAddress[],Trailblazer.Pathing.NavigationAddressStampSet)
BeginMapRemovalFold(System.String,GridForge.Grids.Topology.GridCellPrism[],FixedMathSharp.Vector3d[],Trailblazer.Pathing.NavigationCellAddress[],Trailblazer.Pathing.NavigationAddressStampSet)
.ctor(Trailblazer.Pathing.NavigationOperationCandidate,Trailblazer.Pathing.PreparedNavigationMap,Trailblazer.Pathing.OverlayReplacementPolicy,Trailblazer.Pathing.NavigationOperationLimits,GridForge.Grids.Topology.GridCellPrism[],FixedMathSharp.Vector3d[],Trailblazer.Pathing.NavigationCellAddress[],Trailblazer.Pathing.NavigationAddressStampSet)
.ctor(Trailblazer.Pathing.NavigationOperationCandidate,System.String,GridForge.Grids.Topology.GridCellPrism[],FixedMathSharp.Vector3d[],Trailblazer.Pathing.NavigationCellAddress[],Trailblazer.Pathing.NavigationAddressStampSet)
get_Candidate()
get_DisplacedExplicitPayloadBytes()
get_DisplacedExplicitPayloadPages()
get_DisplacedMapStatePayloadBytes()
get_DisplacedMapStatePayloadPages()
get_RetainedBytes()
get_PersistentPageCount()
GetPendingStateGrowthBytes()
GetPendingStateGrowthPages()
Advance(Trailblazer.Pathing.MaintenanceWorkMeter,Trailblazer.Pathing.NavigationOperationRejection&)
PrepareCommit()
AdvanceCells(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceDynamic(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceAuthoredValidation(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceRuleOwnershipValidation(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceValidation(Trailblazer.Pathing.MaintenanceWorkMeter)
GetValidationState()
AdvanceStateValidation(Trailblazer.Pathing.NavigationOperationCandidate/MapState,Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceDependencies(Trailblazer.Pathing.MaintenanceWorkMeter)
AdvanceStateDependencies(Trailblazer.Pathing.NavigationOperationCandidate/MapState,System.Boolean,Trailblazer.Pathing.MaintenanceWorkMeter)
Commit()
ResetDependencyCursor()