Hello again!
Since a few people were doubtful about my previous answer working in shipped builds, the following is code we use in our game, unmodified, that definitely works in a Shipping build. The gist of it is: Blueprints have two lists for components we care about: UInheritableComponentHandler and USimpleConstructionScript.
The USimpleConstructionScript contains templates for components declared in the current blueprint, possibly overriding a native component.
Whereas the UInheritableComponentHandler contains templates overriding a component declared in a parent blueprint (always seems to point to a node in a USimpleConstructionScript). Hence the ordering of which component template to choose as the desired candidate in the following function.
There is another AnswerHub post with a similar answer here:
How to get a component from a ClassDefaultObject?
There is a pretty good possibility of making a function like this work for any provided subclass of UActorComponent, we just haven’t need one yet
void UFastStaticLibrary::GetItemName(TSubclassOf<AActor> ActorClass, FText & Name)
{
TArray<UObject*> candidates;
//Blueprint Classes
{
UBlueprintGeneratedClass * currentClass = Cast<UBlueprintGeneratedClass>(ActorClass);
while (currentClass)
{
//UInheritableComponentHandler
if (UInheritableComponentHandler * handler = currentClass->InheritableComponentHandler) {
TArray<UActorComponent*> templates;
handler->GetAllTemplates(templates);
for (auto componentTemplate : templates)
{
candidates.AddUnique(componentTemplate);
}
}
//USimpleConstructionScript
if (USimpleConstructionScript * scs = currentClass->SimpleConstructionScript) {
for (auto node : scs->GetAllNodes())
{
candidates.AddUnique(node->ComponentTemplate);
}
}
currentClass = Cast<UBlueprintGeneratedClass>(currentClass->GetSuperClass());
}
}
//C++ Classes
{
TSubclassOf<UObject> currentClass = ActorClass;
while (currentClass)
{
TArray<UObject*> currentSubobjects;
currentClass->GetDefaultObjectSubobjects(currentSubobjects);
for (auto object : currentSubobjects)
{
candidates.AddUnique(object);
}
currentClass = currentClass->GetSuperClass();
}
}
//Loop through candidate objects until we find the first UInventoryItemComponent
for (auto object : candidates)
{
if (auto itemComponent = Cast<UInventoryItemComponent>(object))
{
Name = itemComponent->Name;
return;
}
}
}