The previously presented solution above has a flaw. Imagine you have an Actor base blueprint that has an ActorComponent attached to it and you have a child Actor blueprint derived from the first. If you then call ‘FindDefaultComponentByClass’ with the derived Actor class as parameter it will not find the desired component that was added to the parent class.
The solution presented below will find the desired component in any case:
UActorComponent* FindDefaultComponentByClass(const TSubclassOf<AActor> InActorClass,
const TSubclassOf<UActorComponent> InComponentClass)
{
if (!IsValid(InActorClass))
{
return nullptr;
}
// Check CDO.
AActor* ActorCDO = InActorClass->GetDefaultObject<AActor>();
UActorComponent* FoundComponent = ActorCDO->FindComponentByClass(InComponentClass);
if (FoundComponent != nullptr)
{
return FoundComponent;
}
// Check blueprint nodes. Components added in blueprint editor only (and not in code) are not available from
// CDO.
UBlueprintGeneratedClass* RootBlueprintGeneratedClass = Cast<UBlueprintGeneratedClass>(InActorClass);
UClass* ActorClass = InActorClass;
// Go down the inheritance tree to find nodes that were added to parent blueprints of our blueprint graph.
do
{
UBlueprintGeneratedClass* ActorBlueprintGeneratedClass = Cast<UBlueprintGeneratedClass>(ActorClass);
if (!ActorBlueprintGeneratedClass)
{
return nullptr;
}
const TArray<USCS_Node*>& ActorBlueprintNodes =
ActorBlueprintGeneratedClass->SimpleConstructionScript->GetAllNodes();
for (USCS_Node* Node : ActorBlueprintNodes)
{
if (Node->ComponentClass->IsChildOf(InComponentClass))
{
return Node->GetActualComponentTemplate(RootBlueprintGeneratedClass);
}
}
ActorClass = Cast<UClass>(ActorClass->GetSuperStruct());
} while (ActorClass != AActor::StaticClass());
return nullptr;
}