RagdollImpulseApplier.cs

Component that waits until a newly created ragdoll has ModelPhysics bodies, then applies a single impulse distributed evenly across those physics bodies and destroys itself.

Native Interop
using Sandbox;
using System.Linq;

/// <summary>
/// Waits for a newly created ragdoll's physics bodies, distributes an impulse
/// across them once, then removes itself.
/// </summary>
public sealed class RagdollImpulseApplier : Component
{
	public Vector3 Impulse { get; set; }

	protected override void OnUpdate()
	{
		// Only the network owner simulates and pushes the ragdoll. Proxies receive
		// the resulting ModelPhysics transforms from that authoritative instance.
		if ( IsProxy )
			return;

		if ( Impulse.LengthSquared <= 0f )
		{
			Destroy();
			return;
		}

		var modelPhysics = GetComponent<ModelPhysics>();
		if ( modelPhysics is null || modelPhysics.Bodies is null )
			return;

		// ModelPhysics keeps ragdoll rigidbodies in its Bodies collection rather
		// than exposing them as normal components in the GameObject hierarchy.
		var bodies = modelPhysics.Bodies
			.Where( body => body.Component.IsValid() && body.Component.PhysicsBody.IsValid() )
			.ToArray();

		if ( bodies.Length == 0 )
			return;

		// Divide the total impulse across all bones so models with more physics
		// bodies do not receive a proportionally stronger launch.
		var impulsePerBody = Impulse / bodies.Length;
		foreach ( var body in bodies )
			body.Component.PhysicsBody.ApplyImpulse( impulsePerBody );

		Destroy();
	}
}