< Summary

Line coverage
100%
Covered lines: 1101
Uncovered lines: 0
Coverable lines: 1101
Total lines: 2210
Line coverage: 100%
Branch coverage
100%
Covered branches: 368
Total branches: 368
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: .ctor()100%11100%
File 1: get_Id()100%11100%
File 1: get_ReplayOrdinal()100%11100%
File 1: get_LifetimeVersion()100%11100%
File 1: get_ServiceRefreshIndex()100%11100%
File 1: get_IsPartitioned()100%11100%
File 1: get_PartitionCoordinates()100%11100%
File 1: get_PartitionKind()100%11100%
File 1: get_IsMixedPartitioned()100%11100%
File 1: get_MixedPartitionCoordinates()100%11100%
File 1: get_MixedPartitionKind()100%11100%
File 1: get_BroadPhaseVersion()100%11100%
File 1: get_RuntimeShapeVersion()100%11100%
File 1: get_HasHostBinding()100%11100%
File 1: get_CollisionPairCount()100%11100%
File 1: get_CollisionPairHolderCount()100%11100%
File 1: get_CollisionPairs()100%11100%
File 1: get_CollisionPairHolders()100%11100%
File 1: get_Body()100%11100%
File 1: get_IsStatic()100%22100%
File 1: get_RequiresServiceSideRefresh()100%22100%
File 1: get_Agent()100%11100%
File 1: get_AgentOrNull()100%11100%
File 1: get_Context()100%11100%
File 1: get_IsActive()100%11100%
File 1: set_IsActive(...)100%1212100%
File 1: get_IsTrigger()100%11100%
File 1: set_IsTrigger(...)100%11100%
File 1: get_Layer()100%11100%
File 1: set_Layer(...)100%11100%
File 1: get_IgnoredCollisionLayers()100%11100%
File 1: set_IgnoredCollisionLayers(...)100%44100%
File 1: get_Material()100%11100%
File 1: set_Material(...)100%44100%
File 1: get_Priority()100%11100%
File 1: get_RaycastVersion()100%11100%
File 1: set_RaycastVersion(...)100%11100%
File 1: get_CircleQueryVersion()100%11100%
File 1: set_CircleQueryVersion(...)100%11100%
File 1: get_IsChild()100%11100%
File 1: get_IsParent()100%11100%
File 1: get_ParentId()100%11100%
File 1: get_Parent2D()100%11100%
File 1: get_Parent3D()100%11100%
File 1: get_TopParent2D()100%11100%
File 1: get_TopParent3D()100%11100%
File 1: get_HierarchyChildCount()100%11100%
File 1: get_HierarchyKey()100%22100%
File 1: get_ParentKey()100%11100%
File 1: get_TopParentKey()100%11100%
File 1: get_HierarchyState()100%11100%
File 1: Gravitas.Colliders.IColliderHierarchyNode.get_HierarchyKey()100%11100%
File 1: Gravitas.Colliders.IColliderHierarchyNode.get_HierarchyParent()100%11100%
File 1: get_LocalOffset()100%11100%
File 1: set_LocalOffset(...)100%22100%
File 1: get_Bounds()100%11100%
File 1: get_MixedBounds3D()100%11100%
File 1: get_MixedHalfThickness()100%11100%
File 1: get_MixedSlabCenterY()100%11100%
File 1: get_MixedHalfThicknessOverride()100%11100%
File 1: set_MixedHalfThicknessOverride(...)100%88100%
File 1: get_MinX()100%11100%
File 1: get_MaxX()100%11100%
File 1: get_MinY()100%11100%
File 1: get_MaxY()100%11100%
File 1: Initialize(...)100%11100%
File 1: InitializeWithNoBody(...)100%44100%
File 1: PreflightBodyInitialization(...)100%11100%
File 1: PreflightInitialization(...)100%11100%
File 1: InitCore(...)100%11100%
File 1: OnBeforeInitialize(...)100%11100%
File 1: SetPhysicsState(...)100%11100%
File 1: SetServiceIndex(...)100%11100%
File 1: SetReplayOrdinal(...)100%11100%
File 1: SetServiceRefreshIndex(...)100%11100%
File 1: ClearServiceRefreshIndex()100%11100%
File 1: ClearPhysicsState()100%11100%
File 1: Gravitas.Colliders.IPhysicsColliderRegistryItem.SetRegistryState(...)100%11100%
File 1: Gravitas.Colliders.IPhysicsColliderRegistryItem.get_ServiceIndex()100%11100%
File 1: Gravitas.Colliders.IPhysicsColliderRegistryItem.get_ReplayOrder()100%11100%
File 1: Gravitas.Colliders.IPhysicsColliderRegistryItem.SetRegistryServiceIndex(...)100%11100%
File 1: Gravitas.Colliders.IPhysicsColliderRegistryItem.SetRegistryReplayOrdinal(...)100%11100%
File 1: Gravitas.Colliders.IPhysicsColliderRegistryItem.ClearRegistryState()100%11100%
File 1: ClearBindingState()100%11100%
File 1: Deactivate()100%44100%
File 1: Simulate()100%22100%
File 1: Rebuild()100%44100%
File 1: RebuildRuntimeShapeOnly()100%11100%
File 1: ValidateCurrentRuntimeTransform()100%11100%
File 1: SetParent(...)100%11100%
File 1: SetParent(...)100%11100%
File 1: ClearParent()100%11100%
File 1: IsSibling(...)100%11100%
File 1: ExcludesMixedCollisionWith(...)100%11100%
File 1: GetOrCreatePartitionCoordinates()100%22100%
File 1: GetOrCreateMixedPartitionCoordinates()100%22100%
File 1: MatchesPartitionGridBounds(...)100%11100%
File 1: MatchesMixedPartitionGridBounds(...)100%66100%
File 1: MarkPartitioned(...)100%11100%
File 1: MarkMixedPartitioned(...)100%11100%
File 1: MarkUnpartitioned()100%11100%
File 1: MarkMixedUnpartitioned()100%11100%
File 1: ClearPartitionCoordinates()100%11100%
File 1: ClearMixedPartitionCoordinates()100%11100%
File 1: IsPositionInPlanarBounds(...)100%66100%
File 1: IsPositionInMixedBounds(...)100%1010100%
File 1: TryGetCollisionPair(...)100%11100%
File 1: TryAddCollisionPair(...)100%11100%
File 1: TryRemoveCollisionPair(...)100%11100%
File 1: TryAddCollisionPairHolder(...)100%11100%
File 1: TryRemoveCollisionPairHolder(...)100%11100%
File 1: ClearCollisionPairState()100%11100%
File 1: ClearRuntimeRelationships()100%11100%
File 1: ResolveAgentRotation()100%22100%
File 1: BindContext(...)100%22100%
File 1: ReserveCompoundPart(...)100%22100%
File 1: ThrowIfCompoundPartLifecycle(...)100%11100%
File 1: TransformRelativeMassPropertyPointExact(...)100%22100%
File 1: Rotate(...)100%22100%
File 1: ClampNearZero(...)100%44100%
File 1: SetTrigger(...)100%44100%
File 1: ThrowIfCannotEnableTrigger(...)100%11100%
File 1: ThrowIfTriggerWouldAttachToBody(...)100%11100%
File 1: ThrowIfLoadedTriggerHasBody(...)100%22100%
File 1: RecordData(...)100%22100%
File 1: RecordShapeData(...)100%11100%
File 1: IgnoresCollisionLayer(...)100%11100%
File 1: ApplyLoadedState()100%1212100%
File 2: get_Position()100%22100%
File 2: get_Rotation()100%44100%
File 2: get_LocalScale()100%11100%
File 2: TryGetLocalScale(...)100%22100%
File 2: get_ScaledLocalOffset()100%11100%
File 2: TryGetScaledLocalOffset(...)100%11100%
File 2: get_Center()100%22100%
File 2: get_VertexCount()100%22100%
File 2: get_ConvexRotation()100%11100%
File 2: GetScaledLocalVertexUnchecked(...)100%11100%
File 2: GetConvexSupportAnchor(...)100%11100%
File 2: TryGetClosestBoundaryAnchor(...)100%1010100%
File 2: TryGetClosestBoundaryAnchor(...)100%44100%
File 2: TryGetVertex(...)100%11100%
File 2: GetRoundBoundaryAnchor(...)100%22100%
File 2: TryGetAABoxBoundaryAnchor(...)100%11100%
File 2: TryGetConvexBoundaryAnchor(...)100%11100%
File 2: TryGetCompoundBoundaryAnchor(...)100%22100%
File 2: TryGetCompoundBoundaryAnchor(...)100%1010100%
File 2: TryGetAnchorDistance(...)100%44100%
File 2: CalculateLocalCenterOfMassOffset()100%11100%
File 2: CalculateLocalMassPoint()100%11100%
File 2: CalculatePreparedLocalMassPoint()100%11100%
File 2: CalculateMomentOfInertia(...)100%66100%
File 2: OnMaterialChanged()100%11100%
File 2: TransformPreparedRelativeMassPropertyPointExact(...)100%22100%
File 2: MarkShapeDirty()100%44100%
File 2: RebuildRuntimeShapeState()100%66100%
File 2: ResolveStandalonePosition()100%44100%
File 2: ResolveStandaloneRotation()100%22100%
File 3: ClearChildParentReferences()100%88100%
File 3: Gravitas.Colliders.IColliderHierarchyNode.AddChild(...)100%11100%
File 3: Gravitas.Colliders.IColliderHierarchyNode.RemoveChild(...)100%11100%
File 3: Gravitas.Colliders.IColliderHierarchyNode.ClearParentReference()100%11100%
File 3: Gravitas.Colliders.IColliderHierarchyNode.TryGetHierarchyColliderByKey(...)100%1212100%
File 4: NotifyContact(...)100%22100%
File 4: NotifyContact(...)100%5050100%
File 4: NotifyMixedContact(...)100%11100%
File 4: NotifyMixedContact(...)100%4646100%
File 5: ContributeReplayHash(...)100%44100%
File 5: ContributeShapeReplayHash(...)100%1212100%
File 5: WriteReplayHierarchyKey(...)100%22100%
File 5: TryResolveReplayHierarchyOrdinal(...)100%66100%
File 5: ContributeCompoundPartReplayHash(...)100%22100%
File 5: ContributeShapeDefinitionReplayHash(...)100%44100%
File 5: WriteMaterial(...)100%11100%
File 6: .ctor()100%11100%
File 6: get_HasCommittedShape()100%11100%
File 6: get_PreparedContext()100%11100%
File 6: get_PreparedShapeBounds()100%11100%
File 6: get_CanonicalCenteredProxyRadius()100%11100%
File 6: get_CanonicalGroundProbeRadius()100%11100%
File 6: get_CanonicalCenter()100%11100%
File 6: TryGetCommittedOwnerScale(...)100%22100%
File 6: GetCurrentOwnerScale()100%66100%
File 6: GetCurrentScaleFactors(...)100%44100%
File 6: TryGetCurrentScaledOffset(...)100%22100%
File 6: GetCurrentScaledOffset()100%11100%
File 6: GetUncommittedCenter()100%22100%
File 6: CreateStandaloneSnapshot(...)100%44100%
File 6: CaptureShapeSnapshot()100%88100%
File 6: CreateCompoundPartSnapshot(...)100%11100%
File 6: PrepareRuntimeShape(...)100%66100%
File 6: PublishPreparedShape()100%11100%
File 6: TryPrepareBodyPose(...)100%22100%
File 6: CreateDetachedBodySnapshot(...)100%11100%
File 6: PublishPreparedBodyPose()100%11100%
File 6: PublishPreparedExplicitBodyPose()100%44100%
File 6: PrepareStandaloneInitialization(...)100%11100%
File 6: PrepareCompoundPart(...)100%22100%
File 6: PublishCompoundPart(...)100%11100%
File 6: SetPreparedBounds(...)100%11100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/2D/LSCollider2D.cs

