Download

Possible to loop through all blueprint sub-classes?

Is there any pre-existing way to loop through all blueprints that inherit from a specific parent class or should I look into creating my own method for it?

I’ve created an inventory system using items defined by blueprint sub-classes and when saving the players info I store item ID’s which when loaded need to find their matching blueprint to get the proper item information from. Since this is only done once on launch and stored differently later the initial performance hit against looping through all blueprints shouldn’t be a problem.

Any ideas/suggestions for achieving this or similar are appreciated.

There’s kind of 2 ways of accomplishing this which depending on the set up could have different performance characteristics.

The most straightforward way to accomplish that would be:



for (TObjectIterator<UClass>  It; It; ++It)
{
    if (It->IsChildOf<ParentClass>())
    {
        // It is a child of the Parent Class
        UClass* ChildClass = *It;
    }
}


But since there are a lot of class objects and maybe there are not nearly as many of your inventory class you could instead go looking for the Class Default Object of each class.



for (TObjectIterator<ParentClass>  It; It; ++It)
{
    if (It->HasAnyFlags(RF_ClassDefaultObject))
    {
        // It is the class default object instance of a child class of parent class
        UClass* ChildClass = It->GetClass();
    }
}


One potential problem with both these approaches is blueprint classes and their class default objects will not be loaded in to memory unless something causes them to be (generally via direct referencing).

If that is a problem for you then what you many need to do is use the AssetRegistry to get all the blueprints and then work out from there which ones are children of your root class. If you look at FClassHierarchy::PopluateClassHierarchy you’ll see how this is done for the class pickers in the editor details panels.

Thanks Marc!

The above worked great and I’ve got everything working including loading unused blueprints in certain maps with using PopulateClassHierarchy as a reference.

Would you be willing to share the code privately? I’m looking for a solution to have all child classes of a BP be accessable as an array and im very new to c++ and brand new to Unreals c++ api, all I know how to do is basic bp function librarys with int or string returns, simple stuff like that. I have no idea how to use the PopulateClassHierarcy class to get my blueprint classes into memory (they arnt in the level and I dont want them to be, since they are data only)

No need to make it private. Glad to help anyone that is looking for a solution to this problem and making it public only helps any others in the future. :slight_smile:

Here’s the code trimmed down and slightly modified from what I’m currently using:



        // Retrieve all blueprint classes 
	TArray<TSubclassOf<**YOURBLUEPRINTCLASS**>> ItemReferences;
	TArray<FAssetData> BlueprintList;

	FARFilter Filter;
	Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());
	Filter.ClassNames.Add(UBlueprintGeneratedClass::StaticClass()->GetFName());
	AssetRegistryModule.Get().GetAssets(Filter, BlueprintList);

	for (int32 AssetIdx = 0; AssetIdx < BlueprintList.Num(); ++AssetIdx)
	{
		if (BlueprintList[AssetIdx].GetAsset() != NULL)
		{
			if (UObject* ChildObject = Cast<UObject>(BlueprintList[AssetIdx].GetAsset()))
			{
				UBlueprint* BlueprintObj = Cast<UBlueprint>(StaticLoadObject(UBlueprint::StaticClass(), NULL, *ChildObject->GetPathName()));

				if (BlueprintObj != NULL && BlueprintObj->GeneratedClass != NULL && BlueprintObj->GeneratedClass->GetDefaultObject() != NULL)
				{
					if (Cast<**YOURBLUEPRINTCLASS**>(BlueprintObj->GeneratedClass->GetDefaultObject()) != NULL)
					{
						ItemReferences.Add(*BlueprintObj->GeneratedClass);
					}
				}
			}
		}
	}


Note that for the ItemReferences array you’ll likely want to put it in the header and mark it with UPROPERTY() so references don’t get garbage collected or such. To make use of the items within the array themselves you’ll have to cast them to their class and get the default object when referencing them as such:



**YOURBLUEPRINTCLASS*** TempObj = Cast<**YOURBLUEPRINTCLASS**>(ItemReferences[index]->GetDefaultObject());


I’m a little confused, where would I write this code?

It’s worth noting that this code will not work in a packaged build because Blueprints arent packaged, only their generated classes. I found this out the hard way.