< Summary

Information
Class: Gravitas.GravitasCollision2DService
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Core/2D/GravitasCollision2DService.cs
Line coverage
100%
Covered lines: 311
Uncovered lines: 0
Coverable lines: 311
Total lines: 614
Line coverage: 100%
Branch coverage
100%
Covered branches: 116
Total branches: 116
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%11100%
get_Context()100%11100%
get_ActivePartitionCount()100%11100%
get_InactivePartitionCount()100%11100%
get_RetainedPartitionCount()100%11100%
Reset()100%11100%
RefreshColliderPartition(...)100%66100%
RefreshColliderPartitionAfterShapeChange(...)100%22100%
PartitionCollider(...)100%11100%
PartitionCollider(...)100%11100%
PartitionCollider(...)100%66100%
ClearPartitionedCollider(...)100%1414100%
RefreshPartitionAwakeState(...)100%1414100%
CheckAndDistributeCollisions()100%44100%
CollectBoundsCandidates(...)100%2222100%
IsDuplicateQueryCandidate(...)100%66100%
RefreshDeferredColliderPartitions()100%88100%
CollectCoveredPartitions(...)100%11100%
PartitionCoveredVoxels(...)100%11100%
ScanCoveredQueryPartitions(...)100%11100%
ScanCoveredColliderVoxels(...)100%11100%
VisitPlanarVoxelsForQuery(...)100%88100%
VisitPlanarVoxelsForCollider(...)100%22100%
TryPartitionVoxel(...)100%44100%
GetPlanarCoverageBounds(...)100%11100%
GetMobilityKind(...)100%44100%
GetStoredMobilityKind(...)100%44100%
AddObject(...)100%44100%
RemoveObject(...)100%44100%
DetachRetainedPartitions()100%11100%
TrackRetainedPartition(...)100%11100%
UntrackRetainedPartition(...)100%11100%
RetireExpiredRetainedPartitions()100%11100%
ActivatePartition(...)100%11100%
DeactivatePartition(...)100%11100%
RentPartition()100%44100%
TryRetireEmptyRetainedPartitionForReuse()100%11100%
ReleasePartition(...)100%11100%
Compare(...)100%11100%
Compare(...)100%11100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Core/2D/GravitasCollision2DService.cs

