Player skins require too many material instances

I solved this using Dynamic Material and Data Tables.

SkinComponent holds pointers to UpdatedComponent (MeshComponent) and SkinDataTable.
On BeginPlay it creates and assigns dynamic material to UpdatedComponent.
When SetSkinName is called SkinComponent fetches textures from data table and sets material parameters.

This way I need only 2 (not 30) material instances per module and I can quickly populate data table with script (no manual drag and drop).

void USkinComponent::BeginPlay()
{
	Super::BeginPlay();
	
	check(SkinDataTable);

	if (!UpdatedComponent) return;
	Material = UpdatedComponent->CreateAndSetMaterialInstanceDynamic(0);
	
	SetSkinName(SkinName);
}

void USkinComponent::SetSkinName(const FName& Name)
{
	if (SkinName == NAME_None) return;
	
	FSkinData* SkinData = SkinDataTable->FindRow<FSkinData>(Name, ContextString);
	if (!SkinData) return;

	SkinName = Name;
	
	if (!Material) return;
	Material->SetTextureParameterValue(BaseColor, SkinData->BaseColor.LoadSynchronous());
	Material->SetTextureParameterValue(Normal, SkinData->Normal.LoadSynchronous());
	Material->SetTextureParameterValue(OcclusionRoughnessMetallic, SkinData->OcclusionRoughnessMetallic.LoadSynchronous());
}

This is csv for data table:

Name,BaseColor,Normal,OcclusionRoughnessMetallic
0,"Texture2D'/Game/Meshes/HullLight/Textures/T_HullLight_00_D.T_HullLight_00_D'","Texture2D'/Game/Meshes/HullLight/Textures/T_HullLight_00_N.T_HullLight_00_N'","Texture2D'/Game/Meshes/HullLight/Textures/T_HullLight_00_M.T_HullLight_00_M'"
1,"Texture2D'/Game/Meshes/HullLight/Textures/T_HullLight_01_D.T_HullLight_01_D'","Texture2D'/Game/Meshes/HullLight/Textures/T_HullLight_00_N.T_HullLight_00_N'","Texture2D'/Game/Meshes/HullLight/Textures/T_HullLight_00_M.T_HullLight_00_M'"