Hi Teiwaz,
Sorry for the delay in getting back to you. I don’t typically use Singletons in my test projects, so I wanted to take the time to try to copy your setup as closely as possible, and then see if I could find any possible alternative methods to accomplish what you are doing. The good news is that I think I have managed to accomplish both of those goals.
For my test, I created four different custom component classes derived from UActorComponent
. I added a UPROPERTY
to each of these classes, then created a Blueprint for each one and set a default value for each property. I created a Singleton class containing a UPROPERTY
of each of the four components and made a Blueprint of the Singleton, setting the properties there to use the Blueprints I had created of each component. Then I created a custom UBlueprintFunctionLibrary
containing a function to access the Singleton class. In my character class, I called the library function to access the Singleton and set up a component I had added to the character class in the same way that you did in your pawn sample code. This provided me with the results that you described, where that component was not visible within the character class when the Editor was first opened, but after opening and compiling the character Blueprint, the component was suddenly there.
So the question I wanted to answer became how could I access the Singleton without needing to use GEngine, because there is no way to be certain that GEngine will be available when the class CDO’s are being created. I found out that I could access the CDO for the Singleton Blueprint directly, and that allowed the components to set up correctly when the Editor starts. This is what that portion of code in my character’s constructor looks like:
static ConstructorHelpers::FObjectFinder<UClass> DataObjectAsset(TEXT("Class'/Game/FirstPersonCPP/Blueprints/DataSingleton_BP.DataSingleton_BP_C'"));
if (DataObjectAsset.Succeeded())
{
TheData = Cast<UDataSingleton>(DataObjectAsset.Object->GetDefaultObject());
UE_LOG(LogTemp, Warning, TEXT("Object: %s"), *TheData->GetName());
TSubclassOf<UHandControllerComponent> HandControllerClass = TheData->HandControllerComponent_BPC;
if (HandControllerClass)
{
UE_LOG(LogTemp, Warning, TEXT("Hand Controller Class creation successful."));
TheHand = (UHandControllerComponent*)CreateDefaultSubobject(TEXT("The Hand"), UHandControllerComponent::StaticClass(), HandControllerClass, false, false, false);
UE_LOG(LogTemp, Warning, TEXT("%f"), TheHand->TheFloat);
if (IsValid(TheHand))
{
UE_LOG(LogTemp, Warning, TEXT("%s created successfully."), *TheHand->GetName());
}
else
{
UE_LOG(LogTemp, Warning, TEXT("TheHand creation failed."));
}
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Hand Controller Class creation failed."));
}
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Data Object Asset not available."));
}
In this instance, TheData
is a pointer to my UDataSingleton class, TheHand
is a UHandControllerComponent
property that I added to my Character class, and TheFloat
is the property I added to UHandControllerComponent
to make sure the component was being set up correctly. With this code, all of the messages in the log indicate success, and opening my character Blueprint immediately after the Editor opens shows the TheHand
component is present as expected.
Is this something that would work in your project to allow your Blueprints to be set up correctly when the Editor opens? The function in the Blueprint Function Library would still work fine after the Editor is open, so this method would only be necessary for instances where GEngine
is not available.