< Summary

Information
Class: Gravitas.Constraints.RagdollRuntime3D
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Constraints/3D/RagdollRuntime3D.cs
Line coverage
100%
Covered lines: 61
Uncovered lines: 0
Coverable lines: 61
Total lines: 164
Line coverage: 100%
Branch coverage
100%
Covered branches: 20
Total branches: 20
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Service()100%11100%
get_IsActive()100%11100%
get_LinkCount()100%11100%
get_JointCount()100%11100%
GetLink(...)100%11100%
GetJoint(...)100%11100%
ActivateDynamic()100%11100%
DeactivateToKinematic()100%11100%
RecordData(...)100%22100%
ApplyActivationState(...)100%1818100%
Invalidate()100%11100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Constraints/3D/RagdollRuntime3D.cs

#LineLine coverage
 1//=======================================================================
 2// RagdollRuntime3D.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 System.Runtime.CompilerServices;
 10
 11namespace Gravitas.Constraints;
 12
 13/// <summary>
 14/// Runtime handle for a context-owned 3D ragdoll articulation.
 15/// </summary>
 16public sealed class RagdollRuntime3D : IRecordable
 17{
 18    private readonly GravitasConstraint3DService _service;
 19    private readonly SolidBody[] _links;
 20    private readonly Joint3D[] _joints;
 21    private bool _isActive;
 22
 3723    internal RagdollRuntime3D(
 3724        GravitasConstraint3DService service,
 3725        int id,
 3726        SolidBody[] links,
 3727        Joint3D[] joints,
 3728        RagdollSelfCollisionPolicy selfCollisionPolicy,
 3729        bool startsActive)
 30    {
 3731        _service = service;
 3732        Id = id;
 3733        _links = links;
 3734        _joints = joints;
 3735        SelfCollisionPolicy = selfCollisionPolicy;
 3736        IsRegistered = true;
 3737        ApplyActivationState(startsActive, emitDiagnostics: false);
 3738    }
 39
 440    internal GravitasConstraint3DService Service => _service;
 41
 42    internal RagdollRuntime3D? PreviousRegistered { get; set; }
 43
 44    internal RagdollRuntime3D? NextRegistered { get; set; }
 45
 46    /// <summary>
 47    /// Gets this context-local ragdoll ID.
 48    /// </summary>
 49    public int Id { get; }
 50
 51    /// <summary>
 52    /// Gets ragdoll-internal collision filtering behavior.
 53    /// </summary>
 54    public RagdollSelfCollisionPolicy SelfCollisionPolicy { get; }
 55
 56    /// <summary>
 57    /// Gets whether this articulation remains registered with its owning constraint service.
 58    /// </summary>
 59    public bool IsRegistered { get; private set; }
 60
 61    /// <summary>
 62    /// Gets whether the ragdoll links are currently dynamic.
 63    /// </summary>
 2064    public bool IsActive => _isActive;
 65
 66    /// <summary>
 67    /// Gets the number of links in this ragdoll.
 68    /// </summary>
 5569    public int LinkCount => _links.Length;
 70
 71    /// <summary>
 72    /// Gets the number of joints in this ragdoll.
 73    /// </summary>
 4274    public int JointCount => _joints.Length;
 75
 76    /// <summary>
 77    /// Gets a ragdoll link by runtime index.
 78    /// </summary>
 2579    public SolidBody GetLink(int index) => _links[index];
 80
 81    /// <summary>
 82    /// Gets a ragdoll joint by runtime index.
 83    /// </summary>
 5184    public Joint3D GetJoint(int index) => _joints[index];
 85
 86    /// <summary>
 87    /// Switches all links to dynamic simulation and enables ragdoll joints.
 88    /// </summary>
 89    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 690    public void ActivateDynamic() => ApplyActivationState(isActive: true, emitDiagnostics: true);
 91
 92    /// <summary>
 93    /// Switches all links to kinematic host control and disables ragdoll joints.
 94    /// </summary>
 95    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 496    public void DeactivateToKinematic() => ApplyActivationState(isActive: false, emitDiagnostics: true);
 97
 98    /// <summary>
 99    /// Records runtime activation state for deterministic continuation.
 100    /// </summary>
 101    public void RecordData(IChronicler chronicler)
 102    {
 7103        SwiftThrowHelper.ThrowIfTrue(
 7104            !IsRegistered,
 7105            nameof(RagdollRuntime3D),
 7106            "Removed ragdolls cannot participate in serialization.");
 5107        bool isActive = _isActive;
 5108        RecordValues.Look(chronicler, ref isActive, "IsActive", false);
 5109        if (chronicler.Mode != SerializationMode.Loading)
 3110            return;
 111
 2112        ApplyActivationState(isActive, emitDiagnostics: true);
 2113    }
 114
 115    private void ApplyActivationState(bool isActive, bool emitDiagnostics)
 116    {
 49117        SwiftThrowHelper.ThrowIfTrue(
 49118            !IsRegistered,
 49119            nameof(RagdollRuntime3D),
 49120            "Removed ragdolls cannot mutate simulation state.");
 121
 45122        BodyMotionType targetMotionType = isActive
 45123            ? BodyMotionType.Dynamic
 45124            : BodyMotionType.Kinematic;
 125
 126        // Validate every link and publish every required host pose before any
 127        // runtime role or joint state changes. This keeps the ragdoll atomic if
 128        // a host transform cannot represent one of the authoritative poses.
 308129        for (int i = 0; i < _links.Length; i++)
 110130            _links[i].PrepareMotionTypeTransition(targetMotionType);
 131
 304132        for (int i = 0; i < _links.Length; i++)
 133        {
 108134            if (_links[i].MotionType != targetMotionType)
 16135                _links[i].CommitMotionTypeTransition(targetMotionType);
 136
 108137            if (isActive)
 91138                _links[i].Wake();
 139        }
 140
 44141        if (isActive)
 142        {
 182143            for (int i = 0; i < _joints.Length; i++)
 56144                _joints[i].IsEnabled = true;
 145        }
 146        else
 147        {
 34148            for (int i = 0; i < _joints.Length; i++)
 8149                _joints[i].IsEnabled = false;
 150        }
 151
 44152        _isActive = isActive;
 44153        if (emitDiagnostics)
 7154            _links[0].Context.Diagnostics.EmitRagdollActivated(Id, LinkCount, JointCount, isActive);
 44155    }
 156
 157    internal void Invalidate()
 158    {
 37159        IsRegistered = false;
 37160        _isActive = false;
 37161        PreviousRegistered = null;
 37162        NextRegistered = null;
 37163    }
 164}