Download

Get BP Classes from C++

Hello,
Is there a way to get blueprint classes that have a c++ base class?
For example, I have UItem.h and it is a blueprintable class. When we create items, we create a BP class based on UItem in our Items folder.

I can only think of having a datatable that has all of the itemnames and the exact file location in the table. If i have to do that, I’d like to have C++ automate that process. So when the game starts it scans the folder of items and creates the table and location.

I tried https://github.com/kamrann/KantanCod…lasses/Runtime
but it can’t get it to even instantiate a “GatherSubclasses” class. The error states the constructor is private…

Any one have any ideas or code examples for something like this?

Ok i’m sure someone needs this. The original code is here: http://kantandev.com/ Below is modified for out use but it could help you!
I have a class that is called FOGlobal. It stores some enums and handles a some mappings.
FOGlobal.h:


namespace GatherSubclasses {
    namespace Detail {
        void GetAllBlueprintSubclasses(TArray<TAssetSubclassOf <class UObject> >& OutSubClass, TSubclassOf<UObject> Base, FString const& Path);
    }

    template <typename TBase>
    void GetAllBlueprintSubclasses(TArray <TAssetSubclassOf< TBase> >& Subclasses, TSubclassOf < TBase > Base, FString const& Path) {
        TArray<TAssetSubclassOf < UObject > > Classes;
        Detail::GetAllBlueprintSubclasses(Classes, Base, Path);
        for(auto const& Cls : Classes) {
            Subclasses.Add(Cls);
        }
    }
}

UCLASS()
class FORLORNOUTCAST_API UFOGlobal : public UObject {
    GENERATED_UCLASS_BODY()
public:
    static const UDataTable* GameData;
    static const UDataTable* EffectData;
    static int32 testInt;

private:


public:
    static const FGameDataTable* GetGameDataRow(const FString Row);
    static const FEffectDataTable* GetEffectRow(const FString Row);

    static void GatherEffects(TSubclassOf<UObject> BaseClass);
    static const float GetGameData(const FString Row, EMagicLevel MagicLevel);
};


FOGlobal.cpp:


#include "FOGlobal.h"
#include <UObject/ConstructorHelpers.h>
#include <Engine/DataTable.h>
#include "AssetRegistryModule.h"
#include "Ability/FOEffect.h"
#include "Engine/Blueprint.h"
#include "Modules/ModuleManager.h"
#include "UObject/SoftObjectPtr.h"

int32 UFOGlobal::testInt;
const UDataTable* UFOGlobal::GameData;
const UDataTable* UFOGlobal::EffectData;

namespace GatherSubclasses {
    namespace Detail {
        void GetAllBlueprintSubclasses(TArray< TAssetSubclassOf< UObject > >& Subclasses, TSubclassOf <UObject> Base, FString const& Path) {
            static const FName GeneratedClassTag = TEXT("GeneratedClass");
            static const FName ClassFlagsTag = TEXT("ClassFlags");

            //get the registry
            check(Base);
            FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(FName("AssetRegistry"));
            IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();

            //add any paths you want scanned
            TArray<FString> ContentPaths;
            ContentPaths.Add(Path);
            AssetRegistry.ScanPathsSynchronous(ContentPaths);

            //returns the FName of the UFOEffect
            FName BaseClassName = Base->GetFName();
            TSet<FName> DerivedNames;

            {
                TArray<FName> BaseNames;
                BaseNames.Add(BaseClassName);

                TSet<FName> Excluded;
                //names to get, names to exclude, output
                AssetRegistry.GetDerivedClassNames(BaseNames, Excluded, DerivedNames);
            }

            FARFilter Filter;
            Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());
            Filter.bRecursiveClasses = true;
            TArray<FAssetData> AssetList;
            AssetRegistry.GetAssets(Filter, AssetList);

            for(auto const& Asset : AssetList) {
                if(auto GeneratedClassPathPtr = Asset.TagsAndValues.Find(GeneratedClassTag)) {
                    const FString ClassObjectPath = FPackageName::ExportTextPathToObjectPath(*GeneratedClassPathPtr);
                    const FString ClassName = FPackageName::ObjectPathToObjectName(ClassObjectPath);
                    if(!DerivedNames.Contains(*ClassName)) {
                        continue;
                    }
                    Subclasses.Add(TAssetSubclassOf<UObject>(FStringAssetReference(ClassObjectPath)));
                }
            }
        }
    }
}

UFOGlobal::UFOGlobal(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer) {
    static ConstructorHelpers::FObjectFinder<UDataTable>
        GameDataTable_BP(TEXT("DataTable'/Game/ForlornOutcast/Data/GameData.GameData'"));
    GameData = GameDataTable_BP.Object;

    static ConstructorHelpers::FObjectFinder<UDataTable>
        AbilityDataTable_BP(TEXT("DataTable'/Game/ForlornOutcast/Data/EffectData.EffectData'"));
    EffectData = AbilityDataTable_BP.Object;
    UE_LOG(LogTemp, Warning, TEXT("current: %d"), testInt);
}

const FGameDataTable* UFOGlobal::GetGameDataRow(const FString Row) {
    static const FString ContextString(TEXT("GENERAL"));
    FGameDataTable* DataRow = nullptr;
    if (GameData) {
        return GameData->FindRow<FGameDataTable>(*Row, ContextString);
    }
    return nullptr;
}

const FEffectDataTable* UFOGlobal::GetEffectRow(const FString Row) {
    static const FString ContextString(TEXT("GENERAL"));
    if(EffectData) {
        return EffectData->FindRow<FEffectDataTable>(*Row, ContextString);
    }
    return nullptr;
}

void UFOGlobal::GatherEffects(TSubclassOf<UObject> BaseClass) {
    TArray<TAssetSubclassOf < UObject> > DerivedSet;
    if(BaseClass) {
        GatherSubclasses::GetAllBlueprintSubclasses(DerivedSet, BaseClass, TEXT("/Game/ForlornOutcast/Blueprints/Effects"));
        UE_LOG(LogTemp, Log, TEXT("Subclasses gathered with base '%s':"), *BaseClass->GetName());
        for(auto& AssetClass : DerivedSet) {
            auto LoadedClass = AssetClass.LoadSynchronous();
            UE_LOG(LogTemp, Log, TEXT("%s %s"), AssetClass.IsNull() ? TEXT("[NONE]") : *AssetClass.GetUniqueID().ToString(), !AssetClass.IsNull() && !LoadedClass ? TEXT("_LOAD FAILED_") : TEXT(""));
        }
    }
}

GatherEffects is not something you want to do on tick! I would recommend doing this to load some classes and their reference locations into a table or something. I included some of our getters for table information…

A big thank you to KantanDev!