Revision Difference
Clothing#548177
<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.⤶
/// </summary>⤶
[ConCmd.Admin]⤶
public static void ListAllClothing()⤶
{⤶
foreach (var item in ResourceLibrary.GetAll<Clothing>())⤶
{⤶
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>⤶
/// Set the clothes to whatever the player is wearing⤶
/// </summary>⤶
public void UpdateClothes(Client cl)⤶
{⤶
Clothing ??= new();⤶
Clothing.LoadFromClient(cl);⤶
}⤶
}⤶
```⤶
```csharp⤶
`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.⤶
```csharp⤶
`MyPlayer.Clothes.cs`⤶
⤶
public partial class MyPlayer⤶
{⤶
public ClothingContainer Clothing { get; protected set; }⤶
⤶
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)⤶
{⤶
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.⤶
```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)⤶
{⤶
Clothing ??= new ClothingContainer();⤶
⤶
// 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"));⤶
⤶
// ... Set the rest of the player's clothing manually ...⤶
// (See above)⤶
}⤶
⤶
/// <summary>⤶
/// Deserialises client accessories and equips them.⤶
/// "Accessories" may include Hair, Skin, Etc.⤶
/// </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");⤶
}⤶
}⤶
}⤶
```