#LineLine coverage
 1//=======================================================================
 2// LSCCollider2D.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 Chronicler;
 9using FixedMathSharp;
 10using FixedMathSharp.Geometry;
 11using Gravitas.Materials;
 12using Gravitas.Support;
 13using GridForge.Spatial;
 14using SwiftCollections;
 15using System.Runtime.CompilerServices;
 16
 17namespace Gravitas.Colliders;
 18
 19internal readonly struct ColliderLifetimeToken2D
 20{
 21    internal ColliderLifetimeToken2D(LSCollider2D collider)
 22    {
 23        Collider = collider;
 24        LifetimeVersion = collider.LifetimeVersion;
 25    }
 26
 27    internal LSCollider2D Collider { get; }
 28
 29    internal long LifetimeVersion { get; }
 30
 31    internal bool IsActive => Collider.IsActive && IsCurrentLifetime;
 32
 33    internal bool IsCurrentLifetime => Collider.LifetimeVersion == LifetimeVersion;
 34}
 35
 36/// <summary>
 37/// Common runtime type for the closed set of Gravitas-owned pure 2D collider
 38/// shapes. Use <see cref="ColliderShapeDefinition2D.CreateCollider"/> when
 39/// constructing from engine-adapter shape data.
 40/// </summary>
 41public abstract partial class LSCollider2D : IRecordable, IColliderHierarchyNode, IPhysicsColliderRegistryItem
 42{
 1100843    internal LSCollider2D() { }
 44
 45    private SolidBody2D? _body;
 46    private IMatterAgent? _agent;
 47    private GravitasWorldContext? _context;
 48    private LSCompoundCollider2D? _compoundOwner;
 49    private Fixed64 _compoundLocalRotation;
 550450    private Vector2d _compoundLocalScale = Vector2d.One;
 550451    private int _id = -1;
 550452    private int _serviceIndex = -1;
 550453    private int _replayOrder = -1;
 550454    private int _replayOrdinal = -1;
 55    private long _lifetimeVersion;
 550456    private int _serviceRefreshIndex = -1;
 550457    private bool _isActive = true;
 58    private bool _isTrigger;
 59    private PhysicsLayer _layer = new();
 550460    private PhysicsLayerMask _ignoredCollisionLayers = PhysicsLayerMask.None;
 550461    private PhysicsMaterial _material = PhysicsMaterial.Default;
 62    private Vector2d _localOffset;
 63    private FixedBoundArea _bounds;
 64    private FixedBoundBox _mixedBounds3D;
 65    private Fixed64? _mixedHalfThicknessOverride;
 66    private Fixed64 _mixedHalfThickness;
 67    private Fixed64 _mixedSlabCenterY;
 68    private uint _shapeVersion;
 550469    private readonly ColliderRuntimeShapeState<ColliderShapeSnapshot2D> _runtimeShapeState = new();
 70    private ColliderPartitionState2D _partitionState;
 71    private ColliderPartitionState _mixedPartitionState;
 72    private ColliderQueryState _queryState;
 73    private ColliderPairState<CollisionPair2D> _pairState;
 74    private ColliderHierarchyState _hierarchyState;
 75
 76    /// <summary>Handles a pure 2D contact notification for the other body.</summary>
 77    public delegate void Body2DCollisionFunc(SolidBody2D other);
 78    /// <summary>Handles a pure 2D trigger notification for the other collider.</summary>
 79    public delegate void Trigger2DCollisionFunc(LSCollider2D other);
 80    /// <summary>Handles a mixed contact or trigger notification for the other 3D collider.</summary>
 81    public delegate void Mixed2DCollisionFunc(LSCollider other);
 82
 83    /// <summary>
 84    /// Raised while this collider is touching another collider that owns a 2D body.
 85    /// </summary>
 86    public event Body2DCollisionFunc? OnContact;
 87
 88    /// <summary>
 89    /// Raised on the first simulation frame this non-trigger collider touches another 2D body.
 90    /// </summary>
 91    public event Body2DCollisionFunc? OnContactEnter;
 92
 93    /// <summary>
 94    /// Raised when this collider stops touching another 2D body.
 95    /// </summary>
 96    public event Body2DCollisionFunc? OnContactExit;
 97
 98    /// <summary>
 99    /// Raised on the first simulation frame this collider participates in a valid trigger pair.
 100    /// </summary>
 101    public event Trigger2DCollisionFunc? OnTriggerEnter;
 102
 103    /// <summary>
 104    /// Raised each simulation frame this collider participates in an overlapped valid trigger pair.
 105    /// </summary>
 106    public event Trigger2DCollisionFunc? OnTriggerStay;
 107
 108    /// <summary>
 109    /// Raised when this collider stops participating in a valid trigger pair.
 110    /// </summary>
 111    public event Trigger2DCollisionFunc? OnTriggerExit;
 112
 113    /// <summary>Raised while this collider has a physical mixed contact with a 3D collider.</summary>
 114    public event Mixed2DCollisionFunc? OnMixedContact;
 115    /// <summary>Raised when this collider begins a physical mixed contact with a 3D collider.</summary>
 116    public event Mixed2DCollisionFunc? OnMixedContactEnter;
 117    /// <summary>Raised when this collider ends a physical mixed contact with a 3D collider.</summary>
 118    public event Mixed2DCollisionFunc? OnMixedContactExit;
 119
 120    /// <summary>
 121    /// Raised on the first mixed 2D/3D simulation frame this collider participates in a valid trigger pair.
 122    /// </summary>
 123    public event Mixed2DCollisionFunc? OnMixedTriggerEnter;
 124
 125    /// <summary>
 126    /// Raised each mixed 2D/3D simulation frame this collider participates in an overlapped valid trigger pair.
 127    /// </summary>
 128    public event Mixed2DCollisionFunc? OnMixedTriggerStay;
 129
 130    /// <summary>
 131    /// Raised when this collider stops participating in a valid mixed 2D/3D trigger pair.
 132    /// </summary>
 133    public event Mixed2DCollisionFunc? OnMixedTriggerExit;
 134
 135    /// <summary>Gets the context-local runtime collider identifier.</summary>
 402003136    public int Id => _id;
 137
 862138    internal int ReplayOrdinal => _replayOrdinal;
 139
 19320140    internal long LifetimeVersion => _lifetimeVersion;
 141
 3620142    internal int ServiceRefreshIndex => _serviceRefreshIndex;
 143
 12156144    internal bool IsPartitioned => _partitionState.IsPartitioned;
 145
 8462146    internal SwiftList<WorldVoxelIndex>? PartitionCoordinates => _partitionState.Coordinates;
 147
 2365148    internal int PartitionKind => _partitionState.LastPartitionKind;
 149
 2075150    internal bool IsMixedPartitioned => _mixedPartitionState.IsPartitioned;
 151
 941152    internal SwiftList<WorldVoxelIndex>? MixedPartitionCoordinates => _mixedPartitionState.Coordinates;
 153
 479154    internal int MixedPartitionKind => _mixedPartitionState.LastPartitionKind;
 155
 307156    internal uint BroadPhaseVersion => _partitionState.BroadPhaseVersion;
 157
 249158    internal uint RuntimeShapeVersion => _runtimeShapeState.RuntimeVersion;
 159
 5452160    internal bool HasHostBinding => _agent != null;
 161
 221162    internal int CollisionPairCount => _pairState.CollisionPairCount;
 163
 233164    internal int CollisionPairHolderCount => _pairState.CollisionPairHolderCount;
 165
 814166    internal SwiftDictionary<int, CollisionPair2D>? CollisionPairs => _pairState.CollisionPairs;
 167
 814168    internal SwiftHashSet<int>? CollisionPairHolders => _pairState.CollisionPairHolders;
 169
 170    /// <summary>Gets the owning 2D body, or <see langword="null"/> for a bodyless collider.</summary>
 129395171    public SolidBody2D? Body => _body;
 172
 173    /// <summary>
 174    /// Gets whether this collider is bodyless or belongs to an explicit static
 175    /// body role.
 176    /// </summary>
 14094177    public bool IsStatic => _body == null || _body.IsStatic;
 178
 5240179    internal bool RequiresServiceSideRefresh => _body == null || _body.DynamicId < 0;
 180
 181    /// <summary>Gets the host agent to which this collider is bound.</summary>
 182    public IMatterAgent Agent
 183    {
 184        get
 185        {
 4186            SwiftThrowHelper.ThrowIfTrue(
 4187                _agent == null,
 4188                nameof(LSCollider2D),
 4189                "2D collider is not bound to an IMatterAgent.");
 3190            return _agent!;
 191        }
 192    }
 193
 25328194    internal IMatterAgent? AgentOrNull => _agent;
 195
 196    /// <summary>Gets the world context to which this collider is bound.</summary>
 197    public GravitasWorldContext Context
 198    {
 199        get
 200        {
 19713201            SwiftThrowHelper.ThrowIfTrue(
 19713202                _context == null,
 19713203                nameof(LSCollider2D),
 19713204                "2D collider is not bound to a GravitasWorldContext.");
 19712205            return _context!;
 206        }
 207    }
 208
 209    /// <summary>Gets or sets whether this collider participates in runtime physics.</summary>
 210    public bool IsActive
 211    {
 212        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 403196213        get => _isActive;
 214        set
 215        {
 138216            ThrowIfCompoundPartLifecycle(nameof(IsActive));
 217
 138218            if (_isActive == value)
 4219                return;
 220
 134221            if (_context == null || _id < 0)
 222            {
 123223                _isActive = value;
 123224                return;
 225            }
 226
 11227            if (value)
 228            {
 2229                RebuildRuntimeShapeState();
 2230                _isActive = true;
 2231                _context.Collisions2D.RefreshColliderPartition(this);
 2232                if (_context.Settings.RuntimeMode.RunsMixedContacts())
 1233                    _context.MixedCollisions.Refresh2DColliderPartition(this);
 234            }
 235            else
 236            {
 9237                _isActive = false;
 9238                _context.Collisions2D.ClearPartitionedCollider(this, force: true);
 9239                if (IsMixedPartitioned)
 2240                    _context.MixedCollisions.ClearPartitioned2DCollider(this, force: true);
 241            }
 10242        }
 243    }
 244
 245    /// <summary>
 246    /// Gets or sets whether this bodyless collider is a trigger volume.
 247    /// Trigger volumes raise trigger enter/stay/exit callbacks for valid overlap
 248    /// pairs and never apply physical response.
 249    /// </summary>
 250    public bool IsTrigger
 251    {
 252        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 10846253        get => _isTrigger;
 70254        set => SetTrigger(value);
 255    }
 256
 257    /// <summary>
 258    /// Gets or sets the single physics layer used by 2D collision matrix and query-mask filtering.
 259    /// </summary>
 260    public PhysicsLayer Layer
 261    {
 262        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 111651263        get => _layer;
 264        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 726265        set => _layer = value;
 266    }
 267
 268    /// <summary>
 269    /// Gets or sets physical layers this collider ignores for collider-to-collider
 270    /// interactions. Public queries continue to use the caller's query mask.
 271    /// </summary>
 272    public PhysicsLayerMask IgnoredCollisionLayers
 273    {
 274        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 9275        get => _ignoredCollisionLayers;
 276        set
 277        {
 26278            if (_ignoredCollisionLayers == value)
 1279                return;
 280
 25281            _ignoredCollisionLayers = value;
 25282            _body?.Wake();
 22283        }
 284    }
 285
 286    /// <summary>
 287    /// Gets or sets the deterministic surface material used by pure 2D and
 288    /// mixed collision response for this collider.
 289    /// </summary>
 290    public PhysicsMaterial Material
 291    {
 292        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2356293        get => _material;
 294        set
 295        {
 908296            if (_material == value)
 498297                return;
 298
 410299            _material = value;
 410300            OnMaterialChanged();
 410301            _body?.Wake();
 133302        }
 303    }
 304
 305    /// <summary>Gets the runtime pure 2D shape family.</summary>
 306    public abstract ColliderType2D Shape { get; }
 307
 308    /// <summary>Gets the deterministic pure 2D narrow-phase ordering priority.</summary>
 1539309    public virtual int Priority => ColliderSettings2D.GetPriority(Shape);
 310
 311    internal uint RaycastVersion
 312    {
 313        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 153285314        get => _queryState.RaycastVersion;
 315        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 36867316        set => _queryState.RaycastVersion = value;
 317    }
 318
 319    internal uint CircleQueryVersion
 320    {
 321        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 198839322        get => _queryState.CircleQueryVersion;
 323        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 25199324        set => _queryState.CircleQueryVersion = value;
 325    }
 326
 327    /// <summary>Gets whether this collider has a hierarchy parent.</summary>
 2328    public bool IsChild => _hierarchyState.IsChild;
 329
 330    /// <summary>Gets whether this collider is configured as or currently owns a hierarchy parent.</summary>
 2331    public bool IsParent => _hierarchyState.IsParent;
 332
 333    /// <summary>Gets the context-local identifier of the parent collider, or -1 when unparented.</summary>
 5334    public int ParentId => ParentKey.Id;
 335
 336    /// <summary>Gets the 2D parent collider, when the parent belongs to the 2D runtime.</summary>
 5337    public LSCollider2D? Parent2D => _hierarchyState.Parent as LSCollider2D;
 338
 339    /// <summary>Gets the 3D parent collider, when the parent belongs to the 3D runtime.</summary>
 5340    public LSCollider? Parent3D => _hierarchyState.Parent as LSCollider;
 341
 3683342    internal LSCollider2D? TopParent2D => _hierarchyState.TopParent as LSCollider2D;
 343
 2344    internal LSCollider? TopParent3D => _hierarchyState.TopParent as LSCollider;
 345
 787346    internal int HierarchyChildCount => _hierarchyState.ChildCount;
 347
 24597348    internal ColliderHierarchyKey HierarchyKey => Id >= 0 ? ColliderHierarchyKey.Create2D(Id) : ColliderHierarchyKey.Non
 349
 790350    internal ColliderHierarchyKey ParentKey => _hierarchyState.ParentKey;
 351
 783352    internal ColliderHierarchyKey TopParentKey => _hierarchyState.TopParentKey;
 353
 5224354    internal ColliderHierarchyState HierarchyState => _hierarchyState;
 355
 100356    ColliderHierarchyKey IColliderHierarchyNode.HierarchyKey => HierarchyKey;
 357
 27358    IColliderHierarchyNode? IColliderHierarchyNode.HierarchyParent => _hierarchyState.Parent;
 359
 360    /// <summary>Gets or sets the unscaled local center offset.</summary>
 361    public Vector2d LocalOffset
 362    {
 363        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 36433364        get => _localOffset;
 365        set
 366        {
 317367            if (_localOffset == value)
 73368                return;
 369
 244370            _localOffset = value;
 244371            MarkShapeDirty();
 244372        }
 373    }
 374
 375    /// <summary>Gets the committed pure 2D world-space bounds.</summary>
 1690376    public FixedBoundArea Bounds => _bounds;
 377
 20341378    internal FixedBoundBox MixedBounds3D => _mixedBounds3D;
 379
 14672380    internal Fixed64 MixedHalfThickness => _mixedHalfThickness;
 381
 16261382    internal Fixed64 MixedSlabCenterY => _mixedSlabCenterY;
 383
 384    /// <summary>
 385    /// Gets or sets the optional half-thickness used when this 2D collider is embedded into mixed 2D/3D contacts.
 386    /// </summary>
 387    public Fixed64? MixedHalfThicknessOverride
 388    {
 389        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 8390        get => _mixedHalfThicknessOverride;
 391        set
 392        {
 54393            if (value.HasValue)
 394            {
 51395                SwiftThrowHelper.ThrowIfArgument(
 51396                    value.Value <= Fixed64.Zero,
 51397                    nameof(value),
 51398                    "2D mixed half-thickness override must be greater than zero.");
 399            }
 400
 52401            if (_mixedHalfThicknessOverride == value)
 2402                return;
 403
 50404            _mixedHalfThicknessOverride = value;
 50405            MarkShapeDirty();
 50406        }
 407    }
 408
 409    /// <summary>Gets the minimum world X coordinate of <see cref="Bounds"/>.</summary>
 193714410    public Fixed64 MinX => _bounds.Min.X;
 411
 412    /// <summary>Gets the maximum world X coordinate of <see cref="Bounds"/>.</summary>
 191920413    public Fixed64 MaxX => _bounds.Max.X;
 414
 415    /// <summary>Gets the minimum planar Y coordinate of <see cref="Bounds"/>.</summary>
 163019416    public Fixed64 MinY => _bounds.Min.Y;
 417
 418    /// <summary>Gets the maximum planar Y coordinate of <see cref="Bounds"/>.</summary>
 172905419    public Fixed64 MaxY => _bounds.Max.Y;
 420
 421    internal void Initialize(SolidBody2D body)
 422    {
 4653423        InitCore(body.Agent, body);
 4653424    }
 425
 426    /// <summary>Binds and registers this collider as a bodyless pure 2D collider.</summary>
 427    public void InitializeWithNoBody(IMatterAgent agent)
 428    {
 525429        ThrowIfCompoundPartLifecycle(nameof(InitializeWithNoBody));
 525430        SwiftThrowHelper.ThrowIfNull(agent, nameof(agent));
 525431        SwiftThrowHelper.ThrowIfArgument(
 525432            Id >= 0 || (HasHostBinding && !ReferenceEquals(_agent, agent)),
 525433            nameof(agent),
 525434            "2D collider is already registered or bound to another host agent.");
 523435        PreflightInitialization(agent);
 510436        InitCore(agent, null);
 510437        Context.Physics2D.AssimilateCollider(this);
 510438    }
 439
 440    internal void PreflightBodyInitialization(
 441        SolidBody2D body,
 442        Vector2d requestedPosition,
 443        Fixed64 requestedRotation)
 444    {
 4658445        ThrowIfCompoundPartLifecycle(nameof(Initialize));
 4658446        SwiftThrowHelper.ThrowIfNull(body, nameof(body));
 4658447        ThrowIfTriggerWouldAttachToBody(nameof(Initialize));
 4657448        PreflightInitialization(
 4657449            body.Agent,
 4657450            useRequestedPose: true,
 4657451            requestedPosition,
 4657452            requestedRotation);
 4652453    }
 454
 455    private void PreflightInitialization(
 456        IMatterAgent agent,
 457        bool useRequestedPose = false,
 458        Vector2d requestedPosition = default,
 459        Fixed64 requestedRotation = default)
 460    {
 5180461        SwiftThrowHelper.ThrowIfNull(agent, nameof(agent));
 5180462        OnBeforeInitialize(agent);
 5180463        PrepareStandaloneInitialization(
 5180464            agent,
 5180465            useRequestedPose,
 5180466            requestedPosition,
 5180467            requestedRotation);
 5162468    }
 469
 470    private void InitCore(IMatterAgent agent, SolidBody2D? body)
 471    {
 5163472        _lifetimeVersion++;
 5163473        _body = body;
 5163474        _agent = agent;
 5163475        _context = agent.Context;
 5163476        _isActive = true;
 5163477        _queryState.Reset();
 5163478        _hierarchyState.Initialize(agent.IsParent);
 5163479        PublishPreparedShape();
 5163480    }
 481
 482    /// <summary>Validates or prepares derived shape state before runtime registration.</summary>
 5180483    protected virtual void OnBeforeInitialize(IMatterAgent agent) { }
 484
 485    internal void SetPhysicsState(int id, int serviceIndex, int replayOrder)
 486    {
 5162487        SwiftThrowHelper.ThrowIfNegative(id, nameof(id));
 5162488        SwiftThrowHelper.ThrowIfNegative(serviceIndex, nameof(serviceIndex));
 5162489        SwiftThrowHelper.ThrowIfNegative(replayOrder, nameof(replayOrder));
 5162490        _id = id;
 5162491        _serviceIndex = serviceIndex;
 5162492        _replayOrder = replayOrder;
 5162493        _replayOrdinal = -1;
 5162494    }
 495
 496    internal void SetServiceIndex(int serviceIndex)
 497    {
 66498        SwiftThrowHelper.ThrowIfNegative(serviceIndex, nameof(serviceIndex));
 66499        _serviceIndex = serviceIndex;
 66500    }
 501
 502    internal void SetReplayOrdinal(int replayOrdinal)
 503    {
 1728504        SwiftThrowHelper.ThrowIfNegative(replayOrdinal, nameof(replayOrdinal));
 1728505        _replayOrdinal = replayOrdinal;
 1728506    }
 507
 508    internal void SetServiceRefreshIndex(int serviceRefreshIndex)
 509    {
 1896510        SwiftThrowHelper.ThrowIfNegative(serviceRefreshIndex, nameof(serviceRefreshIndex));
 1896511        _serviceRefreshIndex = serviceRefreshIndex;
 1896512    }
 513
 514    internal void ClearServiceRefreshIndex()
 515    {
 3620516        _serviceRefreshIndex = -1;
 3620517    }
 518
 519    internal void ClearPhysicsState()
 520    {
 405521        _partitionState.MarkUnpartitioned();
 405522        _partitionState.ClearCoordinates();
 405523        _mixedPartitionState.MarkUnpartitioned();
 405524        _mixedPartitionState.ClearCoordinates();
 405525        _pairState.ClearCollisionPairs();
 405526        _pairState.ClearCollisionPairHolders();
 405527        _id = -1;
 405528        _serviceIndex = -1;
 405529        _replayOrder = -1;
 405530        _replayOrdinal = -1;
 405531        _serviceRefreshIndex = -1;
 405532    }
 533
 534    void IPhysicsColliderRegistryItem.SetRegistryState(int id, int serviceIndex, int replayOrder) =>
 5162535        SetPhysicsState(id, serviceIndex, replayOrder);
 536
 263537    int IPhysicsColliderRegistryItem.ServiceIndex => _serviceIndex;
 538
 1208539    int IPhysicsColliderRegistryItem.ReplayOrder => _replayOrder;
 540
 541    void IPhysicsColliderRegistryItem.SetRegistryServiceIndex(int serviceIndex) =>
 66542        SetServiceIndex(serviceIndex);
 543
 544    void IPhysicsColliderRegistryItem.SetRegistryReplayOrdinal(int replayOrdinal) =>
 1728545        SetReplayOrdinal(replayOrdinal);
 546
 282547    void IPhysicsColliderRegistryItem.ClearRegistryState() => ClearPhysicsState();
 548
 549    internal void ClearBindingState()
 550    {
 268551        _body = null;
 268552        _agent = null;
 268553        _context = null;
 268554        _preparedContext = null;
 268555    }
 556
 557    /// <summary>Unregisters this collider, or deactivates its owning body.</summary>
 558    public void Deactivate()
 559    {
 189560        ThrowIfCompoundPartLifecycle(nameof(Deactivate));
 561
 189562        if (_body != null)
 563        {
 44564            _body.Deactivate();
 44565            return;
 566        }
 567
 145568        if (_id >= 0)
 141569            _context!.Physics2D.DessimilateCollider(this);
 570
 145571        _isActive = false;
 145572        ClearBindingState();
 145573    }
 574
 575    /// <summary>Refreshes bodyless collider shape and broad-phase state for one simulation step.</summary>
 576    public void Simulate()
 577    {
 3542578        ThrowIfCompoundPartLifecycle(nameof(Simulate));
 579
 3541580        if (!IsActive)
 1581            return;
 582
 3540583        Rebuild();
 3538584    }
 585
 586    internal bool Rebuild()
 587    {
 4813588        if (!RebuildRuntimeShapeState())
 3478589            return false;
 590
 1333591        if (_id >= 0)
 1326592            return _context!.Collisions2D.RefreshColliderPartitionAfterShapeChange(this);
 593
 7594        return true;
 595    }
 596
 597    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 9843598    internal bool RebuildRuntimeShapeOnly() => RebuildRuntimeShapeState();
 599
 600    internal void ValidateCurrentRuntimeTransform() =>
 129601        PrepareRuntimeShape(
 129602            CaptureShapeSnapshot(),
 129603            requireRepresentableMassPoint: true);
 604
 605    /// <summary>Assigns a 2D hierarchy parent used for collision exclusion.</summary>
 606    public void SetParent(LSCollider2D parent)
 607    {
 16608        ThrowIfCompoundPartLifecycle(nameof(SetParent));
 16609        _hierarchyState.SetParent(this, parent);
 16610    }
 611
 612    /// <summary>Assigns a 3D hierarchy parent used for mixed collision exclusion.</summary>
 613    public void SetParent(LSCollider parent)
 614    {
 6615        ThrowIfCompoundPartLifecycle(nameof(SetParent));
 6616        _hierarchyState.SetParent(this, parent);
 6617    }
 618
 619    /// <summary>Removes this collider from its current hierarchy parent.</summary>
 620    public void ClearParent()
 621    {
 267622        ThrowIfCompoundPartLifecycle(nameof(ClearParent));
 267623        _hierarchyState.ClearParent(this);
 267624    }
 625
 626    /// <summary>Gets whether hierarchy rules exclude collision with another 2D collider.</summary>
 627    public bool IsSibling(LSCollider2D other) =>
 9241628        _hierarchyState.ExcludesCollisionWith(other._hierarchyState, HierarchyKey, other.HierarchyKey);
 629
 630    internal bool ExcludesMixedCollisionWith(LSCollider other) =>
 1631        _hierarchyState.ExcludesCollisionWith(other.HierarchyState, HierarchyKey, other.HierarchyKey);
 632
 633    internal SwiftList<WorldVoxelIndex> GetOrCreatePartitionCoordinates()
 634    {
 7045635        _partitionState.Coordinates ??= new();
 7045636        return _partitionState.Coordinates;
 637    }
 638
 639    internal SwiftList<WorldVoxelIndex> GetOrCreateMixedPartitionCoordinates()
 640    {
 628641        _mixedPartitionState.Coordinates ??= new();
 628642        return _mixedPartitionState.Coordinates;
 643    }
 644
 645    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 646    internal bool MatchesPartitionGridBounds(Vector2d min, Vector2d max, int partitionKind) =>
 2173647        _partitionState.MatchesGridBounds(min, max, partitionKind);
 648
 649    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 650    internal bool MatchesMixedPartitionGridBounds(Vector3d min, Vector3d max, int partitionKind) =>
 1264651        _mixedPartitionState.IsPartitioned
 1264652        && _mixedPartitionState.LastGridBoundsMin == min
 1264653        && _mixedPartitionState.LastGridBoundsMax == max
 1264654        && _mixedPartitionState.LastPartitionKind == partitionKind;
 655
 656    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 657    internal void MarkPartitioned(Vector2d min, Vector2d max, int partitionKind)
 658    {
 6745659        _partitionState.SetPreviousGridBounds(min, max, partitionKind);
 6745660        _partitionState.MarkPartitioned();
 6745661    }
 662
 663    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 664    internal void MarkMixedPartitioned(Vector3d min, Vector3d max, int partitionKind)
 665    {
 617666        _mixedPartitionState.SetPreviousGridBounds(min, max, partitionKind);
 617667        _mixedPartitionState.MarkPartitioned();
 617668    }
 669
 670    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2159671    internal void MarkUnpartitioned() => _partitionState.MarkUnpartitioned();
 672
 673    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 276674    internal void MarkMixedUnpartitioned() => _mixedPartitionState.MarkUnpartitioned();
 675
 676    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2159677    internal void ClearPartitionCoordinates() => _partitionState.ClearCoordinates();
 678
 679    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 276680    internal void ClearMixedPartitionCoordinates() => _mixedPartitionState.ClearCoordinates();
 681
 682    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 683    internal bool IsPositionInPlanarBounds(Fixed64 cellEdge, Vector3d worldPosition)
 684    {
 82393685        Fixed64 padding = cellEdge * Fixed64.Half;
 82393686        return worldPosition.X >= MinX - padding
 82393687            && worldPosition.X <= MaxX + padding
 82393688            && worldPosition.Z >= MinY - padding
 82393689            && worldPosition.Z <= MaxY + padding;
 690    }
 691
 692    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 693    internal bool IsPositionInMixedBounds(Fixed64 cellEdge, Vector3d worldPosition)
 694    {
 29000695        Fixed64 padding = cellEdge * Fixed64.Half;
 29000696        return worldPosition.X >= _mixedBounds3D.Min.X - padding
 29000697            && worldPosition.X <= _mixedBounds3D.Max.X + padding
 29000698            && worldPosition.Y >= _mixedBounds3D.Min.Y - padding
 29000699            && worldPosition.Y <= _mixedBounds3D.Max.Y + padding
 29000700            && worldPosition.Z >= _mixedBounds3D.Min.Z - padding
 29000701            && worldPosition.Z <= _mixedBounds3D.Max.Z + padding;
 702    }
 703
 704    internal bool TryGetCollisionPair(int otherId, out CollisionPair2D? collisionPair) =>
 830705        _pairState.TryGetCollisionPair(otherId, out collisionPair);
 706
 707    internal bool TryAddCollisionPair(int otherId, CollisionPair2D collisionPair) =>
 257708        _pairState.TryAddCollisionPair(otherId, collisionPair);
 709
 710    internal bool TryRemoveCollisionPair(int otherId, out CollisionPair2D? collisionPair) =>
 75711        _pairState.TryRemoveCollisionPair(otherId, out collisionPair);
 712
 255713    internal bool TryAddCollisionPairHolder(int otherId) => _pairState.TryAddCollisionPairHolder(otherId);
 714
 75715    internal bool TryRemoveCollisionPairHolder(int otherId) => _pairState.TryRemoveCollisionPairHolder(otherId);
 716
 717    internal void ClearCollisionPairState()
 718    {
 264719        _pairState.ClearCollisionPairs();
 264720        _pairState.ClearCollisionPairHolders();
 264721    }
 722
 723    internal void ClearRuntimeRelationships()
 724    {
 264725        ClearChildParentReferences();
 264726        ClearParent();
 264727    }
 728
 729    private Fixed64 ResolveAgentRotation()
 730    {
 127731        return _agent == null
 127732            ? Fixed64.Zero
 127733            : _agent.Transform.WorldRotationXZRadians;
 734    }
 735
 736    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 737    internal void BindContext(GravitasWorldContext context)
 738    {
 4739        SwiftThrowHelper.ThrowIfNull(context, nameof(context));
 3740        SwiftThrowHelper.ThrowIfArgument(
 3741            _context != null && !ReferenceEquals(_context, context),
 3742            nameof(context),
 3743            "2D collider is already bound to a different GravitasWorldContext.");
 2744        _context = context;
 2745    }
 746
 747    internal void ReserveCompoundPart(
 748        LSCompoundCollider2D owner,
 749        Fixed64 localRotation,
 750        Vector2d localScale)
 751    {
 249752        SwiftThrowHelper.ThrowIfNull(owner, nameof(owner));
 249753        SwiftThrowHelper.ThrowIfArgument(
 249754            HasHostBinding,
 249755            nameof(owner),
 249756            "2D compound collider parts cannot be initialized as standalone colliders.");
 248757        SwiftThrowHelper.ThrowIfArgument(
 248758            _compoundOwner != null && !ReferenceEquals(_compoundOwner, owner),
 248759            nameof(owner),
 248760            "2D compound collider part is already owned by another compound collider.");
 761
 247762        _compoundOwner = owner;
 247763        _compoundLocalRotation = localRotation;
 247764        _compoundLocalScale = localScale;
 247765    }
 766
 767    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 768    private void ThrowIfCompoundPartLifecycle(string operation)
 769    {
 9367770        SwiftThrowHelper.ThrowIfTrue(
 9367771            _compoundOwner != null,
 9367772            operation,
 9367773            "2D compound collider parts are geometry owned by LSCompoundCollider2D and cannot run standalone lifecycle o
 9366774    }
 775
 776    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 777    internal ExactMassPoint2D TransformRelativeMassPropertyPointExact(
 778        Vector2d partRelativePoint)
 779    {
 35168780        GetCurrentScaleFactors(
 35168781            out Vector2d ownerScale,
 35168782            out _);
 35168783        return _compoundOwner == null
 35168784            ? ExactMassPoint2D.CreateScaledLocalComposition(
 35168785                LocalOffset,
 35168786                ownerScale,
 35168787                Vector2d.Zero,
 35168788                Vector2d.One,
 35168789                partRelativePoint,
 35168790                Fixed64.Zero)
 35168791            : ExactMassPoint2D.CreateScaledLocalComposition(
 35168792                _compoundOwner.LocalOffset,
 35168793                ownerScale,
 35168794                LocalOffset,
 35168795                ownerScale,
 35168796                partRelativePoint,
 35168797                _compoundLocalRotation);
 798    }
 799
 800    /// <summary>Rotates a planar vector and removes fixed-point epsilon residue.</summary>
 801    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 802    protected static Vector2d Rotate(Vector2d value, Fixed64 radians)
 803    {
 764804        if (radians == Fixed64.Zero)
 453805            return value;
 806
 311807        return ClampNearZero(Vector2d.Rotate(value, radians));
 808    }
 809
 810    /// <summary>Replaces vector components within fixed-point epsilon of zero.</summary>
 811    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 812    protected static Vector2d ClampNearZero(Vector2d value)
 813    {
 313814        Fixed64 x = value.X.Abs() <= Fixed64.Epsilon ? Fixed64.Zero : value.X;
 313815        Fixed64 y = value.Y.Abs() <= Fixed64.Epsilon ? Fixed64.Zero : value.Y;
 313816        return new Vector2d(x, y);
 817    }
 818
 819    private void SetTrigger(bool value)
 820    {
 70821        if (_isTrigger == value)
 16822            return;
 823
 54824        if (value)
 51825            ThrowIfCannotEnableTrigger(nameof(IsTrigger));
 826
 53827        _isTrigger = value;
 53828    }
 829
 830    private void ThrowIfCannotEnableTrigger(string operation)
 831    {
 51832        SwiftThrowHelper.ThrowIfArgument(
 51833            _body != null,
 51834            operation,
 51835            "2D trigger colliders must be initialized without a SolidBody2D. Use InitializeWithNoBody for trigger volume
 50836        SwiftThrowHelper.ThrowIfArgument(
 50837            _compoundOwner != null,
 50838            operation,
 50839            "2D compound collider parts are not trigger identities. Set IsTrigger on the owning compound collider.");
 50840    }
 841
 842    private void ThrowIfTriggerWouldAttachToBody(string operation)
 843    {
 4658844        SwiftThrowHelper.ThrowIfArgument(
 4658845            _isTrigger,
 4658846            operation,
 4658847            "2D trigger colliders must be initialized without a SolidBody2D. Use InitializeWithNoBody for trigger volume
 4657848    }
 849
 850    private void ThrowIfLoadedTriggerHasBody(string operation)
 851    {
 79852        SwiftThrowHelper.ThrowIfArgument(
 79853            _isTrigger && _body != null,
 79854            operation,
 79855            "Loaded 2D trigger state is invalid for a collider attached to a SolidBody2D.");
 77856    }
 857
 858    /// <inheritdoc/>
 859    public void RecordData(IChronicler chronicler)
 860    {
 137861        RecordValues.Look(chronicler, ref _isActive, "Active", true);
 137862        RecordValues.Look(chronicler, ref _isTrigger, "IsTrigger", false);
 137863        RecordValues.Look(chronicler, ref _layer, "Layer", new());
 137864        RecordValues.Look(chronicler, ref _ignoredCollisionLayers, "IgnoredCollisionLayers", PhysicsLayerMask.None);
 137865        RecordValues.Look(chronicler, ref _material, "Material", PhysicsMaterial.Default);
 137866        RecordValues.Look(chronicler, ref _localOffset, "LocalOffset", Vector2d.Zero);
 137867        RecordValues.Look(chronicler, ref _mixedHalfThicknessOverride, "MixedHalfThicknessOverride");
 137868        RecordShapeData(chronicler);
 869
 135870        if (chronicler.Mode == SerializationMode.Loading)
 871        {
 79872            ThrowIfLoadedTriggerHasBody(nameof(IsTrigger));
 77873            ApplyLoadedState();
 874        }
 133875    }
 876
 877    /// <summary>Records derived authored shape data.</summary>
 1878    protected virtual void RecordShapeData(IChronicler chronicler) { }
 879
 880    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 24991881    internal bool IgnoresCollisionLayer(PhysicsLayer layer) => _ignoredCollisionLayers.Includes(layer);
 882
 883    private void ApplyLoadedState()
 884    {
 77885        _runtimeShapeState.MarkDirty();
 77886        if (_context == null)
 12887            return;
 888
 65889        RebuildRuntimeShapeState();
 890
 65891        if (_id < 0)
 1892            return;
 893
 64894        if (!_isActive)
 895        {
 10896            if (IsPartitioned)
 6897                _context.Collisions2D.ClearPartitionedCollider(this, force: true);
 10898            MarkUnpartitioned();
 10899            ClearPartitionCoordinates();
 900
 10901            if (IsMixedPartitioned)
 2902                _context.MixedCollisions.ClearPartitioned2DCollider(this, force: true);
 10903            MarkMixedUnpartitioned();
 10904            ClearMixedPartitionCoordinates();
 10905            return;
 906        }
 907
 54908        _context.Collisions2D.RefreshColliderPartition(this);
 54909        if (_context.Settings.RuntimeMode.RunsMixedContacts())
 4910            _context.MixedCollisions.Refresh2DColliderPartition(this);
 54911    }
 912}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/2D/LSCollider2D.Geometry.cs

#LineLine coverage
 1//=======================================================================
 2// LSCollider2D.Geometry.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 FixedMathSharp.Geometry;
 10using System;
 11using System.Runtime.CompilerServices;
 12
 13namespace Gravitas.Colliders;
 14
 15public abstract partial class LSCollider2D
 16{
 17    /// <summary>Gets the planar runtime position.</summary>
 80018    public Vector2d Position => _compoundOwner != null
 80019        ? _compoundOwner.Center
 80020        : ResolveStandalonePosition();
 21
 22    /// <summary>Gets the committed planar rotation in radians.</summary>
 23    public Fixed64 Rotation
 24    {
 25        get
 26        {
 7655227            if (_hasCommittedShape)
 7397928                return _committedRotation;
 257329            if (_compoundOwner == null)
 250730                return ResolveStandaloneRotation();
 31
 6632            return PlanarRotation.Combine(
 6633                _compoundOwner.Rotation,
 6634                _compoundLocalRotation);
 35        }
 36    }
 37
 38    /// <summary>Gets the combined planar owner and compound-part scale.</summary>
 39    public virtual Vector2d LocalScale
 40    {
 41        get
 42        {
 243            bool representable = TryGetLocalScale(out Vector2d scale);
 244            SwiftThrowHelper.ThrowIfTrue(
 245                !representable,
 246                nameof(LocalScale),
 247                "The combined 2D collider scale is outside the Fixed64 coordinate domain.");
 148            return scale;
 49        }
 50    }
 51
 52    /// <summary>
 53    /// Attempts to materialize the combined owner and compound-part scale.
 54    /// Shape preparation retains those factors separately and does not require
 55    /// their product to be representable.
 56    /// </summary>
 57    public bool TryGetLocalScale(out Vector2d scale)
 58    {
 459        GetCurrentScaleFactors(
 460            out Vector2d ownerScale,
 461            out Vector2d partScale);
 62
 463        bool representable = Fixed64.TryMultiplyDivide(
 464                ownerScale.X,
 465                partScale.X,
 466                Fixed64.One,
 467                out Fixed64 x)
 468            & Fixed64.TryMultiplyDivide(
 469                ownerScale.Y,
 470                partScale.Y,
 471                Fixed64.One,
 472                out Fixed64 y);
 473        scale = representable ? new Vector2d(x, y) : default;
 474        return representable;
 75    }
 76
 77    /// <summary>
 78    /// Gets the component-scaled local offset.
 79    /// </summary>
 80    /// <exception cref="InvalidOperationException">
 81    /// The scaled offset itself is outside the Fixed64 coordinate domain. The
 82    /// collider may still have a representable world center through exact
 83    /// transform cancellation.
 84    /// </exception>
 985    public Vector2d ScaledLocalOffset => GetCurrentScaledOffset();
 86
 87    /// <summary>
 88    /// Attempts to materialize the component-scaled local offset independently
 89    /// from the collider's complete world transform.
 90    /// </summary>
 91    public bool TryGetScaledLocalOffset(out Vector2d scaledLocalOffset) =>
 392        TryGetCurrentScaledOffset(out scaledLocalOffset);
 93
 94    /// <summary>Gets the collider center in planar world coordinates.</summary>
 15890595    public Vector2d Center => _hasCommittedShape
 15890596        ? _committedCenter
 15890597        : GetUncommittedCenter();
 98
 99    /// <summary>Gets whether a planar world-space point lies inside this collider.</summary>
 100    public abstract bool ContainsPoint(Vector2d point);
 101
 102    /// <summary>Gets the closest representable point on this collider to a planar world-space point.</summary>
 103    public abstract Vector2d GetClosestPoint(Vector2d point);
 104
 105    /// <summary>Gets the farthest representable point along a planar world-space direction.</summary>
 106    public abstract Vector2d GetSupportPoint(Vector2d direction);
 107
 108    internal int VertexCount
 109    {
 110        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 74270111        get => this is IConvexVertexSource2D source ? source.VertexCount : 0;
 112    }
 113
 114    internal Fixed64 ConvexRotation =>
 31770115        ((IConvexVertexSource2D)this).Rotation;
 116
 117    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 118    internal Vector2d GetScaledLocalVertexUnchecked(int index) =>
 65239119        ((IConvexVertexSource2D)this).GetScaledLocalVertexUnchecked(index);
 120
 121    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 122    internal FixedPointAnchor2d GetConvexSupportAnchor(Vector2d direction) =>
 103123        ((IConvexVertexSource2D)this).GetSupportAnchor(direction);
 124
 125    internal bool TryGetClosestBoundaryAnchor(
 126        Vector2d point,
 127        out FixedPointAnchor2d boundary)
 128    {
 2352129        switch (this)
 130        {
 131            case LSCircleCollider2D circle:
 747132                boundary = GetRoundBoundaryAnchor(
 747133                    circle.Center,
 747134                    circle.Rotation,
 747135                    Vector2d.Forward,
 747136                    Fixed64.Zero,
 747137                    circle.ScaledRadius,
 747138                    point,
 747139                    Vector2d.Right);
 747140                return true;
 141            case LSCapsuleCollider2D capsule:
 91142                boundary = GetRoundBoundaryAnchor(
 91143                    capsule.Center,
 91144                    capsule.Rotation,
 91145                    Vector2d.Forward,
 91146                    capsule.AxisLength,
 91147                    capsule.ScaledRadius,
 91148                    point,
 91149                    capsule.GetNormalFromCenteredAxis(point));
 91150                return true;
 151            case LSAABBoxCollider2D box:
 172152                return TryGetAABoxBoundaryAnchor(
 172153                    box,
 172154                    point,
 172155                    out boundary);
 156            case LSPolygonCollider2D polygon:
 1122157                return TryGetConvexBoundaryAnchor(
 1122158                    polygon.Center,
 1122159                    polygon.Rotation,
 1122160                    polygon.ScaledLocalVertices,
 1122161                    point,
 1122162                    out boundary);
 163            case LSCompoundCollider2D compound:
 219164                return TryGetCompoundBoundaryAnchor(
 219165                    compound,
 219166                    point,
 219167                    out boundary);
 168            default:
 1169                boundary = default;
 1170                return false;
 171        }
 172    }
 173
 174    internal bool TryGetClosestBoundaryAnchor(
 175        Vector2d point,
 176        out FixedPointAnchor2d boundary,
 177        out Fixed64 distance)
 178    {
 1264179        if (TryGetClosestBoundaryAnchor(
 1264180                point,
 1264181                out boundary)
 1264182            && TryGetAnchorDistance(
 1264183                point,
 1264184                boundary,
 1264185                out distance))
 186        {
 1256187            return true;
 188        }
 189
 8190        boundary = default;
 8191        distance = default;
 8192        return false;
 193    }
 194
 195    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 196    internal bool TryGetVertex(int index, out Vector2d vertex) =>
 84197        Vector2d.TryTransformPoint(
 84198            Center,
 84199            GetScaledLocalVertexUnchecked(index),
 84200            ConvexRotation,
 84201            out vertex);
 202
 203    private static FixedPointAnchor2d GetRoundBoundaryAnchor(
 204        Vector2d center,
 205        Fixed64 rotation,
 206        Vector2d localAxis,
 207        Fixed64 axisLength,
 208        Fixed64 radius,
 209        Vector2d point,
 210        Vector2d fallbackNormal)
 211    {
 838212        Vector2d normal = FixedSegment2d.GetDirectionFromCenteredAxis(
 838213            point,
 838214            center,
 838215            rotation,
 838216            axisLength);
 838217        if (normal == Vector2d.Zero)
 88218            normal = fallbackNormal;
 219
 838220        Vector2d localNormal =
 838221            Vector2d.Rotate(normal, -rotation).Normalized;
 838222        return FixedSegment2d.GetSurfaceAnchorOnCenteredCapsule(
 838223            point,
 838224            center,
 838225            rotation,
 838226            localAxis,
 838227            axisLength,
 838228            radius,
 838229            localNormal);
 230    }
 231
 232    private static bool TryGetAABoxBoundaryAnchor(
 233        LSAABBoxCollider2D box,
 234        Vector2d point,
 235        out FixedPointAnchor2d boundary)
 236    {
 172237        Vector2d halfExtents = box.ScaledHalfExtents;
 172238        Span<Vector2d> offsets = stackalloc Vector2d[4];
 172239        offsets[0] = new Vector2d(-halfExtents.X, halfExtents.Y);
 172240        offsets[1] = new Vector2d(-halfExtents.X, -halfExtents.Y);
 172241        offsets[2] = new Vector2d(halfExtents.X, -halfExtents.Y);
 172242        offsets[3] = new Vector2d(halfExtents.X, halfExtents.Y);
 172243        return TryGetConvexBoundaryAnchor(
 172244            box.Center,
 172245            Fixed64.Zero,
 172246            offsets,
 172247            point,
 172248            out boundary);
 249    }
 250
 251    private static bool TryGetConvexBoundaryAnchor(
 252        Vector2d center,
 253        Fixed64 rotation,
 254        ReadOnlySpan<Vector2d> offsets,
 255        Vector2d point,
 256        out FixedPointAnchor2d boundary)
 257    {
 1294258        boundary =
 1294259            FixedConvex2dRelations.GetClosestPointAnchor(
 1294260                point,
 1294261                center,
 1294262                rotation,
 1294263                offsets);
 1294264        return true;
 265    }
 266
 267    private static bool TryGetCompoundBoundaryAnchor(
 268        LSCompoundCollider2D compound,
 269        Vector2d point,
 270        out FixedPointAnchor2d boundary)
 271    {
 219272        var reference = new FixedPointAnchor2d(
 219273            point,
 219274            Fixed64.Zero,
 219275            Vector2d.Zero);
 219276        if (TryGetCompoundBoundaryAnchor(
 219277                compound,
 219278                point,
 219279                reference,
 219280                containingPartsOnly: true,
 219281                out boundary))
 282        {
 2283            return true;
 284        }
 285
 217286        return TryGetCompoundBoundaryAnchor(
 217287            compound,
 217288            point,
 217289            reference,
 217290            containingPartsOnly: false,
 217291            out boundary);
 292    }
 293
 294    private static bool TryGetCompoundBoundaryAnchor(
 295        LSCompoundCollider2D compound,
 296        Vector2d point,
 297        in FixedPointAnchor2d reference,
 298        bool containingPartsOnly,
 299        out FixedPointAnchor2d boundary)
 300    {
 436301        boundary = default;
 436302        bool found = false;
 2606303        for (int i = 0; i < compound.PartCount; i++)
 304        {
 867305            LSCollider2D part = compound.GetPartCollider(i);
 867306            if (containingPartsOnly && !part.ContainsPoint(point))
 307                continue;
 308
 309            // Compound definitions materialize only built-in semantic shapes.
 434310            _ = part.TryGetClosestBoundaryAnchor(
 434311                point,
 434312                out FixedPointAnchor2d candidate);
 434313            if (found
 434314                && reference.CompareSquaredDistance(
 434315                    candidate,
 434316                    boundary) >= 0)
 317            {
 318                continue;
 319            }
 320
 431321            boundary = candidate;
 431322            found = true;
 323        }
 324
 436325        return found;
 326    }
 327
 328    private static bool TryGetAnchorDistance(
 329        Vector2d point,
 330        in FixedPointAnchor2d anchor,
 331        out Fixed64 distance)
 332    {
 1264333        if (anchor.TryGetOffsetFrom(
 1264334                new FixedPointAnchor2d(
 1264335                    point,
 1264336                    Fixed64.Zero,
 1264337                    Vector2d.Zero),
 1264338                out Vector2d difference)
 1264339            && Vector2d.TryGetMagnitude(difference, out distance))
 340        {
 1256341            return true;
 342        }
 343
 8344        distance = default;
 8345        return false;
 346    }
 347
 348    /// <summary>
 349    /// Calculates the body-local center of mass implied by this 2D collider's current shape state.
 350    /// </summary>
 351    public virtual Vector2d CalculateLocalCenterOfMassOffset()
 352    {
 17275353        ExactMassPoint2D point = CalculateLocalMassPoint();
 17274354        SwiftThrowHelper.ThrowIfTrue(
 17274355            !point.TryGetPoint(out Vector2d center),
 17274356            nameof(CalculateLocalCenterOfMassOffset),
 17274357            "The 2D collider's body-local center of mass is outside the Fixed64 coordinate domain.");
 17272358        return center;
 359    }
 360
 361    internal virtual ExactMassPoint2D CalculateLocalMassPoint() =>
 23167362        TransformRelativeMassPropertyPointExact(Vector2d.Zero);
 363
 364    internal virtual ExactMassPoint2D CalculatePreparedLocalMassPoint() =>
 7549365        TransformPreparedRelativeMassPropertyPointExact(Vector2d.Zero);
 366
 367    /// <summary>
 368    /// Calculates the scalar moment of inertia about a requested body-local reference point.
 369    /// </summary>
 370    public virtual Fixed64 CalculateMomentOfInertia(
 371        Fixed64 mass,
 372        Vector2d localReferencePoint)
 373    {
 17183374        if (mass <= Fixed64.Zero)
 5375            return Fixed64.Zero;
 376
 17178377        Fixed64 centerMoment =
 17178378            CalculateCenterOfMassMoment(mass);
 17177379        ExactMassPoint2D massPoint = CalculateLocalMassPoint();
 17177380        if (massPoint.TryAddParallelAxisMoment(
 17177381                centerMoment,
 17177382                mass,
 17177383                localReferencePoint,
 17177384                out Fixed64 moment))
 385        {
 17166386            return moment;
 387        }
 388
 11389        if (!massPoint.TryGetPoint(out Vector2d center))
 390        {
 1391            SwiftThrowHelper.ThrowIfTrue(
 1392                true,
 1393                nameof(localReferencePoint),
 1394                "The requested moment of inertia is outside the Fixed64 scalar domain.");
 395        }
 396
 10397        Vector2d delta = localReferencePoint - center;
 10398        return centerMoment
 10399            + mass * delta.MagnitudeSquared;
 400    }
 401
 402    internal abstract Fixed64 CalculateCenterOfMassMoment(Fixed64 mass);
 403
 404    internal abstract ExactMassWeight CalculateAreaForMassProperties();
 405
 406    internal abstract ExactMassWeight CalculatePreparedAreaForMassProperties();
 407
 408    /// <summary>Updates derived material state after <see cref="Material"/> changes.</summary>
 407409    protected virtual void OnMaterialChanged() { }
 410
 411    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 412    internal ExactMassPoint2D TransformPreparedRelativeMassPropertyPointExact(
 413        Vector2d partRelativePoint) =>
 12997414        _compoundOwner == null
 12997415            ? ExactMassPoint2D.CreateScaledLocalComposition(
 12997416                _preparedSnapshot.LocalOffset,
 12997417                _preparedSnapshot.OwnerScale,
 12997418                Vector2d.Zero,
 12997419                Vector2d.One,
 12997420                partRelativePoint,
 12997421                Fixed64.Zero)
 12997422            : ExactMassPoint2D.CreateScaledLocalComposition(
 12997423                _compoundOwner._preparedSnapshot.LocalOffset,
 12997424                _preparedSnapshot.OwnerScale,
 12997425                _preparedSnapshot.LocalOffset,
 12997426                _preparedSnapshot.OwnerScale,
 12997427                partRelativePoint,
 12997428                _preparedCompoundLocalRotation);
 429
 430    /// <summary>Marks derived runtime shape state for deterministic rebuilding.</summary>
 431    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 432    protected void MarkShapeDirty()
 433    {
 5664434        _shapeVersion++;
 5664435        _runtimeShapeState.MarkDirty();
 5664436        if (_compoundOwner != null)
 437        {
 1438            _compoundOwner.MarkShapeDirty();
 1439            return;
 440        }
 441
 5663442        _body?.Wake();
 50443    }
 444
 445    private bool RebuildRuntimeShapeState()
 446    {
 14723447        ColliderShapeSnapshot2D snapshot = CaptureShapeSnapshot();
 14721448        if (!_runtimeShapeState.ShouldRebuild(snapshot))
 7552449            return false;
 450
 7169451        PrepareRuntimeShape(
 7169452            snapshot,
 7169453            requireRepresentableMassPoint:
 7169454                _body != null || _compoundOwner != null);
 7169455        PublishPreparedShape();
 7169456        _body?.RefreshMassPropertiesFromColliderShape();
 7169457        return true;
 458    }
 459
 460    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 461    private Vector2d ResolveStandalonePosition() =>
 804462        _body?.Position
 804463        ?? _agent?.Transform.WorldPositionXZ
 804464        ?? Vector2d.Zero;
 465
 466    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 467    private Fixed64 ResolveStandaloneRotation() =>
 2515468        _body?.Rotation ?? ResolveAgentRotation();
 469}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/2D/LSCollider2D.Hierarchy.cs

#LineLine coverage
 1//=======================================================================
 2// LSCollider2D.Hierarchy.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 SwiftCollections;
 9
 10namespace Gravitas.Colliders;
 11
 12public abstract partial class LSCollider2D
 13{
 14    private void ClearChildParentReferences()
 15    {
 26416        SwiftHashSet<ulong>? children = _hierarchyState.Children;
 26417        if (children == null || _context == null)
 26218            return;
 19
 820        foreach (ulong childPackedKey in children)
 21        {
 222            ColliderHierarchyKey childKey = ColliderHierarchyKey.FromPacked(childPackedKey);
 223            if (((IColliderHierarchyNode)this).TryGetHierarchyColliderByKey(
 224                    childKey,
 225                    out IColliderHierarchyNode? child))
 26            {
 227                child!.ClearParentReference();
 28            }
 29        }
 30
 231        _hierarchyState.ClearChildren();
 232    }
 33
 34    void IColliderHierarchyNode.AddChild(ColliderHierarchyKey key)
 35    {
 2336        ThrowIfCompoundPartLifecycle(nameof(IColliderHierarchyNode.AddChild));
 2337        _hierarchyState.AddChild(key);
 2338    }
 39
 40    void IColliderHierarchyNode.RemoveChild(ColliderHierarchyKey key)
 41    {
 342        ThrowIfCompoundPartLifecycle(nameof(IColliderHierarchyNode.RemoveChild));
 343        _hierarchyState.RemoveChild(key);
 344    }
 45
 46    void IColliderHierarchyNode.ClearParentReference() =>
 247        _hierarchyState.ClearParentReference();
 48
 49    bool IColliderHierarchyNode.TryGetHierarchyColliderByKey(
 50        ColliderHierarchyKey key,
 51        out IColliderHierarchyNode? collider)
 52    {
 753        collider = null;
 754        if (!key.IsValid || _context == null)
 155            return false;
 56
 657        if (key.Is2D
 658            && _context.Physics2D.TryGetColliderById(
 659                key.Id,
 660                out LSCollider2D? collider2D))
 61        {
 262            collider = collider2D;
 263            return true;
 64        }
 65
 466        if (key.Is3D
 467            && _context.Physics.TryGetColliderById(
 468                key.Id,
 469                out LSCollider? collider3D))
 70        {
 271            collider = collider3D;
 272            return true;
 73        }
 74
 275        return false;
 76    }
 77}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/2D/LSCollider2D.Notifications.cs

#LineLine coverage
 1//=======================================================================
 2// LSCollider2D.Notifications.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
 8namespace Gravitas.Colliders;
 9
 10public abstract partial class LSCollider2D
 11{
 12    internal void NotifyContact(LSCollider2D other, bool isColliding, bool isChanged) =>
 2113        NotifyContact(
 2114            other,
 2115            other.Body,
 2116            isColliding,
 2117            isChanged,
 2118            allowInactive: false,
 2119            new ColliderLifetimeToken2D(this),
 2120            new ColliderLifetimeToken2D(other),
 2121            IsTrigger || other.IsTrigger,
 2122            ColliderTriggerEventPolicy.ShouldRaise(this, other));
 23
 24    internal void NotifyContact(
 25        LSCollider2D other,
 26        SolidBody2D? otherBody,
 27        bool isColliding,
 28        bool isChanged,
 29        bool allowInactive,
 30        in ColliderLifetimeToken2D registration,
 31        in ColliderLifetimeToken2D otherRegistration,
 32        bool isTriggerPair,
 33        bool shouldRaiseTrigger)
 34    {
 126635        if (isColliding
 126636            ? !registration.IsActive || !otherRegistration.IsActive
 126637            : allowInactive ? !registration.IsCurrentLifetime : !registration.IsActive)
 38        {
 439            return;
 40        }
 41
 126242        if (isColliding)
 43        {
 111244            if (isTriggerPair)
 45            {
 5246                if (shouldRaiseTrigger)
 47                {
 4948                    if (isChanged)
 49                    {
 3450                        OnTriggerEnter?.Invoke(other);
 3451                        if (!registration.IsActive || !otherRegistration.IsActive)
 252                            return;
 53                    }
 54
 4755                    OnTriggerStay?.Invoke(other);
 56                }
 57
 2158                return;
 59            }
 60
 106061            if (isChanged && otherBody != null)
 62            {
 52063                OnContactEnter?.Invoke(otherBody);
 51964                if (!registration.IsActive || !otherRegistration.IsActive)
 965                    return;
 66            }
 67
 105068            if (otherBody != null)
 102569                OnContact?.Invoke(otherBody);
 3770            return;
 71        }
 72
 15073        if (!isChanged)
 174            return;
 75
 14976        if (isTriggerPair)
 77        {
 1278            if (shouldRaiseTrigger)
 1079                OnTriggerExit?.Invoke(other);
 80
 981            return;
 82        }
 83
 13784        if (otherBody != null)
 12785            OnContactExit?.Invoke(otherBody);
 2986    }
 87
 88    internal void NotifyMixedContact(LSCollider other, bool isColliding, bool isChanged, bool isTriggerPair) =>
 1589        NotifyMixedContact(
 1590            other,
 1591            isColliding,
 1592            isChanged,
 1593            isTriggerPair,
 1594            allowInactive: false,
 1595            new ColliderLifetimeToken2D(this),
 1596            new ColliderLifetimeToken(other),
 1597            ColliderTriggerEventPolicy.ShouldRaise(other, this));
 98
 99    internal void NotifyMixedContact(
 100        LSCollider other,
 101        bool isColliding,
 102        bool isChanged,
 103        bool isTriggerPair,
 104        bool allowInactive,
 105        in ColliderLifetimeToken2D registration,
 106        in ColliderLifetimeToken otherRegistration,
 107        bool shouldRaiseTrigger)
 108    {
 222109        if (isColliding
 222110            ? !registration.IsActive || !otherRegistration.IsActive
 222111            : allowInactive
 222112                ? !registration.IsCurrentLifetime || !otherRegistration.IsCurrentLifetime
 222113                : !registration.IsActive)
 114        {
 5115            return;
 116        }
 117
 217118        if (isColliding)
 119        {
 186120            if (isTriggerPair)
 121            {
 38122                if (shouldRaiseTrigger)
 123                {
 33124                    if (isChanged)
 125                    {
 28126                        OnMixedTriggerEnter?.Invoke(other);
 28127                        if (!registration.IsActive || !otherRegistration.IsActive)
 2128                            return;
 129                    }
 130
 31131                    OnMixedTriggerStay?.Invoke(other);
 132                }
 133
 14134                return;
 135            }
 136
 148137            if (isChanged)
 138            {
 114139                OnMixedContactEnter?.Invoke(other);
 114140                if (!registration.IsActive || !otherRegistration.IsActive)
 3141                    return;
 142            }
 143
 145144            OnMixedContact?.Invoke(other);
 2145            return;
 146        }
 147
 31148        if (!isChanged)
 1149            return;
 150
 30151        if (isTriggerPair)
 152        {
 10153            if (shouldRaiseTrigger)
 8154                OnMixedTriggerExit?.Invoke(other);
 155
 9156            return;
 157        }
 158
 20159        OnMixedContactExit?.Invoke(other);
 11160    }
 161}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/2D/LSCollider2D.ReplayHash.cs

#LineLine coverage
 1//=======================================================================
 2// LSCollider2D.ReplayHash.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 Chronicler;
 9using FixedMathSharp.Chronicler;
 10using Gravitas.Materials;
 11using System;
 12
 13namespace Gravitas.Colliders;
 14
 15public abstract partial class LSCollider2D
 16{
 17    internal void ContributeReplayHash(
 18        ref ChronicleHashWriter writer,
 19        GravitasReplayHashMode mode)
 20    {
 78321        writer.WriteSection("collider.2d", 4);
 78322        writer.WriteInt32(_replayOrdinal);
 78323        writer.WriteBool(_isActive);
 78324        writer.WriteBool(_isTrigger);
 78325        writer.WritePhysicsLayer(_layer);
 78326        writer.WritePhysicsLayerMask(_ignoredCollisionLayers);
 78327        WriteMaterial(ref writer, _material);
 78328        writer.WriteEnum(Shape);
 78329        writer.WriteInt32(Priority);
 78330        writer.WriteVector2d(_localOffset);
 78331        writer.WriteBool(_mixedHalfThicknessOverride.HasValue);
 78332        if (_mixedHalfThicknessOverride.HasValue)
 133            writer.WriteFixed64(_mixedHalfThicknessOverride.Value);
 78334        writer.WriteVector2d(Position);
 78335        writer.WriteFixed64(Rotation);
 78336        writer.WriteVector2d(_committedOwnerScale);
 78337        writer.WriteVector2d(_committedPartScale);
 78338        writer.WriteVector2d(Center);
 78339        writer.WriteFixed64(_mixedHalfThickness);
 78340        writer.WriteFixed64(_mixedSlabCenterY);
 78341        writer.WriteInt32(HierarchyChildCount);
 78342        WriteReplayHierarchyKey(ref writer, HierarchyKey);
 78343        WriteReplayHierarchyKey(ref writer, ParentKey);
 78344        WriteReplayHierarchyKey(ref writer, TopParentKey);
 45
 78346        ContributeShapeReplayHash(ref writer);
 47
 78348        if (mode != GravitasReplayHashMode.AuthoritativeWithSolverCaches)
 56649            return;
 50
 21751        writer.WriteSection("collider.2d.caches", 1);
 21752        writer.WriteUInt32(RuntimeShapeVersion);
 21753        writer.WriteUInt32(_shapeVersion);
 21754        writer.WriteInt32(_serviceIndex);
 21755        writer.WriteBool(IsPartitioned);
 21756        writer.WriteBool(IsMixedPartitioned);
 21757        writer.WriteInt32(PartitionKind);
 21758        writer.WriteInt32(MixedPartitionKind);
 21759        writer.WriteUInt32(BroadPhaseVersion);
 21760        writer.WriteUInt32(RaycastVersion);
 21761        writer.WriteUInt32(CircleQueryVersion);
 21762        writer.WriteFixed64(MinX);
 21763        writer.WriteFixed64(MinY);
 21764        writer.WriteFixed64(MaxX);
 21765        writer.WriteFixed64(MaxY);
 21766        writer.WriteVector3d(_mixedBounds3D.Min);
 21767        writer.WriteVector3d(_mixedBounds3D.Max);
 21768        writer.WriteInt32(CollisionPairCount);
 21769        writer.WriteInt32(CollisionPairHolderCount);
 21770    }
 71
 72    private void ContributeShapeReplayHash(ref ChronicleHashWriter writer)
 73    {
 78374        writer.WriteSection("collider.2d.shape", 3);
 78375        switch (this)
 76        {
 77            case LSCircleCollider2D circle:
 58378                writer.WriteFixed64(circle.Radius);
 58379                writer.WriteFixed64(circle.ScaledRadius);
 58380                break;
 81
 82            case LSAABBoxCollider2D box:
 18283                writer.WriteVector2d(box.Size);
 18284                writer.WriteVector2d(box.ScaledHalfExtents);
 18285                break;
 86
 87            case LSCapsuleCollider2D capsule:
 288                writer.WriteFixed64(capsule.Radius);
 289                writer.WriteFixed64(capsule.Height);
 290                writer.WriteVector2d(capsule.Center);
 291                writer.WriteFixed64(capsule.AxisLength);
 292                writer.WriteFixed64(capsule.ScaledRadius);
 293                break;
 94
 95            case LSCompoundCollider2D compound:
 1096                writer.WriteInt32(compound.PartCount);
 1097                ReadOnlySpan<CompoundColliderPart2D> parts = compound.Parts;
 10098                for (int i = 0; i < parts.Length; i++)
 4099                    ContributeCompoundPartReplayHash(ref writer, parts[i]);
 100                break;
 101        }
 102
 783103        writer.WriteInt32(VertexCount);
 3066104        for (int i = 0; i < VertexCount; i++)
 750105            writer.WriteVector2d(GetScaledLocalVertexUnchecked(i));
 783106    }
 107
 108    private void WriteReplayHierarchyKey(ref ChronicleHashWriter writer, ColliderHierarchyKey key)
 109    {
 2349110        if (!TryResolveReplayHierarchyOrdinal(key, out int replayOrdinal))
 111        {
 1554112            writer.WriteUInt64(0UL);
 1554113            return;
 114        }
 115
 795116        writer.WriteUInt64(((ulong)key.Dimension << 32) | (uint)replayOrdinal);
 795117    }
 118
 119    private bool TryResolveReplayHierarchyOrdinal(ColliderHierarchyKey key, out int replayOrdinal)
 120    {
 2349121        replayOrdinal = -1;
 2349122        if (!key.IsValid || _context == null)
 1554123            return false;
 124
 795125        if (key.Is2D)
 126        {
 785127            _context.Physics2D.TryGetColliderById(key.Id, out LSCollider2D? collider);
 785128            replayOrdinal = collider!.ReplayOrdinal;
 785129            return replayOrdinal >= 0;
 130        }
 131
 10132        _context.Physics.TryGetColliderById(key.Id, out LSCollider? collider3D);
 10133        replayOrdinal = collider3D!.ReplayOrdinal;
 10134        return replayOrdinal >= 0;
 135    }
 136
 137    private static void ContributeCompoundPartReplayHash(
 138        ref ChronicleHashWriter writer,
 139        CompoundColliderPart2D part)
 140    {
 40141        writer.WriteVector2d(part.LocalOffset);
 40142        writer.WriteFixed64(part.LocalRotation);
 40143        writer.WriteVector2d(part.LocalScale);
 40144        writer.WriteBool(part.HasMaterial);
 40145        if (part.TryGetMaterial(out PhysicsMaterial material))
 20146            WriteMaterial(ref writer, material);
 40147        ContributeShapeDefinitionReplayHash(ref writer, part.Shape);
 40148    }
 149
 150    private static void ContributeShapeDefinitionReplayHash(
 151        ref ChronicleHashWriter writer,
 152        ColliderShapeDefinition2D definition)
 153    {
 40154        writer.WriteEnum(definition.Kind);
 40155        writer.WriteBool(definition.HasMaterial);
 40156        if (definition.HasMaterial)
 10157            WriteMaterial(ref writer, definition.Material);
 40158        writer.WriteFixed64(definition.Radius);
 40159        writer.WriteVector2d(definition.Size);
 40160        writer.WriteInt32(definition.PolygonVertexCount);
 140161        for (int i = 0; i < definition.PolygonVertexCount; i++)
 30162            writer.WriteVector2d(definition.GetPolygonVertex(i));
 40163    }
 164
 165    private static void WriteMaterial(ref ChronicleHashWriter writer, PhysicsMaterial material)
 166    {
 813167        writer.WriteFixed64(material.StaticFriction);
 813168        writer.WriteFixed64(material.DynamicFriction);
 813169        writer.WriteFixed64(material.Restitution);
 813170        writer.WriteEnum(material.FrictionCombine);
 813171        writer.WriteEnum(material.RestitutionCombine);
 813172    }
 173}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/2D/LSCollider2D.ShapeTransaction.cs

#LineLine coverage
 1//=======================================================================
 2// LSCollider2D.ShapeTransaction.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 FixedMathSharp.Geometry;
 10
 11namespace Gravitas.Colliders;
 12
 13public abstract partial class LSCollider2D
 14{
 15    private Vector2d _committedCenter;
 16    private Fixed64 _committedRotation;
 550417    private Vector2d _committedOwnerScale = Vector2d.One;
 550418    private Vector2d _committedPartScale = Vector2d.One;
 19    private bool _hasCommittedShape;
 20
 21    /// <summary>Gets whether this collider has committed runtime shape state.</summary>
 18592722    protected bool HasCommittedShape => _hasCommittedShape;
 23
 24    private ColliderShapeSnapshot2D _preparedSnapshot;
 25    private FixedBoundArea _preparedBounds;
 26    private FixedBoundBox _preparedMixedBounds;
 550427    private Fixed64 _canonicalCenteredProxyRadius = Fixed64.MaxValue;
 28    private Fixed64 _canonicalGroundProbeRadius;
 29    private GravitasWorldContext? _preparedContext;
 30    private Fixed64 _preparedCompoundLocalRotation;
 31
 44432    private protected GravitasWorldContext PreparedContext => _preparedContext!;
 33
 44434    internal FixedBoundArea PreparedShapeBounds => _preparedBounds;
 35
 36    internal Fixed64 CanonicalCenteredProxyRadius =>
 768837        _canonicalCenteredProxyRadius;
 38
 39    internal Fixed64 CanonicalGroundProbeRadius =>
 1041440        _canonicalGroundProbeRadius;
 41
 77142    internal Vector2d CanonicalCenter => _committedCenter;
 43
 44    internal bool TryGetCommittedOwnerScale(out Vector2d scale)
 45    {
 42946        if (_hasCommittedShape)
 47        {
 42548            scale = _committedOwnerScale;
 42549            return true;
 50        }
 51
 452        scale = default;
 453        return false;
 54    }
 55
 56    private Vector2d GetCurrentOwnerScale()
 57    {
 6644158        if (_hasCommittedShape)
 3290859            return _committedOwnerScale;
 3353360        if (_compoundOwner != null)
 220361            return _compoundOwner.GetCurrentOwnerScale();
 3133062        if (_agent == null)
 1648963            return Vector2d.One;
 64
 1484165        return ColliderScalePolicy.CapturePlanar(
 1484166            _agent.Transform,
 1484167            out _,
 1484168            out _);
 69    }
 70
 71    /// <summary>Gets the current owner and compound-part scale factors separately.</summary>
 72    protected void GetCurrentScaleFactors(
 73        out Vector2d ownerScale,
 74        out Vector2d partScale)
 75    {
 5674676        ownerScale = GetCurrentOwnerScale();
 5674677        partScale = _hasCommittedShape
 5674678            ? _committedPartScale
 5674679            : _compoundOwner != null
 5674680                ? _compoundLocalScale
 5674681                : Vector2d.One;
 5674682    }
 83
 84    internal bool TryGetCurrentScaledOffset(out Vector2d scaledOffset)
 85    {
 747686        Vector2d ownerScale = GetCurrentOwnerScale();
 747687        bool representable = Fixed64.TryMultiplyDivide(
 747688                _localOffset.X,
 747689                ownerScale.X,
 747690                Fixed64.One,
 747691                out Fixed64 x)
 747692            & Fixed64.TryMultiplyDivide(
 747693                _localOffset.Y,
 747694                ownerScale.Y,
 747695                Fixed64.One,
 747696                out Fixed64 y);
 747697        scaledOffset = representable ? new Vector2d(x, y) : default;
 747698        return representable;
 99    }
 100
 101    internal Vector2d GetCurrentScaledOffset()
 102    {
 9103        bool representable =
 9104            TryGetCurrentScaledOffset(out Vector2d scaledOffset);
 9105        SwiftThrowHelper.ThrowIfTrue(
 9106            !representable,
 9107            nameof(ScaledLocalOffset),
 9108            "The scaled 2D collider offset is outside the Fixed64 coordinate domain.");
 8109        return scaledOffset;
 110    }
 111
 112    private Vector2d GetUncommittedCenter()
 113    {
 16114        Vector2d ownerScale = GetCurrentOwnerScale();
 16115        bool representable = Vector2d.TryTransformScaledPoint(
 16116            Position,
 16117            _localOffset,
 16118            ownerScale,
 16119            _compoundOwner?.Rotation ?? Rotation,
 16120            out Vector2d center);
 16121        SwiftThrowHelper.ThrowIfTrue(
 16122            !representable,
 16123            nameof(Center),
 16124            "The 2D collider center is outside the Fixed64 coordinate domain.");
 16125        return center;
 126    }
 127
 128    private ColliderShapeSnapshot2D CreateStandaloneSnapshot(
 129        IMatterAgent agent,
 130        bool useRequestedPose,
 131        Vector2d requestedPosition,
 132        Fixed64 requestedRotation)
 133    {
 20842134        Vector2d ownerScale = ColliderScalePolicy.CapturePlanar(
 20842135            agent.Transform,
 20842136            out Fixed4x4 worldMatrix,
 20842137            out Fixed64 matrixRotation);
 138        Vector2d center;
 139        Fixed64 rotation;
 20825140        if (useRequestedPose)
 141        {
 19528142            rotation = PlanarRotation.Canonicalize(requestedRotation);
 19528143            bool representable = Vector2d.TryTransformScaledPoint(
 19528144                requestedPosition,
 19528145                _localOffset,
 19528146                ownerScale,
 19528147                rotation,
 19528148                out center);
 19528149            SwiftThrowHelper.ThrowIfArgument(
 19528150                !representable,
 19528151                nameof(requestedPosition),
 19528152                "2D collider center must be representable after applying the requested body pose.");
 153        }
 154        else
 155        {
 1297156            rotation = matrixRotation;
 1297157            SwiftThrowHelper.ThrowIfArgument(
 1297158                !Fixed4x4.TryTransformAffinePoint(
 1297159                    worldMatrix,
 1297160                    _localOffset.ToVector3d(Fixed64.Zero),
 1297161                    out Vector3d transformed),
 1297162                nameof(agent),
 1297163                "2D collider center must be representable after applying the host transform.");
 1297164            center = transformed.ToVector2d();
 165        }
 166
 20821167        return new ColliderShapeSnapshot2D(
 20821168            center,
 20821169            rotation,
 20821170            ownerScale,
 20821171            Vector2d.One,
 20821172            _localOffset,
 20821173            _shapeVersion,
 20821174            worldMatrix.M42,
 20821175            _mixedHalfThicknessOverride ?? agent.Context.Settings.Mixed2DHalfThickness);
 176    }
 177
 178    private ColliderShapeSnapshot2D CaptureShapeSnapshot()
 179    {
 14852180        if (_compoundOwner != null)
 181        {
 1182            return CreateCompoundPartSnapshot(
 1183                _compoundOwner._preparedSnapshot,
 1184                _compoundLocalRotation,
 1185                _compoundLocalScale);
 186        }
 187
 14851188        IMatterAgent? agent = _agent;
 14851189        if (agent == null)
 190        {
 8191            Vector2d ownerScale = Vector2d.One;
 8192            Fixed64 rotation = PlanarRotation.Canonicalize(
 8193                ResolveStandaloneRotation());
 8194            _ = Vector2d.TryTransformScaledPoint(
 8195                ResolveStandalonePosition(),
 8196                _localOffset,
 8197                ownerScale,
 8198                rotation,
 8199                out Vector2d center);
 8200            return new ColliderShapeSnapshot2D(
 8201                center,
 8202                rotation,
 8203                ownerScale,
 8204                Vector2d.One,
 8205                _localOffset,
 8206                _shapeVersion,
 8207                Fixed64.Zero,
 8208                _mixedHalfThicknessOverride ?? PhysicsSettings.DefaultMixed2DHalfThickness);
 209        }
 210
 14843211        return _body == null
 14843212            ? CreateStandaloneSnapshot(
 14843213                agent,
 14843214                useRequestedPose: false,
 14843215                default,
 14843216                default)
 14843217            : CreateStandaloneSnapshot(
 14843218                agent,
 14843219                useRequestedPose: true,
 14843220                _body.Position,
 14843221                _body.Rotation);
 222    }
 223
 224    private ColliderShapeSnapshot2D CreateCompoundPartSnapshot(
 225        in ColliderShapeSnapshot2D ownerSnapshot,
 226        Fixed64 localRotation,
 227        Vector2d localScale)
 228    {
 226229        ColliderScalePolicy.Validate(localScale);
 226230        bool representable = Vector2d.TryTransformScaledPoint(
 226231            ownerSnapshot.Center,
 226232            _localOffset,
 226233            ownerSnapshot.OwnerScale,
 226234            ownerSnapshot.Rotation,
 226235            out Vector2d center);
 226236        SwiftThrowHelper.ThrowIfArgument(
 226237            !representable,
 226238            nameof(_localOffset),
 226239            "Compound-part center must be representable in the owner's world frame.");
 226240        return new ColliderShapeSnapshot2D(
 226241            center,
 226242            PlanarRotation.Combine(ownerSnapshot.Rotation, localRotation),
 226243            ownerSnapshot.OwnerScale,
 226244            localScale,
 226245            _localOffset,
 226246            _shapeVersion,
 226247            ownerSnapshot.MixedSlabCenterY,
 226248            ownerSnapshot.MixedHalfThickness);
 249    }
 250
 251    private void PrepareRuntimeShape(
 252        in ColliderShapeSnapshot2D snapshot,
 253        bool requireRepresentableMassPoint)
 254    {
 13505255        _preparedContext ??= _context;
 13505256        _preparedSnapshot = snapshot;
 13505257        PrepareShape(snapshot);
 13496258        if (requireRepresentableMassPoint
 13496259            && !CalculatePreparedLocalMassPoint().TryGetPoint(out _))
 260        {
 1261            throw new System.InvalidOperationException(
 1262                "The 2D collider's body-local center of mass is outside the Fixed64 coordinate domain.");
 263        }
 13495264        Vector2d min = _preparedBounds.Min;
 13495265        Vector2d max = _preparedBounds.Max;
 13495266        _preparedMixedBounds = FixedBoundBox.FromMinMax(
 13495267            new Vector3d(
 13495268                min.X,
 13495269                snapshot.MixedSlabCenterY - snapshot.MixedHalfThickness,
 13495270                min.Y),
 13495271            new Vector3d(
 13495272                max.X,
 13495273                snapshot.MixedSlabCenterY + snapshot.MixedHalfThickness,
 13495274                max.Y));
 13495275    }
 276
 277    private void PublishPreparedShape()
 278    {
 13366279        _committedCenter = _preparedSnapshot.Center;
 13366280        _committedRotation = _preparedSnapshot.Rotation;
 13366281        _committedOwnerScale = _preparedSnapshot.OwnerScale;
 13366282        _committedPartScale = _preparedSnapshot.PartScale;
 13366283        _bounds = _preparedBounds;
 13366284        _mixedBounds3D = _preparedMixedBounds;
 13366285        _mixedSlabCenterY = _preparedSnapshot.MixedSlabCenterY;
 13366286        _mixedHalfThickness = _preparedSnapshot.MixedHalfThickness;
 13366287        PublishShape();
 13366288        _canonicalCenteredProxyRadius =
 13366289            ColliderCanonicalBounds2D.GetCenteredProxyRadius(this);
 13366290        _canonicalGroundProbeRadius =
 13366291            ColliderCanonicalBounds2D.GetGroundProbeRadius(this);
 13366292        _runtimeShapeState.Commit(_preparedSnapshot);
 13366293        _hasCommittedShape = true;
 13366294    }
 295
 296    internal bool TryPrepareBodyPose(
 297        Vector2d position,
 298        Fixed64 rotation)
 299    {
 300        try
 301        {
 821302            ColliderShapeSnapshot2D snapshot = _agent != null
 821303                ? CreateStandaloneSnapshot(
 821304                    _agent,
 821305                    useRequestedPose: true,
 821306                    position,
 821307                    rotation)
 821308                : CreateDetachedBodySnapshot(position, rotation);
 817309            PrepareRuntimeShape(
 817310                snapshot,
 817311                requireRepresentableMassPoint: true);
 816312            return true;
 313        }
 4314        catch (System.ArgumentException)
 315        {
 4316            return false;
 317        }
 1318        catch (System.InvalidOperationException)
 319        {
 1320            return false;
 321        }
 821322    }
 323
 324    private ColliderShapeSnapshot2D CreateDetachedBodySnapshot(
 325        Vector2d position,
 326        Fixed64 rotation)
 327    {
 2328        bool representable = Vector2d.TryTransformScaledPoint(
 2329            position,
 2330            _localOffset,
 2331            _committedOwnerScale,
 2332            rotation,
 2333            out Vector2d center);
 2334        SwiftThrowHelper.ThrowIfArgument(
 2335            !representable,
 2336            nameof(position),
 2337            "2D collider center must be representable after applying the detached body pose.");
 2338        return new ColliderShapeSnapshot2D(
 2339            center,
 2340            rotation,
 2341            _committedOwnerScale,
 2342            Vector2d.One,
 2343            _localOffset,
 2344            _shapeVersion,
 2345            _mixedSlabCenterY,
 2346            _mixedHalfThickness);
 347    }
 348
 349    internal void PublishPreparedBodyPose()
 350    {
 202351        PublishPreparedShape();
 202352    }
 353
 354    internal void PublishPreparedExplicitBodyPose()
 355    {
 613356        PublishPreparedShape();
 613357        _body?.RefreshMassPropertiesFromColliderShape();
 613358        if (_id >= 0)
 612359            _context!.Collisions2D.RefreshColliderPartitionAfterShapeChange(this);
 613360    }
 361
 362    private void PrepareStandaloneInitialization(
 363        IMatterAgent agent,
 364        bool useRequestedPose,
 365        Vector2d requestedPosition,
 366        Fixed64 requestedRotation)
 367    {
 5180368        ColliderShapeSnapshot2D snapshot = CreateStandaloneSnapshot(
 5180369            agent,
 5180370            useRequestedPose,
 5180371            requestedPosition,
 5180372            requestedRotation);
 5168373        _preparedContext = agent.Context;
 5168374        PrepareRuntimeShape(
 5168375            snapshot,
 5168376            requireRepresentableMassPoint: useRequestedPose);
 5162377    }
 378
 379    internal void PrepareCompoundPart(
 380        in ColliderShapeSnapshot2D ownerSnapshot,
 381        Fixed64 localRotation,
 382        Vector2d localScale,
 383        GravitasWorldContext context)
 384    {
 225385        SwiftThrowHelper.ThrowIfArgument(
 225386            _context != null && !ReferenceEquals(_context, context),
 225387            nameof(context),
 225388            "2D compound collider part is already bound to a different GravitasWorldContext.");
 225389        ColliderShapeSnapshot2D snapshot = CreateCompoundPartSnapshot(
 225390            ownerSnapshot,
 225391            localRotation,
 225392            localScale);
 225393        _preparedContext = context;
 225394        _preparedCompoundLocalRotation = localRotation;
 225395        PrepareRuntimeShape(
 225396            snapshot,
 225397            requireRepresentableMassPoint: false);
 222398    }
 399
 400    internal void PublishCompoundPart(
 401        Fixed64 localRotation,
 402        Vector2d localScale,
 403        GravitasWorldContext context)
 404    {
 219405        _compoundLocalRotation = localRotation;
 219406        _compoundLocalScale = localScale;
 219407        _context = context;
 219408        PublishPreparedShape();
 219409    }
 410
 411    /// <summary>Sets the bounds for the shape transaction being prepared.</summary>
 412    protected void SetPreparedBounds(FixedBoundArea bounds) =>
 13496413        _preparedBounds = bounds;
 414
 415    private protected abstract void PrepareShape(in ColliderShapeSnapshot2D snapshot);
 416
 417    private protected abstract void PublishShape();
 418}

Methods/Properties

.ctor()
get_Id()
get_ReplayOrdinal()
get_LifetimeVersion()
get_ServiceRefreshIndex()
get_IsPartitioned()
get_PartitionCoordinates()
get_PartitionKind()
get_IsMixedPartitioned()
get_MixedPartitionCoordinates()
get_MixedPartitionKind()
get_BroadPhaseVersion()
get_RuntimeShapeVersion()
get_HasHostBinding()
get_CollisionPairCount()
get_CollisionPairHolderCount()
get_CollisionPairs()
get_CollisionPairHolders()
get_Body()
get_IsStatic()
get_RequiresServiceSideRefresh()
get_Agent()
get_AgentOrNull()
get_Context()
get_IsActive()
set_IsActive(System.Boolean)
get_IsTrigger()
set_IsTrigger(System.Boolean)
get_Layer()
set_Layer(Gravitas.Support.PhysicsLayer)
get_IgnoredCollisionLayers()
set_IgnoredCollisionLayers(Gravitas.Support.PhysicsLayerMask)
get_Material()
set_Material(Gravitas.Materials.PhysicsMaterial)
get_Priority()
get_RaycastVersion()
set_RaycastVersion(System.UInt32)
get_CircleQueryVersion()
set_CircleQueryVersion(System.UInt32)
get_IsChild()
get_IsParent()
get_ParentId()
get_Parent2D()
get_Parent3D()
get_TopParent2D()
get_TopParent3D()
get_HierarchyChildCount()
get_HierarchyKey()
get_ParentKey()
get_TopParentKey()
get_HierarchyState()
Gravitas.Colliders.IColliderHierarchyNode.get_HierarchyKey()
Gravitas.Colliders.IColliderHierarchyNode.get_HierarchyParent()
get_LocalOffset()
set_LocalOffset(FixedMathSharp.Vector2d)
get_Bounds()
get_MixedBounds3D()
get_MixedHalfThickness()
get_MixedSlabCenterY()
get_MixedHalfThicknessOverride()
set_MixedHalfThicknessOverride(System.Nullable`1<FixedMathSharp.Fixed64>)
get_MinX()
get_MaxX()
get_MinY()
get_MaxY()
Initialize(Gravitas.SolidBody2D)
InitializeWithNoBody(Gravitas.IMatterAgent)
PreflightBodyInitialization(Gravitas.SolidBody2D,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
PreflightInitialization(Gravitas.IMatterAgent,System.Boolean,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
InitCore(Gravitas.IMatterAgent,Gravitas.SolidBody2D)
OnBeforeInitialize(Gravitas.IMatterAgent)
SetPhysicsState(System.Int32,System.Int32,System.Int32)
SetServiceIndex(System.Int32)
SetReplayOrdinal(System.Int32)
SetServiceRefreshIndex(System.Int32)
ClearServiceRefreshIndex()
ClearPhysicsState()
Gravitas.Colliders.IPhysicsColliderRegistryItem.SetRegistryState(System.Int32,System.Int32,System.Int32)
Gravitas.Colliders.IPhysicsColliderRegistryItem.get_ServiceIndex()
Gravitas.Colliders.IPhysicsColliderRegistryItem.get_ReplayOrder()
Gravitas.Colliders.IPhysicsColliderRegistryItem.SetRegistryServiceIndex(System.Int32)
Gravitas.Colliders.IPhysicsColliderRegistryItem.SetRegistryReplayOrdinal(System.Int32)
Gravitas.Colliders.IPhysicsColliderRegistryItem.ClearRegistryState()
ClearBindingState()
Deactivate()
Simulate()
Rebuild()
RebuildRuntimeShapeOnly()
ValidateCurrentRuntimeTransform()
SetParent(Gravitas.Colliders.LSCollider2D)
SetParent(Gravitas.Colliders.LSCollider)
ClearParent()
IsSibling(Gravitas.Colliders.LSCollider2D)
ExcludesMixedCollisionWith(Gravitas.Colliders.LSCollider)
GetOrCreatePartitionCoordinates()
GetOrCreateMixedPartitionCoordinates()
MatchesPartitionGridBounds(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Int32)
MatchesMixedPartitionGridBounds(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Int32)
MarkPartitioned(FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,System.Int32)
MarkMixedPartitioned(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Int32)
MarkUnpartitioned()
MarkMixedUnpartitioned()
ClearPartitionCoordinates()
ClearMixedPartitionCoordinates()
IsPositionInPlanarBounds(FixedMathSharp.Fixed64,FixedMathSharp.Vector3d)
IsPositionInMixedBounds(FixedMathSharp.Fixed64,FixedMathSharp.Vector3d)
TryGetCollisionPair(System.Int32,Gravitas.CollisionPair2D&)
TryAddCollisionPair(System.Int32,Gravitas.CollisionPair2D)
TryRemoveCollisionPair(System.Int32,Gravitas.CollisionPair2D&)
TryAddCollisionPairHolder(System.Int32)
TryRemoveCollisionPairHolder(System.Int32)
ClearCollisionPairState()
ClearRuntimeRelationships()
ResolveAgentRotation()
BindContext(Gravitas.GravitasWorldContext)
ReserveCompoundPart(Gravitas.Colliders.LSCompoundCollider2D,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d)
ThrowIfCompoundPartLifecycle(System.String)
TransformRelativeMassPropertyPointExact(FixedMathSharp.Vector2d)
Rotate(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
ClampNearZero(FixedMathSharp.Vector2d)
SetTrigger(System.Boolean)
ThrowIfCannotEnableTrigger(System.String)
ThrowIfTriggerWouldAttachToBody(System.String)
ThrowIfLoadedTriggerHasBody(System.String)
RecordData(Chronicler.IChronicler)
RecordShapeData(Chronicler.IChronicler)
IgnoresCollisionLayer(Gravitas.Support.PhysicsLayer)
ApplyLoadedState()
get_Position()
get_Rotation()
get_LocalScale()
TryGetLocalScale(FixedMathSharp.Vector2d&)
get_ScaledLocalOffset()
TryGetScaledLocalOffset(FixedMathSharp.Vector2d&)
get_Center()
get_VertexCount()
get_ConvexRotation()
GetScaledLocalVertexUnchecked(System.Int32)
GetConvexSupportAnchor(FixedMathSharp.Vector2d)
TryGetClosestBoundaryAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetClosestBoundaryAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Fixed64&)
TryGetVertex(System.Int32,FixedMathSharp.Vector2d&)
GetRoundBoundaryAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d)
TryGetAABoxBoundaryAnchor(Gravitas.Colliders.LSAABBoxCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetConvexBoundaryAnchor(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.ReadOnlySpan`1<FixedMathSharp.Vector2d>,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetCompoundBoundaryAnchor(Gravitas.Colliders.LSCompoundCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetCompoundBoundaryAnchor(Gravitas.Colliders.LSCompoundCollider2D,FixedMathSharp.Vector2d,FixedMathSharp.Geometry.FixedPointAnchor2d&,System.Boolean,FixedMathSharp.Geometry.FixedPointAnchor2d&)
TryGetAnchorDistance(FixedMathSharp.Vector2d,FixedMathSharp.Geometry.FixedPointAnchor2d&,FixedMathSharp.Fixed64&)
CalculateLocalCenterOfMassOffset()
CalculateLocalMassPoint()
CalculatePreparedLocalMassPoint()
CalculateMomentOfInertia(FixedMathSharp.Fixed64,FixedMathSharp.Vector2d)
OnMaterialChanged()
TransformPreparedRelativeMassPropertyPointExact(FixedMathSharp.Vector2d)
MarkShapeDirty()
RebuildRuntimeShapeState()
ResolveStandalonePosition()
ResolveStandaloneRotation()
ClearChildParentReferences()
Gravitas.Colliders.IColliderHierarchyNode.AddChild(Gravitas.Colliders.ColliderHierarchyKey)
Gravitas.Colliders.IColliderHierarchyNode.RemoveChild(Gravitas.Colliders.ColliderHierarchyKey)
Gravitas.Colliders.IColliderHierarchyNode.ClearParentReference()
Gravitas.Colliders.IColliderHierarchyNode.TryGetHierarchyColliderByKey(Gravitas.Colliders.ColliderHierarchyKey,Gravitas.Colliders.IColliderHierarchyNode&)
NotifyContact(Gravitas.Colliders.LSCollider2D,System.Boolean,System.Boolean)
NotifyContact(Gravitas.Colliders.LSCollider2D,Gravitas.SolidBody2D,System.Boolean,System.Boolean,System.Boolean,Gravitas.Colliders.ColliderLifetimeToken2D&,Gravitas.Colliders.ColliderLifetimeToken2D&,System.Boolean,System.Boolean)
NotifyMixedContact(Gravitas.Colliders.LSCollider,System.Boolean,System.Boolean,System.Boolean)
NotifyMixedContact(Gravitas.Colliders.LSCollider,System.Boolean,System.Boolean,System.Boolean,System.Boolean,Gravitas.Colliders.ColliderLifetimeToken2D&,Gravitas.Colliders.ColliderLifetimeToken&,System.Boolean)
ContributeReplayHash(Chronicler.ChronicleHashWriter&,Gravitas.GravitasReplayHashMode)
ContributeShapeReplayHash(Chronicler.ChronicleHashWriter&)
WriteReplayHierarchyKey(Chronicler.ChronicleHashWriter&,Gravitas.Colliders.ColliderHierarchyKey)
TryResolveReplayHierarchyOrdinal(Gravitas.Colliders.ColliderHierarchyKey,System.Int32&)
ContributeCompoundPartReplayHash(Chronicler.ChronicleHashWriter&,Gravitas.Colliders.CompoundColliderPart2D)
ContributeShapeDefinitionReplayHash(Chronicler.ChronicleHashWriter&,Gravitas.Colliders.ColliderShapeDefinition2D)
WriteMaterial(Chronicler.ChronicleHashWriter&,Gravitas.Materials.PhysicsMaterial)
.ctor()
get_HasCommittedShape()
get_PreparedContext()
get_PreparedShapeBounds()
get_CanonicalCenteredProxyRadius()
get_CanonicalGroundProbeRadius()
get_CanonicalCenter()
TryGetCommittedOwnerScale(FixedMathSharp.Vector2d&)
GetCurrentOwnerScale()
GetCurrentScaleFactors(FixedMathSharp.Vector2d&,FixedMathSharp.Vector2d&)
TryGetCurrentScaledOffset(FixedMathSharp.Vector2d&)
GetCurrentScaledOffset()
GetUncommittedCenter()
CreateStandaloneSnapshot(Gravitas.IMatterAgent,System.Boolean,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
CaptureShapeSnapshot()
CreateCompoundPartSnapshot(Gravitas.Colliders.ColliderShapeSnapshot2D&,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d)
PrepareRuntimeShape(Gravitas.Colliders.ColliderShapeSnapshot2D&,System.Boolean)
PublishPreparedShape()
TryPrepareBodyPose(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
CreateDetachedBodySnapshot(FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
PublishPreparedBodyPose()
PublishPreparedExplicitBodyPose()
PrepareStandaloneInitialization(Gravitas.IMatterAgent,System.Boolean,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64)
PrepareCompoundPart(Gravitas.Colliders.ColliderShapeSnapshot2D&,FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,Gravitas.GravitasWorldContext)
PublishCompoundPart(FixedMathSharp.Fixed64,FixedMathSharp.Vector2d,Gravitas.GravitasWorldContext)
SetPreparedBounds(FixedMathSharp.Geometry.FixedBoundArea)