< 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: 207
Uncovered lines: 0
Coverable lines: 207
Total lines: 630
Line coverage: 100%
Branch coverage
100%
Covered branches: 98
Total branches: 98
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// Voxel.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using GridForge.Grids.Topology;
 10using GridForge.Spatial;
 11using SwiftCollections;
 12using SwiftCollections.Pool;
 13using System;
 14using System.Runtime.CompilerServices;
 15
 16namespace GridForge.Grids;
 17
 18/// <summary>
 19/// Represents a voxel within a 3D grid, handling spatial positioning, obstacles, occupants, and neighbor relationships.
 20/// </summary>
 21public class Voxel : IEquatable<Voxel>
 22{
 23    #region Properties & Fields
 24
 25    /// <summary>
 26    /// Unique token identifying this voxel instance.
 27    /// </summary>
 28    public int SpawnToken { get; private set; }
 29
 30    /// <summary>
 31    /// The world-scoped runtime identity of this voxel within the grid system.
 32    /// </summary>
 33    public WorldVoxelIndex WorldIndex { get; set; }
 34
 35    /// <summary>
 36    /// The world-local index of the grid this voxel belongs to.
 37    /// </summary>
 338    public ushort GridIndex => WorldIndex.GridIndex;
 39
 40    /// <summary>
 41    /// The local coordinates of this voxel within its grid.
 42    /// </summary>
 1094943    public VoxelIndex Index => WorldIndex.VoxelIndex;
 44
 45    /// <summary>
 46    /// The grid-local key of the scan cell that this voxel belongs to.
 47    /// </summary>
 48    public int ScanCellKey { get; private set; }
 49
 50    /// <summary>
 51    /// The world-space position of this voxel.
 52    /// </summary>
 53    public Vector3d WorldPosition { get; private set; }
 54
 55    /// <summary>
 56    /// Stores a unique <see cref="BoundsKey" /> for each obstacle added to this voxel to prevent adding duplicates
 57    /// </summary>
 58    public SwiftHashSet<BoundsKey>? ObstacleTracker { get; internal set; }
 59
 60    /// <summary>
 61    /// The current number of obstacles on this voxel.
 62    /// </summary>
 63    public byte ObstacleCount { get; internal set; }
 64
 65    /// <summary>
 66    /// The current number of occupants on this voxel.
 67    /// </summary>
 68    public byte OccupantCount { get; internal set; }
 69
 70    /// <summary>
 71    /// Handles management of partitioned data.
 72    /// </summary>
 8546273    private readonly PartitionProvider<IVoxelPartition> _partitionProvider = new();
 74
 75    /// <summary>
 76    /// Indicates whether this voxel has any active partitions.
 77    /// </summary>
 880578    public bool IsPartioned => !_partitionProvider.IsEmpty;
 79
 8546280    private readonly object _partitionLock = new();
 81
 82    /// <summary>
 83    /// Determines if this voxel is a boundary voxel.
 84    /// </summary>
 85    public bool IsBoundaryVoxel { get; private set; }
 86
 87    /// <summary>
 88    /// The current version of the grid at the time this voxel was created.
 89    /// </summary>
 90    public uint CachedGridVersion { get; internal set; }
 91
 92    /// <summary>
 93    /// Indicates whether this voxel is allocated within a grid.
 94    /// </summary>
 95    public bool IsAllocated { get; private set; }
 96
 97    /// <summary>
 98    /// Determines whether this voxel is blocked due to obstacles.
 99    /// </summary>
 18079100    public bool IsBlocked => IsAllocated && ObstacleCount > 0;
 101
 102    /// <summary>
 103    /// Determines if this voxel can accept additional obstacles.
 104    /// </summary>
 754105    public bool IsBlockable => IsAllocated
 754106        && ObstacleCount < GridObstacleManager.MaxObstacleCount
 754107        && !IsOccupied;
 108
 109    /// <summary>
 110    /// Determines whether this voxel is occupied by entities.
 111    /// </summary>
 18548112    public bool IsOccupied => IsAllocated && OccupantCount > 0;
 113
 114    /// <summary>
 115    /// Checks if this voxel has open slots for new occupants.
 116    /// </summary>
 407117    public bool HasVacancy => !IsBlocked && OccupantCount < GridOccupantManager.MaxOccupantCount;
 118
 119    internal bool HasEventSubscribers =>
 13120        _onObstacleAdded != null
 13121        || _onObstacleRemoved != null
 13122        || _onObstaclesCleared != null
 13123        || _onOccupantAdded != null
 13124        || _onOccupantRemoved != null;
 125
 126    #endregion
 127
 128    #region Events
 129
 130    /// <summary>
 131    /// Event triggered when an obstacle is added.
 132    /// </summary>
 133    private Action<ObstacleEventInfo>? _onObstacleAdded;
 134
 135    /// <inheritdoc cref="_onObstacleAdded"/>
 136    public event Action<ObstacleEventInfo> OnObstacleAdded
 137    {
 3138        add => _onObstacleAdded += value;
 3139        remove => _onObstacleAdded -= value;
 140    }
 141
 142    /// <summary>
 143    /// Event triggered when an obstacle is removed.
 144    /// </summary>
 145    private Action<ObstacleEventInfo>? _onObstacleRemoved;
 146
 147    /// <inheritdoc cref="_onObstacleRemoved"/>
 148    public event Action<ObstacleEventInfo> OnObstacleRemoved
 149    {
 2150        add => _onObstacleRemoved += value;
 2151        remove => _onObstacleRemoved -= value;
 152    }
 153
 154    /// <summary>
 155    /// Event triggered when all obstacles on the voxel are cleared at once.
 156    /// </summary>
 157    private Action<ObstacleClearEventInfo>? _onObstaclesCleared;
 158
 159    /// <inheritdoc cref="_onObstaclesCleared"/>
 160    public event Action<ObstacleClearEventInfo> OnObstaclesCleared
 161    {
 2162        add => _onObstaclesCleared += value;
 2163        remove => _onObstaclesCleared -= value;
 164    }
 165
 166    /// <summary>
 167    /// Event triggered when an occupant is added.
 168    /// </summary>
 169    private Action<OccupantEventInfo>? _onOccupantAdded;
 170
 171    /// <inheritdoc cref="_onOccupantAdded"/>
 172    public event Action<OccupantEventInfo> OnOccupantAdded
 173    {
 2174        add => _onOccupantAdded += value;
 2175        remove => _onOccupantAdded -= value;
 176    }
 177
 178    /// <summary>
 179    /// Event triggered when an occupant is removed.
 180    /// </summary>
 181    private Action<OccupantEventInfo>? _onOccupantRemoved;
 182
 183    /// <inheritdoc cref="_onOccupantRemoved"/>
 184    public event Action<OccupantEventInfo> OnOccupantRemoved
 185    {
 2186        add => _onOccupantRemoved += value;
 2187        remove => _onOccupantRemoved -= value;
 188    }
 189
 190    #endregion
 191
 192    #region Initialization & Reset
 193
 194    /// <summary>
 195    /// Configures the voxel with its position, grid version, and boundary status.
 196    /// </summary>
 197    internal void Initialize(
 198        WorldVoxelIndex worldVoxelIndex,
 199        Vector3d worldPosition,
 200        int scanCellKey,
 201        bool isBoundaryVoxel,
 202        uint gridVersion)
 203    {
 95899204        ScanCellKey = scanCellKey;
 95899205        IsBoundaryVoxel = isBoundaryVoxel;
 206
 95899207        WorldIndex = worldVoxelIndex;
 95899208        WorldPosition = worldPosition;
 209
 95899210        SpawnToken = GetHashCode();
 95899211        CachedGridVersion = gridVersion;
 95899212        IsAllocated = true;
 95899213    }
 214
 215    /// <summary>
 216    /// Resets the voxel, clearing all allocated data and returning it to pools.
 217    /// </summary>
 218    internal void Reset(VoxelGrid? ownerGrid = null)
 219    {
 191798220        if (!IsAllocated)
 95899221            return;
 222
 95899223        RemovePartitions();
 95899224        ReleaseObstacleState(ownerGrid);
 95899225        ClearRuntimeState();
 95899226    }
 227
 228    private void RemovePartitions()
 229    {
 95899230        if (!_partitionProvider.IsEmpty)
 231        {
 8232            lock (_partitionLock)
 233            {
 34234                foreach (IVoxelPartition partition in _partitionProvider.Partitions)
 235                {
 236                    try
 237                    {
 9238                        partition.OnRemoveFromVoxel(this);
 8239                    }
 1240                    catch (Exception ex)
 241                    {
 1242                        GridForgeLogger.Channel.Error(
 1243                            $"Attempting to call {nameof(partition.OnRemoveFromVoxel)} on {partition.GetType().Name}: {e
 1244                    }
 245                }
 246
 8247                _partitionProvider.Clear();
 8248            }
 249        }
 95899250    }
 251
 252    private void ReleaseObstacleState(VoxelGrid? ownerGrid)
 253    {
 95899254        if (ownerGrid != null && ObstacleCount > 0)
 558255            ownerGrid.ClearObstacles(this);
 95341256        else if (ObstacleTracker != null)
 2257            SwiftHashSetPool<BoundsKey>.Shared.Release(ObstacleTracker);
 258
 95899259        ObstacleTracker = null;
 95899260        ObstacleCount = 0;
 95899261    }
 262
 263    private void ClearRuntimeState()
 264    {
 95899265        IsBoundaryVoxel = false;
 266
 95899267        SpawnToken = 0;
 95899268        ScanCellKey = 0;
 95899269        WorldIndex = default;
 270
 95899271        OccupantCount = 0;
 95899272        _onObstacleAdded = null;
 95899273        _onObstacleRemoved = null;
 95899274        _onObstaclesCleared = null;
 95899275        _onOccupantAdded = null;
 95899276        _onOccupantRemoved = null;
 277
 95899278        IsAllocated = false;
 95899279    }
 280
 281    #endregion
 282
 283    #region Notifications
 284
 285    internal void NotifyObstacleAdded(ObstacleEventInfo eventInfo)
 286    {
 746287        Action<ObstacleEventInfo>? handlers = _onObstacleAdded;
 746288        if (handlers == null)
 744289            return;
 290
 2291        var handlerDelegates = handlers.GetInvocationList();
 12292        for (int i = 0; i < handlerDelegates.Length; i++)
 293        {
 294            try
 295            {
 4296                ((Action<ObstacleEventInfo>)handlerDelegates[i])(eventInfo);
 2297            }
 2298            catch (Exception ex)
 299            {
 2300                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Obstacle add error: {ex.Message}");
 2301            }
 302        }
 2303    }
 304
 305    internal void NotifyObstacleRemoved(ObstacleEventInfo eventInfo)
 306    {
 71307        Action<ObstacleEventInfo>? handlers = _onObstacleRemoved;
 71308        if (handlers == null)
 70309            return;
 310
 1311        var handlerDelegates = handlers.GetInvocationList();
 6312        for (int i = 0; i < handlerDelegates.Length; i++)
 313        {
 314            try
 315            {
 2316                ((Action<ObstacleEventInfo>)handlerDelegates[i])(eventInfo);
 1317            }
 1318            catch (Exception ex)
 319            {
 1320                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Obstacle remove error: {ex.Message}");
 1321            }
 322        }
 1323    }
 324
 325    internal void NotifyObstaclesCleared(ObstacleClearEventInfo eventInfo)
 326    {
 560327        Action<ObstacleClearEventInfo>? handlers = _onObstaclesCleared;
 560328        if (handlers == null)
 559329            return;
 330
 1331        var handlerDelegates = handlers.GetInvocationList();
 6332        for (int i = 0; i < handlerDelegates.Length; i++)
 333        {
 334            try
 335            {
 2336                ((Action<ObstacleClearEventInfo>)handlerDelegates[i])(eventInfo);
 1337            }
 1338            catch (Exception ex)
 339            {
 1340                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Obstacle clear error: {ex.Message}");
 1341            }
 342        }
 1343    }
 344
 345    internal void NotifyOccupantAdded(OccupantEventInfo eventInfo)
 346    {
 402347        Action<OccupantEventInfo>? handlers = _onOccupantAdded;
 402348        if (handlers == null)
 401349            return;
 350
 1351        var handlerDelegates = handlers.GetInvocationList();
 6352        for (int i = 0; i < handlerDelegates.Length; i++)
 353        {
 354            try
 355            {
 2356                ((Action<OccupantEventInfo>)handlerDelegates[i])(eventInfo);
 1357            }
 1358            catch (Exception ex)
 359            {
 1360                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Occupant add error: {ex.Message}");
 1361            }
 362        }
 1363    }
 364
 365    internal void NotifyOccupantRemoved(OccupantEventInfo eventInfo)
 366    {
 153367        Action<OccupantEventInfo>? handlers = _onOccupantRemoved;
 153368        if (handlers == null)
 152369            return;
 370
 1371        var handlerDelegates = handlers.GetInvocationList();
 6372        for (int i = 0; i < handlerDelegates.Length; i++)
 373        {
 374            try
 375            {
 2376                ((Action<OccupantEventInfo>)handlerDelegates[i])(eventInfo);
 1377            }
 1378            catch (Exception ex)
 379            {
 1380                GridForgeLogger.Channel.Error($"[Voxel {WorldIndex}] Occupant remove error: {ex.Message}");
 1381            }
 382        }
 1383    }
 384
 385    #endregion
 386
 387    #region Partition Management
 388
 389    /// <summary>
 390    /// Adds a partition to this voxel, allowing specialized behaviors.
 391    /// </summary>
 392    public bool TryAddPartition(IVoxelPartition partition)
 393    {
 16394        if (partition == null)
 1395            return false;
 396
 15397        Type partitionType = partition.GetType();
 15398        string partitionName = partitionType.Name;
 399
 15400        lock (_partitionLock)
 401        {
 15402            if (!_partitionProvider.TryAdd(partitionType, partition))
 2403                return false;
 13404        }
 405
 406        try
 407        {
 13408            partition.SetParentIndex(WorldIndex);
 13409            partition.OnAddToVoxel(this);
 12410            return true;
 411        }
 1412        catch (Exception ex)
 413        {
 1414            lock (_partitionLock)
 1415                _partitionProvider.TryRemove(partitionType, out _);
 416
 1417            GridForgeLogger.Channel.Error($"Error attempting to attach partition {partitionName}: {ex.Message}");
 1418            return false;
 419        }
 15420    }
 421
 422    /// <summary>
 423    /// Removes a partition from this voxel.
 424    /// </summary>
 425    public bool TryRemovePartition<T>() where T : IVoxelPartition
 426    {
 5427        Type partitionType = typeof(T);
 5428        string partitionName = partitionType.Name;
 429
 5430        IVoxelPartition? partition = null;
 5431        lock (_partitionLock)
 5432            _partitionProvider.TryRemove(partitionType, out partition);
 433
 5434        if (partition == null)
 435        {
 2436            GridForgeLogger.Channel.Warn($"Partition {partitionName} not found on this voxel.");
 2437            return false;
 438        }
 439
 440        try
 441        {
 3442            partition.OnRemoveFromVoxel(this);
 2443        }
 1444        catch (Exception ex)
 445        {
 1446            GridForgeLogger.Channel.Error($"Attempting to call {nameof(partition.OnRemoveFromVoxel)} on {partitionName}:
 1447        }
 448
 3449        return true;
 450    }
 451
 452    /// <summary>
 453    /// Checks whether or not this voxel contains a specific partition.
 454    /// </summary>
 455    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 456    public bool HasPartition<T>() where T : IVoxelPartition
 457    {
 5458        lock (_partitionLock)
 5459            return _partitionProvider.Has<T>();
 5460    }
 461
 462    /// <summary>
 463    /// Retrieves a partition from the voxel by type.
 464    /// </summary>
 465    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 466    public bool TryGetPartition<T>(out T? partition) where T : IVoxelPartition
 467    {
 9468        lock (_partitionLock)
 9469            return _partitionProvider.TryGet(out partition);
 9470    }
 471
 472    /// <summary>
 473    /// Retrieves a partition from the voxel by type and returns null if it doesn't exist.
 474    /// </summary>
 475    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 476    public T? GetPartitionOrDefault<T>() where T : class, IVoxelPartition
 477    {
 5478        lock (_partitionLock)
 5479            return _partitionProvider.TryGet(out T? partition)
 5480                ? partition
 5481                : null;
 5482    }
 483
 484    #endregion
 485
 486    #region Neighbor Handling
 487
 488    /// <summary>
 489    /// Clears and fills caller-owned storage with neighboring voxels whose
 490    /// world-space voxel footprints touch this voxel's footprint.
 491    /// </summary>
 492    /// <param name="ownerGrid">The active grid that owns this voxel.</param>
 493    /// <param name="results">Caller-owned storage cleared and filled with contact neighbors.</param>
 494    /// <param name="scope">The grid groups included by the contact query.</param>
 495    /// <param name="tolerance">Optional fixed-point tolerance applied to footprint contact checks.</param>
 496    public void GetNeighborsInto(
 497        VoxelGrid ownerGrid,
 498        SwiftList<Voxel> results,
 499        VoxelNeighborScope scope = VoxelNeighborScope.All,
 500        Fixed64? tolerance = null)
 501    {
 23502        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 503
 23504        results.Clear();
 23505        if (!IsValidOwnerGrid(ownerGrid))
 1506            return;
 507
 22508        VoxelNeighborResolver.AddContactNeighbors(this, ownerGrid, results, scope, tolerance);
 22509    }
 510
 511    /// <summary>
 512    /// Determines whether this voxel has at least one footprint-contact neighbor in the requested scope.
 513    /// </summary>
 514    /// <param name="ownerGrid">The active grid that owns this voxel.</param>
 515    /// <param name="scope">The grid groups included by the contact query.</param>
 516    /// <param name="tolerance">Optional fixed-point tolerance applied to footprint contact checks.</param>
 517    /// <returns>True when at least one contact exists; otherwise false.</returns>
 518    public bool HasNeighbor(
 519        VoxelGrid ownerGrid,
 520        VoxelNeighborScope scope = VoxelNeighborScope.All,
 521        Fixed64? tolerance = null)
 522    {
 10523        if (!IsValidOwnerGrid(ownerGrid))
 1524            return false;
 525
 9526        return VoxelNeighborResolver.HasContactNeighbor(this, ownerGrid, scope, tolerance);
 527    }
 528
 529    /// <summary>
 530    /// Retrieves the rectangular-prism neighbor voxel in the supplied topology-local direction.
 531    /// </summary>
 532    /// <param name="ownerGrid">The active grid that owns this voxel.</param>
 533    /// <param name="direction">The rectangular-prism direction to resolve.</param>
 534    /// <param name="neighbor">The resolved same-topology neighbor when found.</param>
 535    /// <returns>True when a same-topology neighbor exists in the supplied direction; otherwise false.</returns>
 536    public bool TryGetNeighbor(
 537        VoxelGrid ownerGrid,
 538        RectangularDirection direction,
 539        out Voxel? neighbor)
 540    {
 75541        neighbor = null;
 75542        if (!IsValidOwnerGrid(ownerGrid))
 4543            return false;
 544
 71545        return VoxelNeighborResolver.TryGetNeighbor(this, ownerGrid, direction, out neighbor);
 546    }
 547
 548    /// <summary>
 549    /// Retrieves the hex-prism neighbor voxel in the supplied topology-local direction.
 550    /// </summary>
 551    /// <param name="ownerGrid">The active grid that owns this voxel.</param>
 552    /// <param name="direction">The hex-prism direction to resolve.</param>
 553    /// <param name="neighbor">The resolved same-topology neighbor when found.</param>
 554    /// <returns>True when a same-topology neighbor exists in the supplied direction; otherwise false.</returns>
 555    public bool TryGetNeighbor(
 556        VoxelGrid ownerGrid,
 557        HexDirection direction,
 558        out Voxel? neighbor)
 559    {
 6560        neighbor = null;
 6561        if (!IsValidOwnerGrid(ownerGrid))
 1562            return false;
 563
 5564        return VoxelNeighborResolver.TryGetNeighbor(this, ownerGrid, direction, out neighbor);
 565    }
 566
 567    /// <summary>
 568    /// Clears and fills caller-owned storage with rectangular-prism neighbors in deterministic direction order.
 569    /// </summary>
 570    /// <param name="ownerGrid">The active grid that owns this voxel.</param>
 571    /// <param name="results">Caller-owned storage cleared and filled with direction-labeled neighbors.</param>
 572    public void GetRectangularNeighborsInto(
 573        VoxelGrid ownerGrid,
 574        SwiftList<(RectangularDirection Direction, Voxel Voxel)> results)
 575    {
 9576        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 577
 9578        results.Clear();
 9579        if (!IsValidOwnerGrid(ownerGrid))
 1580            return;
 581
 8582        VoxelNeighborResolver.AddRectangularNeighbors(this, ownerGrid, results);
 8583    }
 584
 585    /// <summary>
 586    /// Clears and fills caller-owned storage with hex-prism neighbors in deterministic direction order.
 587    /// </summary>
 588    /// <param name="ownerGrid">The active grid that owns this voxel.</param>
 589    /// <param name="results">Caller-owned storage cleared and filled with direction-labeled neighbors.</param>
 590    public void GetHexNeighborsInto(
 591        VoxelGrid ownerGrid,
 592        SwiftList<(HexDirection Direction, Voxel Voxel)> results)
 593    {
 4594        SwiftThrowHelper.ThrowIfNull(results, nameof(results));
 595
 4596        results.Clear();
 4597        if (!IsValidOwnerGrid(ownerGrid))
 1598            return;
 599
 3600        VoxelNeighborResolver.AddHexNeighbors(this, ownerGrid, results);
 3601    }
 602
 603    private bool IsValidOwnerGrid(VoxelGrid? ownerGrid)
 604    {
 127605        return ownerGrid != null
 127606            && ownerGrid.IsActive
 127607            && ownerGrid.GridIndex == WorldIndex.GridIndex
 127608            && ownerGrid.SpawnToken == WorldIndex.GridSpawnToken
 127609            && ownerGrid.World != null
 127610            && ownerGrid.World.SpawnToken == WorldIndex.WorldSpawnToken;
 611    }
 612
 613    #endregion
 614
 615    #region Utility
 616
 617    /// <inheritdoc/>
 97453618    public override int GetHashCode() => RuntimeHelpers.GetHashCode(this);
 619
 620    /// <inheritdoc/>
 1621    public override string ToString() => WorldIndex.ToString();
 622
 623    /// <inheritdoc/>
 81624    public bool Equals(Voxel? other) => ReferenceEquals(this, other);
 625
 626    /// <inheritdoc/>
 2627    public override bool Equals(object? obj) => ReferenceEquals(this, obj);
 628
 629    #endregion
 630}

Methods/Properties

get_GridIndex()
get_Index()
.ctor()
get_IsPartioned()
get_IsBlocked()
get_IsBlockable()
get_IsOccupied()
get_HasVacancy()
get_HasEventSubscribers()
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)
RemovePartitions()
ReleaseObstacleState(GridForge.Grids.VoxelGrid)
ClearRuntimeState()
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()
GetNeighborsInto(GridForge.Grids.VoxelGrid,SwiftCollections.SwiftList`1<GridForge.Grids.Voxel>,GridForge.Spatial.VoxelNeighborScope,System.Nullable`1<FixedMathSharp.Fixed64>)
HasNeighbor(GridForge.Grids.VoxelGrid,GridForge.Spatial.VoxelNeighborScope,System.Nullable`1<FixedMathSharp.Fixed64>)
TryGetNeighbor(GridForge.Grids.VoxelGrid,GridForge.Spatial.RectangularDirection,GridForge.Grids.Voxel&)
TryGetNeighbor(GridForge.Grids.VoxelGrid,GridForge.Spatial.HexDirection,GridForge.Grids.Voxel&)
GetRectangularNeighborsInto(GridForge.Grids.VoxelGrid,SwiftCollections.SwiftList`1<System.ValueTuple`2<GridForge.Spatial.RectangularDirection,GridForge.Grids.Voxel>>)
GetHexNeighborsInto(GridForge.Grids.VoxelGrid,SwiftCollections.SwiftList`1<System.ValueTuple`2<GridForge.Spatial.HexDirection,GridForge.Grids.Voxel>>)
IsValidOwnerGrid(GridForge.Grids.VoxelGrid)
GetHashCode()
ToString()
Equals(GridForge.Grids.Voxel)
Equals(System.Object)