Get default object for blueprint class

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 :slight_smile:


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;
		}
	}
}
5 Likes