< Summary

Information
Class: GridForge.Grids.Voxel
Assembly: GridForge
File(s): /home/runner/work/GridForge/GridForge/src/GridForge/Grids/Nodes/Voxel.cs
Line coverage
100%
Covered lines: 231
Uncovered lines: 0
Coverable lines: 231
Total lines: 628
Line coverage: 100%
Branch coverage
98%
Covered branches: 116
Total branches: 118
Branch coverage: 98.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_SpawnToken()100%11100%
get_WorldIndex()100%11100%
get_GridIndex()100%11100%
get_Index()100%11100%
get_ScanCellKey()100%11100%
get_WorldPosition()100%11100%
get_ObstacleTracker()100%11100%
get_ObstacleCount()100%11100%
get_OccupantCount()100%11100%
.ctor()100%11100%
get_IsPartioned()100%11100%
get_IsBoundaryVoxel()100%11100%
get_CachedGridVersion()100%11100%
get_IsAllocated()100%11100%
get_IsBlocked()100%22100%
get_IsBlockable()100%44100%
get_IsOccupied()100%22100%
get_HasVacancy()100%22100%
add_OnObstacleAdded(...)100%11100%
remove_OnObstacleAdded(...)100%11100%
add_OnObstacleRemoved(...)100%11100%
remove_OnObstacleRemoved(...)100%11100%
add_OnObstaclesCleared(...)100%11100%
remove_OnObstaclesCleared(...)100%11100%
add_OnOccupantAdded(...)100%11100%
remove_OnOccupantAdded(...)100%11100%
add_OnOccupantRemoved(...)100%11100%
remove_OnOccupantRemoved(...)100%11100%
Initialize(...)100%11100%
Reset(...)100%2020100%
NotifyObstacleAdded(...)100%66100%
NotifyObstacleRemoved(...)100%66100%
NotifyObstaclesCleared(...)100%66100%
NotifyOccupantAdded(...)100%66100%
NotifyOccupantRemoved(...)100%66100%
TryAddPartition(...)100%66100%
TryRemovePartition()83.33%66100%
HasPartition()100%11100%
TryGetPartition(...)100%11100%
GetPartitionOrDefault()75%44100%
InvalidateNeighborCache()100%11100%
GetNeighbors()100%1212100%
TryGetNeighborFromDirection(...)100%1010100%
TryGetNeighborFromOffset(...)100%1414100%
RefreshNeighborCache(...)100%66100%
GetHashCode()100%11100%
ToString()100%11100%
Equals(...)100%11100%
Equals(...)100%11100%

File(s)

/home/runner/work/GridForge/GridForge/src/GridForge/Grids/Nodes/Voxel.cs

