What is Clothing?
s&box ships with pre-made clothing that developers and players alike can use to dress their character (pawn). You can view some of the available clothing from the main menu. In some gamemodes, developers may wish to manually set the clothing of players, for example to create a visual distinction between teams. You can do so by loading the clothing via the ResourceLibrary
system using the clothing's Resource ID
.
Resource IDs?
Resource IDs are how s&box internally holds a reference to clothing, among other assets. You can view a list of available clothing names and resource IDs by adding the below console command to your game.
/// <summary>
///
/// </summary>
[ConCmd.Admin]
public static void ListAllClothing()
{
foreach ( var item in ResourceLibrary.GetAll<Clothing>() )
{
Log.Info( $"{item.Title} - {item.ResourceId}" );
}
}
Dressing Players
Gamemodes must implement a clothing system in order to prevent naked pawns from spawning. You can do so either automatically (using the players selected clothing) or manually (for team based gamemodes, etc). s&box comes with a ClothingContainer
class that abstracts away the loading of clothes and prevents potential collisions when adding clothes (e.g. two shirts, two shoes, etc.)
Automatically
The following code will dress the player in whatever clothing they have selected from the main menu. Note that Clothing.DressEntity
can dress any Pawn instance, such as NPCs.
`MyPlayer.Clothing.cs`
public partial class MyPlayer
{
public ClothingContainer Clothing { get; protected set; }
/// <summary>
///
/// </summary>
public void UpdateClothes( Client cl )
{
Clothing ??= new();
Clothing.LoadFromClient( cl );
}
}
`MyPlayer.cs`
public partial class MyPlayer : Player
{
public override void Respawn()
{
UpdateClothes( Client );
Clothing.DressEntity( this );
}
}
Manually
You can also manually set player clothing, ignoring what they may have previously configured in the main menu. This is often important for team-based gamemodes.
`MyPlayer.Clothes.cs`
public partial class MyPlayer
{
public ClothingContainer Clothing { get; protected set; }
private static readonly int[] TeamAClothing =
{
1846461341,
-923065548,
1761917151,
1194605997,
-1377292782
};
private static readonly int[] TeamBClothing =
{
-394380878,
591027714
};
/// <summary>
///
/// </summary>
public void UpdateClothes( Client cl )
{
Clothing ??= new ClothingContainer();
var player = cl.Pawn as MyPlayer;
Clothing.Clothing.Clear();
if ( player.Team == Team.A )
{
foreach ( var itemId in TeamAClothing )
{
Clothing.Toggle( ResourceLibrary.Get<Clothing>( itemId ) );
}
}
else
{
foreach ( var itemId in TeamBClothing )
{
Clothing.Toggle( ResourceLibrary.Get<Clothing>( itemId ) );
}
}
}
}
Whitelisting Clothing Categories
To enable some degree of customisation, you may want to allow players to configure their hair, skin, etc, while forcing them to wear a specific shirt and pair of shoes. To do this, you can whitelist certain clothing categories and manually deserialise what the player has equipped.
`MyPlayer.Clothes.cs`
public partial class MyPlayer
{
public ClothingContainer Clothing { get; protected set; }
private static readonly Clothing.ClothingCategory[] WhitelistedAccessories =
{
Sandbox.Clothing.ClothingCategory.Skin, Sandbox.Clothing.ClothingCategory.Facial,
Sandbox.Clothing.ClothingCategory.Hair
};
public void UpdateClothes( Client cl )
{
Clothing ??= new ClothingContainer();
Clothing.Clothing.Clear();
DeserializeAccessories( cl.GetClientData( "avatar" ) );
}
/// <summary>
///
///
/// </summary>
/// <param name="json"></param>
private void DeserializeAccessories( string json )
{
if ( string.IsNullOrWhiteSpace( json ) )
{
return;
}
try
{
var entries = JsonSerializer.Deserialize<ClothingContainer.Entry[]>( json );
foreach ( var entry in entries! )
{
var item = ResourceLibrary.Get<Clothing>( entry.Id );
if ( item == null ) continue;
if ( !WhitelistedAccessories.Contains( item.Category ) ) continue;
Clothing.Toggle( item );
}
}
catch ( System.Exception e )
{
Log.Warning( e, "Error deserializing accessories" );
}
}
}