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:
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?
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.
Ok so I created an object library blueprint and put two Blueprint-Items in there for testing:
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);
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
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.
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
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());
}