#LineLine coverage
 1using FixedMathSharp;
 2using GridForge.Spatial;
 3using SwiftCollections;
 4using SwiftCollections.Pool;
 5using System;
 6using System.Collections.Generic;
 7using System.Runtime.CompilerServices;
 8
 9namespace GridForge.Grids;
 10
 11/// <summary>
 12/// Represents a voxel within a 3D grid, handling spatial positioning, obstacles, occupants, and neighbor relationships.
 13/// </summary>
 14public class Voxel : IEquatable<Voxel>
 15{
 16    #region Properties & Fields
 17
 18    /// <summary>
 19    /// Unique token identifying this voxel instance.
 20    /// </summary>
 15628721    public int SpawnToken { get; private set; }
 22
 23    /// <summary>
 24    /// The world-scoped runtime identity of this voxel within the grid system.
 25    /// </summary>
 16110426    public WorldVoxelIndex WorldIndex { get; set; }
 27
 28    /// <summary>
 29    /// The world-local index of the grid this voxel belongs to.
 30    /// </summary>
 131    public ushort GridIndex => WorldIndex.GridIndex;
 32
 33    /// <summary>
 34    /// The local coordinates of this voxel within its grid.
 35    /// </summary>
 95436    public VoxelIndex Index => WorldIndex.VoxelIndex;
 37
 38    /// <summary>
 39    /// The grid-local key of the scan cell that this voxel belongs to.
 40    /// </summary>
 15714341    public int ScanCellKey { get; private set; }
 42
 43    /// <summary>
 44    /// The world-space position of this voxel.
 45    /// </summary>
 7966546    public Vector3d WorldPosition { get; private set; }
 47
 48    /// <summary>
 49    /// Indicates whether the neighbor cache is valid.
 50    /// </summary>
 51    private bool _isNeighborCacheValid;
 52
 53    /// <summary>
 54    /// Cached array of neighboring voxels for fast lookup representing a 3x3x3 linear direction grid
 55    /// </summary>
 56    /// <remarks>
 57    /// Unlike Grid adjacency (which is 1:many), voxels can only have 1 neighbor in any one direction (1:1).
 58    /// </remarks>
 59    private Voxel[]? _cachedNeighbors;
 60
 61    /// <summary>
 62    /// Stores a unique <see cref="BoundsKey" /> for each obstacle added to this voxel to prevent adding duplicates
 63    /// </summary>
 16041064    public SwiftHashSet<BoundsKey>? ObstacleTracker { get; internal set; }
 65
 66    /// <summary>
 67    /// The current number of obstacles on this voxel.
 68    /// </summary>
 8352069    public byte ObstacleCount { get; internal set; }
 70
 71    /// <summary>
 72    /// The current number of occupants on this voxel.
 73    /// </summary>
 8085674    public byte OccupantCount { get; internal set; }
 75
 76    /// <summary>
 77    /// Handles management of partitioned data.
 78    /// </summary>
 7088179    private readonly PartitionProvider<IVoxelPartition> _partitionProvider = new();
 80
 81    /// <summary>
 82    /// Indicates whether this voxel has any active partitions.
 83    /// </summary>
 384    public bool IsPartioned => !_partitionProvider.IsEmpty;
 85
 7088186    private readonly object _partitionLock = new();
 87
 88    /// <summary>
 89    /// Determines if this voxel is a boundary voxel.
 90    /// </summary>
 15628791    public bool IsBoundaryVoxel { get; private set; }
 92
 93    /// <summary>
 94    /// The current version of the grid at the time this voxel was created.
 95    /// </summary>
 7938196    public uint CachedGridVersion { get; internal set; }
 97
 98    /// <summary>
 99    /// Indicates whether this voxel is allocated within a grid.
 100    /// </summary>
 316234101    public bool IsAllocated { get; private set; }
 102
 103    /// <summary>
 104    /// Determines whether this voxel is blocked due to obstacles.
 105    /// </summary>
 376106    public bool IsBlocked => IsAllocated && ObstacleCount > 0;
 107
 108    /// <summary>
 109    /// Determines if this voxel can accept additional obstacles.
 110    /// </summary>
 683111    public bool IsBlockable => IsAllocated
 683112        && ObstacleCount < GridObstacleManager.MaxObstacleCount
 683113        && !IsOccupied;
 114
 115    /// <summary>
 116    /// Determines whether this voxel is occupied by entities.
 117    /// </summary>
 868118    public bool IsOccupied => IsAllocated && OccupantCount > 0;
 119
 120    /// <summary>
 121    /// Checks if this voxel has open slots for new occupants.
 122    /// </summary>
 317123    public bool HasVacancy => !IsBlocked && OccupantCount < GridOccupantManager.MaxOccupantCount;
 124
 125    #endregion
 126
 127    #region Events
 128
 129    /// <summary>
 130    /// Event triggered when an obstacle is added.
 131    /// </summary>
 132    private Action<ObstacleEventInfo>? _onObstacleAdded;
 133
 134    /// <inheritdoc cref="_onObstacleAdded"/>
 135    public event Action<ObstacleEventInfo> OnObstacleAdded
 136    {
 2137        add => _onObstacleAdded += value;
 2138        remove => _onObstacleAdded -= value;
 139    }
 140
 141    /// <summary>
 142    /// Event triggered when an obstacle is removed.
 143    /// </summary>
 144    private Action<ObstacleEventInfo>? _onObstacleRemoved;
 145
 146    /// <inheritdoc cref="_onObstacleRemoved"/>
 147    public event Action<ObstacleEventInfo> OnObstacleRemoved
 148    {
 2149        add => _onObstacleRemoved += value;
 2150        remove => _onObstacleRemoved -= value;
 151    }
 152
 153    /// <summary>
 154    /// Event triggered when all obstacles on the voxel are cleared at once.
 155    /// </summary>
 156    private Action<ObstacleClearEventInfo>? _onObstaclesCleared;
 157
 158    /// <inheritdoc cref="_onObstaclesCleared"/>
 159    public event Action<ObstacleClearEventInfo> OnObstaclesCleared
 160    {
 2161        add => _onObstaclesCleared += value;
 2162        remove => _onObstaclesCleared -= value;
 163    }
 164
 165    /// <summary>
 166    /// Event triggered when an occupant is added.
 167    /// </summary>
 168    private Action<OccupantEventInfo>? _onOccupantAdded;
 169
 170    /// <inheritdoc cref="_onOccupantAdded"/>
 171    public event Action<OccupantEventInfo> OnOccupantAdded
 172    {
 2173        add => _onOccupantAdded += value;
 2174        remove => _onOccupantAdded -= value;
 175    }
 176
 177    /// <summary>
 178    /// Event triggered when an occupant is removed.
 179    /// </summary>
 180    private Action<OccupantEventInfo>? _onOccupantRemoved;
 181
 182    /// <inheritdoc cref="_onOccupantRemoved"/>
 183    public event Action<OccupantEventInfo> OnOccupantRemoved
 184    {
 2185        add => _onOccupantRemoved += value;
 2186        remove => _onOccupantRemoved -= value;
 187    }
 188
 189    #endregion
 190
 191    #region Initialization & Reset
 192
 193    /// <summary>
 194    /// Configures the voxel with its position, grid version, and boundary status.
 195    /// </summary>
 196    internal void Initialize(
 197        WorldVoxelIndex worldVoxelIndex,
 198        Vector3d worldPosition,
 199        int scanCellKey,
 200        bool isBoundaryVoxel,
 201        uint gridVersion)
 202    {
 78144203        ScanCellKey = scanCellKey;
 78144204        IsBoundaryVoxel = isBoundaryVoxel;
 205
 78144206        WorldIndex = worldVoxelIndex;
 78144207        WorldPosition = worldPosition;
 208
 78144209        SpawnToken = GetHashCode();
 78144210        CachedGridVersion = gridVersion;
 78144211        IsAllocated = true;
 78144212    }
 213
 214    /// <summary>
 215    /// Resets the voxel, clearing all allocated data and returning it to pools.
 216    /// </summary>
 217    internal void Reset(VoxelGrid? ownerGrid = null)
 218    {
 156289219        if (!IsAllocated)
 78146220            return;
 221
 78143222        if (!_partitionProvider.IsEmpty)
 223        {
 5224            lock (_partitionLock)
 225            {
 22226                foreach (IVoxelPartition partition in _partitionProvider.Partitions)
 227                {
 228                    try
 229                    {
 6230                        partition.OnRemoveFromVoxel(this);
 5231                    }
 1232                    catch (Exception ex)
 233                    {
 1234                        GridForgeLogger.Channel.Error(
 1235                            $"Attempting to call {nameof(partition.OnRemoveFromVoxel)} on {partition.GetType().Name}: {e
 1236                    }
 237                }
 238
 5239                _partitionProvider.Clear();
 5240            }
 241        }
 242
 78143243        if (_cachedNeighbors != null)
 244        {
 9245            Pools.VoxelNeighborPool.Release(_cachedNeighbors);
 9246            _cachedNeighbors = null;
 247        }
 248
 78143249        if (ObstacleTracker != null && ObstacleTracker.Count > 0)
 250        {
 522251            if (ownerGrid == null)
 252            {
 2253                if (ObstacleTracker != null)
 254                {
 2255                    SwiftHashSetPool<BoundsKey>.Shared.Release(ObstacleTracker);
 2256                    ObstacleTracker = null;
 257                }
 258
 2259                ObstacleCount = 0;
 260            }
 261            else
 520262                ownerGrid?.ClearObstacles(this);
 263        }
 264
 78143265        ObstacleTracker = null;
 78143266        ObstacleCount = 0;
 267
 78143268        _isNeighborCacheValid = false;
 78143269        IsBoundaryVoxel = false;
 270
 78143271        SpawnToken = 0;
 78143272        ScanCellKey = 0;
 78143273        WorldIndex = default;
 274
 78143275        OccupantCount = 0;
 78143276        _onObstacleAdded = null;
 78143277        _onObstacleRemoved = null;
 78143278        _onObstaclesCleared = null;
 78143279        _onOccupantAdded = null;
 78143280        _onOccupantRemoved = null;
 281
 78143282        IsAllocated = false;
 78143283    }
 284
 285    #endregion
 286
 287    #region Notifications
 288
 289    internal void NotifyObstacleAdded(ObstacleEventInfo eventInfo)
 290    {
 676291        Action<ObstacleEventInfo>? handlers = _onObstacleAdded;
 676292        if (handlers == null)
 674293            return;
 294
 2295        var handlerDelegates = handlers.GetInvocationList();
 12296        for (int i = 0; i < handlerDelegates.Length; i++)
 297        {
 298            try
 299            {
 4300                ((Action<ObstacleEventInfo>)handlerDelegates[i])(eventInfo);
 2301            }
 2302            catch (Exception ex)
 303            {
 2304                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Obstacle add error: {ex.Message}");
 2305            }
 306        }
 2307    }
 308
 309    internal void NotifyObstacleRemoved(ObstacleEventInfo eventInfo)
 310    {
 39311        Action<ObstacleEventInfo>? handlers = _onObstacleRemoved;
 39312        if (handlers == null)
 38313            return;
 314
 1315        var handlerDelegates = handlers.GetInvocationList();
 6316        for (int i = 0; i < handlerDelegates.Length; i++)
 317        {
 318            try
 319            {
 2320                ((Action<ObstacleEventInfo>)handlerDelegates[i])(eventInfo);
 1321            }
 1322            catch (Exception ex)
 323            {
 1324                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Obstacle remove error: {ex.Message}");
 1325            }
 326        }
 1327    }
 328
 329    internal void NotifyObstaclesCleared(ObstacleClearEventInfo eventInfo)
 330    {
 522331        Action<ObstacleClearEventInfo>? handlers = _onObstaclesCleared;
 522332        if (handlers == null)
 521333            return;
 334
 1335        var handlerDelegates = handlers.GetInvocationList();
 6336        for (int i = 0; i < handlerDelegates.Length; i++)
 337        {
 338            try
 339            {
 2340                ((Action<ObstacleClearEventInfo>)handlerDelegates[i])(eventInfo);
 1341            }
 1342            catch (Exception ex)
 343            {
 1344                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Obstacle clear error: {ex.Message}");
 1345            }
 346        }
 1347    }
 348
 349    internal void NotifyOccupantAdded(OccupantEventInfo eventInfo)
 350    {
 314351        Action<OccupantEventInfo>? handlers = _onOccupantAdded;
 314352        if (handlers == null)
 313353            return;
 354
 1355        var handlerDelegates = handlers.GetInvocationList();
 6356        for (int i = 0; i < handlerDelegates.Length; i++)
 357        {
 358            try
 359            {
 2360                ((Action<OccupantEventInfo>)handlerDelegates[i])(eventInfo);
 1361            }
 1362            catch (Exception ex)
 363            {
 1364                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Occupant add error: {ex.Message}");
 1365            }
 366        }
 1367    }
 368
 369    internal void NotifyOccupantRemoved(OccupantEventInfo eventInfo)
 370    {
 146371        Action<OccupantEventInfo>? handlers = _onOccupantRemoved;
 146372        if (handlers == null)
 145373            return;
 374
 1375        var handlerDelegates = handlers.GetInvocationList();
 6376        for (int i = 0; i < handlerDelegates.Length; i++)
 377        {
 378            try
 379            {
 2380                ((Action<OccupantEventInfo>)handlerDelegates[i])(eventInfo);
 1381            }
 1382            catch (Exception ex)
 383            {
 1384                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Occupant remove error: {ex.Message}");
 1385            }
 386        }
 1387    }
 388
 389    #endregion
 390
 391    #region Partition Management
 392
 393    /// <summary>
 394    /// Adds a partition to this voxel, allowing specialized behaviors.
 395    /// </summary>
 396    public bool TryAddPartition(IVoxelPartition partition)
 397    {
 12398        if (partition == null)
 1399            return false;
 400
 11401        Type partitionType = partition.GetType();
 11402        string partitionName = partitionType.Name;
 403
 11404        lock (_partitionLock)
 405        {
 11406            if (!_partitionProvider.TryAdd(partitionType, partition))
 2407                return false;
 9408        }
 409
 410        try
 411        {
 9412            partition.SetParentIndex(WorldIndex);
 9413            partition.OnAddToVoxel(this);
 8414            return true;
 415        }
 1416        catch (Exception ex)
 417        {
 1418            lock (_partitionLock)
 1419                _partitionProvider.TryRemove(partitionType, out _);
 420
 1421            GridForgeLogger.Channel.Error($"Error attempting to attach partition {partitionName}: {ex.Message}");
 1422            return false;
 423        }
 11424    }
 425
 426    /// <summary>
 427    /// Removes a partition from this voxel.
 428    /// </summary>
 429    public bool TryRemovePartition<T>() where T : IVoxelPartition
 430    {
 3431        Type partitionType = typeof(T);
 3432        string partitionName = partitionType.Name;
 433
 3434        IVoxelPartition? partition = null;
 3435        lock (_partitionLock)
 3436            _partitionProvider.TryRemove(partitionType, out partition);
 437
 3438        if (partition == null)
 439        {
 1440            GridForgeLogger.Channel.Warn($"Partition {partitionName} not found on this voxel.");
 1441            return false;
 442        }
 443
 444        try
 445        {
 2446            partition.OnRemoveFromVoxel(this);
 1447        }
 1448        catch (Exception ex)
 449        {
 1450            GridForgeLogger.Channel.Error($"Attempting to call {nameof(partition.OnRemoveFromVoxel)} on {partitionName}:
 1451        }
 452
 2453        return true;
 454    }
 455
 456    /// <summary>
 457    /// Checks whether or not this voxel contains a specific partition.
 458    /// </summary>
 459    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 460    public bool HasPartition<T>() where T : IVoxelPartition
 461    {
 5462        lock (_partitionLock)
 5463            return _partitionProvider.Has<T>();
 5464    }
 465
 466    /// <summary>
 467    /// Retrieves a partition from the voxel by type.
 468    /// </summary>
 469    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 470    public bool TryGetPartition<T>(out T? partition) where T : IVoxelPartition
 471    {
 7472        lock (_partitionLock)
 7473            return _partitionProvider.TryGet(out partition);
 7474    }
 475
 476    /// <summary>
 477    /// Retrieves a partition from the voxel by type and returns null if it doesn't exist.
 478    /// </summary>
 479    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 480    public T? GetPartitionOrDefault<T>() where T : class, IVoxelPartition
 481    {
 5482        lock (_partitionLock)
 5483            return _partitionProvider?.TryGet(out T? partition) ?? false
 5484                ? partition
 5485                : null;
 5486    }
 487
 488    #endregion
 489
 490    #region Neighbor Handling
 491
 492    /// <summary>
 493    /// Invalidates the neighbor cache when a boundary relationship changes.
 494    /// </summary>
 144495    internal void InvalidateNeighborCache() => _isNeighborCacheValid = false;
 496
 497    /// <summary>
 498    /// Retrieves the neighbors of this voxel, caching results if specified.
 499    /// </summary>
 500    public IEnumerable<(SpatialDirection, Voxel)> GetNeighbors(VoxelGrid ownerGrid, bool useCache = true)
 501    {
 7502        if (useCache && _isNeighborCacheValid)
 503        {
 108504            for (int i = 0; i < _cachedNeighbors!.Length; i++)
 505            {
 52506                if (_cachedNeighbors[i] == null)
 507                    continue;
 33508                yield return ((SpatialDirection)i, _cachedNeighbors[i]);
 509            }
 510
 2511            yield break;
 512        }
 513
 5514        RefreshNeighborCache(ownerGrid);
 515
 270516        for (int i = 0; i < _cachedNeighbors!.Length; i++)
 517        {
 130518            if (_cachedNeighbors[i] == null)
 519                continue;
 69520            yield return ((SpatialDirection)i, _cachedNeighbors[i]);
 521        }
 5522    }
 523
 524    /// <summary>
 525    /// Retrieves a neighbor voxel in a specific direction.
 526    /// </summary>
 527    public bool TryGetNeighborFromDirection(
 528        VoxelGrid ownerGrid,
 529        SpatialDirection direction,
 530        out Voxel? neighbor,
 531        bool useCache = true)
 532    {
 61533        neighbor = null;
 534
 535        // Validate the index
 61536        int directionIndex = (int)direction;
 61537        if (direction == SpatialDirection.None
 61538            || directionIndex < 0
 61539            || directionIndex >= SpatialAwareness.DirectionOffsets.Length)
 3540            return false;
 541
 542        // Check cached neighbors if caching is enabled
 58543        if (useCache)
 544        {
 32545            if (!_isNeighborCacheValid)
 7546                RefreshNeighborCache(ownerGrid);
 547
 32548            neighbor = _cachedNeighbors![directionIndex];
 32549            return neighbor != null;
 550        }
 551
 26552        (int x, int y, int z) offset = SpatialAwareness.DirectionOffsets[directionIndex];
 26553        return TryGetNeighborFromOffset(ownerGrid, offset, out neighbor);
 554    }
 555
 556    /// <summary>
 557    /// Retrieves a neighbor voxel based on a coordinate offset.
 558    /// </summary>
 559    public bool TryGetNeighborFromOffset(
 560        VoxelGrid ownerGrid,
 561        (int x, int y, int z) offset,
 562        out Voxel? neighbor)
 563    {
 340564        neighbor = null;
 340565        if (ownerGrid == null
 340566            || !ownerGrid.IsActive
 340567            || ownerGrid.GridIndex != WorldIndex.GridIndex
 340568            || ownerGrid.SpawnToken != WorldIndex.GridSpawnToken
 340569            || ownerGrid.World == null
 340570            || ownerGrid.World.SpawnToken != WorldIndex.WorldSpawnToken)
 571        {
 27572            return false;
 573        }
 574
 313575        VoxelIndex neighborCoords = new(
 313576            Index.x + offset.x,
 313577            Index.y + offset.y,
 313578            Index.z + offset.z
 313579        );
 580
 313581        if (ownerGrid.TryGetVoxel(neighborCoords, out neighbor))
 130582            return true;
 583
 183584        Fixed64 voxelSize = ownerGrid.World.VoxelSize;
 183585        Vector3d neighborPosition = new(
 183586            WorldPosition.x + offset.x * voxelSize,
 183587            WorldPosition.y + offset.y * voxelSize,
 183588            WorldPosition.z + offset.z * voxelSize);
 589
 183590        return ownerGrid.World.TryGetVoxel(neighborPosition, out neighbor);
 591    }
 592
 593    /// <summary>
 594    /// Updates and caches the neighboring voxels of this voxel.
 595    /// </summary>
 596    private void RefreshNeighborCache(VoxelGrid ownerGrid)
 597    {
 12598        _cachedNeighbors ??= Pools.VoxelNeighborPool.Rent(SpatialAwareness.DirectionOffsets.Length);
 12599        Array.Clear(_cachedNeighbors, 0, _cachedNeighbors.Length); // Ensure clean state
 600
 648601        for (int i = 0; i < SpatialAwareness.DirectionOffsets.Length; i++)
 602        {
 312603            (int x, int y, int z) offset = SpatialAwareness.DirectionOffsets[i];
 312604            if (TryGetNeighborFromOffset(ownerGrid, offset, out Voxel? neighbor))
 108605                _cachedNeighbors[i] = neighbor!;
 606        }
 607
 12608        _isNeighborCacheValid = true;
 12609    }
 610
 611    #endregion
 612
 613    #region Utility
 614
 615    /// <inheritdoc/>
 79152616    public override int GetHashCode() => RuntimeHelpers.GetHashCode(this);
 617
 618    /// <inheritdoc/>
 1619    public override string ToString() => WorldIndex.ToString();
 620
 621    /// <inheritdoc/>
 15622    public bool Equals(Voxel? other) => ReferenceEquals(this, other);
 623
 624    /// <inheritdoc/>
 2625    public override bool Equals(object? obj) => ReferenceEquals(this, obj);
 626
 627    #endregion
 628}

Methods/Properties

get_SpawnToken()
get_WorldIndex()
get_GridIndex()
get_Index()
get_ScanCellKey()
get_WorldPosition()
get_ObstacleTracker()
get_ObstacleCount()
get_OccupantCount()
.ctor()
get_IsPartioned()
get_IsBoundaryVoxel()
get_CachedGridVersion()
get_IsAllocated()
get_IsBlocked()
get_IsBlockable()
get_IsOccupied()
get_HasVacancy()
add_OnObstacleAdded(System.Action`1<GridForge.Grids.ObstacleEventInfo>)
remove_OnObstacleAdded(System.Action`1<GridForge.Grids.ObstacleEventInfo>)
add_OnObstacleRemoved(System.Action`1<GridForge.Grids.ObstacleEventInfo>)
remove_OnObstacleRemoved(System.Action`1<GridForge.Grids.ObstacleEventInfo>)
add_OnObstaclesCleared(System.Action`1<GridForge.Grids.ObstacleClearEventInfo>)
remove_OnObstaclesCleared(System.Action`1<GridForge.Grids.ObstacleClearEventInfo>)
add_OnOccupantAdded(System.Action`1<GridForge.Grids.OccupantEventInfo>)
remove_OnOccupantAdded(System.Action`1<GridForge.Grids.OccupantEventInfo>)
add_OnOccupantRemoved(System.Action`1<GridForge.Grids.OccupantEventInfo>)
remove_OnOccupantRemoved(System.Action`1<GridForge.Grids.OccupantEventInfo>)
Initialize(GridForge.Spatial.WorldVoxelIndex,FixedMathSharp.Vector3d,System.Int32,System.Boolean,System.UInt32)
Reset(GridForge.Grids.VoxelGrid)
NotifyObstacleAdded(GridForge.Grids.ObstacleEventInfo)
NotifyObstacleRemoved(GridForge.Grids.ObstacleEventInfo)
NotifyObstaclesCleared(GridForge.Grids.ObstacleClearEventInfo)
NotifyOccupantAdded(GridForge.Grids.OccupantEventInfo)
NotifyOccupantRemoved(GridForge.Grids.OccupantEventInfo)
TryAddPartition(GridForge.Spatial.IVoxelPartition)
TryRemovePartition()
HasPartition()
TryGetPartition(T&)
GetPartitionOrDefault()
InvalidateNeighborCache()
GetNeighbors()
TryGetNeighborFromDirection(GridForge.Grids.VoxelGrid,GridForge.Spatial.SpatialDirection,GridForge.Grids.Voxel&,System.Boolean)
TryGetNeighborFromOffset(GridForge.Grids.VoxelGrid,System.ValueTuple`3<System.Int32,System.Int32,System.Int32>,GridForge.Grids.Voxel&)
RefreshNeighborCache(GridForge.Grids.VoxelGrid)
GetHashCode()
ToString()
Equals(GridForge.Grids.Voxel)
Equals(System.Object)