Download

Blueprint Event Problem with Singleton type class

Hello,

I am having problems with custom blueprint events inside a singleton type class.

If I use the BlueprintNativeEvent specifier. the C++ implementation gets called, but not the blueprint override.

I’ve narrowed it down to being a result of the singleton pattern integration in C++. The reason for the Singleton Pattern is because I want the class to be instantiated once and call “Get” from anywhere. I find this odd, as if I had done this in blueprints, even with the singleton design pattern, it would have worked(Have many blueprint managers using the singleton pattern.The singleton ‘Get’ is done inside the VM).

The way I call the method that calls the event in C++ is by a delegate that is called from Blueprints. (Works for the C++ implementation).

.h



UCLASS(Blueprintable)
class QUESTASSET_API UQuestManager : public UObject
{
GENERATED_BODY()

public:

//QuestManagerUpdate Delegate
UPROPERTY(BlueprintAssignable, BlueprintCallable, BlueprintReadWrite, Category = "Quest", meta = (DisplayName = "Update Quest Manager"))
FQuestManagerUpdateDelegate QuestManagerUpdate;

//Singleton Get Method
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Quest | Manager", meta = (DisplayName = "Get Quest Manager"))
static UQuestManager* GetQuestManagerInstance();

//Kills the singleton
UFUNCTION(BlueprintCallable, Category = "Quest | Manager", meta = (DisplayName = "Kill Quest Manager"))
static void KillQuestManagerInstance();

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Quest", meta = (DisplayName = "Notify"))
void BeginNotify();

void BeginNotify_Implementation();

//Test delegate binding
UFUNCTION(BlueprintCallable, Category = "Quest | Manager", meta = (DisplayName = "TestPrint"))
void printString();

//Register Bindings
void CreateBindings();

// ~-- Begin UObject Overrides --~ //
virtual UWorld* GetWorld() const override;
// ~-- End UObject Overrides --~ //

private:

//Quest Manager Singleton Instance
static UQuestManager* QuestManagerInstance;
};



.cpp



UQuestManager* UQuestManager::QuestManagerInstance = nullptr;

DEFINE_LOG_CATEGORY(LogQuestManager);

UWorld* UQuestManager::GetWorld() const
{
#if WITH_EDITOR
if (GIsEditor)
{
return GWorld;
}
#endif // WITH_EDITOR

return HasAnyFlags(RF_ClassDefaultObject) ? nullptr : GetOuter()->GetWorld();
}

UQuestManager* UQuestManager::GetQuestManagerInstance()
{
if ((QuestManagerInstance != nullptr) && (IsValid(QuestManagerInstance)))
{
return QuestManagerInstance;
}
else
{
QuestManagerInstance = NewObject<UQuestManager>();

QuestManagerInstance->CreateBindings();

return QuestManagerInstance;
}
}

void UQuestManager::KillQuestManagerInstance()
{
QuestManagerInstance = nullptr;
}

void UQuestManager::BeginNotify_Implementation()
{
UE_LOG(LogQuestManager, Warning, TEXT("In Implementation!"));
}

void UQuestManager::printString()
{
UE_LOG(LogQuestManager, Warning, TEXT("Test String"));

QuestManagerInstance->BeginNotify();
}

void UQuestManager::CreateBindings()
{
if (QuestManagerUpdate.IsBound())
{
QuestManagerUpdate.RemoveAll(this);
}

QuestManagerUpdate.AddDynamic(this, &UQuestManager::printString);
}



Any thoughts?

Cheers,

Have you taken a look into Subsystems? Programming Subsystems | Unreal Engine Documentation

Personally, I never found a reason to use Singleton pattern inside Unreal because Subsystems provides a direct alternative that automatically works with both C++ and Blueprints.

Frankly, I have no need for SubSystems with this particular class, nor any of my manager classes. Regardless of if I am using the Singleton pattern or not, this issue pertains to a static uobject. It’s odd, because the C++ implemented event fires, just not the Blueprint event. What is more weird is that the event is triggered by calling the Blueprint event.

I’m just gonna throw some stuff in the air. So Unreal has different “worlds” running while you are working on the game. A world can be the opened map in the editor, blueprints that you have opened, the game you are testing through the editor, etc. In theory, if these worlds are running under one process, a singleton pattern can fail here.

I agree with @_brunocoimbra, a GameInstanceSubsystem is exactly what you are looking for.

Subsystem is the way to go when you need singletons inside Unreal. Subsystem are just like singletons, but instead of “only one at all” you have “one per World” instead. So unless you are dealing with some multiple-worlds problem, go for Subsystems and everything will work as intended.

Here is a good read:Unreal-style Singletons with Subsystems · ben🌱ui

You’re only getting the native calls because your implementation of GetQuestManagerInstance only ever creates an instance of UQuestManager. Regardless of any of the blueprint types you may define, Get Instance will always create a UQuestManager. You’re never creating an instance of your blueprint type so it won’t exist to handle the call. You would need something with TSubclassOf/TSoftClassPtr to specify one of the subtypes that you’ve created.

One solution is the Subsystems. My solution (not because of any particular dislike for Subsystems, it just predates that code and I don’t really have any reason to update it) is TSubclassOf members on my GameMode. The GameMode is then responsible for instancing my “singleton” at level load and not on the first call to a “Get” (which has other setup benefits).