List of blueprints which are accessible through C++

Hello there,

I am trying to make a list of blueprint-references in the editor which can then be accessed in C+±Code. I tried it with a Blueprint-Struct:

29437-unbenannt.jpg

Then I can make a variable of that Blueprint-Struct in C++:

static ConstructorHelpers::FObjectFinder<UUserDefinedStruct> All_Gear_Obj(TEXT("UserDefinedStruct'/Game/Pickups/Gear/All_Gear.All_Gear'"));
	if (All_Gear_Obj.Object != NULL)
		All_Gear = All_Gear_Obj.Object;

But how can I access those entries in the blueprint-struct? Say I want to know the Number/Name of “Shabby Pants”? Or is there another (perhaps better) way to tackle this problem?

Thanks in advance

This might help you https://docs.unrealengine.com/latest/INT/Programming/Assets/AsyncLoading/index.html

I’m making a board game and I have blueprints representing game cards. Depending on the game mode I want to load a specific set of cards so I create an asset library in c++ that finds just those blueprints and stores their names so they can be loaded in the future.

That actually looks very useful. I will try it out. Thanks falola!

Ok so I created an object library blueprint and put two Blueprint-Items in there for testing:

31696-objectlibrary.jpg

I referenced it in the constructor aswell as calling a function to test it:

Constructor

static ConstructorHelpers::FObjectFinder<UObjectLibrary> All_Gear_Obj(TEXT("ObjectLibrary'/Game/Pickups/Gear/All_Gear.All_Gear'"));
	if (All_Gear_Obj.Object != NULL)
		All_Gear_Library = All_Gear_Obj.Object;

//Determine the ID for this Item
	PickupID = DetermineID(All_Gear_Library);

Function

int32 ASomPickup::DetermineID(UObjectLibrary* Library)
{
	TArray<FAssetData> AssetDatas;

	if (!Library->IsValidLowLevel())
		return -2;

	Library->GetAssetDataList(AssetDatas);

	print(FString::FromInt(AssetDatas.Num()));

	return -1;
}

But so far, it just prints out “0”, which can only mean that the asset data array has a length of 0 and no assets have been found. Do you know what could be the problem?
Thanks in advance

I haven’t actually tried to use an ObjectLibrary created in the editor, I’ve only created one in c++

Example:

UObjectLibrary* ObjectLibrary;
	ObjectLibrary = UObjectLibrary::CreateLibrary(AInvestigator::StaticClass(), true, GIsEditor);
	ObjectLibrary->AddToRoot();
	ObjectLibrary->LoadBlueprintAssetDataFromPath(TEXT("/Game/Characters/Player/Blueprints"));
	TArray<FAssetData> AssetDatas;
	ObjectLibrary->GetAssetDataList(AssetDatas);

	for (int32 i = 0; i < AssetDatas.Num(); ++i)
	{
		FAssetData& AssetData = AssetDatas[i];
		auto Name = AssetData.AssetName.ToString();
		InvestigatorNames.Add(Name);
	}

You could try in c++ to make sure that your blueprints are getting added to the library correctly.

Thanks again for answering falola. I thought about that, too. And it is actually a more flexible way.
But since I am saving/loading this to a mysql-database, I need to make sure that the assets are getting a permanent/non-changing index in the asset list.
And I think this cannot be assured when all the assets from a folder are being loaded. Especially becuase the folder structure is going to grow.

Hi,

I’am having the exact same problem.

Any solution yet ?

Thanks

Cedric

