< Summary

Information
Class: Trailblazer.Pathing.PathManager
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/PathManager.cs
Line coverage
99%
Covered lines: 1184
Uncovered lines: 11
Coverable lines: 1195
Total lines: 2665
Line coverage: 99%
Branch coverage
93%
Covered branches: 562
Total branches: 598
Branch coverage: 93.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
get_PartitionPool()100%11100%
get_VolumeChartPartitionPool()100%11100%
get_AllCharts()100%44100%
get__navigationChartMap()100%11100%
get__resolvedChartVoxelStates()100%11100%
get__initializedChartTouchCountsByGridIndex()100%11100%
get__navigationChartMapLock()100%11100%
get__nextChartRegistrationOrder()100%11100%
set__nextChartRegistrationOrder(...)100%11100%
get_ActiveState()50%22100%
TryGetActiveState(...)100%22100%
EnterState(...)100%11100%
.ctor(...)100%11100%
Dispose()100%11100%
get_HasConfiguredWorld()100%11100%
get_ConfiguredWorld()100%11100%
LinkWorld(...)75%5466.66%
GetConfiguredWorld()100%11100%
Tick()50%22100%
Reset()100%22100%
Reset(...)100%11100%
ResetPathingState(...)100%66100%
Register(...)100%11100%
Register(...)100%11100%
Register(...)100%11100%
Register(...)100%11100%
ThrowIfDirectWorldRegisterCall()100%22100%
RegisterChartInternal(...)100%66100%
ValidateChartVoxelSizeCompatibility(...)100%22100%
IsChartRegistered(...)100%11100%
TryGetNavigationChart(...)100%22100%
TryGetNavigationChartRegistration(...)100%11100%
IsChartInitialized(...)100%22100%
IsChartInitialized(...)50%22100%
TryGetNavigationChartRegistration_NoLock(...)100%22100%
TryGetEffectiveCell(...)100%22100%
TryGetEffectiveCell(...)100%22100%
TryGetEffectiveCell(...)100%11100%
TryGetEffectiveChartOwner(...)100%22100%
TryGetEffectiveChartOwner(...)100%22100%
TryGetEffectiveChartOwner(...)100%11100%
TryGetClosestActiveTransition(...)81.81%2222100%
TryGetClosestActiveTransition(...)100%11100%
InitializeAllCharts()100%11100%
InitializeAllCharts(...)100%22100%
EvaluateClosestTransitionCandidates(...)100%66100%
GetBoundsDistanceSq(...)100%11100%
GetAxisDistanceToBounds(...)100%44100%
TryUpdateChartCell(...)100%11100%
TryUpdateChartCell(...)100%22100%
TryUpdateChartCell(...)100%22100%
TryUpdateChartCell(...)100%11100%
TryUpdateChartCell(...)75%44100%
ApplyChartUpdates(...)100%11100%
ApplyChartUpdates(...)100%88100%
InitializeChart(...)100%11100%
InitializeChart(...)87.5%1616100%
UnloadChart(...)100%11100%
UnloadChart(...)100%22100%
UnloadChart(...)100%11100%
UnloadChart(...)100%44100%
UnloadChart(...)100%1616100%
RebuildInitializedChartsAgainstExternalGridRequests(...)100%11100%
RebuildInitializedChartsAgainstExternalGridRequests(...)83.33%66100%
RebuildInitializedChartsAgainstExternalGridBounds(...)100%11100%
RebuildInitializedChartsAgainstCurrentGrids(...)100%44100%
SuppressManagedGeneratedTransitionsForCharts(...)100%1010100%
GetInitializedChartsSnapshot()100%66100%
GetInitializedChartsIntersectingBoundsSnapshot(...)100%88100%
GetInitializedChartsTouchingGridSnapshot(...)100%22100%
GetInitializedChartsWithAuthoredCellsIntersectingBoundsSnapshot(...)100%22100%
GetInitializedChartsAffectedByExternalGridRequestsSnapshot(...)100%1010100%
AddInitializedChartsTouchingGrid_NoLock(...)100%1212100%
AddInitializedChartsWithAuthoredCellsIntersectingBounds_NoLock(...)100%88100%
BuildInitializedChartSelectionSnapshot_NoLock(...)100%44100%
ChartHasAuthoredCellInsideBounds(...)100%44100%
ClearInitializedChartLiveStatePreservingRegistration(...)50%4480%
ClearInitializedChartLiveStatePreservingRegistration(...)91.66%1212100%
ClearLiveGridState(...)100%44100%
ClearLiveGridState()100%11100%
DoBoundsOverlap(...)100%1010100%
IsPositionInsideBounds(...)100%1010100%
RemoveLivePathingPartitions(...)100%44100%
BuildInitializedChartSelectionSnapshot(...)100%22100%
CopyCharts(...)100%22100%
CompareRegistrationsByRegistrationOrder(...)100%11100%
TrackInitializedChartGridTouch(...)100%22100%
UntrackInitializedChartGridTouch(...)100%88100%
TrackInitializedChartGridTouchDelta(...)100%66100%
TryRegisterManagedGeneratedTransitions(...)100%1212100%
RememberManagedGeneratedTransitions(...)100%44100%
RemoveManagedGeneratedTransitions(...)100%22100%
TryGetManagedGeneratedTransitionState(...)100%11100%
RefreshManagedGeneratedTransitionsForCharts(...)90%1010100%
RefreshManagedGeneratedTransitionsForCharts(...)100%22100%
RefreshManagedTransitionsForVoxel(...)100%22100%
RefreshManagedManualTransitionsForVoxels(...)83.33%66100%
RefreshManagedGeneratedTransitionsForChart(...)100%44100%
CollectManagedGeneratedTransitionsForChart(...)100%1010100%
RefreshManagedGeneratedTransitionsForVoxel(...)100%1414100%
RefreshManagedGeneratedTransitionsForVoxel(...)100%1616100%
RefreshManagedGeneratedTransitionsForPair(...)78.57%141492.64%
GetObsoleteManagedGeneratedTransitionIds(...)100%1212100%
GetMissingManagedGeneratedTransitions(...)100%88100%
ApplyManagedGeneratedTransitionDelta(...)75%88100%
GetObsoleteManagedGeneratedTransitionIds(...)100%88100%
SyncManagedGeneratedTransitionSuppressions(...)100%1010100%
CollectManagedGeneratedTransitionsForPair(...)91.66%1212100%
CanResolveManagedGeneratedPairAnchors(...)100%22100%
AddPotentialManagedGeneratedTransitionIds(...)100%22100%
ShouldCollectManagedGeneratedPair(...)100%1212100%
IsManagedGeneratedTransitionCandidate(...)100%22100%
IsManagedGeneratedPairActive(...)100%44100%
IsChartEffectiveOwnerAtPosition(...)100%22100%
AddManagedGeneratedTransitionIds(...)100%44100%
RemoveManagedGeneratedTransitionIds(...)100%44100%
CopyTransitionIds(...)100%44100%
CopyTransitionIds(...)100%22100%
RemoveChartFromRegistry(...)100%11100%
TryGetResolvedChartVoxelState(...)100%22100%
TryGetResolvedChartVoxelState(...)100%88100%
TryApplyChartCellUpdate(...)81.25%1616100%
TrackManagedChartRefresh(...)100%11100%
TryGetChartUpdateVoxelContext(...)83.33%66100%
TryUpdateResolvedVoxelStateForChartCell(...)90%1010100%
RebindAndInvalidate(...)100%66100%
CollectEffectiveStateInvalidations(...)100%88100%
HasAuthoredVolumeMedium(...)100%11100%
HasAuthoredVolumeMedium(...)100%44100%
ApplyResolvedVoxelState(...)75%282892.59%
UpdateActiveVolumeMediumCounts(...)100%88100%
ClearActiveAuthoredVolumeMediumCounts()100%11100%
AdjustActiveAuthoredGasCellCount(...)100%11100%
AdjustActiveAuthoredLiquidCellCount(...)100%11100%
CollectSolidPartitionsForRebind(...)90%101088.88%
BindCollectedSolidPartitions(...)100%66100%
TryGetMaxSearchSize(...)100%66100%
TryGetMaxSearchSize(...)100%11100%
NeedsPath(...)100%1212100%
NeedsPath(...)100%11100%

File(s)

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