#LineLine coverage
 1//=======================================================================
 2// GravitasCollision2DService.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using Gravitas.Colliders;
 10using Gravitas.Support;
 11using GridForge.Grids;
 12using GridForge.Spatial;
 13using GridForge.Utility;
 14using SwiftCollections;
 15using System;
 16using System.Collections.Generic;
 17using System.Runtime.CompilerServices;
 18
 19namespace Gravitas;
 20
 21/// <summary>
 22/// Owns GridForge-backed pure 2D collision partitioning state for one context.
 23/// </summary>
 24public sealed class GravitasCollision2DService
 25{
 26    private const int DefaultPartitionPoolCapacity = 1024;
 127    private static readonly PhysicsPartition2DOrderComparer PartitionOrderComparer = new();
 128    private static readonly Collider2DIdComparer ColliderIdComparer = new();
 29
 30    private readonly GravitasWorldContext _context;
 508331    private readonly SwiftBucket<PhysicsPartition2D> _activePartitions = new(DefaultPartitionPoolCapacity);
 508332    private readonly SwiftStack<PhysicsPartition2D> _inactivePartitionPool = new(DefaultPartitionPoolCapacity);
 508333    private readonly SwiftList<Voxel> _coveredVoxels = new();
 508334    private readonly GridTraceScratch _traceScratch = new();
 508335    private readonly SwiftList<PhysicsPartition2D> _retainedPartitions = new();
 508336    private readonly SwiftList<PhysicsPartition2D> _distributionPartitions = new();
 508337    private readonly SwiftList<int> _distributionDynamicIds = new();
 508338    private readonly SwiftList<int> _distributionStaticIds = new();
 508339    private readonly SwiftList<PhysicsPartition2D> _queryPartitions = new();
 508340    private readonly SwiftList<int> _queryColliderIds = new();
 41    private readonly Action<PhysicsPartition2D> _releaseRetainedPartition;
 508342    private readonly SwiftSparseSet _deferredPartitionRefreshIds = new();
 43
 44    private int _retainedPartitionRetirementCursor;
 45    private bool _isDistributing;
 46
 47    /// <summary>Creates the pure 2D collision partition service for a world context.</summary>
 508348    public GravitasCollision2DService(GravitasWorldContext context)
 49    {
 508350        SwiftThrowHelper.ThrowIfNull(context, nameof(context));
 508351        _context = context;
 508352        _releaseRetainedPartition = ReleasePartition;
 508353    }
 54
 55    /// <summary>Gets the world context that owns this service.</summary>
 5951456    public GravitasWorldContext Context => _context;
 57
 58    /// <summary>Gets the current partition-distribution pass version.</summary>
 59    public uint Version { get; private set; } = 1;
 60
 61    /// <summary>Gets the number of partitions participating in collision work.</summary>
 1362    public int ActivePartitionCount => _activePartitions.Count;
 63
 64    /// <summary>Gets the number of partitions available for reuse.</summary>
 965    public int InactivePartitionCount => _inactivePartitionPool.Count;
 66
 1867    internal int RetainedPartitionCount => _retainedPartitions.Count;
 68
 69    /// <summary>Clears all context-local 2D partitioning state.</summary>
 70    public void Reset()
 71    {
 3172        DetachRetainedPartitions();
 3173        _activePartitions.Clear();
 3174        _coveredVoxels.FastClear();
 3175        _traceScratch.Clear();
 3176        _distributionPartitions.FastClear();
 3177        _distributionDynamicIds.FastClear();
 3178        _distributionStaticIds.FastClear();
 3179        _queryPartitions.FastClear();
 3180        _queryColliderIds.FastClear();
 3181        _deferredPartitionRefreshIds.Clear();
 3182        _inactivePartitionPool.Clear();
 3183        Version = 1;
 3184        _retainedPartitionRetirementCursor = 0;
 3185        _isDistributing = false;
 3186    }
 87
 88    internal bool RefreshColliderPartition(LSCollider2D collider)
 89    {
 217390        SwiftThrowHelper.ThrowIfNull(collider, nameof(collider));
 217391        SwiftThrowHelper.ThrowIfArgument(
 217392            !ReferenceEquals(collider.Context, _context),
 217393            nameof(collider),
 217394            "2D collider must belong to this collision service context.");
 95
 217396        if (!collider.IsActive)
 97        {
 198            ClearPartitionedCollider(collider, force: true);
 199            collider.MarkUnpartitioned();
 1100            collider.ClearPartitionCoordinates();
 101
 1102            return false;
 103        }
 104
 2172105        GetPlanarCoverageBounds(collider, out Vector2d coverageMin, out Vector2d coverageMax);
 2172106        PhysicsPartitionMobilityKind kind = GetMobilityKind(collider);
 2172107        if (collider.MatchesPartitionGridBounds(coverageMin, coverageMax, (int)kind))
 291108            return false;
 109
 1881110        if (collider.IsPartitioned)
 1866111            ClearPartitionedCollider(collider, force: true);
 112
 1881113        return PartitionCollider(collider, coverageMin, coverageMax, kind);
 114    }
 115
 116    internal bool RefreshColliderPartitionAfterShapeChange(LSCollider2D collider)
 117    {
 1938118        SwiftThrowHelper.ThrowIfNull(collider, nameof(collider));
 1938119        if (!_isDistributing)
 120        {
 1935121            _deferredPartitionRefreshIds.Remove(collider.Id);
 122
 1935123            return RefreshColliderPartition(collider);
 124        }
 125
 3126        _deferredPartitionRefreshIds.Add(collider.Id);
 127
 3128        return false;
 129    }
 130
 131    internal bool PartitionCollider(LSCollider2D collider)
 132    {
 5164133        GetPlanarCoverageBounds(collider, out Vector2d coverageMin, out Vector2d coverageMax);
 5164134        return PartitionCollider(collider, coverageMin, coverageMax);
 135    }
 136
 137    private bool PartitionCollider(LSCollider2D collider, Vector2d coverageMin, Vector2d coverageMax)
 138    {
 5164139        return PartitionCollider(collider, coverageMin, coverageMax, GetMobilityKind(collider));
 140    }
 141
 142    private bool PartitionCollider(
 143        LSCollider2D collider,
 144        Vector2d coverageMin,
 145        Vector2d coverageMax,
 146        PhysicsPartitionMobilityKind kind)
 147    {
 7045148        SwiftThrowHelper.ThrowIfNull(collider, nameof(collider));
 7045149        SwiftThrowHelper.ThrowIfArgument(
 7045150            !ReferenceEquals(collider.Context, _context),
 7045151            nameof(collider),
 7045152            "2D collider must belong to this collision service context.");
 153
 7045154        if (collider.IsPartitioned || !collider.IsActive)
 2155            return false;
 156
 7043157        SwiftList<WorldVoxelIndex> partitionedCoordinates = collider.GetOrCreatePartitionCoordinates();
 7043158        partitionedCoordinates.FastClear();
 159
 7043160        PartitionCoveredVoxels(collider, coverageMin, coverageMax, partitionedCoordinates, kind);
 7043161        if (partitionedCoordinates.Count == 0)
 298162            return false;
 163
 6745164        collider.MarkPartitioned(coverageMin, coverageMax, (int)kind);
 6745165        return true;
 166    }
 167
 168    internal bool ClearPartitionedCollider(LSCollider2D collider, bool force = false)
 169    {
 2151170        SwiftThrowHelper.ThrowIfNull(collider, nameof(collider));
 2151171        SwiftThrowHelper.ThrowIfArgument(
 2151172            !ReferenceEquals(collider.Context, _context),
 2151173            nameof(collider),
 2151174            "2D collider must belong to this collision service context.");
 175
 2151176        if (!collider.IsPartitioned)
 2177            return false;
 178
 2149179        GetPlanarCoverageBounds(collider, out Vector2d coverageMin, out Vector2d coverageMax);
 2149180        PhysicsPartitionMobilityKind currentKind = GetMobilityKind(collider);
 2149181        if (!force && collider.MatchesPartitionGridBounds(coverageMin, coverageMax, (int)currentKind))
 1182            return false;
 183
 2148184        SwiftList<WorldVoxelIndex> coordinates = collider.PartitionCoordinates!;
 2148185        GridWorld world = _context.World;
 2148186        PhysicsPartitionMobilityKind partitionKind = GetStoredMobilityKind(collider.PartitionKind);
 39006187        for (int i = 0; i < coordinates.Count; i++)
 188        {
 17355189            WorldVoxelIndex coordinate = coordinates[i];
 17355190            if (!world.ActiveGrids.IsAllocated(coordinate.GridIndex)
 17355191                || !world.TryGetVoxel(coordinate, out Voxel? voxel)
 17355192                || !voxel!.TryGetPartition(out PhysicsPartition2D? partition))
 193            {
 194                continue;
 195            }
 196
 17327197            RemoveObject(partition!, collider.Id, partitionKind);
 198        }
 199
 2148200        collider.MarkUnpartitioned();
 2148201        collider.ClearPartitionCoordinates();
 2148202        return true;
 203    }
 204
 205    internal void RefreshPartitionAwakeState(LSCollider2D collider)
 206    {
 365207        SwiftThrowHelper.ThrowIfNull(collider, nameof(collider));
 365208        SwiftThrowHelper.ThrowIfArgument(
 365209            !ReferenceEquals(collider.Context, _context),
 365210            nameof(collider),
 365211            "2D collider must belong to this collision service context.");
 212
 365213        if (!collider.IsPartitioned)
 2214            return;
 215
 363216        SwiftList<WorldVoxelIndex> coordinates = collider.PartitionCoordinates!;
 363217        SolidBody2D? body = collider.Body;
 363218        if (collider.IsStatic || body!.IsKinematic)
 2219            return;
 220
 361221        bool awake = body.IsAwakeForCollision;
 361222        GridWorld world = _context.World;
 223
 5264224        for (int i = 0; i < coordinates.Count; i++)
 225        {
 2271226            WorldVoxelIndex coordinate = coordinates[i];
 2271227            if (!world.ActiveGrids.IsAllocated(coordinate.GridIndex)
 2271228                || !world.TryGetVoxel(coordinate, out Voxel? voxel)
 2271229                || !voxel!.TryGetPartition(out PhysicsPartition2D? partition))
 230            {
 231                continue;
 232            }
 233
 2252234            partition!.SetDynamicObjectAwake(collider.Id, awake);
 235        }
 361236    }
 237
 238    internal void CheckAndDistributeCollisions()
 239    {
 1003240        RefreshDeferredColliderPartitions();
 1003241        Version++;
 242
 1003243        _distributionPartitions.FastClear();
 33080244        foreach (PhysicsPartition2D partition in _activePartitions)
 15537245            _distributionPartitions.Add(partition);
 246
 1003247        _distributionPartitions.SortInPlace(PartitionOrderComparer);
 248
 1003249        _isDistributing = true;
 250        try
 251        {
 33098252            for (int i = 0; i < _distributionPartitions.Count; i++)
 253            {
 15546254                _distributionPartitions[i].Distribute(
 15546255                    _distributionDynamicIds,
 15546256                    _distributionStaticIds);
 257            }
 1003258        }
 259        finally
 260        {
 1003261            _isDistributing = false;
 1003262        }
 1003263    }
 264
 265    internal void CollectBoundsCandidates(
 266        Vector2d min,
 267        Vector2d max,
 268        PhysicsLayerMask layerMask,
 269        uint queryVersion,
 270        bool raycastQuery,
 271        SwiftList<LSCollider2D> candidates,
 272        bool staticStyleOnly = false)
 273    {
 8794274        RefreshDeferredColliderPartitions();
 8794275        candidates.FastClear();
 276
 8794277        CollectCoveredPartitions(min, max, _queryPartitions);
 8794278        _queryPartitions.SortInPlace(PartitionOrderComparer);
 279
 358236280        for (int i = 0; i < _queryPartitions.Count; i++)
 281        {
 170324282            PhysicsPartition2D partition = _queryPartitions[i];
 170324283            if (staticStyleOnly)
 49902284                partition.CopyStaticStyleColliderIds(_queryColliderIds);
 285            else
 120422286                partition.CopyAllColliderIds(_queryColliderIds);
 287
 1044060288            for (int j = 0; j < _queryColliderIds.Count; j++)
 289            {
 351706290                int colliderId = _queryColliderIds[j];
 351706291                if (!_context.Physics2D.TryGetColliderById(colliderId, out LSCollider2D? collider)
 351706292                    || !collider!.IsActive
 351706293                    || IsDuplicateQueryCandidate(collider, queryVersion, raycastQuery)
 351706294                    || !layerMask.Includes(collider.Layer)
 351706295                    || collider.MaxX < min.X
 351706296                    || collider.MinX > max.X
 351706297                    || collider.MaxY < min.Y
 351706298                    || collider.MinY > max.Y)
 299                {
 300                    continue;
 301                }
 302
 44194303                candidates.Add(collider);
 304            }
 305        }
 306
 8794307        candidates.SortInPlace(ColliderIdComparer);
 8794308    }
 309
 310    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 311    private static bool IsDuplicateQueryCandidate(LSCollider2D collider, uint queryVersion, bool raycastQuery)
 312    {
 351688313        if (raycastQuery)
 314        {
 153067315            if (collider.RaycastVersion == queryVersion)
 116204316                return true;
 317
 36863318            collider.RaycastVersion = queryVersion;
 36863319            return false;
 320        }
 321
 198621322        if (collider.CircleQueryVersion == queryVersion)
 173426323            return true;
 324
 25195325        collider.CircleQueryVersion = queryVersion;
 25195326        return false;
 327    }
 328
 329    private void RefreshDeferredColliderPartitions()
 330    {
 9797331        if (_deferredPartitionRefreshIds.Count == 0)
 9795332            return;
 333
 10334        for (int i = 0; i < _deferredPartitionRefreshIds.Count; i++)
 335        {
 3336            int colliderId = _deferredPartitionRefreshIds.DenseKeys[i];
 3337            if (_context.Physics2D.TryGetColliderById(colliderId, out LSCollider2D? collider) && collider!.IsActive)
 1338                RefreshColliderPartition(collider);
 339        }
 340
 2341        _deferredPartitionRefreshIds.Clear();
 2342    }
 343
 344    private void CollectCoveredPartitions(
 345        Vector2d min,
 346        Vector2d max,
 347        SwiftList<PhysicsPartition2D> partitions)
 348    {
 8794349        partitions.FastClear();
 8794350        ScanCoveredQueryPartitions(min, max, min, max, partitions);
 8794351    }
 352
 353    private void PartitionCoveredVoxels(
 354        LSCollider2D collider,
 355        Vector2d coverageMin,
 356        Vector2d coverageMax,
 357        SwiftList<WorldVoxelIndex> partitionedCoordinates,
 358        PhysicsPartitionMobilityKind kind)
 359    {
 7043360        ScanCoveredColliderVoxels(collider, coverageMin, coverageMax, partitionedCoordinates, kind);
 7043361    }
 362
 363    private void ScanCoveredQueryPartitions(
 364        Vector2d coverageMin,
 365        Vector2d coverageMax,
 366        Vector2d queryMin,
 367        Vector2d queryMax,
 368        SwiftList<PhysicsPartition2D> partitions)
 369    {
 8794370        GridWorld world = _context.World;
 8794371        GridTracer.GetCoveredVoxelsInto(
 8794372            world,
 8794373            coverageMin,
 8794374            coverageMax,
 8794375            _coveredVoxels,
 8794376            _traceScratch,
 8794377            layerY: Fixed64.Zero);
 378
 8794379        VisitPlanarVoxelsForQuery(world, queryMin, queryMax, partitions);
 8794380    }
 381
 382    private void ScanCoveredColliderVoxels(
 383        LSCollider2D collider,
 384        Vector2d coverageMin,
 385        Vector2d coverageMax,
 386        SwiftList<WorldVoxelIndex> partitionedCoordinates,
 387        PhysicsPartitionMobilityKind kind)
 388    {
 7043389        GridWorld world = _context.World;
 7043390        GridTracer.GetCoveredVoxelsInto(
 7043391            world,
 7043392            coverageMin,
 7043393            coverageMax,
 7043394            _coveredVoxels,
 7043395            _traceScratch,
 7043396            layerY: Fixed64.Zero);
 397
 7043398        VisitPlanarVoxelsForCollider(world, collider, partitionedCoordinates, kind);
 7043399    }
 400
 401    private void VisitPlanarVoxelsForQuery(
 402        GridWorld world,
 403        Vector2d queryMin,
 404        Vector2d queryMax,
 405        SwiftList<PhysicsPartition2D> partitions)
 406    {
 8794407        var traversal = new GridTraversalState(world, GridTraversalPaddingMode.PlanarMaxCellEdge);
 909754408        for (int i = 0; i < _coveredVoxels.Count; i++)
 409        {
 446083410            Voxel voxel = _coveredVoxels[i];
 411
 446083412            Fixed64 cellEdge = traversal.GetCellEdge(voxel);
 446083413            if (!GridTraversal.IsPlanarPositionInPaddedBounds(queryMin, queryMax, cellEdge, voxel.WorldPosition)
 446083414                || !voxel.TryGetPartition(out PhysicsPartition2D? partition)
 446083415                || partition!.IsEmpty)
 416            {
 417                continue;
 418            }
 419
 170324420            partitions.Add(partition);
 421        }
 8794422    }
 423
 424    private void VisitPlanarVoxelsForCollider(
 425        GridWorld world,
 426        LSCollider2D collider,
 427        SwiftList<WorldVoxelIndex> partitionedCoordinates,
 428        PhysicsPartitionMobilityKind kind)
 429    {
 7043430        var traversal = new GridTraversalState(world, GridTraversalPaddingMode.PlanarMaxCellEdge);
 178872431        for (int i = 0; i < _coveredVoxels.Count; i++)
 82393432            TryPartitionVoxel(collider, partitionedCoordinates, _coveredVoxels[i], ref traversal, kind);
 7043433    }
 434
 435    private void TryPartitionVoxel(
 436        LSCollider2D collider,
 437        SwiftList<WorldVoxelIndex> partitionedCoordinates,
 438        Voxel voxel,
 439        ref GridTraversalState traversal,
 440        PhysicsPartitionMobilityKind kind)
 441    {
 82393442        Fixed64 cellEdge = traversal.GetCellEdge(voxel);
 82393443        if (!collider.IsPositionInPlanarBounds(cellEdge, voxel.WorldPosition))
 15776444            return;
 445
 66617446        if (!voxel.TryGetPartition(out PhysicsPartition2D? partition))
 447        {
 50458448            partition = RentPartition();
 50458449            SwiftThrowHelper.ThrowIfTrue(
 50458450                !voxel.TryAddPartition(partition),
 50458451                nameof(GravitasCollision2DService),
 50458452                "Unable to attach 2D physics partition to voxel.");
 453
 50458454            TrackRetainedPartition(partition);
 455        }
 456
 66617457        partitionedCoordinates.Add(voxel.WorldIndex);
 66617458        AddObject(partition!, collider.Id, kind);
 66617459    }
 460
 461    private void GetPlanarCoverageBounds(LSCollider2D collider, out Vector2d coverageMin, out Vector2d coverageMax)
 462    {
 9485463        coverageMin = new Vector2d(collider.MinX, collider.MinY);
 9485464        coverageMax = new Vector2d(collider.MaxX, collider.MaxY);
 9485465    }
 466
 467    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 468    private static PhysicsPartitionMobilityKind GetMobilityKind(LSCollider2D collider)
 469    {
 9485470        if (collider.IsStatic)
 2126471            return PhysicsPartitionMobilityKind.Static;
 472
 7359473        SolidBody2D? body = collider.Body;
 7359474        return body!.IsKinematic ? PhysicsPartitionMobilityKind.Kinematic : PhysicsPartitionMobilityKind.Dynamic;
 475    }
 476
 477    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 478    private static PhysicsPartitionMobilityKind GetStoredMobilityKind(int partitionKind)
 479    {
 2148480        return partitionKind == (int)PhysicsPartitionMobilityKind.Kinematic
 2148481            ? PhysicsPartitionMobilityKind.Kinematic
 2148482            : partitionKind == (int)PhysicsPartitionMobilityKind.Static
 2148483                ? PhysicsPartitionMobilityKind.Static
 2148484                : PhysicsPartitionMobilityKind.Dynamic;
 485    }
 486
 487    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 488    private static void AddObject(PhysicsPartition2D partition, int id, PhysicsPartitionMobilityKind kind)
 489    {
 66617490        if (kind == PhysicsPartitionMobilityKind.Static)
 491        {
 22182492            partition.AddStaticObject(id);
 22182493            return;
 494        }
 495
 44435496        if (kind == PhysicsPartitionMobilityKind.Kinematic)
 497        {
 3805498            partition.AddKinematicObject(id);
 3805499            return;
 500        }
 501
 40630502        partition.AddDynamicObject(id);
 40630503    }
 504
 505    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 506    private static void RemoveObject(PhysicsPartition2D partition, int id, PhysicsPartitionMobilityKind kind)
 507    {
 17327508        if (kind == PhysicsPartitionMobilityKind.Static)
 509        {
 1792510            partition.RemoveStaticObject(id);
 1792511            return;
 512        }
 513
 15535514        if (kind == PhysicsPartitionMobilityKind.Kinematic)
 515        {
 2088516            partition.RemoveKinematicObject(id);
 2088517            return;
 518        }
 519
 13447520        partition.RemoveDynamicObject(id);
 13447521    }
 522
 31523    private void DetachRetainedPartitions() => RetainedPartitionLifecycle.DetachAll(
 31524        _retainedPartitions,
 31525        _context.World,
 31526        this,
 31527        _releaseRetainedPartition,
 31528        nameof(PhysicsPartition2D),
 31529        "Unable to detach retained 2D physics partition from its voxel during reset.");
 530
 50458531    private void TrackRetainedPartition(PhysicsPartition2D partition) => RetainedPartitionLifecycle.Track(
 50458532        _retainedPartitions,
 50458533        this,
 50458534        partition,
 50458535        nameof(PhysicsPartition2D));
 536
 50463537    private void UntrackRetainedPartition(PhysicsPartition2D partition) => RetainedPartitionLifecycle.Untrack(
 50463538        _retainedPartitions,
 50463539        this,
 50463540        partition,
 50463541        ref _retainedPartitionRetirementCursor);
 542
 1003543    internal void RetireExpiredRetainedPartitions() => RetainedPartitionLifecycle.RetireExpired(
 1003544            _retainedPartitions,
 1003545            _context.World,
 1003546            this,
 1003547            _context.Settings.RetainedPartitionRetirementSweepBudget,
 1003548            _context.FrameCount,
 1003549            _context.Settings.RetainedPartitionTimeToKillFrames,
 1003550            _releaseRetainedPartition,
 1003551            ref _retainedPartitionRetirementCursor);
 552
 553    internal int ActivatePartition(PhysicsPartition2D partition)
 554    {
 36445555        SwiftThrowHelper.ThrowIfNull(partition, nameof(partition));
 36445556        SwiftThrowHelper.ThrowIfArgument(
 36445557            !ReferenceEquals(partition.Owner, this),
 36445558            nameof(partition),
 36445559            "2D partition must belong to this collision service.");
 560
 36445561        return _activePartitions.Add(partition);
 562    }
 563
 564    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 36444565    internal void DeactivatePartition(int activationId) => _activePartitions.TryRemoveAt(activationId);
 566
 567    internal PhysicsPartition2D RentPartition()
 568    {
 50465569        if (_inactivePartitionPool.Count == 0)
 50446570            TryRetireEmptyRetainedPartitionForReuse();
 571
 50465572        PhysicsPartition2D partition = _inactivePartitionPool.Count > 0
 50465573            ? _inactivePartitionPool.Pop()
 50465574            : new PhysicsPartition2D();
 50465575        partition.SetOwner(this);
 50465576        return partition;
 577    }
 578
 579    private bool TryRetireEmptyRetainedPartitionForReuse()
 580    {
 50446581        return RetainedPartitionLifecycle.TryRetireEmptyForReuse(
 50446582            _retainedPartitions,
 50446583            _inactivePartitionPool,
 50446584            _context.World,
 50446585            this,
 50446586            _releaseRetainedPartition,
 50446587            ref _retainedPartitionRetirementCursor);
 588    }
 589
 590    internal void ReleasePartition(PhysicsPartition2D partition)
 591    {
 50463592        SwiftThrowHelper.ThrowIfNull(partition, nameof(partition));
 50463593        SwiftThrowHelper.ThrowIfArgument(
 50463594            !ReferenceEquals(partition.Owner, this),
 50463595            nameof(partition),
 50463596            "2D partition must be released through its owning collision service.");
 597
 50463598        UntrackRetainedPartition(partition);
 50463599        partition.ResetForPool();
 50463600        _inactivePartitionPool.Push(partition);
 50463601    }
 602
 603    private sealed class PhysicsPartition2DOrderComparer : IComparer<PhysicsPartition2D>
 604    {
 605        public int Compare(PhysicsPartition2D? left, PhysicsPartition2D? right) =>
 468722606            WorldVoxelIndexOrdering.ComparePlanar(left!.WorldIndex, right!.WorldIndex);
 607    }
 608
 609    private sealed class Collider2DIdComparer : IComparer<LSCollider2D>
 610    {
 611        public int Compare(LSCollider2D? left, LSCollider2D? right) =>
 77385612            left!.Id.CompareTo(right!.Id);
 613    }
 614}