Here is some code snippet from my pickup spawner which spawns a random Blueprint out of a given folder path inside the editor of the class “ASomPickup”. Hope it helps.

           FString PickupSubPath = "None";
			int32 ChosenArrayIndex = -1;

			//Get Type of pickup
			while (PickupSubPath == "None")
			{
				//new randoms
				TempRandFloat = FMath::FRand();
				TempRandInt = FMath::RandRange(0, Probability_Array.Num() - 1);

				if (TempRandFloat <= Probability_Array[TempRandInt])
					ChosenArrayIndex = TempRandInt;


				if (ChosenArrayIndex > -1)
				{
					if (ChosenArrayIndex == 0)
						PickupSubPath = "Gear";
					if (ChosenArrayIndex == 1)
						PickupSubPath = "Food";
					if (ChosenArrayIndex == 2)
						PickupSubPath = "Drink";
					if (ChosenArrayIndex == 3)
						PickupSubPath = "Spellbook";
					if (ChosenArrayIndex == 4)
						PickupSubPath = "Weapon";
					if (ChosenArrayIndex == 5)
						PickupSubPath = "Misc";
				}
			}



			//Create object library 
			TArray<FAssetData> AssetDatas;
			TArray<FAssetData> RelevantAssetDatas;
			FAssetData ChosenAssetData;
			UObjectLibrary* ObjLib = UObjectLibrary::CreateLibrary(ASomPickup::StaticClass(), true, GIsEditor);

			//Load data of the "pickup" classes into the object library
			ObjLib->AddToRoot();
			ObjLib->LoadBlueprintAssetDataFromPath(TEXT("/Game/Pickups/" + PickupSubPath));

			ObjLib->GetAssetDataList(AssetDatas);


			if (AssetDatas.Num() > 0)
			{
				if (AssetDatas.Num() == 1)
				{
					//Get the only Asset in this folder
					ChosenAssetData = AssetDatas[0];
				}
				else
				{

					while (RelevantAssetDatas.Num() <= 0)
					{
						//new random float
						TempRandFloat = FMath::FRand();

						//Find relevant Assets (in terms of spawn probability)
						for (int32 iList = 0; iList < AssetDatas.Num(); iList++)
						{
							FAssetData& AssetData = AssetDatas[iList];

							const FString* FoundTypeNameString = AssetData.TagsAndValues.Find(GET_MEMBER_NAME_CHECKED(ASomPickup, SpawnProbability));

							if (FoundTypeNameString &&  TempRandFloat < FCString::Atof(**FoundTypeNameString))
							{
								RelevantAssetDatas.Add(AssetData);
							}
						}
					}

					//new random int
					TempRandInt = FMath::RandRange(0, RelevantAssetDatas.Num() - 1);

					//Choose random asset from suitable ones
					ChosenAssetData = RelevantAssetDatas[TempRandInt];
				}



				//Load class from chosen (unloaded) asset/class
				FString LoadClassString = ChosenAssetData.ToStringReference().ToString() + "_C";


				ChosenSpawnItemClass = LoadClass<ASomPickup>(NULL, *LoadClassString, NULL, LOAD_None, NULL);

			}


//SPAWN ITEM
	if (ChosenSpawnItemClass != nullptr)
	{
		FActorSpawnParameters SpawnInfo;

		ASomPickup* SpawnedActor =  GetWorld()->SpawnActor<ASomPickup>(ChosenSpawnItemClass, SpawnInfo);
		SpawnedActor->SetActorLocation(this->GetActorLocation());
	}

Thanks for sharing your code, but if i understand it correctly, you finally decided to create the library in the code, so i guess you didn’t succeed in using an editor-born library.

I’ll still try to do something with an editor-made library and will report here if i get any luck :slight_smile:

Thanks !

Cedric

Theoretically it should work similarly.

In that case you wouldn’t have to get the content of the folders but get a reference to the ObjectLibrary-Blueprint (e.g. with a construction helper like I stated in a comment above).

After that you could use it the same way I did (from line 44). Kinda like this:

In your constructor:

 static ConstructorHelpers::FObjectFinder<UObjectLibrary> ObjLib_Obj(TEXT("ObjectLibrary'/Game/Pickups/Gear/All_Gear.All_Gear'"));
     if (ObjLib_Obj.Object != NULL)
         ObjLib = ObjLib_Obj.Object;

In your function:

TArray<FAssetData> AssetDatas;
FAssetData ChosenAssetData;

ObjLib->AddToRoot();
ObjLib->GetAssetDataList(AssetDatas);

//Get Random element of the Object library
if(AssetDatas.Num() > 0)
ChosenAssetData = AssetDatas[FMath::RandRange(0, AssetDatas.Num() - 1)];

//Load class from chosen (unloaded) asset/class
FString LoadClassString = ChosenAssetData.ToStringReference().ToString() + "_C";
ChosenSpawnItemClass = LoadClass<AActor>(NULL, *LoadClassString, NULL, LOAD_None, NULL);

//SPAWN ITEM
if (ChosenSpawnItemClass != nullptr)
{
    FActorSpawnParameters SpawnInfo;
 
    AActor* SpawnedActor =  GetWorld()->SpawnActor<AActor>(ChosenSpawnItemClass, SpawnInfo);
    SpawnedActor->SetActorLocation(this->GetActorLocation());
}