Edit:
4.23 has this now built-in. For older Engine Versions, please look at the following:
In the end we solved this by implementing IsDataValid
for UBlueprintGeneratedClass
and calling this method instead of directly calling the CDO
of the generated class:
EDataValidationResult UBlueprintGeneratedClass::IsDataValid(TArray<FText>& ValidationErrors)
{
EDataValidationResult Result = EDataValidationResult::NotValidated;
if (SimpleConstructionScript)
{
for (const USCS_Node* Node : SimpleConstructionScript->GetAllNodes())
{
if (Node)
{
UActorComponent* ActorComponent = Node->GetActualComponentTemplate(this);
if (ActorComponent)
{
const EDataValidationResult ValidationResult = ActorComponent->IsDataValid(ValidationErrors);
// Only allow upward escalation from NotValidated -> Valid -> Invalid
if (static_cast<uint8>(ValidationResult) < static_cast<uint8>(Result))
{
Result = ValidationResult;
}
}
}
}
}
const EDataValidationResult DefaultObjectResult = GetDefaultObject()->IsDataValid(ValidationErrors);
// Only allow upward escalation from NotValidated -> Valid -> Invalid
if (static_cast<uint8>(DefaultObjectResult) < static_cast<uint8>(Result))
{
Result = DefaultObjectResult;
}
return Result;
}
This is called by the associated blueprint:
EDataValidationResult UBlueprint::IsDataValid(TArray<FText>& ValidationErrors)
{
return GeneratedClass ? GeneratedClass->IsDataValid(ValidationErrors) : EDataValidationResult::Invalid;
}
Now data validation is called for all Components, which are spawned by blueprints (these are handled in C++ using the SimpleConstructionScript
). The only thing which is missing for those components are the attachment setups, which are set, when the blueprint is actually spawned.