Methods/Properties

.cctor()
.ctor(Gravitas.GravitasWorldContext)
get_Context()
get_ActivePartitionCount()
get_InactivePartitionCount()
get_RetainedPartitionCount()
Reset()
RefreshColliderPartition(Gravitas.Colliders.LSCollider2D)
RefreshColliderPartitionAfterShapeChange(Gravitas.Colliders.LSCollider2D)
PartitionCollider(Gravitas.Colliders.LSCollider2D)
PartitionCollider(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
PartitionCollider(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,Gravitas.PhysicsPartitionMobilityKind)
ClearPartitionedCollider(Gravitas.Colliders.LSCollider2D,System.Boolean)
RefreshPartitionAwakeState(Gravitas.Colliders.LSCollider2D)
CheckAndDistributeCollisions()
CollectBoundsCandidates(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,Gravitas.Support.PhysicsLayerMask,System.UInt32,System.Boolean,SwiftCollections.SwiftList`1<Gravitas.Colliders.LSCollider2D>,System.Boolean)
IsDuplicateQueryCandidate(Gravitas.Colliders.LSCollider2D,System.UInt32,System.Boolean)
RefreshDeferredColliderPartitions()
CollectCoveredPartitions(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,SwiftCollections.SwiftList`1<Gravitas.PhysicsPartition2D>)
PartitionCoveredVoxels(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,SwiftCollections.SwiftList`1<GridForge.Spatial.WorldVoxelIndex>,Gravitas.PhysicsPartitionMobilityKind)
ScanCoveredQueryPartitions(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,SwiftCollections.SwiftList`1<Gravitas.PhysicsPartition2D>)
ScanCoveredColliderVoxels(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,SwiftCollections.SwiftList`1<GridForge.Spatial.WorldVoxelIndex>,Gravitas.PhysicsPartitionMobilityKind)
VisitPlanarVoxelsForQuery(GridForge.Grids.GridWorld,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,SwiftCollections.SwiftList`1<Gravitas.PhysicsPartition2D>)
VisitPlanarVoxelsForCollider(GridForge.Grids.GridWorld,Gravitas.Colliders.LSCollider2D,SwiftCollections.SwiftList`1<GridForge.Spatial.WorldVoxelIndex>,Gravitas.PhysicsPartitionMobilityKind)
TryPartitionVoxel(Gravitas.Colliders.LSCollider2D,SwiftCollections.SwiftList`1<GridForge.Spatial.WorldVoxelIndex>,GridForge.Grids.Voxel,GridForge.Utility.GridTraversalState&,Gravitas.PhysicsPartitionMobilityKind)
GetPlanarCoverageBounds(Gravitas.Colliders.LSCollider2D,FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
GetMobilityKind(Gravitas.Colliders.LSCollider2D)
GetStoredMobilityKind(System.Int32)
AddObject(Gravitas.PhysicsPartition2D,System.Int32,Gravitas.PhysicsPartitionMobilityKind)
RemoveObject(Gravitas.PhysicsPartition2D,System.Int32,Gravitas.PhysicsPartitionMobilityKind)
DetachRetainedPartitions()
TrackRetainedPartition(Gravitas.PhysicsPartition2D)
UntrackRetainedPartition(Gravitas.PhysicsPartition2D)
RetireExpiredRetainedPartitions()
ActivatePartition(Gravitas.PhysicsPartition2D)
DeactivatePartition(System.Int32)
RentPartition()
TryRetireEmptyRetainedPartitionForReuse()
ReleasePartition(Gravitas.PhysicsPartition2D)
Compare(Gravitas.PhysicsPartition2D,Gravitas.PhysicsPartition2D)
Compare(Gravitas.Colliders.LSCollider2D,Gravitas.Colliders.LSCollider2D)