#LineLine coverage
 1using FixedMathSharp;
 2using GridForge;
 3using GridForge.Grids;
 4using GridForge.Spatial;
 5using GridForge.Utility;
 6using SwiftCollections;
 7using SwiftCollections.Pool;
 8using System;
 9using System.Collections.Generic;
 10using System.Runtime.CompilerServices;
 11using System.Threading;
 12
 13namespace Trailblazer.Pathing;
 14
 15/// <summary>
 16/// Implements context-scoped chart registration, initialization, validation,
 17/// neighbor discovery, and related pathing operations.
 18/// </summary>
 19internal static class PathManager
 20{
 21    [ThreadStatic]
 22    private static PathingWorldState? _activeState;
 23
 24    #region Pools
 25
 126    internal static readonly SwiftHashSetPool<SolidChartPartition> PartitionSetPool = new();
 27
 28    /// <summary>
 29    /// Pool of reusable <see cref="SolidChartPartition"/> instances used for partitioning the navigation grid.
 30    /// </summary>
 244231    internal static SwiftObjectPool<SolidChartPartition> PartitionPool => ActiveState.PartitionPool;
 32
 33    /// <summary>
 34    /// Pool of reusable <see cref="VolumeChartPartition"/> instances used for authored raw-volume traversal.
 35    /// </summary>
 60736    internal static SwiftObjectPool<VolumeChartPartition> VolumeChartPartitionPool => ActiveState.VolumeChartPartitionPo
 37
 38    #endregion
 39
 40    #region Properties
 41
 42    /// <summary>
 43    /// Gets an enumerable collection of all currently registered navigation charts.
 44    /// </summary>
 45    public static IEnumerable<NavigationChart> AllCharts
 46    {
 47        get
 48        {
 6649            _navigationChartMapLock.EnterReadLock();
 50            try
 51            {
 6652                if (_navigationChartMap.Count == 0)
 453                    return Array.Empty<NavigationChart>();
 54
 6255                NavigationChart[] charts = new NavigationChart[_navigationChartMap.Count];
 6256                int index = 0;
 31057                foreach (NavigationChartRegistration registration in _navigationChartMap.Values)
 9358                    charts[index++] = registration.Chart;
 6259                return charts;
 60            }
 13261            finally { _navigationChartMapLock.ExitReadLock(); }
 6662        }
 63    }
 64
 65    /// <summary>
 66    /// Internal dictionary of all registered navigation charts, keyed by their unique names.
 67    /// </summary>
 68    private static SwiftDictionary<string, NavigationChartRegistration> _navigationChartMap =>
 1045769        ActiveState.NavigationChartMap;
 70
 71    private static SwiftDictionary<WorldVoxelIndex, ResolvedChartVoxelState> _resolvedChartVoxelStates =>
 1471572        ActiveState.ResolvedChartVoxelStates;
 73
 74    private static SwiftDictionary<ushort, SwiftDictionary<string, int>> _initializedChartTouchCountsByGridIndex =>
 878175        ActiveState.InitializedChartTouchCountsByGridIndex;
 76
 77    /// <summary>
 78    /// Lock for managing concurrent access to <c>_navigationChartMap</c> operations.
 79    /// Ensures thread safety for read/write operations.
 80    /// </summary>
 1776081    private static ReaderWriterLockSlim _navigationChartMapLock => ActiveState.NavigationChartMapLock;
 82
 83    private static int _nextChartRegistrationOrder
 84    {
 90685        get => ActiveState.NextChartRegistrationOrder;
 253886        set => ActiveState.NextChartRegistrationOrder = value;
 87    }
 88
 23543289    internal static PathingWorldState ActiveState => _activeState ?? throw new InvalidOperationException(
 23543290        "Trailblazer pathing operations require an explicit TrailblazerWorldContext.");
 91
 92    internal static bool TryGetActiveState(out PathingWorldState? state)
 93    {
 1267294        if (_activeState != null)
 95        {
 1176396            state = _activeState;
 1176397            return true;
 98        }
 99
 909100        state = null;
 909101        return false;
 102    }
 103
 104    internal static IDisposable EnterState(PathingWorldState state)
 105    {
 10565106        return new PathingWorldStateScope(state);
 107    }
 108
 109    private sealed class PathingWorldStateScope : IDisposable
 110    {
 111        private readonly PathingWorldState? _previousState;
 112
 10565113        public PathingWorldStateScope(PathingWorldState state)
 114        {
 10565115            _previousState = _activeState;
 10565116            _activeState = state;
 10565117        }
 118
 119        public void Dispose()
 120        {
 10564121            _activeState = _previousState;
 10564122        }
 123    }
 124
 125    #endregion
 126
 127    #region Lifecycle Hooks
 128
 129    /// <summary>
 130    /// Gets whether Trailblazer currently has an active configured grid world.
 131    /// </summary>
 714132    public static bool HasConfiguredWorld => _activeState != null;
 133
 134    /// <summary>
 135    /// Gets the active configured grid world.
 136    /// </summary>
 1137    public static GridWorld ConfiguredWorld => GetConfiguredWorld();
 138
 139    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 140    private static void LinkWorld(GridWorld world)
 141    {
 2246142        if (_activeState != null)
 143        {
 2246144            if (!ReferenceEquals(_activeState.World, world))
 1145                throw new InvalidOperationException("The supplied GridWorld does not belong to the active Trailblazer pa
 146
 2245147            return;
 148        }
 149
 0150        throw new InvalidOperationException(
 0151            "PathManager operations require TrailblazerWorldContext.Pathing to select the owning context.");
 152    }
 153
 154    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 753155    private static GridWorld GetConfiguredWorld() => ActiveState.World;
 156
 157    internal static void Tick()
 158    {
 1159        if (HasConfiguredWorld)
 1160            ActiveState.ExternalGridBridge.FlushPendingGridChanges();
 1161    }
 162
 163    /// <summary>
 164    /// Clears all registered maps, partitions, and guide pools.
 165    /// </summary>
 166    public static void Reset()
 167    {
 713168        if (!HasConfiguredWorld)
 48169            return;
 170
 665171        ResetPathingState(ActiveState, resetScopedRegistries: true, flushGuideCache: true);
 665172    }
 173
 174    /// <summary>
 175    /// Clears all registered maps, partitions, and guide pools.
 176    /// </summary>
 177    public static void Reset(GridWorld world)
 178    {
 1179        LinkWorld(world);
 1180        ResetPathingState(ActiveState, resetScopedRegistries: true, flushGuideCache: true);
 1181    }
 182
 183    internal static void ResetPathingState(
 184        PathingWorldState state,
 185        bool resetScopedRegistries,
 186        bool flushGuideCache)
 187    {
 1632188        using (EnterState(state))
 189        {
 1632190            if (resetScopedRegistries)
 191            {
 1632192                VolumeMediumRules.Reset();
 1632193                TraversalTransitionRegistry.Reset();
 194            }
 195
 1632196            ClearLiveGridState(state.World);
 1632197            PathManagerExternalGridBridge.ResetDiagnostics();
 198
 1632199            _navigationChartMapLock.EnterWriteLock();
 200            try
 201            {
 1632202                _navigationChartMap.Clear();
 1632203                _nextChartRegistrationOrder = 0;
 1632204            }
 205            finally
 206            {
 1632207                _navigationChartMapLock.ExitWriteLock();
 1632208            }
 209
 1632210            _resolvedChartVoxelStates.Clear();
 1632211            _initializedChartTouchCountsByGridIndex.Clear();
 1632212            ClearActiveAuthoredVolumeMediumCounts();
 213
 1632214            if (flushGuideCache && PathGuideFactory.IsPooling)
 38215                PathGuideFactory.FlushCache(true);
 216
 1632217            SolidPartitionReachability.Invalidate();
 1632218        }
 1632219    }
 220
 221    #endregion
 222
 223    #region Navigation Map Management
 224
 225    /// <summary>
 226    /// Attempts to register a new navigation chart with the manager.
 227    /// </summary>
 228    /// <param name="chart">The map to register.</param>
 229    /// <param name="initializeChart">Whether to initialize the chart after registration succeeds.</param>
 230    /// <returns>True if successful, false if a duplicate name exists.</returns>
 231    /// <exception cref="ArgumentNullException">Thrown when <paramref name="chart"/> is null.</exception>
 232    /// <exception cref="ArgumentException">
 233    /// Thrown when <paramref name="chart"/>'s interval does not match the owning world's voxel size.
 234    /// </exception>
 235    public static bool Register(NavigationChart chart, bool initializeChart = true)
 236    {
 97237        PathingWorldState state = ActiveState;
 97238        using (EnterState(state))
 97239            return Register(state.World, chart, initializeChart);
 96240    }
 241
 242    /// <summary>
 243    /// Attempts to register a new navigation chart with the manager.
 244    /// </summary>
 245    /// <param name="world">The grid world context for the chart.</param>
 246    /// <param name="chart">The map to register.</param>
 247    /// <param name="initializeChart">Whether to initialize the chart after registration succeeds.</param>
 248    /// <returns>True if successful, false if a duplicate name exists.</returns>
 249    /// <exception cref="ArgumentNullException">Thrown when <paramref name="chart"/> is null.</exception>
 250    /// <exception cref="ArgumentException">
 251    /// Thrown when <paramref name="chart"/>'s interval does not match <paramref name="world"/>'s voxel size.
 252    /// </exception>
 253    public static bool Register(GridWorld world, NavigationChart chart, bool initializeChart = true)
 254    {
 895255        SwiftThrowHelper.ThrowIfNull(chart, nameof(chart));
 895256        ThrowIfDirectWorldRegisterCall();
 893257        LinkWorld(world);
 258
 892259        return RegisterChartInternal(
 892260            world,
 892261            chart,
 892262            generatedTransitionIdPrefix: chart.Name,
 892263            precomputedGeneratedTransitions: null,
 892264            initializeChart);
 265    }
 266
 267    /// <summary>
 268    /// Attempts to register the chart and generated transitions produced by a traversal authoring build.
 269    /// </summary>
 270    /// <param name="buildResult">The build result to register.</param>
 271    /// <param name="initializeChart">Whether to initialize the built chart after registration succeeds.</param>
 272    /// <returns>True when the chart and all generated transitions are registered successfully; otherwise, false.</retur
 273    /// <exception cref="ArgumentNullException">Thrown when <paramref name="buildResult"/> is null.</exception>
 274    public static bool Register(TraversalBuildResult buildResult, bool initializeChart = true)
 275    {
 12276        PathingWorldState state = ActiveState;
 12277        using (EnterState(state))
 12278            return Register(state.World, buildResult, initializeChart);
 12279    }
 280
 281    /// <summary>
 282    /// Attempts to register the chart and generated transitions produced by a traversal authoring build.
 283    /// </summary>
 284    /// <param name="world">The grid world context for the chart.</param>
 285    /// <param name="buildResult">The build result to register.</param>
 286    /// <param name="initializeChart">Whether to initialize the built chart after registration succeeds.</param>
 287    /// <returns>True when the chart and all generated transitions are registered successfully; otherwise, false.</retur
 288    /// <exception cref="ArgumentNullException">Thrown when <paramref name="buildResult"/> is null.</exception>
 289    public static bool Register(GridWorld world, TraversalBuildResult buildResult, bool initializeChart = true)
 290    {
 16291        SwiftThrowHelper.ThrowIfNull(buildResult, nameof(buildResult));
 16292        ThrowIfDirectWorldRegisterCall();
 16293        LinkWorld(world);
 294
 16295        return RegisterChartInternal(
 16296            world,
 16297            buildResult.Chart,
 16298            buildResult.GeneratedTransitionIdPrefix,
 16299            buildResult.GeneratedTransitions,
 16300            initializeChart);
 301    }
 302
 303    private static void ThrowIfDirectWorldRegisterCall()
 304    {
 911305        if (_activeState != null)
 909306            return;
 307
 2308        throw new InvalidOperationException(
 2309            "PathManager.Register(world, ...) is no longer a multi-world registration API. " +
 2310            "Create a TrailblazerWorldContext for that GridWorld and call context.Pathing.Register(...), " +
 2311            "or initialize the single default facade and call PathManager.Register(chart).");
 312    }
 313
 314    private static bool RegisterChartInternal(
 315        GridWorld world,
 316        NavigationChart chart,
 317        string generatedTransitionIdPrefix,
 318        TraversalTransition[]? precomputedGeneratedTransitions,
 319        bool initializeChart)
 320    {
 908321        _navigationChartMapLock.EnterWriteLock();
 322        try
 323        {
 908324            if (_navigationChartMap.ContainsKey(chart.Name))
 1325                return false;
 326
 907327            ValidateChartVoxelSizeCompatibility(world, chart);
 328
 906329            var registration = new NavigationChartRegistration(
 906330                chart,
 906331                unchecked(++_nextChartRegistrationOrder),
 906332                generatedTransitionIdPrefix);
 906333            _navigationChartMap.Add(chart.Name, registration);
 906334        }
 1816335        finally { _navigationChartMapLock.ExitWriteLock(); }
 336
 906337        if (!TryRegisterManagedGeneratedTransitions(chart.Name, precomputedGeneratedTransitions))
 338        {
 1339            RemoveChartFromRegistry(chart.Name);
 1340            return false;
 341        }
 342
 905343        if (initializeChart)
 886344            InitializeChart(world, chart.Name);
 345
 905346        return true;
 1347    }
 348
 349    private static void ValidateChartVoxelSizeCompatibility(GridWorld world, NavigationChart chart)
 350    {
 907351        if (chart.Interval == world.VoxelSize)
 906352            return;
 353
 1354        throw new ArgumentException(
 1355            $"Navigation chart '{chart.Name}' uses interval {chart.Interval}, but the owning GridWorld uses voxel size {
 1356            "Rebuild the chart with the context voxel size before registration.",
 1357            nameof(chart));
 358    }
 359
 360    /// <summary>
 361    /// Checks if a navigation map is already registered under the specified name.
 362    /// </summary>
 363    /// <param name="name">The map name to check.</param>
 364    /// <returns>True if registered; otherwise, false.</returns>
 365    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 366    public static bool IsChartRegistered(string name)
 367    {
 18368        _navigationChartMapLock.EnterReadLock();
 18369        try { return _navigationChartMap.ContainsKey(name); }
 36370        finally { _navigationChartMapLock.ExitReadLock(); }
 18371    }
 372
 373    /// <summary>
 374    /// Attempts to retrieve a registered navigation chart by name.
 375    /// </summary>
 376    /// <param name="name">The name of the map.</param>
 377    /// <param name="chart">The retrieved navigation chart.</param>
 378    /// <returns>True if the map exists; otherwise, false.</returns>
 379    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 380    public static bool TryGetNavigationChart(string name, out NavigationChart chart)
 381    {
 1048382        _navigationChartMapLock.EnterReadLock();
 383        try
 384        {
 1048385            if (_navigationChartMap.TryGetValue(name, out NavigationChartRegistration registration))
 386            {
 1046387                chart = registration.Chart;
 1046388                return true;
 389            }
 390
 2391            chart = null!;
 2392            return false;
 393        }
 394        finally
 395        {
 1048396            _navigationChartMapLock.ExitReadLock();
 1048397        }
 1048398    }
 399
 400    /// <summary>
 401    /// Attempts to retrieve live registration state for a chart by name.
 402    /// </summary>
 403    /// <param name="name">The registered chart name.</param>
 404    /// <param name="registration">The live chart registration.</param>
 405    /// <returns>True when a registration exists; otherwise, false.</returns>
 406    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 407    public static bool TryGetNavigationChartRegistration(
 408        string name,
 409        out NavigationChartRegistration registration)
 410    {
 2323411        _navigationChartMapLock.EnterReadLock();
 2323412        try { return TryGetNavigationChartRegistration_NoLock(name, out registration); }
 4646413        finally { _navigationChartMapLock.ExitReadLock(); }
 2323414    }
 415
 416    /// <summary>
 417    /// Gets whether a registered chart is currently initialized into live voxel state.
 418    /// </summary>
 419    /// <param name="name">The registered chart name.</param>
 420    /// <returns>True when the chart has an initialized live registration; otherwise, false.</returns>
 421    public static bool IsChartInitialized(string name)
 422    {
 160423        return TryGetNavigationChartRegistration(name, out NavigationChartRegistration registration)
 160424            && registration.IsInitialized;
 425    }
 426
 427    /// <summary>
 428    /// Gets whether an authored chart's current registration is initialized.
 429    /// </summary>
 430    /// <param name="chart">The authored chart to inspect.</param>
 431    /// <returns>True when the chart is registered and initialized; otherwise, false.</returns>
 432    public static bool IsChartInitialized(NavigationChart chart)
 433    {
 33434        return chart != null && IsChartInitialized(chart.Name);
 435    }
 436
 437    private static bool TryGetNavigationChartRegistration_NoLock(
 438        string name,
 439        out NavigationChartRegistration registration)
 440    {
 4534441        if (_navigationChartMap.TryGetValue(name, out registration))
 4521442            return true;
 443
 13444        registration = null!;
 13445        return false;
 446    }
 447
 448    /// <summary>
 449    /// Attempts to retrieve the winning effective authored cell at the provided voxel.
 450    /// </summary>
 451    /// <param name="voxelIndex">The voxel to inspect.</param>
 452    /// <param name="cell">The effective authored cell currently winning overlap resolution.</param>
 453    /// <returns>True when the voxel currently has an effective authored chart cell; otherwise, false.</returns>
 454    public static bool TryGetEffectiveCell(WorldVoxelIndex voxelIndex, out NavigationChartCell cell)
 455    {
 3456        if (TryGetResolvedChartVoxelState(voxelIndex, out ResolvedChartVoxelState? state))
 457        {
 2458            cell = state!.EffectiveCell;
 2459            return true;
 460        }
 461
 1462        cell = NavigationChartCell.Empty;
 1463        return false;
 464    }
 465
 466    /// <summary>
 467    /// Attempts to retrieve the winning effective authored cell at the provided world position.
 468    /// </summary>
 469    /// <param name="world">The grid world context to search.</param>
 470    /// <param name="worldPosition">The world position to inspect.</param>
 471    /// <param name="cell">The effective authored cell currently winning overlap resolution.</param>
 472    /// <returns>True when the position resolves to a voxel with an effective authored chart cell; otherwise, false.</re
 473    public static bool TryGetEffectiveCell(GridWorld world, Vector3d worldPosition, out NavigationChartCell cell)
 474    {
 25475        LinkWorld(world);
 25476        if (TryGetResolvedChartVoxelState(world, worldPosition, out _, out ResolvedChartVoxelState? state))
 477        {
 15478            cell = state!.EffectiveCell;
 15479            return true;
 480        }
 481
 10482        cell = NavigationChartCell.Empty;
 10483        return false;
 484    }
 485
 486    /// <summary>
 487    /// Attempts to retrieve the winning effective authored cell at the provided world position using the configured wor
 488    /// </summary>
 489    public static bool TryGetEffectiveCell(Vector3d worldPosition, out NavigationChartCell cell)
 490    {
 15491        return TryGetEffectiveCell(GetConfiguredWorld(), worldPosition, out cell);
 492    }
 493
 494    /// <summary>
 495    /// Attempts to retrieve the chart currently winning overlap resolution at the provided voxel.
 496    /// </summary>
 497    /// <param name="voxelIndex">The voxel to inspect.</param>
 498    /// <param name="chartName">The effective chart owner.</param>
 499    /// <returns>True when the voxel currently has an effective chart owner; otherwise, false.</returns>
 500    public static bool TryGetEffectiveChartOwner(WorldVoxelIndex voxelIndex, out string? chartName)
 501    {
 3502        if (TryGetResolvedChartVoxelState(voxelIndex, out ResolvedChartVoxelState? state))
 503        {
 2504            chartName = state!.EffectiveChartOwner;
 2505            return true;
 506        }
 507
 1508        chartName = null;
 1509        return false;
 510    }
 511
 512    /// <summary>
 513    /// Attempts to retrieve the chart currently winning overlap resolution at the provided world position.
 514    /// </summary>
 515    /// <param name="world">The grid world context to search.</param>
 516    /// <param name="worldPosition">The world position to inspect.</param>
 517    /// <param name="chartName">The effective chart owner.</param>
 518    /// <returns>True when the position resolves to a voxel with an effective chart owner; otherwise, false.</returns>
 519    public static bool TryGetEffectiveChartOwner(GridWorld world, Vector3d worldPosition, out string? chartName)
 520    {
 10521        LinkWorld(world);
 10522        if (TryGetResolvedChartVoxelState(world, worldPosition, out _, out ResolvedChartVoxelState? state))
 523        {
 7524            chartName = state!.EffectiveChartOwner;
 7525            return true;
 526        }
 527
 3528        chartName = null;
 3529        return false;
 530    }
 531
 532    /// <summary>
 533    /// Attempts to retrieve the chart currently winning overlap resolution at the provided world position using the con
 534    /// </summary>
 535    public static bool TryGetEffectiveChartOwner(Vector3d worldPosition, out string? chartName)
 536    {
 6537        return TryGetEffectiveChartOwner(GetConfiguredWorld(), worldPosition, out chartName);
 538    }
 539
 540    /// <summary>
 541    /// Attempts to retrieve the closest currently active directed transition of the requested type.
 542    /// </summary>
 543    /// <param name="world">The grid world context to search.</param>
 544    /// <param name="worldPosition">The position to measure from.</param>
 545    /// <param name="transitionType">The directed handoff family to search.</param>
 546    /// <param name="transition">
 547    /// The closest active directed transition. Bidirectional registrations may return the reversed
 548    /// directed view when that source anchor is closer.
 549    /// </param>
 550    /// <returns>True when at least one active directed transition of that type exists; otherwise, false.</returns>
 551    public static bool TryGetClosestActiveTransition(
 552        GridWorld world,
 553        Vector3d worldPosition,
 554        TraversalTransitionType transitionType,
 555        out TraversalTransition transition)
 556    {
 8557        LinkWorld(world);
 8558        int[] sourceGridIndices = TraversalTransitionQuery.GetSourceGridIndices(transitionType);
 8559        if (sourceGridIndices.Length == 0)
 560        {
 1561            transition = default;
 1562            return false;
 563        }
 564
 7565        bool found = false;
 7566        transition = default;
 7567        Fixed64 closestDistanceSq = Fixed64.Zero;
 7568        int originGridIndex = -1;
 569
 7570        if (world.TryGetGrid(worldPosition, out VoxelGrid? originGrid))
 571        {
 6572            originGridIndex = originGrid!.GridIndex;
 6573            EvaluateClosestTransitionCandidates(
 6574                TraversalTransitionQuery.GetDirectedTransitionsFromSourceGrid(originGridIndex, transitionType),
 6575                worldPosition,
 6576                ref found,
 6577                ref transition,
 6578                ref closestDistanceSq);
 579
 6580            if (found && closestDistanceSq == Fixed64.Zero)
 3581                return true;
 582        }
 583
 18584        for (int i = 0; i < sourceGridIndices.Length; i++)
 585        {
 5586            int sourceGridIndex = sourceGridIndices[i];
 5587            if (sourceGridIndex == originGridIndex
 5588                || !world.TryGetGrid(sourceGridIndex, out VoxelGrid? sourceGrid)
 5589                || (found && GetBoundsDistanceSq(worldPosition, sourceGrid!.BoundsMin, sourceGrid.BoundsMax) >= closestD
 590            {
 591                continue;
 592            }
 593
 2594            EvaluateClosestTransitionCandidates(
 2595                TraversalTransitionQuery.GetDirectedTransitionsFromSourceGrid(sourceGridIndex, transitionType),
 2596                worldPosition,
 2597                ref found,
 2598                ref transition,
 2599                ref closestDistanceSq);
 600
 2601            if (found && closestDistanceSq == Fixed64.Zero)
 602                break;
 603        }
 604
 4605        return found;
 606    }
 607
 608    /// <summary>
 609    /// Attempts to retrieve the closest currently active directed transition of the requested type using the configured
 610    /// </summary>
 611    public static bool TryGetClosestActiveTransition(
 612        Vector3d worldPosition,
 613        TraversalTransitionType transitionType,
 614        out TraversalTransition transition)
 615    {
 8616        return TryGetClosestActiveTransition(GetConfiguredWorld(), worldPosition, transitionType, out transition);
 617    }
 618
 619    /// <summary>
 620    /// Initializes all registered navigation charts by materializing their authored surface and volume partitions.
 621    /// </summary>
 622    public static void InitializeAllCharts()
 623    {
 1624        InitializeAllCharts(GetConfiguredWorld());
 1625    }
 626
 627    /// <summary>
 628    /// Initializes all registered navigation charts by materializing their authored surface and volume partitions.
 629    /// </summary>
 630    public static void InitializeAllCharts(GridWorld world)
 631    {
 2632        LinkWorld(world);
 10633        foreach (NavigationChart chart in AllCharts)
 3634            InitializeChart(world, chart.Name);
 2635    }
 636
 637    private static void EvaluateClosestTransitionCandidates(
 638        TraversalTransition[] candidates,
 639        Vector3d worldPosition,
 640        ref bool found,
 641        ref TraversalTransition closestTransition,
 642        ref Fixed64 closestDistanceSq)
 643    {
 44644        for (int i = 0; i < candidates.Length; i++)
 645        {
 14646            Fixed64 candidateDistanceSq = (candidates[i].Source.Position - worldPosition).SqrMagnitude;
 14647            if (!found || candidateDistanceSq < closestDistanceSq)
 648            {
 12649                found = true;
 12650                closestDistanceSq = candidateDistanceSq;
 12651                closestTransition = candidates[i];
 652            }
 653        }
 8654    }
 655
 656    private static Fixed64 GetBoundsDistanceSq(
 657        Vector3d worldPosition,
 658        Vector3d boundsMin,
 659        Vector3d boundsMax)
 660    {
 1661        Fixed64 xDistance = GetAxisDistanceToBounds(worldPosition.x, boundsMin.x, boundsMax.x);
 1662        Fixed64 yDistance = GetAxisDistanceToBounds(worldPosition.y, boundsMin.y, boundsMax.y);
 1663        Fixed64 zDistance = GetAxisDistanceToBounds(worldPosition.z, boundsMin.z, boundsMax.z);
 1664        return xDistance * xDistance + yDistance * yDistance + zDistance * zDistance;
 665    }
 666
 667    private static Fixed64 GetAxisDistanceToBounds(Fixed64 value, Fixed64 boundsMin, Fixed64 boundsMax)
 668    {
 3669        if (value < boundsMin)
 1670            return boundsMin - value;
 671
 2672        if (value > boundsMax)
 1673            return value - boundsMax;
 674
 1675        return Fixed64.Zero;
 676    }
 677
 678    /// <summary>
 679    /// Applies one authored cell mutation to a registered chart using chart-local indices.
 680    /// </summary>
 681    /// <returns>
 682    /// <c>true</c> when the target cell was in bounds and the authored payload changed; otherwise, <c>false</c>.
 683    /// </returns>
 684    public static bool TryUpdateChartCell(string chartName, int x, int y, int z, NavigationChartCell cell)
 685    {
 15686        return TryUpdateChartCell(GetConfiguredWorld(), chartName, x, y, z, cell);
 687    }
 688
 689    /// <summary>
 690    /// Applies one authored cell mutation to a registered chart using chart-local indices.
 691    /// </summary>
 692    /// <returns>
 693    /// <c>true</c> when the target cell was in bounds and the authored payload changed; otherwise, <c>false</c>.
 694    /// </returns>
 695    public static bool TryUpdateChartCell(GridWorld world, string chartName, int x, int y, int z, NavigationChartCell ce
 696    {
 16697        LinkWorld(world);
 16698        if (!TryGetNavigationChartRegistration(chartName, out NavigationChartRegistration registration))
 1699            return false;
 700
 15701        return TryUpdateChartCell(world, registration, x, y, z, cell);
 702    }
 703
 704    private static bool TryUpdateChartCell(
 705        GridWorld world,
 706        NavigationChartRegistration registration,
 707        int x,
 708        int y,
 709        int z,
 710        NavigationChartCell cell)
 711    {
 21712        NavigationChart chart = registration.Chart;
 21713        SwiftHashSet<SolidChartPartition> partitionsToRebind = PartitionSetPool.Rent();
 21714        SwiftHashSet<string> invalidatedChartKeys = SwiftHashSetPool<string>.Shared.Rent();
 21715        SwiftHashSet<string> managedChartsToRefresh = SwiftHashSetPool<string>.Shared.Rent();
 716        try
 717        {
 21718            bool changed = TryApplyChartCellUpdate(
 21719                world,
 21720                registration,
 21721                x,
 21722                y,
 21723                z,
 21724                cell,
 21725                partitionsToRebind,
 21726                invalidatedChartKeys,
 21727                managedChartsToRefresh);
 728
 21729            if (changed)
 18730                RefreshManagedTransitionsForVoxel(
 18731                    world,
 18732                    chart.GetWorldPosition(x, y, z),
 18733                    managedChartsToRefresh);
 734
 21735            RebindAndInvalidate(partitionsToRebind, invalidatedChartKeys);
 21736            return changed;
 737        }
 738        finally
 739        {
 21740            PartitionSetPool.Release(partitionsToRebind);
 21741            SwiftHashSetPool<string>.Shared.Release(invalidatedChartKeys);
 21742            SwiftHashSetPool<string>.Shared.Release(managedChartsToRefresh);
 21743        }
 21744    }
 745
 746    /// <summary>
 747    /// Applies one authored cell mutation to a registered chart using a world-space position.
 748    /// </summary>
 749    /// <returns>
 750    /// <c>true</c> when the position resolves inside the chart and the authored payload changed; otherwise, <c>false</c
 751    /// </returns>
 752    public static bool TryUpdateChartCell(string chartName, Vector3d worldPosition, NavigationChartCell cell)
 753    {
 5754        return TryUpdateChartCell(GetConfiguredWorld(), chartName, worldPosition, cell);
 755    }
 756
 757    /// <summary>
 758    /// Applies one authored cell mutation to a registered chart using a world-space position.
 759    /// </summary>
 760    /// <returns>
 761    /// <c>true</c> when the position resolves inside the chart and the authored payload changed; otherwise, <c>false</c
 762    /// </returns>
 763    public static bool TryUpdateChartCell(GridWorld world, string chartName, Vector3d worldPosition, NavigationChartCell
 764    {
 7765        LinkWorld(world);
 7766        if (!TryGetNavigationChartRegistration(chartName, out NavigationChartRegistration registration)
 7767            || !registration.Chart.TryWorldToIndex(worldPosition, out int x, out int y, out int z))
 768        {
 1769            return false;
 770        }
 771
 6772        return TryUpdateChartCell(world, registration, x, y, z, cell);
 773    }
 774
 775    /// <summary>
 776    /// Applies a sparse batch of authored cell mutations to a registered chart.
 777    /// </summary>
 778    /// <param name="chartName">The registered chart to mutate.</param>
 779    /// <param name="updates">The sparse set of cell changes to apply in order.</param>
 780    /// <returns>The number of authored cell mutations that changed the chart payload.</returns>
 781    /// <exception cref="ArgumentNullException">Thrown when <paramref name="updates"/> is null.</exception>
 782    public static int ApplyChartUpdates(string chartName, IReadOnlyList<NavigationChartCellUpdate> updates)
 783    {
 4784        return ApplyChartUpdates(GetConfiguredWorld(), chartName, updates);
 785    }
 786
 787    /// <summary>
 788    /// Applies a sparse batch of authored cell mutations to a registered chart.
 789    /// </summary>
 790    /// <param name="world">The grid world context for the chart.</param>
 791    /// <param name="chartName">The registered chart to mutate.</param>
 792    /// <param name="updates">The sparse set of cell changes to apply in order.</param>
 793    /// <returns>The number of authored cell mutations that changed the chart payload.</returns>
 794    /// <exception cref="ArgumentNullException">Thrown when <paramref name="updates"/> is null.</exception>
 795    public static int ApplyChartUpdates(GridWorld world, string chartName, IReadOnlyList<NavigationChartCellUpdate> upda
 796    {
 5797        SwiftThrowHelper.ThrowIfNull(updates, nameof(updates));
 4798        LinkWorld(world);
 799
 4800        if (updates.Count == 0
 4801            || !TryGetNavigationChartRegistration(chartName, out NavigationChartRegistration registration))
 802        {
 2803            return 0;
 804        }
 805
 2806        NavigationChart chart = registration.Chart;
 2807        SwiftHashSet<SolidChartPartition> partitionsToRebind = PartitionSetPool.Rent();
 2808        SwiftHashSet<string> invalidatedChartKeys = SwiftHashSetPool<string>.Shared.Rent();
 2809        SwiftHashSet<string> managedChartsToRefresh = SwiftHashSetPool<string>.Shared.Rent();
 810        try
 811        {
 2812            int changedCount = 0;
 12813            for (int i = 0; i < updates.Count; i++)
 814            {
 4815                managedChartsToRefresh.Clear();
 4816                NavigationChartCellUpdate update = updates[i];
 4817                if (TryApplyChartCellUpdate(
 4818                    world,
 4819                    registration,
 4820                    update.X,
 4821                    update.Y,
 4822                    update.Z,
 4823                    update.Cell,
 4824                    partitionsToRebind,
 4825                    invalidatedChartKeys,
 4826                    managedChartsToRefresh))
 827                {
 2828                    changedCount++;
 2829                    RefreshManagedTransitionsForVoxel(
 2830                        world,
 2831                        chart.GetWorldPosition(update.X, update.Y, update.Z),
 2832                        managedChartsToRefresh);
 833                }
 834            }
 835
 2836            RebindAndInvalidate(partitionsToRebind, invalidatedChartKeys);
 2837            return changedCount;
 838        }
 839        finally
 840        {
 2841            PartitionSetPool.Release(partitionsToRebind);
 2842            SwiftHashSetPool<string>.Shared.Release(invalidatedChartKeys);
 2843            SwiftHashSetPool<string>.Shared.Release(managedChartsToRefresh);
 2844        }
 2845    }
 846
 847    /// <summary>
 848    /// Initializes a specific navigation chart by materializing its authored surface and volume partitions.
 849    /// </summary>
 850    /// <param name="chartKey">The name of the map to initialize.</param>
 851    public static void InitializeChart(string chartKey)
 852    {
 27853        InitializeChart(GetConfiguredWorld(), chartKey);
 27854    }
 855
 856    /// <summary>
 857    /// Initializes a specific navigation chart by materializing its authored surface and volume partitions.
 858    /// </summary>
 859    /// <param name="world">The grid world context for the chart.</param>
 860    /// <param name="chartKey">The name of the map to initialize.</param>
 861    public static void InitializeChart(GridWorld world, string chartKey)
 862    {
 969863        LinkWorld(world);
 969864        if (string.IsNullOrEmpty(chartKey)
 969865            || !TryGetNavigationChartRegistration(chartKey, out NavigationChartRegistration registration)
 969866            || registration.IsInitialized)
 867        {
 24868            return;
 869        }
 870
 945871        NavigationChart chart = registration.Chart;
 945872        PathManagerExternalGridBridge.FlushPendingGridChanges();
 873
 945874        SwiftHashSet<SolidChartPartition> partitionsToRebind = PartitionSetPool.Rent();
 945875        SwiftHashSet<string> affectedChartKeys = SwiftHashSetPool<string>.Shared.Rent();
 945876        SwiftHashSet<WorldVoxelIndex> touchedVoxelIndices = SwiftHashSetPool<WorldVoxelIndex>.Shared.Rent();
 877        try
 878        {
 8170879            foreach ((Vector3d pos, NavigationChartCell cell) in chart.GetAuthoredCells())
 880            {
 3140881                if (!world.TryGetVoxel(pos, out Voxel? voxel))
 882                    continue;
 883
 2942884                touchedVoxelIndices.Add(voxel!.WorldIndex);
 885
 2942886                if (!_resolvedChartVoxelStates.TryGetValue(voxel.WorldIndex, out ResolvedChartVoxelState state))
 887                {
 2928888                    state = new ResolvedChartVoxelState();
 2928889                    _resolvedChartVoxelStates[voxel.WorldIndex] = state;
 890                }
 14891                else if (state.HasAnyOwners)
 14892                    state.AddChartOwnersTo(affectedChartKeys);
 893
 2942894                NavigationChartCell previousEffectiveCell = state.EffectiveCell;
 2942895                state.AddOwner(chart.Name, cell, chart.Priority, registration.RegistrationOrder);
 2942896                ApplyResolvedVoxelState(world, voxel, state, previousEffectiveCell, partitionsToRebind);
 2942897                TrackInitializedChartGridTouch(voxel.GridIndex, chart.Name);
 898            }
 899
 945900            BindCollectedSolidPartitions(partitionsToRebind);
 901
 945902            registration.IsInitialized = true;
 945903            affectedChartKeys.Add(chart.Name);
 945904            SolidPartitionReachability.Invalidate();
 905
 945906            RefreshManagedManualTransitionsForVoxels(touchedVoxelIndices);
 945907            RefreshManagedGeneratedTransitionsForCharts(world, affectedChartKeys);
 908
 3806909            foreach (string affectedChartKey in affectedChartKeys)
 958910                PathGuideFactory.InvalidateCacheFor(affectedChartKey);
 911        }
 912        finally
 913        {
 945914            PartitionSetPool.Release(partitionsToRebind);
 945915            SwiftHashSetPool<string>.Shared.Release(affectedChartKeys);
 945916            SwiftHashSetPool<WorldVoxelIndex>.Shared.Release(touchedVoxelIndices);
 945917        }
 945918    }
 919
 920    /// <summary>
 921    /// Unloads the navigation chart identified by the specified key from the given world.
 922    /// </summary>
 923    /// <param name="chartKey">
 924    /// The unique key identifying the navigation chart to unload.
 925    /// If the key does not correspond to a loaded chart, no action is taken.</param>
 926    public static void UnloadChart(string chartKey)
 927    {
 186928        UnloadChart(GetConfiguredWorld(), chartKey);
 186929    }
 930
 931    /// <summary>
 932    /// Unloads the navigation chart identified by the specified key from the given world.
 933    /// </summary>
 934    /// <param name="world">The world instance from which to unload the navigation chart.</param>
 935    /// <param name="chartKey">
 936    /// The unique key identifying the navigation chart to unload.
 937    /// If the key does not correspond to a loaded chart, no action is taken.</param>
 938    public static void UnloadChart(GridWorld world, string chartKey)
 939    {
 189940        LinkWorld(world);
 189941        if (!TryGetNavigationChartRegistration(chartKey, out NavigationChartRegistration registration))
 1942            return;
 943
 188944        UnloadChart(world, registration);
 188945    }
 946
 947    /// <summary>
 948    /// Unloads a navigation map by name and releases associated partitions.
 949    /// </summary>
 950    /// <param name="chart">The navigation chart to unload.</param>
 951    public static void UnloadChart(NavigationChart chart)
 952    {
 13953        UnloadChart(GetConfiguredWorld(), chart);
 13954    }
 955
 956    /// <summary>
 957    /// Unloads a navigation map by name and releases associated partitions.
 958    /// </summary>
 959    /// <param name="world">The grid world context for the chart.</param>
 960    /// <param name="chart">The navigation chart to unload.</param>
 961    public static void UnloadChart(GridWorld world, NavigationChart chart)
 962    {
 15963        LinkWorld(world);
 15964        if (chart == null)
 1965            return;
 966
 14967        if (!TryGetNavigationChartRegistration(chart.Name, out NavigationChartRegistration registration))
 1968            return;
 969
 13970        UnloadChart(world, registration);
 13971    }
 972
 973    private static void UnloadChart(GridWorld world, NavigationChartRegistration registration)
 974    {
 201975        NavigationChart chart = registration.Chart;
 201976        string[] generatedTransitionIds = RemoveManagedGeneratedTransitions(chart.Name);
 977
 201978        if (!registration.IsInitialized)
 979        {
 7980            RemoveChartFromRegistry(chart.Name);
 7981            TraversalTransitionRegistry.UnregisterRange(generatedTransitionIds);
 7982            return;
 983        }
 984
 985        // invalidate any survey results currently using this chart
 194986        PathGuideFactory.InvalidateCacheFor(chart.Name);
 987
 194988        SwiftHashSet<SolidChartPartition> partitionsToRebind = PartitionSetPool.Rent();
 194989        SwiftHashSet<string> affectedChartKeys = SwiftHashSetPool<string>.Shared.Rent();
 194990        SwiftHashSet<WorldVoxelIndex> touchedVoxelIndices = SwiftHashSetPool<WorldVoxelIndex>.Shared.Rent();
 991        try
 992        {
 194993            affectedChartKeys.Add(chart.Name);
 4492994            foreach ((Vector3d position, _) in chart.GetAuthoredCells())
 995            {
 2052996                if (!world.TryGetVoxel(position, out Voxel? voxel))
 997                    continue;
 998
 1861999                touchedVoxelIndices.Add(voxel!.WorldIndex);
 1000
 18611001                if (!_resolvedChartVoxelStates.TryGetValue(voxel.WorldIndex, out ResolvedChartVoxelState state)
 18611002                    || !state.ContainsOwner(chart.Name))
 1003                {
 1004                    continue;
 1005                }
 1006
 18611007                state.AddChartOwnersTo(affectedChartKeys);
 1008
 18611009                NavigationChartCell previousEffectiveCell = state.EffectiveCell;
 18611010                state.RemoveOwner(chart.Name);
 18611011                ApplyResolvedVoxelState(world, voxel, state, previousEffectiveCell, partitionsToRebind);
 18611012                UntrackInitializedChartGridTouch(voxel.GridIndex, chart.Name);
 1013
 18611014                if (!state.HasAnyOwners)
 18541015                    _resolvedChartVoxelStates.Remove(voxel.WorldIndex);
 1016            }
 1017
 1941018            BindCollectedSolidPartitions(partitionsToRebind);
 1019
 1941020            TraversalTransitionRegistry.UnregisterRange(generatedTransitionIds);
 1941021            registration.IsInitialized = false;
 1941022            RemoveChartFromRegistry(chart.Name);
 1941023            SolidPartitionReachability.Invalidate();
 1024
 1941025            RefreshManagedManualTransitionsForVoxels(touchedVoxelIndices);
 1941026            RefreshManagedGeneratedTransitionsForCharts(world, affectedChartKeys, chart.Name);
 1027
 7881028            foreach (string affectedChartKey in affectedChartKeys)
 1029            {
 2001030                if (affectedChartKey == chart.Name)
 1031                    continue;
 1032
 61033                PathGuideFactory.InvalidateCacheFor(affectedChartKey);
 1034            }
 1035        }
 1036        finally
 1037        {
 1941038            PartitionSetPool.Release(partitionsToRebind);
 1941039            SwiftHashSetPool<string>.Shared.Release(affectedChartKeys);
 1941040            SwiftHashSetPool<WorldVoxelIndex>.Shared.Release(touchedVoxelIndices);
 1941041        }
 1941042    }
 1043
 1044    #endregion
 1045
 1046    #region Pathfinding Utilities
 1047
 1048    internal static int RebuildInitializedChartsAgainstExternalGridRequests(
 1049        ExternalGridChartRebuildRequest[] rebuildRequests)
 1050    {
 4661051        return RebuildInitializedChartsAgainstExternalGridRequests(GetConfiguredWorld(), rebuildRequests);
 1052    }
 1053
 1054    internal static int RebuildInitializedChartsAgainstExternalGridRequests(
 1055        GridWorld world,
 1056        ExternalGridChartRebuildRequest[] rebuildRequests)
 1057    {
 4691058        if (rebuildRequests == null || rebuildRequests.Length == 0)
 11059            return 0;
 1060
 4681061        NavigationChart[] initializedCharts = GetInitializedChartsAffectedByExternalGridRequestsSnapshot(rebuildRequests
 4681062        if (initializedCharts.Length == 0)
 4441063            return 0;
 1064
 241065        RebuildInitializedChartsAgainstCurrentGrids(world, initializedCharts);
 241066        return initializedCharts.Length;
 1067    }
 1068
 1069    internal static int RebuildInitializedChartsAgainstExternalGridBounds(
 1070        GridWorld world,
 1071        ushort gridIndex,
 1072        Vector3d boundsMin,
 1073        Vector3d boundsMax,
 1074        bool useLiveGridTouchIndex)
 1075    {
 21076        ExternalGridChartRebuildRequest[] rebuildRequests =
 21077        {
 21078            new(
 21079                gridIndex,
 21080                boundsMin,
 21081                boundsMax,
 21082                includeLiveGridTouches: useLiveGridTouchIndex,
 21083                includeAuthoredCellsInBounds: !useLiveGridTouchIndex)
 21084        };
 1085
 21086        return RebuildInitializedChartsAgainstExternalGridRequests(world, rebuildRequests);
 1087    }
 1088
 1089    private static void RebuildInitializedChartsAgainstCurrentGrids(GridWorld world, NavigationChart[] chartsToRebuild)
 1090    {
 241091        SuppressManagedGeneratedTransitionsForCharts(chartsToRebuild);
 1092
 1521093        for (int i = 0; i < chartsToRebuild.Length; i++)
 521094            ClearInitializedChartLiveStatePreservingRegistration(world, chartsToRebuild[i]);
 1095
 1521096        for (int i = 0; i < chartsToRebuild.Length; i++)
 521097            InitializeChart(world, chartsToRebuild[i].Name);
 1098
 241099        RefreshManagedGeneratedTransitionsForCharts(world, GetInitializedChartsSnapshot());
 241100        TraversalTransitionRegistry.RefreshManagedManualTransitions();
 241101    }
 1102
 1103    private static void SuppressManagedGeneratedTransitionsForCharts(NavigationChart[] charts)
 1104    {
 241105        SwiftList<string> transitionIds = new();
 241106        _navigationChartMapLock.EnterReadLock();
 1107        try
 1108        {
 1521109            for (int i = 0; i < charts.Length; i++)
 1110            {
 521111                NavigationChart chart = charts[i];
 521112                if (!TryGetNavigationChartRegistration_NoLock(chart.Name, out NavigationChartRegistration registration)
 521113                    || registration.TransitionIds.Count == 0)
 1114                {
 1115                    continue;
 1116                }
 1117
 121118                foreach (string transitionId in registration.TransitionIds)
 41119                    transitionIds.Add(transitionId);
 1120            }
 241121        }
 1122        finally
 1123        {
 241124            _navigationChartMapLock.ExitReadLock();
 241125        }
 1126
 241127        if (transitionIds.Count == 0)
 221128            return;
 1129
 21130        TraversalTransitionRegistry.SetManagedTransitionsSuppressed(
 21131            transitionIds.ToArray(),
 21132            suppressed: true);
 21133    }
 1134
 1135    private static NavigationChart[] GetInitializedChartsSnapshot()
 1136    {
 261137        _navigationChartMapLock.EnterReadLock();
 1138        try
 1139        {
 261140            if (_navigationChartMap.Count == 0)
 11141                return Array.Empty<NavigationChart>();
 1142
 251143            SwiftList<NavigationChartRegistration> initializedCharts = new();
 1681144            foreach (NavigationChartRegistration registration in _navigationChartMap.Values)
 1145            {
 591146                if (registration.IsInitialized)
 561147                    initializedCharts.Add(registration);
 1148            }
 1149
 251150            return BuildInitializedChartSelectionSnapshot(initializedCharts);
 1151        }
 1152        finally
 1153        {
 261154            _navigationChartMapLock.ExitReadLock();
 261155        }
 261156    }
 1157
 1158    private static NavigationChart[] GetInitializedChartsIntersectingBoundsSnapshot(
 1159        Vector3d boundsMin,
 1160        Vector3d boundsMax)
 1161    {
 21162        _navigationChartMapLock.EnterReadLock();
 1163        try
 1164        {
 21165            if (_navigationChartMap.Count == 0)
 11166                return Array.Empty<NavigationChart>();
 1167
 11168            SwiftList<NavigationChartRegistration> initializedCharts = new();
 81169            foreach (NavigationChartRegistration registration in _navigationChartMap.Values)
 1170            {
 31171                NavigationChart chart = registration.Chart;
 31172                if (!registration.IsInitialized
 31173                    || !DoBoundsOverlap(chart.MinBounds, chart.MaxBounds, boundsMin, boundsMax))
 1174                {
 1175                    continue;
 1176                }
 1177
 11178                initializedCharts.Add(registration);
 1179            }
 1180
 11181            return BuildInitializedChartSelectionSnapshot(initializedCharts);
 1182        }
 1183        finally
 1184        {
 21185            _navigationChartMapLock.ExitReadLock();
 21186        }
 21187    }
 1188
 1189    private static NavigationChart[] GetInitializedChartsTouchingGridSnapshot(ushort gridIndex)
 1190    {
 21191        _navigationChartMapLock.EnterReadLock();
 1192        try
 1193        {
 21194            if (_navigationChartMap.Count == 0)
 11195                return Array.Empty<NavigationChart>();
 1196
 11197            SwiftDictionary<string, NavigationChartRegistration> selectedCharts = new(4, StringComparer.Ordinal);
 11198            AddInitializedChartsTouchingGrid_NoLock(gridIndex, selectedCharts);
 11199            return BuildInitializedChartSelectionSnapshot_NoLock(selectedCharts);
 1200        }
 1201        finally
 1202        {
 21203            _navigationChartMapLock.ExitReadLock();
 21204        }
 21205    }
 1206
 1207    private static NavigationChart[] GetInitializedChartsWithAuthoredCellsIntersectingBoundsSnapshot(
 1208        Vector3d boundsMin,
 1209        Vector3d boundsMax)
 1210    {
 21211        _navigationChartMapLock.EnterReadLock();
 1212        try
 1213        {
 21214            if (_navigationChartMap.Count == 0)
 11215                return Array.Empty<NavigationChart>();
 1216
 11217            SwiftDictionary<string, NavigationChartRegistration> selectedCharts = new(4, StringComparer.Ordinal);
 11218            AddInitializedChartsWithAuthoredCellsIntersectingBounds_NoLock(boundsMin, boundsMax, selectedCharts);
 11219            return BuildInitializedChartSelectionSnapshot_NoLock(selectedCharts);
 1220        }
 1221        finally
 1222        {
 21223            _navigationChartMapLock.ExitReadLock();
 21224        }
 21225    }
 1226
 1227    private static NavigationChart[] GetInitializedChartsAffectedByExternalGridRequestsSnapshot(
 1228        ExternalGridChartRebuildRequest[] rebuildRequests)
 1229    {
 4681230        _navigationChartMapLock.EnterReadLock();
 1231        try
 1232        {
 4681233            if (_navigationChartMap.Count == 0)
 131234                return Array.Empty<NavigationChart>();
 1235
 4551236            SwiftDictionary<string, NavigationChartRegistration> selectedCharts = new(8, StringComparer.Ordinal);
 18401237            for (int i = 0; i < rebuildRequests.Length; i++)
 1238            {
 4651239                ExternalGridChartRebuildRequest rebuildRequest = rebuildRequests[i];
 4651240                if (!rebuildRequest.HasSelectionCriteria)
 1241                    continue;
 1242
 4651243                if (rebuildRequest.IncludeLiveGridTouches)
 211244                    AddInitializedChartsTouchingGrid_NoLock(rebuildRequest.GridIndex, selectedCharts);
 1245
 4651246                if (rebuildRequest.IncludeAuthoredCellsInBounds)
 1247                {
 4451248                    AddInitializedChartsWithAuthoredCellsIntersectingBounds_NoLock(
 4451249                        rebuildRequest.BoundsMin,
 4451250                        rebuildRequest.BoundsMax,
 4451251                        selectedCharts);
 1252                }
 1253            }
 1254
 4551255            return BuildInitializedChartSelectionSnapshot_NoLock(selectedCharts);
 1256        }
 1257        finally
 1258        {
 4681259            _navigationChartMapLock.ExitReadLock();
 4681260        }
 4681261    }
 1262
 1263    private static void AddInitializedChartsTouchingGrid_NoLock(
 1264        ushort gridIndex,
 1265        SwiftDictionary<string, NavigationChartRegistration> selectedCharts)
 1266    {
 221267        if (!_initializedChartTouchCountsByGridIndex.TryGetValue(gridIndex, out SwiftDictionary<string, int> chartTouche
 221268            || chartTouches.Count == 0)
 1269        {
 21270            return;
 1271        }
 1272
 1341273        foreach (KeyValuePair<string, int> pair in chartTouches)
 1274        {
 471275            if (pair.Value <= 0
 471276                || !_navigationChartMap.TryGetValue(pair.Key, out NavigationChartRegistration registration)
 471277                || !registration.IsInitialized)
 1278            {
 1279                continue;
 1280            }
 1281
 471282            selectedCharts[registration.Chart.Name] = registration;
 1283        }
 201284    }
 1285
 1286    private static void AddInitializedChartsWithAuthoredCellsIntersectingBounds_NoLock(
 1287        Vector3d boundsMin,
 1288        Vector3d boundsMax,
 1289        SwiftDictionary<string, NavigationChartRegistration> selectedCharts)
 1290    {
 18061291        foreach (NavigationChartRegistration registration in _navigationChartMap.Values)
 1292        {
 4571293            NavigationChart chart = registration.Chart;
 4571294            if (!registration.IsInitialized
 4571295                || !DoBoundsOverlap(chart.MinBounds, chart.MaxBounds, boundsMin, boundsMax)
 4571296                || !ChartHasAuthoredCellInsideBounds(chart, boundsMin, boundsMax))
 1297            {
 1298                continue;
 1299            }
 1300
 81301            selectedCharts[chart.Name] = registration;
 1302        }
 4461303    }
 1304
 1305    private static NavigationChart[] BuildInitializedChartSelectionSnapshot_NoLock(
 1306        SwiftDictionary<string, NavigationChartRegistration> selectedCharts)
 1307    {
 4571308        if (selectedCharts.Count == 0)
 4311309            return Array.Empty<NavigationChart>();
 1310
 261311        NavigationChartRegistration[] snapshot = new NavigationChartRegistration[selectedCharts.Count];
 261312        int index = 0;
 1621313        foreach (NavigationChartRegistration registration in selectedCharts.Values)
 551314            snapshot[index++] = registration;
 1315
 261316        Array.Sort(snapshot, CompareRegistrationsByRegistrationOrder);
 261317        return CopyCharts(snapshot);
 1318    }
 1319
 1320    private static bool ChartHasAuthoredCellInsideBounds(
 1321        NavigationChart chart,
 1322        Vector3d boundsMin,
 1323        Vector3d boundsMax)
 1324    {
 281325        foreach ((Vector3d position, _) in chart.GetAuthoredCells())
 1326        {
 91327            if (IsPositionInsideBounds(position, boundsMin, boundsMax))
 81328                return true;
 1329        }
 1330
 11331        return false;
 81332    }
 1333
 1334    private static void ClearInitializedChartLiveStatePreservingRegistration(GridWorld world, NavigationChart chart)
 1335    {
 531336        if (chart == null
 531337            || !TryGetNavigationChartRegistration(chart.Name, out NavigationChartRegistration registration))
 1338        {
 01339            return;
 1340        }
 1341
 531342        ClearInitializedChartLiveStatePreservingRegistration(world, registration);
 531343    }
 1344
 1345    private static void ClearInitializedChartLiveStatePreservingRegistration(
 1346        GridWorld world,
 1347        NavigationChartRegistration registration)
 1348    {
 531349        NavigationChart chart = registration.Chart;
 531350        PathGuideFactory.InvalidateCacheFor(chart.Name);
 1351
 531352        SwiftHashSet<SolidChartPartition> partitionsToRebind = PartitionSetPool.Rent();
 531353        SwiftList<WorldVoxelIndex> resolvedVoxelIndicesToRemove = new();
 1354        try
 1355        {
 3341356            foreach (KeyValuePair<WorldVoxelIndex, ResolvedChartVoxelState> pair in _resolvedChartVoxelStates)
 1357            {
 1141358                ResolvedChartVoxelState state = pair.Value;
 1141359                if (!state.ContainsOwner(chart.Name))
 1360                    continue;
 1361
 501362                NavigationChartCell previousEffectiveCell = state.EffectiveCell;
 501363                state.RemoveOwner(chart.Name);
 1364
 501365                bool hasLiveVoxel = world.TryGetGridAndVoxel(pair.Key, out _, out Voxel? voxel);
 501366                if (hasLiveVoxel)
 1367                {
 441368                    ApplyResolvedVoxelState(world, voxel!, state, previousEffectiveCell, partitionsToRebind);
 441369                    UntrackInitializedChartGridTouch(voxel!.GridIndex, chart.Name);
 1370                }
 1371
 501372                if (!state.HasAnyOwners
 501373                    || !hasLiveVoxel)
 1374                {
 501375                    resolvedVoxelIndicesToRemove.Add(pair.Key);
 1376                }
 1377            }
 1378
 2061379            for (int i = 0; i < resolvedVoxelIndicesToRemove.Count; i++)
 501380                _resolvedChartVoxelStates.Remove(resolvedVoxelIndicesToRemove[i]);
 1381
 531382            BindCollectedSolidPartitions(partitionsToRebind);
 1383
 531384            registration.IsInitialized = false;
 531385            SolidPartitionReachability.Invalidate();
 531386        }
 1387        finally
 1388        {
 531389            PartitionSetPool.Release(partitionsToRebind);
 531390        }
 531391    }
 1392
 1393    private static void ClearLiveGridState(GridWorld world)
 1394    {
 53121395        foreach (KeyValuePair<WorldVoxelIndex, ResolvedChartVoxelState> pair in _resolvedChartVoxelStates)
 1396        {
 10241397            if (!world.TryGetGridAndVoxel(pair.Key, out _, out Voxel? voxel))
 1398                continue;
 1399
 10231400            RemoveLivePathingPartitions(voxel!);
 1401        }
 1402
 16321403        ClearLiveGridState();
 16321404    }
 1405
 1406    private static void ClearLiveGridState()
 1407    {
 16321408        _resolvedChartVoxelStates.Clear();
 16321409        _initializedChartTouchCountsByGridIndex.Clear();
 16321410        ClearActiveAuthoredVolumeMediumCounts();
 16321411        SolidPartitionReachability.Invalidate();
 16321412    }
 1413
 1414    private static bool DoBoundsOverlap(
 1415        Vector3d firstMin,
 1416        Vector3d firstMax,
 1417        Vector3d secondMin,
 1418        Vector3d secondMax)
 1419    {
 151420        return firstMin.x <= secondMax.x
 151421            && firstMax.x >= secondMin.x
 151422            && firstMin.y <= secondMax.y
 151423            && firstMax.y >= secondMin.y
 151424            && firstMin.z <= secondMax.z
 151425            && firstMax.z >= secondMin.z;
 1426    }
 1427
 1428    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1429    private static bool IsPositionInsideBounds(
 1430        Vector3d position,
 1431        Vector3d boundsMin,
 1432        Vector3d boundsMax)
 1433    {
 91434        return position.x >= boundsMin.x
 91435            && position.x <= boundsMax.x
 91436            && position.y >= boundsMin.y
 91437            && position.y <= boundsMax.y
 91438            && position.z >= boundsMin.z
 91439            && position.z <= boundsMax.z;
 1440    }
 1441
 1442    private static void RemoveLivePathingPartitions(Voxel voxel)
 1443    {
 10231444        if (voxel.TryGetPartition<SolidChartPartition>(out _))
 6281445            voxel.TryRemovePartition<SolidChartPartition>();
 1446
 10231447        if (voxel.TryGetPartition<VolumeChartPartition>(out _))
 4171448            voxel.TryRemovePartition<VolumeChartPartition>();
 10231449    }
 1450
 1451    private static NavigationChart[] BuildInitializedChartSelectionSnapshot(
 1452        SwiftList<NavigationChartRegistration> registrations)
 1453    {
 271454        if (registrations.Count == 0)
 11455            return Array.Empty<NavigationChart>();
 1456
 261457        NavigationChartRegistration[] snapshot = registrations.ToArray();
 261458        Array.Sort(snapshot, CompareRegistrationsByRegistrationOrder);
 261459        return CopyCharts(snapshot);
 1460    }
 1461
 1462    private static NavigationChart[] CopyCharts(NavigationChartRegistration[] registrations)
 1463    {
 521464        NavigationChart[] charts = new NavigationChart[registrations.Length];
 3281465        for (int i = 0; i < registrations.Length; i++)
 1121466            charts[i] = registrations[i].Chart;
 1467
 521468        return charts;
 1469    }
 1470
 1471    private static int CompareRegistrationsByRegistrationOrder(
 1472        NavigationChartRegistration left,
 1473        NavigationChartRegistration right)
 1474    {
 1071475        return left.RegistrationOrder.CompareTo(right.RegistrationOrder);
 1476    }
 1477
 1478    private static void TrackInitializedChartGridTouch(ushort gridIndex, string chartName)
 1479    {
 29471480        if (!_initializedChartTouchCountsByGridIndex.TryGetValue(gridIndex, out SwiftDictionary<string, int> chartTouche
 1481        {
 4581482            chartTouches = new SwiftDictionary<string, int>(4, StringComparer.Ordinal);
 4581483            _initializedChartTouchCountsByGridIndex[gridIndex] = chartTouches;
 1484        }
 1485
 29471486        chartTouches.TryGetValue(chartName, out int touchCount);
 29471487        chartTouches[chartName] = touchCount + 1;
 29471488    }
 1489
 1490    private static void UntrackInitializedChartGridTouch(ushort gridIndex, string chartName)
 1491    {
 19121492        if (!_initializedChartTouchCountsByGridIndex.TryGetValue(gridIndex, out SwiftDictionary<string, int> chartTouche
 19121493            || !chartTouches.TryGetValue(chartName, out int touchCount))
 1494        {
 11495            return;
 1496        }
 1497
 19111498        if (touchCount <= 1)
 2381499            chartTouches.Remove(chartName);
 1500        else
 16731501            chartTouches[chartName] = touchCount - 1;
 1502
 19111503        if (chartTouches.Count == 0)
 1781504            _initializedChartTouchCountsByGridIndex.Remove(gridIndex);
 19111505    }
 1506
 1507    private static void TrackInitializedChartGridTouchDelta(
 1508        ushort gridIndex,
 1509        string chartName,
 1510        NavigationChartCell previousCell,
 1511        NavigationChartCell currentCell)
 1512    {
 151513        if (previousCell.HasTraversalData == currentCell.HasTraversalData)
 41514            return;
 1515
 111516        if (previousCell.HasTraversalData)
 61517            UntrackInitializedChartGridTouch(gridIndex, chartName);
 1518
 111519        if (currentCell.HasTraversalData)
 51520            TrackInitializedChartGridTouch(gridIndex, chartName);
 111521    }
 1522
 11523    private static readonly (int Dx, int Dy, int Dz)[] ManagedGeneratedNeighborOffsets =
 11524    {
 11525        (1, 0, 0),
 11526        (-1, 0, 0),
 11527        (0, 1, 0),
 11528        (0, -1, 0),
 11529        (0, 0, 1),
 11530        (0, 0, -1)
 11531    };
 1532
 1533    private static bool TryRegisterManagedGeneratedTransitions(
 1534        string chartName,
 1535        TraversalTransition[]? precomputedGeneratedTransitions)
 1536    {
 9071537        if (!TryGetNavigationChartRegistration(chartName, out NavigationChartRegistration registration))
 11538            return false;
 1539
 9061540        NavigationChart chart = registration.Chart;
 9061541        TraversalTransition[] generatedTransitions = precomputedGeneratedTransitions
 9061542            ?? GeneratedTraversalTransitionBuilder.BuildTransitions(chart, registration.TransitionIdPrefix);
 9061543        int transitionCount = generatedTransitions.Length;
 9061544        if (transitionCount > 0
 9061545            && !TraversalTransitionRegistry.RegisterGeneratedRange(
 9061546                generatedTransitions,
 9061547                chart.Priority,
 9061548                startSuppressed: true))
 1549        {
 11550            return false;
 1551        }
 1552
 9051553        string[] registeredTransitionIds = transitionCount == 0
 9051554            ? Array.Empty<string>()
 9051555            : new string[transitionCount];
 19181556        for (int i = 0; i < transitionCount; i++)
 541557            registeredTransitionIds[i] = generatedTransitions[i].Id;
 1558
 9051559        RememberManagedGeneratedTransitions(chart.Name, registeredTransitionIds, transitionCount);
 9051560        return true;
 1561    }
 1562
 1563    private static void RememberManagedGeneratedTransitions(
 1564        string chartName,
 1565        string[] transitionIds,
 1566        int transitionCount)
 1567    {
 9061568        _navigationChartMapLock.EnterWriteLock();
 1569        try
 1570        {
 9061571            if (!TryGetNavigationChartRegistration_NoLock(chartName, out NavigationChartRegistration registration))
 11572                return;
 1573
 9051574            registration.TransitionIds.Clear();
 19181575            for (int i = 0; i < transitionCount; i++)
 541576                registration.TransitionIds.Add(transitionIds[i]);
 9051577        }
 18121578        finally { _navigationChartMapLock.ExitWriteLock(); }
 9061579    }
 1580
 1581    private static string[] RemoveManagedGeneratedTransitions(string chartName)
 1582    {
 2031583        _navigationChartMapLock.EnterWriteLock();
 1584        try
 1585        {
 2031586            if (!TryGetNavigationChartRegistration_NoLock(chartName, out NavigationChartRegistration registration))
 11587                return Array.Empty<string>();
 1588
 2021589            string[] transitionIds = CopyTransitionIds(registration.TransitionIds);
 2021590            registration.TransitionIds.Clear();
 2021591            return transitionIds;
 1592        }
 4061593        finally { _navigationChartMapLock.ExitWriteLock(); }
 2031594    }
 1595
 1596    private static bool TryGetManagedGeneratedTransitionState(
 1597        string chartName,
 1598        out NavigationChartRegistration state)
 1599    {
 10411600        _navigationChartMapLock.EnterReadLock();
 10411601        try { return TryGetNavigationChartRegistration_NoLock(chartName, out state); }
 20821602        finally { _navigationChartMapLock.ExitReadLock(); }
 10411603    }
 1604
 1605    private static void RefreshManagedGeneratedTransitionsForCharts(
 1606        GridWorld world,
 1607        SwiftHashSet<string> chartNames,
 1608        string? excludedChartName = null)
 1609    {
 11641610        if (chartNames == null || chartNames.Count == 0)
 11611            return;
 1612
 47501613        foreach (string chartName in chartNames)
 1614        {
 12121615            if (string.IsNullOrEmpty(chartName)
 12121616                || string.Equals(chartName, excludedChartName, StringComparison.Ordinal))
 1617            {
 1618                continue;
 1619            }
 1620
 10181621            RefreshManagedGeneratedTransitionsForChart(world, chartName);
 1622        }
 11631623    }
 1624
 1625    private static void RefreshManagedGeneratedTransitionsForCharts(GridWorld world, NavigationChart[] charts)
 1626    {
 241627        SwiftHashSet<string> chartNames = SwiftHashSetPool<string>.Shared.Rent();
 1628        try
 1629        {
 1561630            for (int i = 0; i < charts.Length; i++)
 541631                chartNames.Add(charts[i].Name);
 1632
 241633            RefreshManagedGeneratedTransitionsForCharts(world, chartNames);
 241634        }
 1635        finally
 1636        {
 241637            SwiftHashSetPool<string>.Shared.Release(chartNames);
 241638        }
 241639    }
 1640
 1641    private static void RefreshManagedTransitionsForVoxel(
 1642        GridWorld world,
 1643        Vector3d worldPosition,
 1644        SwiftHashSet<string> chartNames)
 1645    {
 201646        if (world.TryGetVoxel(worldPosition, out Voxel? voxel))
 191647            TraversalTransitionRegistry.RefreshManagedManualTransitionsForVoxel(voxel!.WorldIndex);
 1648
 201649        RefreshManagedGeneratedTransitionsForVoxel(world, worldPosition, chartNames);
 201650    }
 1651
 1652    private static void RefreshManagedManualTransitionsForVoxels(SwiftHashSet<WorldVoxelIndex> voxelIndices)
 1653    {
 11391654        if (voxelIndices == null || voxelIndices.Count == 0)
 181655            return;
 1656
 118481657        foreach (WorldVoxelIndex voxelIndex in voxelIndices)
 48031658            TraversalTransitionRegistry.RefreshManagedManualTransitionsForVoxel(voxelIndex);
 11211659    }
 1660
 1661    private static void RefreshManagedGeneratedTransitionsForChart(GridWorld world, string chartName)
 1662    {
 10191663        if (!TryGetNavigationChart(chartName, out NavigationChart chart)
 10191664            || !TryGetManagedGeneratedTransitionState(chartName, out NavigationChartRegistration state))
 1665        {
 11666            return;
 1667        }
 1668
 10181669        SwiftHashSet<string> desiredTransitionIds = SwiftHashSetPool<string>.Shared.Rent();
 10181670        SwiftHashSet<string> activeTransitionIds = SwiftHashSetPool<string>.Shared.Rent();
 1671        try
 1672        {
 10181673            TraversalTransition[] missingTransitions = CollectManagedGeneratedTransitionsForChart(
 10181674                world,
 10181675                chart,
 10181676                state,
 10181677                desiredTransitionIds,
 10181678                activeTransitionIds);
 1679
 10181680            ApplyManagedGeneratedTransitionDelta(
 10181681                chartName,
 10181682                state,
 10181683                desiredTransitionIds,
 10181684                activeTransitionIds,
 10181685                missingTransitions);
 10181686        }
 1687        finally
 1688        {
 10181689            SwiftHashSetPool<string>.Shared.Release(desiredTransitionIds);
 10181690            SwiftHashSetPool<string>.Shared.Release(activeTransitionIds);
 10181691        }
 10181692    }
 1693
 1694    private static TraversalTransition[] CollectManagedGeneratedTransitionsForChart(
 1695        GridWorld world,
 1696        NavigationChart chart,
 1697        NavigationChartRegistration state,
 1698        SwiftHashSet<string> desiredTransitionIds,
 1699        SwiftHashSet<string> activeTransitionIds)
 1700    {
 10211701        SwiftList<TraversalTransition> missingTransitions = new();
 10211702        int[] generatedIndices = chart.GetGeneratedTransitionIndices();
 21381703        for (int i = 0; i < generatedIndices.Length; i++)
 1704        {
 481705            chart.DecodeIndex(generatedIndices[i], out int x, out int y, out int z);
 6721706            for (int neighborOffsetIndex = 0; neighborOffsetIndex < ManagedGeneratedNeighborOffsets.Length; neighborOffs
 1707            {
 2881708                (int dx, int dy, int dz) = ManagedGeneratedNeighborOffsets[neighborOffsetIndex];
 2881709                int neighborX = x + dx;
 2881710                int neighborY = y + dy;
 2881711                int neighborZ = z + dz;
 2881712                if (!chart.IsInBounds(neighborX, neighborY, neighborZ))
 1713                    continue;
 1714
 861715                NavigationChartCell neighborCell = chart.GetCell(neighborX, neighborY, neighborZ);
 861716                if (!ShouldCollectManagedGeneratedPair(
 861717                    x,
 861718                    y,
 861719                    z,
 861720                    neighborX,
 861721                    neighborY,
 861722                    neighborZ,
 861723                    neighborCell))
 1724                {
 1725                    continue;
 1726                }
 1727
 601728                CollectManagedGeneratedTransitionsForPair(
 601729                    world,
 601730                    chart,
 601731                    state,
 601732                    x,
 601733                    y,
 601734                    z,
 601735                    neighborX,
 601736                    neighborY,
 601737                    neighborZ,
 601738                    desiredTransitionIds,
 601739                    activeTransitionIds,
 601740                    missingTransitions);
 1741            }
 1742        }
 1743
 10211744        return missingTransitions.Count == 0
 10211745            ? Array.Empty<TraversalTransition>()
 10211746            : missingTransitions.ToArray();
 1747    }
 1748
 1749    private static void RefreshManagedGeneratedTransitionsForVoxel(
 1750        GridWorld world,
 1751        Vector3d worldPosition,
 1752        SwiftHashSet<string> chartNames)
 1753    {
 221754        if (chartNames == null || chartNames.Count == 0)
 11755            return;
 1756
 921757        foreach (string chartName in chartNames)
 1758        {
 251759            if (string.IsNullOrEmpty(chartName)
 251760                || !TryGetNavigationChart(chartName, out NavigationChart chart)
 251761                || !TryGetManagedGeneratedTransitionState(chartName, out NavigationChartRegistration state)
 251762                || !chart.TryWorldToIndex(worldPosition, out int x, out int y, out int z))
 1763            {
 1764                continue;
 1765            }
 1766
 231767            RefreshManagedGeneratedTransitionsForVoxel(world, chartName, chart, state, x, y, z);
 1768        }
 211769    }
 1770
 1771    private static void RefreshManagedGeneratedTransitionsForVoxel(
 1772        GridWorld world,
 1773        string chartName,
 1774        NavigationChart chart,
 1775        NavigationChartRegistration state,
 1776        int x,
 1777        int y,
 1778        int z)
 1779    {
 3221780        for (int i = 0; i < ManagedGeneratedNeighborOffsets.Length; i++)
 1781        {
 1381782            (int dx, int dy, int dz) = ManagedGeneratedNeighborOffsets[i];
 1381783            int neighborX = x + dx;
 1381784            int neighborY = y + dy;
 1381785            int neighborZ = z + dz;
 1381786            if (!chart.IsInBounds(neighborX, neighborY, neighborZ))
 1787                continue;
 1788
 711789            if (neighborX < x
 711790                || (neighborX == x && neighborY < y)
 711791                || (neighborX == x && neighborY == y && neighborZ < z))
 1792            {
 381793                RefreshManagedGeneratedTransitionsForPair(
 381794                    world,
 381795                    chartName,
 381796                    chart,
 381797                    state,
 381798                    neighborX,
 381799                    neighborY,
 381800                    neighborZ,
 381801                    x,
 381802                    y,
 381803                    z);
 1804            }
 1805            else
 1806            {
 331807                RefreshManagedGeneratedTransitionsForPair(
 331808                    world,
 331809                    chartName,
 331810                    chart,
 331811                    state,
 331812                    x,
 331813                    y,
 331814                    z,
 331815                    neighborX,
 331816                    neighborY,
 331817                    neighborZ);
 1818            }
 1819        }
 231820    }
 1821
 1822    private static void RefreshManagedGeneratedTransitionsForPair(
 1823        GridWorld world,
 1824        string chartName,
 1825        NavigationChart chart,
 1826        NavigationChartRegistration state,
 1827        int firstX,
 1828        int firstY,
 1829        int firstZ,
 1830        int secondX,
 1831        int secondY,
 1832        int secondZ)
 1833    {
 711834        string[] potentialTransitionIds = GeneratedTraversalTransitionBuilder.GetPotentialTransitionIdsForPair(
 711835            state.TransitionIdPrefix,
 711836            firstX,
 711837            firstY,
 711838            firstZ,
 711839            secondX,
 711840            secondY,
 711841            secondZ);
 1842
 711843        if (!CanResolveManagedGeneratedPairAnchors(world, chart, firstX, firstY, firstZ, secondX, secondY, secondZ))
 1844        {
 121845            if (GeneratedTraversalTransitionBuilder.CanBuildTransitionsForPairFromChartData(
 121846                chart,
 121847                firstX,
 121848                firstY,
 121849                firstZ,
 121850                secondX,
 121851                secondY,
 121852                secondZ))
 1853            {
 01854                TraversalTransitionRegistry.SetManagedTransitionsSuppressed(
 01855                    potentialTransitionIds,
 01856                    suppressed: true);
 1857            }
 1858            else
 1859            {
 121860                string[] obsoleteSuppressedTransitionIds = GetObsoleteManagedGeneratedTransitionIds(
 121861                    state,
 121862                    potentialTransitionIds,
 121863                    Array.Empty<TraversalTransition>());
 121864                if (obsoleteSuppressedTransitionIds.Length > 0)
 1865                {
 01866                    TraversalTransitionRegistry.UnregisterRange(obsoleteSuppressedTransitionIds);
 01867                    RemoveManagedGeneratedTransitionIds(chartName, obsoleteSuppressedTransitionIds);
 1868                }
 1869            }
 1870
 121871            return;
 1872        }
 1873
 591874        TraversalTransition[] desiredTransitions = GeneratedTraversalTransitionBuilder.BuildTransitionsForPair(
 591875            chart,
 591876            state.TransitionIdPrefix,
 591877            firstX,
 591878            firstY,
 591879            firstZ,
 591880            secondX,
 591881            secondY,
 591882            secondZ);
 1883
 591884        string[] obsoleteTransitionIds = GetObsoleteManagedGeneratedTransitionIds(
 591885            state,
 591886            potentialTransitionIds,
 591887            desiredTransitions);
 591888        if (obsoleteTransitionIds.Length > 0)
 1889        {
 11890            TraversalTransitionRegistry.UnregisterRange(obsoleteTransitionIds);
 11891            RemoveManagedGeneratedTransitionIds(chartName, obsoleteTransitionIds);
 1892        }
 1893
 591894        TraversalTransition[] missingTransitions = GetMissingManagedGeneratedTransitions(state, desiredTransitions);
 591895        if (missingTransitions.Length > 0
 591896            && TraversalTransitionRegistry.RegisterGeneratedRange(
 591897                missingTransitions,
 591898                state.Priority,
 591899                startSuppressed: true))
 1900        {
 21901            AddManagedGeneratedTransitionIds(chartName, missingTransitions);
 1902        }
 1903
 591904        if (desiredTransitions.Length == 0)
 571905            return;
 1906
 21907        string[] desiredTransitionIds = CopyTransitionIds(desiredTransitions);
 21908        bool shouldBeActive = IsManagedGeneratedPairActive(
 21909            world,
 21910            chartName,
 21911            chart,
 21912            firstX,
 21913            firstY,
 21914            firstZ,
 21915            secondX,
 21916            secondY,
 21917            secondZ);
 21918        TraversalTransitionRegistry.SetManagedTransitionsSuppressed(
 21919            desiredTransitionIds,
 21920            suppressed: !shouldBeActive);
 21921    }
 1922
 1923    private static string[] GetObsoleteManagedGeneratedTransitionIds(
 1924        NavigationChartRegistration state,
 1925        string[] potentialTransitionIds,
 1926        TraversalTransition[] desiredTransitions)
 1927    {
 731928        if (potentialTransitionIds.Length == 0)
 11929            return Array.Empty<string>();
 1930
 721931        SwiftHashSet<string> desiredTransitionIds = SwiftHashSetPool<string>.Shared.Rent();
 1932        try
 1933        {
 1541934            for (int i = 0; i < desiredTransitions.Length; i++)
 51935                desiredTransitionIds.Add(desiredTransitions[i].Id);
 1936
 721937            SwiftList<string> obsoleteTransitionIds = new();
 15661938            for (int i = 0; i < potentialTransitionIds.Length; i++)
 1939            {
 7111940                string transitionId = potentialTransitionIds[i];
 7111941                if (state.TransitionIds.Contains(transitionId)
 7111942                    && !desiredTransitionIds.Contains(transitionId))
 1943                {
 21944                    obsoleteTransitionIds.Add(transitionId);
 1945                }
 1946            }
 1947
 721948            return obsoleteTransitionIds.Count == 0
 721949                ? Array.Empty<string>()
 721950                : obsoleteTransitionIds.ToArray();
 1951        }
 1952        finally
 1953        {
 721954            SwiftHashSetPool<string>.Shared.Release(desiredTransitionIds);
 721955        }
 721956    }
 1957
 1958    private static TraversalTransition[] GetMissingManagedGeneratedTransitions(
 1959        NavigationChartRegistration state,
 1960        TraversalTransition[] desiredTransitions)
 1961    {
 601962        if (desiredTransitions.Length == 0)
 571963            return Array.Empty<TraversalTransition>();
 1964
 31965        SwiftList<TraversalTransition> missingTransitions = new();
 161966        for (int i = 0; i < desiredTransitions.Length; i++)
 1967        {
 51968            TraversalTransition transition = desiredTransitions[i];
 51969            if (!state.TransitionIds.Contains(transition.Id))
 41970                missingTransitions.Add(transition);
 1971        }
 1972
 31973        return missingTransitions.Count == 0
 31974            ? Array.Empty<TraversalTransition>()
 31975            : missingTransitions.ToArray();
 1976    }
 1977
 1978    private static void ApplyManagedGeneratedTransitionDelta(
 1979        string chartName,
 1980        NavigationChartRegistration state,
 1981        SwiftHashSet<string> desiredTransitionIds,
 1982        SwiftHashSet<string> activeTransitionIds,
 1983        TraversalTransition[] missingTransitions)
 1984    {
 10191985        if (missingTransitions != null
 10191986            && missingTransitions.Length > 0
 10191987            && TraversalTransitionRegistry.RegisterGeneratedRange(
 10191988                missingTransitions,
 10191989                state.Priority,
 10191990                startSuppressed: true))
 1991        {
 11992            AddManagedGeneratedTransitionIds(chartName, missingTransitions);
 1993        }
 1994
 10191995        string[] obsoleteTransitionIds = GetObsoleteManagedGeneratedTransitionIds(state, desiredTransitionIds);
 10191996        if (obsoleteTransitionIds.Length > 0)
 1997        {
 11998            TraversalTransitionRegistry.UnregisterRange(obsoleteTransitionIds);
 11999            RemoveManagedGeneratedTransitionIds(chartName, obsoleteTransitionIds);
 2000        }
 2001
 10192002        SyncManagedGeneratedTransitionSuppressions(state, activeTransitionIds);
 10192003    }
 2004
 2005    private static string[] GetObsoleteManagedGeneratedTransitionIds(
 2006        NavigationChartRegistration state,
 2007        SwiftHashSet<string> desiredTransitionIds)
 2008    {
 10192009        if (state.TransitionIds.Count == 0)
 10002010            return Array.Empty<string>();
 2011
 192012        SwiftList<string> obsoleteTransitionIds = new();
 1662013        foreach (string transitionId in state.TransitionIds)
 2014        {
 642015            if (!desiredTransitionIds.Contains(transitionId))
 12016                obsoleteTransitionIds.Add(transitionId);
 2017        }
 2018
 192019        return obsoleteTransitionIds.Count == 0
 192020            ? Array.Empty<string>()
 192021            : obsoleteTransitionIds.ToArray();
 2022    }
 2023
 2024    private static void SyncManagedGeneratedTransitionSuppressions(
 2025        NavigationChartRegistration state,
 2026        SwiftHashSet<string> activeTransitionIds)
 2027    {
 10192028        if (state.TransitionIds.Count == 0)
 10002029            return;
 2030
 192031        SwiftList<string> transitionsToSuppress = new();
 192032        SwiftList<string> transitionsToUnsuppress = new();
 1642033        foreach (string transitionId in state.TransitionIds)
 2034        {
 632035            if (activeTransitionIds.Contains(transitionId))
 572036                transitionsToUnsuppress.Add(transitionId);
 2037            else
 62038                transitionsToSuppress.Add(transitionId);
 2039        }
 2040
 192041        if (transitionsToSuppress.Count > 0)
 32042            TraversalTransitionRegistry.SetManagedTransitionsSuppressed(
 32043                transitionsToSuppress.ToArray(),
 32044                suppressed: true);
 2045
 192046        if (transitionsToUnsuppress.Count > 0)
 162047            TraversalTransitionRegistry.SetManagedTransitionsSuppressed(
 162048                transitionsToUnsuppress.ToArray(),
 162049                suppressed: false);
 192050    }
 2051
 2052    private static void CollectManagedGeneratedTransitionsForPair(
 2053        GridWorld world,
 2054        NavigationChart chart,
 2055        NavigationChartRegistration state,
 2056        int firstX,
 2057        int firstY,
 2058        int firstZ,
 2059        int secondX,
 2060        int secondY,
 2061        int secondZ,
 2062        SwiftHashSet<string> desiredTransitionIds,
 2063        SwiftHashSet<string> activeTransitionIds,
 2064        SwiftList<TraversalTransition> missingTransitions)
 2065    {
 612066        if (!CanResolveManagedGeneratedPairAnchors(world, chart, firstX, firstY, firstZ, secondX, secondY, secondZ))
 2067        {
 22068            if (GeneratedTraversalTransitionBuilder.CanBuildTransitionsForPairFromChartData(
 22069                chart,
 22070                firstX,
 22071                firstY,
 22072                firstZ,
 22073                secondX,
 22074                secondY,
 22075                secondZ))
 2076            {
 22077                AddPotentialManagedGeneratedTransitionIds(
 22078                    state.TransitionIdPrefix,
 22079                    firstX,
 22080                    firstY,
 22081                    firstZ,
 22082                    secondX,
 22083                    secondY,
 22084                    secondZ,
 22085                    desiredTransitionIds);
 2086            }
 2087
 22088            return;
 2089        }
 2090
 592091        TraversalTransition[] pairTransitions = GeneratedTraversalTransitionBuilder.BuildTransitionsForPair(
 592092            chart,
 592093            state.TransitionIdPrefix,
 592094            firstX,
 592095            firstY,
 592096            firstZ,
 592097            secondX,
 592098            secondY,
 592099            secondZ);
 592100        if (pairTransitions.Length == 0)
 272101            return;
 2102
 322103        bool isActive = IsManagedGeneratedPairActive(
 322104            world,
 322105            chart.Name,
 322106            chart,
 322107            firstX,
 322108            firstY,
 322109            firstZ,
 322110            secondX,
 322111            secondY,
 322112            secondZ);
 1922113        for (int i = 0; i < pairTransitions.Length; i++)
 2114        {
 642115            TraversalTransition transition = pairTransitions[i];
 642116            desiredTransitionIds.Add(transition.Id);
 642117            if (isActive)
 602118                activeTransitionIds.Add(transition.Id);
 2119
 642120            if (!state.TransitionIds.Contains(transition.Id))
 42121                missingTransitions.Add(transition);
 2122        }
 322123    }
 2124
 2125    private static bool CanResolveManagedGeneratedPairAnchors(
 2126        GridWorld world,
 2127        NavigationChart chart,
 2128        int firstX,
 2129        int firstY,
 2130        int firstZ,
 2131        int secondX,
 2132        int secondY,
 2133        int secondZ)
 2134    {
 1322135        return world.TryGetVoxel(chart.GetWorldPosition(firstX, firstY, firstZ), out _)
 1322136            && world.TryGetVoxel(chart.GetWorldPosition(secondX, secondY, secondZ), out _);
 2137    }
 2138
 2139    private static void AddPotentialManagedGeneratedTransitionIds(
 2140        string transitionIdPrefix,
 2141        int firstX,
 2142        int firstY,
 2143        int firstZ,
 2144        int secondX,
 2145        int secondY,
 2146        int secondZ,
 2147        SwiftHashSet<string> desiredTransitionIds)
 2148    {
 22149        string[] potentialTransitionIds = GeneratedTraversalTransitionBuilder.GetPotentialTransitionIdsForPair(
 22150            transitionIdPrefix,
 22151            firstX,
 22152            firstY,
 22153            firstZ,
 22154            secondX,
 22155            secondY,
 22156            secondZ);
 2157
 442158        for (int i = 0; i < potentialTransitionIds.Length; i++)
 202159            desiredTransitionIds.Add(potentialTransitionIds[i]);
 22160    }
 2161
 2162    private static bool ShouldCollectManagedGeneratedPair(
 2163        int firstX,
 2164        int firstY,
 2165        int firstZ,
 2166        int secondX,
 2167        int secondY,
 2168        int secondZ,
 2169        NavigationChartCell secondCell)
 2170    {
 862171        if (!IsManagedGeneratedTransitionCandidate(secondCell))
 342172            return true;
 2173
 522174        return firstX < secondX
 522175            || (firstX == secondX && firstY < secondY)
 522176            || (firstX == secondX && firstY == secondY && firstZ < secondZ);
 2177    }
 2178
 2179    private static bool IsManagedGeneratedTransitionCandidate(NavigationChartCell cell)
 2180    {
 862181        return cell.CanGenerateTransition
 862182            || (cell.Flags & NavigationChartCellFlags.ClimbSurfaceHint) != 0;
 2183    }
 2184
 2185    private static bool IsManagedGeneratedPairActive(
 2186        GridWorld world,
 2187        string chartName,
 2188        NavigationChart chart,
 2189        int firstX,
 2190        int firstY,
 2191        int firstZ,
 2192        int secondX,
 2193        int secondY,
 2194        int secondZ)
 2195    {
 342196        if (!IsChartInitialized(chartName))
 32197            return false;
 2198
 312199        return IsChartEffectiveOwnerAtPosition(world, chartName, chart.GetWorldPosition(firstX, firstY, firstZ))
 312200            && IsChartEffectiveOwnerAtPosition(world, chartName, chart.GetWorldPosition(secondX, secondY, secondZ));
 2201    }
 2202
 2203    private static bool IsChartEffectiveOwnerAtPosition(GridWorld world, string chartName, Vector3d worldPosition)
 2204    {
 642205        if (!TryGetResolvedChartVoxelState(world, worldPosition, out _, out ResolvedChartVoxelState? state))
 12206            return false;
 2207
 632208        return string.Equals(state!.EffectiveChartOwner, chartName, StringComparison.Ordinal);
 2209    }
 2210
 2211    private static void AddManagedGeneratedTransitionIds(
 2212        string chartName,
 2213        TraversalTransition[] transitions)
 2214    {
 52215        _navigationChartMapLock.EnterWriteLock();
 2216        try
 2217        {
 52218            if (!TryGetNavigationChartRegistration_NoLock(chartName, out NavigationChartRegistration state))
 12219                return;
 2220
 202221            for (int i = 0; i < transitions.Length; i++)
 62222                state.TransitionIds.Add(transitions[i].Id);
 42223        }
 102224        finally { _navigationChartMapLock.ExitWriteLock(); }
 52225    }
 2226
 2227    private static void RemoveManagedGeneratedTransitionIds(
 2228        string chartName,
 2229        string[] transitionIds)
 2230    {
 42231        _navigationChartMapLock.EnterWriteLock();
 2232        try
 2233        {
 42234            if (!TryGetNavigationChartRegistration_NoLock(chartName, out NavigationChartRegistration state))
 12235                return;
 2236
 142237            for (int i = 0; i < transitionIds.Length; i++)
 42238                state.TransitionIds.Remove(transitionIds[i]);
 32239        }
 82240        finally { _navigationChartMapLock.ExitWriteLock(); }
 42241    }
 2242
 2243    private static string[] CopyTransitionIds(SwiftHashSet<string> transitionIds)
 2244    {
 2022245        if (transitionIds.Count == 0)
 1962246            return Array.Empty<string>();
 2247
 62248        string[] copy = new string[transitionIds.Count];
 62249        int index = 0;
 382250        foreach (string transitionId in transitionIds)
 132251            copy[index++] = transitionId;
 2252
 62253        return copy;
 2254    }
 2255
 2256    private static string[] CopyTransitionIds(TraversalTransition[] transitions)
 2257    {
 22258        string[] ids = new string[transitions.Length];
 122259        for (int i = 0; i < transitions.Length; i++)
 42260            ids[i] = transitions[i].Id;
 2261
 22262        return ids;
 2263    }
 2264
 2265    private static void RemoveChartFromRegistry(string chartName)
 2266    {
 2022267        _navigationChartMapLock.EnterWriteLock();
 4042268        try { _navigationChartMap.Remove(chartName); }
 4042269        finally { _navigationChartMapLock.ExitWriteLock(); }
 2022270    }
 2271
 2272    private static bool TryGetResolvedChartVoxelState(
 2273        GridWorld world,
 2274        Vector3d worldPosition,
 2275        out WorldVoxelIndex voxelIndex,
 2276        out ResolvedChartVoxelState? state)
 2277    {
 992278        if (world.TryGetVoxel(worldPosition, out Voxel? voxel))
 2279        {
 942280            voxelIndex = voxel!.WorldIndex;
 942281            return TryGetResolvedChartVoxelState(voxelIndex, out state);
 2282        }
 2283
 52284        voxelIndex = default;
 52285        state = null;
 52286        return false;
 2287    }
 2288
 2289    private static bool TryGetResolvedChartVoxelState(
 2290        WorldVoxelIndex voxelIndex,
 2291        out ResolvedChartVoxelState? state)
 2292    {
 1002293        if (_resolvedChartVoxelStates.TryGetValue(voxelIndex, out state)
 1002294            && state != null
 1002295            && state.HasAnyOwners
 1002296            && !string.IsNullOrEmpty(state.EffectiveChartOwner))
 2297        {
 892298            return true;
 2299        }
 2300
 112301        state = null;
 112302        return false;
 2303    }
 2304
 2305    private static bool TryApplyChartCellUpdate(
 2306        GridWorld world,
 2307        NavigationChartRegistration registration,
 2308        int x,
 2309        int y,
 2310        int z,
 2311        NavigationChartCell cell,
 2312        SwiftHashSet<SolidChartPartition> partitionsToRebind,
 2313        SwiftHashSet<string> invalidatedChartKeys,
 2314        SwiftHashSet<string> managedChartsToRefresh)
 2315    {
 262316        NavigationChart chart = registration.Chart;
 262317        if (!chart.TrySetCell(x, y, z, cell, out NavigationChartCell previousCell))
 52318            return false;
 2319
 212320        TrackManagedChartRefresh(chart, managedChartsToRefresh);
 2321
 212322        if (!registration.IsInitialized)
 52323            return true;
 2324
 162325        if (!TryGetChartUpdateVoxelContext(
 162326            world,
 162327            chart,
 162328            x,
 162329            y,
 162330            z,
 162331            managedChartsToRefresh,
 162332            out Voxel? voxel,
 162333            out ResolvedChartVoxelState? state,
 162334            out NavigationChartCell previousEffectiveCell,
 162335            out string? previousEffectiveOwner))
 2336        {
 12337            return true;
 2338        }
 2339
 152340        TryUpdateResolvedVoxelStateForChartCell(registration, cell, voxel!.WorldIndex, ref state);
 152341        TrackInitializedChartGridTouchDelta(voxel.GridIndex, chart.Name, previousCell, cell);
 2342
 152343        ApplyResolvedVoxelState(world, voxel, state, previousEffectiveCell, partitionsToRebind);
 152344        CollectEffectiveStateInvalidations(
 152345            previousEffectiveOwner,
 152346            previousEffectiveCell,
 152347            state?.EffectiveChartOwner ?? string.Empty,
 152348            state?.EffectiveCell ?? NavigationChartCell.Empty,
 152349            invalidatedChartKeys);
 152350        if (state != null && state.HasAnyOwners)
 102351            state.AddChartOwnersTo(managedChartsToRefresh);
 2352
 152353        return true;
 2354    }
 2355
 2356    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2357    private static void TrackManagedChartRefresh(
 2358        NavigationChart chart,
 2359        SwiftHashSet<string> managedChartsToRefresh)
 2360    {
 212361        managedChartsToRefresh.Add(chart.Name);
 212362    }
 2363
 2364    private static bool TryGetChartUpdateVoxelContext(
 2365        GridWorld world,
 2366        NavigationChart chart,
 2367        int x,
 2368        int y,
 2369        int z,
 2370        SwiftHashSet<string> managedChartsToRefresh,
 2371        out Voxel? voxel,
 2372        out ResolvedChartVoxelState? state,
 2373        out NavigationChartCell previousEffectiveCell,
 2374        out string? previousEffectiveOwner)
 2375    {
 162376        state = null;
 162377        previousEffectiveCell = NavigationChartCell.Empty;
 162378        previousEffectiveOwner = null;
 2379
 162380        Vector3d position = chart.GetWorldPosition(x, y, z);
 162381        if (!world.TryGetVoxel(position, out voxel))
 12382            return false;
 2383
 152384        _resolvedChartVoxelStates.TryGetValue(voxel!.WorldIndex, out state);
 152385        if (state != null && state.HasAnyOwners)
 2386        {
 122387            state.AddChartOwnersTo(managedChartsToRefresh);
 122388            previousEffectiveCell = state.EffectiveCell;
 122389            previousEffectiveOwner = state.EffectiveChartOwner;
 2390        }
 2391
 152392        return true;
 2393    }
 2394
 2395    private static void TryUpdateResolvedVoxelStateForChartCell(
 2396        NavigationChartRegistration registration,
 2397        NavigationChartCell cell,
 2398        WorldVoxelIndex voxelIndex,
 2399        ref ResolvedChartVoxelState? state)
 2400    {
 182401        NavigationChart chart = registration.Chart;
 182402        if (cell.HasTraversalData)
 2403        {
 102404            state ??= new ResolvedChartVoxelState();
 102405            state.AddOwner(chart.Name, cell, chart.Priority, registration.RegistrationOrder);
 102406            _resolvedChartVoxelStates[voxelIndex] = state;
 102407            return;
 2408        }
 2409
 82410        if (state == null || !state.ContainsOwner(chart.Name))
 12411            return;
 2412
 72413        state.RemoveOwner(chart.Name);
 72414        if (!state.HasAnyOwners)
 62415            _resolvedChartVoxelStates.Remove(voxelIndex);
 72416    }
 2417
 2418    private static void RebindAndInvalidate(
 2419        SwiftHashSet<SolidChartPartition> partitionsToRebind,
 2420        SwiftHashSet<string> invalidatedChartKeys)
 2421    {
 232422        BindCollectedSolidPartitions(partitionsToRebind);
 2423
 232424        if (partitionsToRebind.Count > 0 || invalidatedChartKeys.Count > 0)
 142425            SolidPartitionReachability.Invalidate();
 2426
 782427        foreach (string chartKey in invalidatedChartKeys)
 162428            PathGuideFactory.InvalidateCacheFor(chartKey);
 232429    }
 2430
 2431    private static void CollectEffectiveStateInvalidations(
 2432        string? previousEffectiveOwner,
 2433        NavigationChartCell previousEffectiveCell,
 2434        string? currentEffectiveOwner,
 2435        NavigationChartCell currentEffectiveCell,
 2436        SwiftHashSet<string> invalidatedChartKeys)
 2437    {
 152438        if (previousEffectiveCell.Equals(currentEffectiveCell)
 152439            && string.Equals(previousEffectiveOwner, currentEffectiveOwner, StringComparison.Ordinal))
 2440        {
 12441            return;
 2442        }
 2443
 142444        if (!string.IsNullOrEmpty(previousEffectiveOwner))
 112445            invalidatedChartKeys.Add(previousEffectiveOwner);
 2446
 142447        if (!string.IsNullOrEmpty(currentEffectiveOwner))
 92448            invalidatedChartKeys.Add(currentEffectiveOwner);
 142449    }
 2450
 2451    internal static bool HasAuthoredVolumeMedium(TraversalMedium medium)
 2452    {
 12453        return HasAuthoredVolumeMedium(ActiveState, medium);
 2454    }
 2455
 2456    internal static bool HasAuthoredVolumeMedium(PathingWorldState state, TraversalMedium medium)
 2457    {
 4542458        return medium switch
 4542459        {
 2592460            TraversalMedium.Gas => state.ActiveAuthoredGasCellCount > 0,
 1942461            TraversalMedium.Liquid => state.ActiveAuthoredLiquidCellCount > 0,
 12462            _ => false
 4542463        };
 2464    }
 2465
 2466    private static void ApplyResolvedVoxelState(
 2467        GridWorld world,
 2468        Voxel voxel,
 2469        ResolvedChartVoxelState? state,
 2470        NavigationChartCell previousEffectiveCell,
 2471        SwiftHashSet<SolidChartPartition> partitionsToRebind)
 2472    {
 48622473        NavigationChartCell effectiveCell = state?.EffectiveCell ?? NavigationChartCell.Empty;
 48622474        UpdateActiveVolumeMediumCounts(previousEffectiveCell, effectiveCell);
 2475
 48622476        bool solidPresenceChanged = previousEffectiveCell.HasSolid != effectiveCell.HasSolid;
 2477
 48622478        if (effectiveCell.HasSolid)
 2479        {
 24562480            if (!voxel.TryGetPartition(out SolidChartPartition? solidPartition))
 2481            {
 24422482                solidPartition = PartitionPool.Rent();
 24422483                solidPartition.SetOwner(ActiveState);
 24422484                voxel.TryAddPartition(solidPartition);
 2485            }
 142486            else if (solidPartition!.OwnerState == null)
 02487                solidPartition.SetOwner(ActiveState);
 2488
 24562489            solidPartition!.ApplyAuthoredState(state, state?.EffectiveChartOwner, effectiveCell);
 24562490            if (solidPresenceChanged)
 24422491                CollectSolidPartitionsForRebind(world, voxel, partitionsToRebind);
 2492        }
 24062493        else if (previousEffectiveCell.HasSolid && voxel.TryGetPartition<SolidChartPartition>(out _))
 2494        {
 18082495            voxel.TryRemovePartition<SolidChartPartition>();
 18082496            CollectSolidPartitionsForRebind(world, voxel, partitionsToRebind);
 2497        }
 2498
 48622499        if (effectiveCell.HasVolume)
 2500        {
 6122501            if (!voxel.TryGetPartition(out VolumeChartPartition? volumePartition))
 2502            {
 6072503                volumePartition = VolumeChartPartitionPool.Rent();
 6072504                volumePartition.SetOwner(ActiveState);
 6072505                voxel.TryAddPartition(volumePartition);
 2506            }
 52507            else if (volumePartition!.OwnerState == null)
 02508                volumePartition.SetOwner(ActiveState);
 2509
 6122510            volumePartition!.ApplyAuthoredState(state, state?.EffectiveChartOwner, effectiveCell);
 2511        }
 42502512        else if (previousEffectiveCell.HasVolume && voxel.TryGetPartition<VolumeChartPartition>(out _))
 1892513            voxel.TryRemovePartition<VolumeChartPartition>();
 42502514    }
 2515
 2516    private static void UpdateActiveVolumeMediumCounts(
 2517        NavigationChartCell previousEffectiveCell,
 2518        NavigationChartCell currentEffectiveCell)
 2519    {
 48622520        if (previousEffectiveCell.SupportsMedium(TraversalMedium.Gas))
 1702521            AdjustActiveAuthoredGasCellCount(-1);
 2522
 48622523        if (previousEffectiveCell.SupportsMedium(TraversalMedium.Liquid))
 242524            AdjustActiveAuthoredLiquidCellCount(-1);
 2525
 48622526        if (currentEffectiveCell.SupportsMedium(TraversalMedium.Gas))
 4492527            AdjustActiveAuthoredGasCellCount(1);
 2528
 48622529        if (currentEffectiveCell.SupportsMedium(TraversalMedium.Liquid))
 1632530            AdjustActiveAuthoredLiquidCellCount(1);
 48622531    }
 2532
 2533    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2534    private static void ClearActiveAuthoredVolumeMediumCounts()
 2535    {
 32642536        PathingWorldState state = ActiveState;
 32642537        state.ActiveAuthoredGasCellCount = 0;
 32642538        state.ActiveAuthoredLiquidCellCount = 0;
 32642539    }
 2540
 2541    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2542    private static void AdjustActiveAuthoredGasCellCount(int delta)
 2543    {
 6192544        ActiveState.ActiveAuthoredGasCellCount += delta;
 6192545    }
 2546
 2547    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2548    private static void AdjustActiveAuthoredLiquidCellCount(int delta)
 2549    {
 1872550        ActiveState.ActiveAuthoredLiquidCellCount += delta;
 1872551    }
 2552
 2553    private static void CollectSolidPartitionsForRebind(
 2554        GridWorld world,
 2555        Voxel voxel,
 2556        SwiftHashSet<SolidChartPartition> partitionsToRebind)
 2557    {
 42502558        if (!world.TryGetGrid(voxel.WorldIndex.GridIndex, out VoxelGrid? grid))
 02559            return;
 2560
 42502561        if (voxel.TryGetPartition(out SolidChartPartition? currentPartition))
 24422562            partitionsToRebind.Add(currentPartition!);
 2563
 2295002564        foreach (SpatialDirection direction in SpatialAwareness.AllDirections)
 2565        {
 1105002566            if (voxel.TryGetNeighborFromDirection(grid!, direction, out Voxel? neighborVoxel, useCache: true)
 1105002567                && neighborVoxel!.TryGetPartition(out SolidChartPartition? neighborPartition))
 2568            {
 104972569                partitionsToRebind.Add(neighborPartition!);
 2570            }
 2571        }
 42502572    }
 2573
 2574    private static void BindCollectedSolidPartitions(SwiftHashSet<SolidChartPartition> partitionsToRebind)
 2575    {
 12152576        PathingWorldState activeState = ActiveState;
 105722577        foreach (SolidChartPartition partition in partitionsToRebind)
 2578        {
 40712579            if (partition.IsPartitioned && ReferenceEquals(partition.OwnerState, activeState))
 24832580                partition.BindNeighbors();
 2581        }
 12152582    }
 2583
 2584    #endregion
 2585
 2586    #region Public Utility Methods
 2587
 2588    /// <summary>
 2589    /// Determines the maximum number of voxels to search based on the start and end voxel's grid sizes.
 2590    /// </summary>
 2591    /// <param name="world">The grid world.</param>
 2592    /// <param name="start">The start voxel.</param>
 2593    /// <param name="end">The end voxel.</param>
 2594    /// <param name="maxSearchSize">The output max search size.</param>
 2595    /// <returns>True if both voxels belong to valid grids; otherwise, false.</returns>
 2596    public static bool TryGetMaxSearchSize(GridWorld world, Voxel start, Voxel end, out int maxSearchSize)
 2597    {
 32598        LinkWorld(world);
 32599        if (!world.TryGetGrid(start.WorldIndex.GridIndex, out VoxelGrid? startGrid)
 32600            || !world.TryGetGrid(end.WorldIndex.GridIndex, out VoxelGrid? endGrid))
 2601        {
 12602            maxSearchSize = 0;
 12603            return false;
 2604        }
 2605
 22606        maxSearchSize = startGrid == endGrid
 22607            ? startGrid!.Size
 22608            : startGrid!.Size + endGrid!.Size;
 22609        return true;
 2610    }
 2611
 2612    /// <summary>
 2613    /// Determines the maximum number of voxels to search based on the start and end voxel's grid sizes using the config
 2614    /// </summary>
 2615    public static bool TryGetMaxSearchSize(Voxel start, Voxel end, out int maxSearchSize)
 2616    {
 32617        return TryGetMaxSearchSize(GetConfiguredWorld(), start, end, out maxSearchSize);
 2618    }
 2619
 2620    /// <summary>
 2621    /// Checks if a path is needed between the start and end positions based on traced voxels and unit size.
 2622    /// </summary>
 2623    /// <param name="world">The grid world.</param>
 2624    /// <param name="startPos">The starting position.</param>
 2625    /// <param name="endPos">The destination position.</param>
 2626    /// <param name="unitSize">The size of the navigating unit.</param>
 2627    /// <param name="includeEnd">Whether to permit unwalkable voxels.</param>
 2628    /// <returns>True if a path is required; otherwise, false.</returns>
 2629    public static bool NeedsPath(
 2630        GridWorld world,
 2631        Vector3d startPos,
 2632        Vector3d endPos,
 2633        Fixed64 unitSize,
 2634        bool includeEnd = false)
 2635    {
 882636        LinkWorld(world);
 3232637        foreach (GridVoxelSet gridVoxelSet in GridTracer.TraceLine(world, startPos, endPos))
 2638        {
 6772639            foreach (Voxel voxel in gridVoxelSet.Voxels)
 2640            {
 2641                // A path is required if a voxel doesn't exist in the traced line
 2652642                if (!voxel.TryGetPartition(out SolidChartPartition? partition))
 282643                    return true;
 2644
 2372645                if (!includeEnd && !voxel.IsBlocked && partition!.IsImpassable(unitSize))
 12646                    return true;
 2647            }
 2648        }
 592649        return false;
 292650    }
 2651
 2652    /// <summary>
 2653    /// Checks if a path is needed between the start and end positions using the configured world.
 2654    /// </summary>
 2655    public static bool NeedsPath(
 2656        Vector3d startPos,
 2657        Vector3d endPos,
 2658        Fixed64 unitSize,
 2659        bool includeEnd = false)
 2660    {
 32661        return NeedsPath(GetConfiguredWorld(), startPos, endPos, unitSize, includeEnd);
 2662    }
 2663
 2664    #endregion
 2665}

Methods/Properties

.cctor()
get_PartitionPool()
get_VolumeChartPartitionPool()
get_AllCharts()
get__navigationChartMap()
get__resolvedChartVoxelStates()
get__initializedChartTouchCountsByGridIndex()
get__navigationChartMapLock()
get__nextChartRegistrationOrder()
set__nextChartRegistrationOrder(System.Int32)
get_ActiveState()
TryGetActiveState(Trailblazer.Pathing.PathingWorldState&)
EnterState(Trailblazer.Pathing.PathingWorldState)
.ctor(Trailblazer.Pathing.PathingWorldState)
Dispose()
get_HasConfiguredWorld()
get_ConfiguredWorld()
LinkWorld(GridForge.Grids.GridWorld)
GetConfiguredWorld()
Tick()
Reset()
Reset(GridForge.Grids.GridWorld)
ResetPathingState(Trailblazer.Pathing.PathingWorldState,System.Boolean,System.Boolean)
Register(Trailblazer.Pathing.NavigationChart,System.Boolean)
Register(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart,System.Boolean)
Register(Trailblazer.Pathing.TraversalBuildResult,System.Boolean)
Register(GridForge.Grids.GridWorld,Trailblazer.Pathing.TraversalBuildResult,System.Boolean)
ThrowIfDirectWorldRegisterCall()
RegisterChartInternal(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart,System.String,Trailblazer.Pathing.TraversalTransition[],System.Boolean)
ValidateChartVoxelSizeCompatibility(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart)
IsChartRegistered(System.String)
TryGetNavigationChart(System.String,Trailblazer.Pathing.NavigationChart&)
TryGetNavigationChartRegistration(System.String,Trailblazer.Pathing.NavigationChartRegistration&)
IsChartInitialized(System.String)
IsChartInitialized(Trailblazer.Pathing.NavigationChart)
TryGetNavigationChartRegistration_NoLock(System.String,Trailblazer.Pathing.NavigationChartRegistration&)
TryGetEffectiveCell(GridForge.Spatial.WorldVoxelIndex,Trailblazer.Pathing.NavigationChartCell&)
TryGetEffectiveCell(GridForge.Grids.GridWorld,FixedMathSharp.Vector3d,Trailblazer.Pathing.NavigationChartCell&)
TryGetEffectiveCell(FixedMathSharp.Vector3d,Trailblazer.Pathing.NavigationChartCell&)
TryGetEffectiveChartOwner(GridForge.Spatial.WorldVoxelIndex,System.String&)
TryGetEffectiveChartOwner(GridForge.Grids.GridWorld,FixedMathSharp.Vector3d,System.String&)
TryGetEffectiveChartOwner(FixedMathSharp.Vector3d,System.String&)
TryGetClosestActiveTransition(GridForge.Grids.GridWorld,FixedMathSharp.Vector3d,Trailblazer.Pathing.TraversalTransitionType,Trailblazer.Pathing.TraversalTransition&)
TryGetClosestActiveTransition(FixedMathSharp.Vector3d,Trailblazer.Pathing.TraversalTransitionType,Trailblazer.Pathing.TraversalTransition&)
InitializeAllCharts()
InitializeAllCharts(GridForge.Grids.GridWorld)
EvaluateClosestTransitionCandidates(Trailblazer.Pathing.TraversalTransition[],FixedMathSharp.Vector3d,System.Boolean&,Trailblazer.Pathing.TraversalTransition&,FixedMathSharp.Fixed64&)
GetBoundsDistanceSq(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetAxisDistanceToBounds(FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64)
TryUpdateChartCell(System.String,System.Int32,System.Int32,System.Int32,Trailblazer.Pathing.NavigationChartCell)
TryUpdateChartCell(GridForge.Grids.GridWorld,System.String,System.Int32,System.Int32,System.Int32,Trailblazer.Pathing.NavigationChartCell)
TryUpdateChartCell(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChartRegistration,System.Int32,System.Int32,System.Int32,Trailblazer.Pathing.NavigationChartCell)
TryUpdateChartCell(System.String,FixedMathSharp.Vector3d,Trailblazer.Pathing.NavigationChartCell)
TryUpdateChartCell(GridForge.Grids.GridWorld,System.String,FixedMathSharp.Vector3d,Trailblazer.Pathing.NavigationChartCell)
ApplyChartUpdates(System.String,System.Collections.Generic.IReadOnlyList`1<Trailblazer.Pathing.NavigationChartCellUpdate>)
ApplyChartUpdates(GridForge.Grids.GridWorld,System.String,System.Collections.Generic.IReadOnlyList`1<Trailblazer.Pathing.NavigationChartCellUpdate>)
InitializeChart(System.String)
InitializeChart(GridForge.Grids.GridWorld,System.String)
UnloadChart(System.String)
UnloadChart(GridForge.Grids.GridWorld,System.String)
UnloadChart(Trailblazer.Pathing.NavigationChart)
UnloadChart(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart)
UnloadChart(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChartRegistration)
RebuildInitializedChartsAgainstExternalGridRequests(Trailblazer.Pathing.ExternalGridChartRebuildRequest[])
RebuildInitializedChartsAgainstExternalGridRequests(GridForge.Grids.GridWorld,Trailblazer.Pathing.ExternalGridChartRebuildRequest[])
RebuildInitializedChartsAgainstExternalGridBounds(GridForge.Grids.GridWorld,System.UInt16,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean)
RebuildInitializedChartsAgainstCurrentGrids(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart[])
SuppressManagedGeneratedTransitionsForCharts(Trailblazer.Pathing.NavigationChart[])
GetInitializedChartsSnapshot()
GetInitializedChartsIntersectingBoundsSnapshot(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetInitializedChartsTouchingGridSnapshot(System.UInt16)
GetInitializedChartsWithAuthoredCellsIntersectingBoundsSnapshot(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
GetInitializedChartsAffectedByExternalGridRequestsSnapshot(Trailblazer.Pathing.ExternalGridChartRebuildRequest[])
AddInitializedChartsTouchingGrid_NoLock(System.UInt16,SwiftCollections.SwiftDictionary`2<System.String,Trailblazer.Pathing.NavigationChartRegistration>)
AddInitializedChartsWithAuthoredCellsIntersectingBounds_NoLock(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,SwiftCollections.SwiftDictionary`2<System.String,Trailblazer.Pathing.NavigationChartRegistration>)
BuildInitializedChartSelectionSnapshot_NoLock(SwiftCollections.SwiftDictionary`2<System.String,Trailblazer.Pathing.NavigationChartRegistration>)
ChartHasAuthoredCellInsideBounds(Trailblazer.Pathing.NavigationChart,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
ClearInitializedChartLiveStatePreservingRegistration(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart)
ClearInitializedChartLiveStatePreservingRegistration(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChartRegistration)
ClearLiveGridState(GridForge.Grids.GridWorld)
ClearLiveGridState()
DoBoundsOverlap(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
IsPositionInsideBounds(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
RemoveLivePathingPartitions(GridForge.Grids.Voxel)
BuildInitializedChartSelectionSnapshot(SwiftCollections.SwiftList`1<Trailblazer.Pathing.NavigationChartRegistration>)
CopyCharts(Trailblazer.Pathing.NavigationChartRegistration[])
CompareRegistrationsByRegistrationOrder(Trailblazer.Pathing.NavigationChartRegistration,Trailblazer.Pathing.NavigationChartRegistration)
TrackInitializedChartGridTouch(System.UInt16,System.String)
UntrackInitializedChartGridTouch(System.UInt16,System.String)
TrackInitializedChartGridTouchDelta(System.UInt16,System.String,Trailblazer.Pathing.NavigationChartCell,Trailblazer.Pathing.NavigationChartCell)
TryRegisterManagedGeneratedTransitions(System.String,Trailblazer.Pathing.TraversalTransition[])
RememberManagedGeneratedTransitions(System.String,System.String[],System.Int32)
RemoveManagedGeneratedTransitions(System.String)
TryGetManagedGeneratedTransitionState(System.String,Trailblazer.Pathing.NavigationChartRegistration&)
RefreshManagedGeneratedTransitionsForCharts(GridForge.Grids.GridWorld,SwiftCollections.SwiftHashSet`1<System.String>,System.String)
RefreshManagedGeneratedTransitionsForCharts(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart[])
RefreshManagedTransitionsForVoxel(GridForge.Grids.GridWorld,FixedMathSharp.Vector3d,SwiftCollections.SwiftHashSet`1<System.String>)
RefreshManagedManualTransitionsForVoxels(SwiftCollections.SwiftHashSet`1<GridForge.Spatial.WorldVoxelIndex>)
RefreshManagedGeneratedTransitionsForChart(GridForge.Grids.GridWorld,System.String)
CollectManagedGeneratedTransitionsForChart(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart,Trailblazer.Pathing.NavigationChartRegistration,SwiftCollections.SwiftHashSet`1<System.String>,SwiftCollections.SwiftHashSet`1<System.String>)
RefreshManagedGeneratedTransitionsForVoxel(GridForge.Grids.GridWorld,FixedMathSharp.Vector3d,SwiftCollections.SwiftHashSet`1<System.String>)
RefreshManagedGeneratedTransitionsForVoxel(GridForge.Grids.GridWorld,System.String,Trailblazer.Pathing.NavigationChart,Trailblazer.Pathing.NavigationChartRegistration,System.Int32,System.Int32,System.Int32)
RefreshManagedGeneratedTransitionsForPair(GridForge.Grids.GridWorld,System.String,Trailblazer.Pathing.NavigationChart,Trailblazer.Pathing.NavigationChartRegistration,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32)
GetObsoleteManagedGeneratedTransitionIds(Trailblazer.Pathing.NavigationChartRegistration,System.String[],Trailblazer.Pathing.TraversalTransition[])
GetMissingManagedGeneratedTransitions(Trailblazer.Pathing.NavigationChartRegistration,Trailblazer.Pathing.TraversalTransition[])
ApplyManagedGeneratedTransitionDelta(System.String,Trailblazer.Pathing.NavigationChartRegistration,SwiftCollections.SwiftHashSet`1<System.String>,SwiftCollections.SwiftHashSet`1<System.String>,Trailblazer.Pathing.TraversalTransition[])
GetObsoleteManagedGeneratedTransitionIds(Trailblazer.Pathing.NavigationChartRegistration,SwiftCollections.SwiftHashSet`1<System.String>)
SyncManagedGeneratedTransitionSuppressions(Trailblazer.Pathing.NavigationChartRegistration,SwiftCollections.SwiftHashSet`1<System.String>)
CollectManagedGeneratedTransitionsForPair(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart,Trailblazer.Pathing.NavigationChartRegistration,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,SwiftCollections.SwiftHashSet`1<System.String>,SwiftCollections.SwiftHashSet`1<System.String>,SwiftCollections.SwiftList`1<Trailblazer.Pathing.TraversalTransition>)
CanResolveManagedGeneratedPairAnchors(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32)
AddPotentialManagedGeneratedTransitionIds(System.String,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,SwiftCollections.SwiftHashSet`1<System.String>)
ShouldCollectManagedGeneratedPair(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,Trailblazer.Pathing.NavigationChartCell)
IsManagedGeneratedTransitionCandidate(Trailblazer.Pathing.NavigationChartCell)
IsManagedGeneratedPairActive(GridForge.Grids.GridWorld,System.String,Trailblazer.Pathing.NavigationChart,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32)
IsChartEffectiveOwnerAtPosition(GridForge.Grids.GridWorld,System.String,FixedMathSharp.Vector3d)
AddManagedGeneratedTransitionIds(System.String,Trailblazer.Pathing.TraversalTransition[])
RemoveManagedGeneratedTransitionIds(System.String,System.String[])
CopyTransitionIds(SwiftCollections.SwiftHashSet`1<System.String>)
CopyTransitionIds(Trailblazer.Pathing.TraversalTransition[])
RemoveChartFromRegistry(System.String)
TryGetResolvedChartVoxelState(GridForge.Grids.GridWorld,FixedMathSharp.Vector3d,GridForge.Spatial.WorldVoxelIndex&,Trailblazer.Pathing.ResolvedChartVoxelState&)
TryGetResolvedChartVoxelState(GridForge.Spatial.WorldVoxelIndex,Trailblazer.Pathing.ResolvedChartVoxelState&)
TryApplyChartCellUpdate(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChartRegistration,System.Int32,System.Int32,System.Int32,Trailblazer.Pathing.NavigationChartCell,SwiftCollections.SwiftHashSet`1<Trailblazer.Pathing.SolidChartPartition>,SwiftCollections.SwiftHashSet`1<System.String>,SwiftCollections.SwiftHashSet`1<System.String>)
TrackManagedChartRefresh(Trailblazer.Pathing.NavigationChart,SwiftCollections.SwiftHashSet`1<System.String>)
TryGetChartUpdateVoxelContext(GridForge.Grids.GridWorld,Trailblazer.Pathing.NavigationChart,System.Int32,System.Int32,System.Int32,SwiftCollections.SwiftHashSet`1<System.String>,GridForge.Grids.Voxel&,Trailblazer.Pathing.ResolvedChartVoxelState&,Trailblazer.Pathing.NavigationChartCell&,System.String&)
TryUpdateResolvedVoxelStateForChartCell(Trailblazer.Pathing.NavigationChartRegistration,Trailblazer.Pathing.NavigationChartCell,GridForge.Spatial.WorldVoxelIndex,Trailblazer.Pathing.ResolvedChartVoxelState&)
RebindAndInvalidate(SwiftCollections.SwiftHashSet`1<Trailblazer.Pathing.SolidChartPartition>,SwiftCollections.SwiftHashSet`1<System.String>)
CollectEffectiveStateInvalidations(System.String,Trailblazer.Pathing.NavigationChartCell,System.String,Trailblazer.Pathing.NavigationChartCell,SwiftCollections.SwiftHashSet`1<System.String>)
HasAuthoredVolumeMedium(Trailblazer.TraversalMedium)
HasAuthoredVolumeMedium(Trailblazer.Pathing.PathingWorldState,Trailblazer.TraversalMedium)
ApplyResolvedVoxelState(GridForge.Grids.GridWorld,GridForge.Grids.Voxel,Trailblazer.Pathing.ResolvedChartVoxelState,Trailblazer.Pathing.NavigationChartCell,SwiftCollections.SwiftHashSet`1<Trailblazer.Pathing.SolidChartPartition>)
UpdateActiveVolumeMediumCounts(Trailblazer.Pathing.NavigationChartCell,Trailblazer.Pathing.NavigationChartCell)
ClearActiveAuthoredVolumeMediumCounts()
AdjustActiveAuthoredGasCellCount(System.Int32)
AdjustActiveAuthoredLiquidCellCount(System.Int32)
CollectSolidPartitionsForRebind(GridForge.Grids.GridWorld,GridForge.Grids.Voxel,SwiftCollections.SwiftHashSet`1<Trailblazer.Pathing.SolidChartPartition>)
BindCollectedSolidPartitions(SwiftCollections.SwiftHashSet`1<Trailblazer.Pathing.SolidChartPartition>)
TryGetMaxSearchSize(GridForge.Grids.GridWorld,GridForge.Grids.Voxel,GridForge.Grids.Voxel,System.Int32&)
TryGetMaxSearchSize(GridForge.Grids.Voxel,GridForge.Grids.Voxel,System.Int32&)
NeedsPath(GridForge.Grids.GridWorld,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Boolean)
NeedsPath(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Boolean)