Revision Difference
Clothing#548612
<cat>Code.Player</cat>
<title>Clothing</title>
# 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 ID's?
Resource ID's are how s&box internally holds a reference to clothing, among other assets. You can view a list of available clothing names and resource id's by adding the below console command to your game.
```csharp
/// <summary>
/// Debug console command to list all available s&box clothing.
/// Debug console command to list all available player clothing.
/// </summary>
[ConCmd.Admin]
public static void ListAllClothing()
{
foreach (var item in ResourceLibrary.GetAll<Clothing>())
foreach ( var item in ResourceLibrary.GetAll<Clothing>() )
{
Log.Info($"{item.Title} - {item.ResourceId}");
Log.Info( $"{item.Title} - {item.ResourceId}" );
}
}
```
# Dressing Player's
Gamemodes must implement a clothing system in order to prevent naked Pawn's 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 NPC's.
```csharp
`MyPlayer.Clothing.cs`
public partial class MyPlayer
{
public ClothingContainer Clothing { get; protected set; }
⤶
/// <summary>⤶
⤶
/// <summary>⤶
/// Set the clothes to whatever the player is wearing
/// </summary>
public void UpdateClothes(Client cl)
public void UpdateClothes( Client cl )
{
Clothing ??= new();
Clothing.LoadFromClient(cl);
Clothing.LoadFromClient( cl );
}
}
```
```csharp
`MyPlayer.cs`
public partial class MyPlayer : Player
{
public override void Respawn()
{
UpdateClothes(Client);
Clothing.DressEntity(this);
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.
```csharp
`MyPlayer.Clothes.cs`
public partial class MyPlayer
{
public ClothingContainer Clothing { get; protected set; }
private static readonly int[] TeamAClothing =
private static readonly int[] TeamAClothing =
{⤶
1846461341, // Police Cap.⤶
-923065548, // Suit Jacket.⤶
1761917151, // Tactical Vest.⤶
1194605997, // Smart Trousers.⤶
-1377292782 // Black Boots.⤶
};⤶
⤶
private static readonly int[] TeamBClothing =⤶
{⤶
-394380878, // Prison Jumpsuit.⤶
591027714 // Sneakers.⤶
};⤶
⤶
/// <summary>⤶
/// Set the clothes depending on the players team⤶
/// </summary>⤶
public void UpdateClothes( Client cl )⤶
{⤶
Clothing ??= new ClothingContainer();⤶
⤶
var player = cl.Pawn as MyPlayer;⤶
⤶
// Clear out any previously equipped clothing.⤶
Clothing.Clothing.Clear();⤶
⤶
// NOTE: You could refactor this code into a `GetTeamClothing` method.⤶
if ( player.Team == Team.A )⤶
{
1846461341, // Police Cap.
-923065548, // Suit Jacket.⤶
1761917151, // Tactical Vest.⤶
1194605997, // Smart Trousers.⤶
-1377292782 // Black Boots.⤶
};⤶
⤶
private static readonly int[] TeamBClothing =⤶
{⤶
-394380878, // Prison Jumpsuit.⤶
591027714 // Sneakers.⤶
};⤶
⤶
/// <summary>⤶
/// Set the clothes depending on the players team⤶
/// </summary>⤶
public void UpdateClothes(Client cl)⤶
{⤶
Clothing ??= new ClothingContainer();⤶
⤶
var player = cl.Pawn as MyPlayer;⤶
⤶
// Clear out any previously equipped clothing.⤶
Clothing.Clothing.Clear();⤶
⤶
// NOTE: You could refactor this code into a `GetTeamClothing` method.⤶
if (player.Team == Team.A)⤶
foreach ( var itemId in TeamAClothing )
{
foreach (var itemId in TeamAClothing)
{⤶
Clothing.Toggle(ResourceLibrary.Get<Clothing>(itemId));⤶
}⤶
Clothing.Toggle( ResourceLibrary.Get<Clothing>( itemId ) );
}
else⤶
}⤶
else⤶
{⤶
foreach ( var itemId in TeamBClothing )⤶
{
foreach (var itemId in TeamBClothing)
{⤶
Clothing.Toggle(ResourceLibrary.Get<Clothing>(itemId));⤶
}⤶
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.
```csharp
`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)
public void UpdateClothes( Client cl )
{
Clothing ??= new ClothingContainer();
// Clear out any previously equipped clothing.⤶
⤶
// Clear out any previously equipped clothing.
Clothing.Clothing.Clear();
// Only loads certain client configured clothing items.
// E.g. Hair, Skin, etc.
DeserializeAccessories(cl.GetClientData("avatar"));
DeserializeAccessories( cl.GetClientData( "avatar" ) );
// ... Set the rest of the player's clothing manually ...
// (See above)
}
/// <summary>
/// Deserialises client accessories and equips them.
/// Deserializes client accessories and equips them.
/// "Accessories" may include Hair, Skin, Etc.
/// </summary>
/// <param name="json"></param>
private void DeserializeAccessories(string json)
private void DeserializeAccessories( string json )
{
if (string.IsNullOrWhiteSpace(json))
if ( string.IsNullOrWhiteSpace( json ) )
{
return;
}
try
{
var entries = JsonSerializer.Deserialize<ClothingContainer.Entry[]>(json);
foreach (var entry in entries!)
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);
var item = ResourceLibrary.Get<Clothing>( entry.Id );
if ( item == null ) continue;
if ( !WhitelistedAccessories.Contains( item.Category ) ) continue;
Clothing.Toggle( item );
}
}
catch (System.Exception e)
catch ( System.Exception e )
{
Log.Warning(e, "Error deserializing accessories");
Log.Warning( e, "Error deserializing accessories" );
}
}
}
```