I am writing an editor utility tool. I scour the asset registry for blueprints with a certain ParentClass tag, and am receiving assets which when loaded are of type UBlueprint.
What I’d like to do with these blueprints is to then call a function on them (which returns a boolean determining whether or not to do an action involving one of their properties), but I’m having the hardest time trying to get a reference to the class instance itself.
The native class of my blueprints extends from UObject. The function and property I want to access is defined in the native class, and the blueprint just overrides the function (this is why I am extending from UObject and not UDataAsset). I wonder if I need to spawn the object before I can call functions / access properties on it? They are not static functions/properties.
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<
FAssetRegistryModule>("AssetRegistry");
TArray<FAssetData> AssetData;
// Value taken from Blueprint.cpp GetAssetRegistryTags()
const FString NativeParentClass = FString::Printf(
TEXT("%s'%s'"), *UET_Descriptor::StaticClass()->GetClass()->GetName(),
*UET_ToolDescriptor::StaticClass()->GetPathName());
TMultiMap<FName, FString> TagsValues;
TagsValues.Add(FName("NativeParentClass"), NativeParentClass);
AssetRegistryModule.Get().GetAssetsByTagValues(TagsValues, AssetData);
for (auto Asset : AssetData)
{
// This is valid
UBlueprint* BlueprintAsset = Cast<UBlueprint>(Asset.GetAsset());
// All attempts to cast below classes to UET_Descriptor* with Cast<UET_Descriptor>() fail.
UClass* ParentClass = GetParentNativeClass(BlueprintAsset->GeneratedClass);
UClass* BlueprintClass = BlueprintAsset->GetBlueprintClass();
FString ObjPath = Asset.ObjectPath.ToString().Append("_C");
UClass* Class = StaticLoadClass(UObject::StaticClass(), NULL, *ObjPath, NULL, LOAD_None, NULL);
I’m absolutely certain I’m just not understanding some aspect of what I’m doing here, doing something wrong, or am missing a step. Is anyone able to help?
One thing that gives me pause for thought is that for these assets to appear in a BP asset selector, they must be of type TSubclassOf<UET_Descriptor> instead of UET_Descriptor*, so I wonder if my cast method is wrong.
You can call a function without the need to spawn the actor. Just access the default object version of it.
AMyClass* tempItem = MyClass->GetDefaultObject();
tempItem->MyFunctionToCall();
(ofc AMyclass would be the actor that comes from the class and myclass is your actor class)
I use this to call functions on my inventory items when I just keep a reference to their class.
Thank you, that is good to know. I cannot cast from the blueprint class’s DefaultObject to my class type, though, as the DefaultObject is a BlueprintGeneratedClass type. I’m sitll unclear on how to get from UBlueprint to a UET_Descriptor (which is a UObject, not AActor, if that makes a difference).
Thanks, I decided not to use CallFunctionByNameWithArguments() as it felt like bypassing my issue instead of solving it, but I eventually figured it out.
I’ve ended up spawning the objects and storing them on the calling object, which is preferential for me as I need to access their methods/properties frequently. The missing piece of the puzzle was having to get the class name by appending "_C" to the blueprint name, and then spawning the object. Previously I was trying to work with the class like it was an object itself.