PlayerEmote.cs

Component attached to a player that toggles an emote (sitting) state. It reads input to toggle emote, cancels emote if the character moves, and updates either a CitizenAnimationHelper or a SkinnedModelRenderer properties before render.

Native Interop
using Sandbox;
using Sandbox.Citizen;

public sealed class PlayerEmote : Component
{
    [Property] public SkinnedModelRenderer BodyRenderer { get; set; }

    private bool isEmoting;

    protected override void OnEnabled()
    {
        base.OnEnabled();

        if ( !BodyRenderer.IsValid() )
            BodyRenderer = Components.GetInChildren<SkinnedModelRenderer>();
    }

    protected override void OnUpdate()
    {
        base.OnUpdate();

        if ( IsProxy ) return;

        if ( Input.Pressed( "Emote" ) )
        {
            isEmoting = !isEmoting;
        }

        var controller = Components.Get<CharacterController>();
        if ( controller.IsValid() && controller.Velocity.Length > 5f && isEmoting )
        {
            isEmoting = false;
        }
    }

    protected override void OnPreRender()
    {
        base.OnPreRender();

        if ( !BodyRenderer.IsValid() ) return;

        var anim = Components.Get<CitizenAnimationHelper>() ?? Components.GetInChildren<CitizenAnimationHelper>();

        if ( isEmoting )
        {
            if ( anim.IsValid() )
            {
                anim.IsSitting = true;
                anim.Sitting = CitizenAnimationHelper.SittingStyle.Floor;
            }
            else
            {
                BodyRenderer.Set( "b_sit", true );
                BodyRenderer.Set( "sit", 1 );
            }
        }
        else
        {
            if ( anim.IsValid() )
            {
                anim.IsSitting = false;
            }
            else
            {
                BodyRenderer.Set( "b_sit", false );
                BodyRenderer.Set( "sit", 0 );
            }
        }
    }
}