Code/CharacterKit/UnifiedWardrobe.cs

Utility for resolving and fitting "human" clothing models to a unified character body. It chooses which model path to use for an item (native, male/female human variants), checks whether head replacements should keep the human neck skin, loads the model, and calls AutomaticWardrobeFit.Fit to retarget meshes and apply morphs to the renderer.

Native Interop
namespace CharacterEditor;
/// <summary>Authored human cuts fitted automatically to both unified body endpoints.</summary>
public static partial class UnifiedWardrobe
{
	/// <summary>Head replacements can retain skin or deliberately replace the entire neck.</summary>
	public static bool RetainsHumanNeck(Clothing item)
	{
		if (string.IsNullOrEmpty(item.HumanSkinModel)) return true;
		var skin = Model.Load(item.HumanSkinModel);
		// Use the replacement's native skin presentation. A transparent/non-skin
		// head material must not be replaced with the unified human's skin neck.
		return skin.MeshInfo.Meshes.Where(m => m.Name == "head_01")
			.SelectMany(m => m.DrawCalls).Any(d => d.Material?.ShaderName == "shaders/skin.shader");
	}

	public static string ModelPath(Clothing item, IEnumerable<Clothing> selected, TagSet tags, CharacterAppearanceData data)
	{
		var native = item.GetModel(selected.ToArray(), tags);
		if (data.BaseShape is null)
			return native;
		// Preserve conditional model overrides selected by native clothing metadata.
		if (native != item.Model && native != item.HumanAltModel && native != item.HumanAltFemaleModel)
			return native;
		// Explicit preference selects only the authored cut; the morph still uses
		// the actual body blend. Single-variant items retain their usual fallback.
		if (data.BaseShape.ClothingVariant is not null && !string.IsNullOrEmpty(item.HumanAltModel) && !string.IsNullOrEmpty(item.HumanAltFemaleModel))
		{
			var choice = data.BaseShape.ClothingVariant == "male" ? item.HumanAltModel : item.HumanAltFemaleModel;
			return choice;
		}

		// A single authored human variant is usable across the full body range.
		var preferred = data.BaseShape.MaleBody >= .5f ? item.HumanAltModel : item.HumanAltFemaleModel;
		if (string.IsNullOrEmpty(preferred))
			preferred = string.IsNullOrEmpty(item.HumanAltModel) ? item.HumanAltFemaleModel : item.HumanAltModel;
		return !string.IsNullOrEmpty(preferred) ? preferred : native;
	}

	public static Model Resolve(Clothing item, IEnumerable<Clothing> selected, TagSet tags, CharacterAppearanceData data)
	{
		var path = ModelPath(item, selected, tags, data);
		var native = Model.Load(path);
		if (data.BaseShape is null || string.IsNullOrEmpty(path) || (string.IsNullOrEmpty(item.HumanAltModel) && string.IsNullOrEmpty(item.HumanAltFemaleModel)))
			return native;
		if (item.Category.ToString().StartsWith("FacialHair") || item.Category.ToString().StartsWith("Hair"))
			return native;
		bool female = path == item.HumanAltFemaleModel && path != item.HumanAltModel;
		if (path != item.HumanAltModel && path != item.HumanAltFemaleModel)
			female = tags.Has("female");
		return AutomaticWardrobeFit.Fit(native, female, fitFace: (item.HideBody & Clothing.BodyGroups.Head) == 0);
	}

	public static void Apply(SkinnedModelRenderer renderer, CharacterAppearanceData data)
	{
		if (data.BaseShape is not null && AutomaticWardrobeFit.IsFitted(renderer.Model))
			renderer.Morphs.Set("ce_body_female", 1 - data.BaseShape.MaleBody);
	}
}// Keep hair outside body fitting.