k/ClothesHelper.cs
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Sandbox.k.Extensions;

namespace Sandbox.k;

[Title( nameof(ClothesHelper) )]
[Category( "k.Clothing" )]
public class ClothesHelper : Component
{
	public enum ClothingSourceType
	{
		Nude = 0,
		Player = 1,
		Custom = 2
	}

	[Group( "_References" )]
	[Property]
	[Required]
	public required SkinnedModelRenderer Model { get; set; }

	[Group( "Custom" )]
	[Property]
	[Required]
	public ClothingSourceType ClothingSource { get; set; } = ClothingSourceType.Nude;

	[Property]
	[ShowIf( nameof(ClothingSource), ClothingSourceType.Custom )]
	[Group( "Custom" )]
	[TextArea]
	public string CustomClothingJson { get; set; } = "";

	[Sync] public string ClothingString { get; set; } = "";

	protected override void OnStart()
	{
		if ( !Network.IsProxy )
		{
			LoadClothing();
		}

		if ( string.IsNullOrWhiteSpace( ClothingString ) ) return;
		ApplyClothing( ClothingString );
	}

	public void LoadClothing()
	{
		switch ( ClothingSource )
		{
			case ClothingSourceType.Player:
				{
					ClothingString = Connection.Local.GetUserData( "avatar" );
					break;
				}
			case ClothingSourceType.Custom when !string.IsNullOrWhiteSpace( CustomClothingJson ):
				{
					ClothingString = CustomClothingJson;
					break;
				}
			case ClothingSourceType.Nude:
				break;
			default:
				throw new ArgumentOutOfRangeException();
		}
	}

	[Rpc.Broadcast]
	public void ApplyClothing( string from )
	{
		ClothingContainer.CreateFromJson( from ).Apply( Model );
	}

	[Rpc.Broadcast]
	public void ApplyClothing( ClothingContainer container )
	{
		container.Apply( Model );
	}

	// [Rpc.Broadcast]
	public async Task ApplyClothingAsync( ClothingContainer container )
	{
		await container.ApplyAsync( Model );
	}
}