Skip to content

Instantly share code, notes, and snippets.

@drichardson
Created December 31, 2020 22:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drichardson/51544ebe014b129d435d5bbd9d725fc4 to your computer and use it in GitHub Desktop.
Save drichardson/51544ebe014b129d435d5bbd9d725fc4 to your computer and use it in GitHub Desktop.
UE4 World Singleton
#pragma once
#include "CoreMinimal.h"
#include "Engine/World.h"
#include "EngineUtils.h"
/*
* TWorldSingleton is a weak pointer to a actor in a level, which is only a
* singleton by convention of only one actor of that type being in a UWorld.
* Unlike code based singletons, it is therefore okay to have multiple
* TWorldSingleton's pointing to the same actor, thought this is typically
* unnecessary and less performant since each instance of TWorldSingleton must
* do an actor search the first time it is used.
*
* Example Use Case
* If you have an single inventory catalog actor in your level that all other
* actors should be able to find, you can use TWorldSingleton to access it.
*/
template <typename ActorType>
class TWorldSingleton
{
private:
TWeakObjectPtr<ActorType> Singleton;
public:
// Get the actor instance in this world, if any, logging errors if there is more than one.
// This function should only be called after all actors are loaded. You wouldn't want to use it,
// for example, in a constructor.
ActorType* Get(UWorld* World)
{
if (!World)
{
// Although Singleton.Get() could be returned here, don't. Rather,
// error out on null World now, so that anyone passing in a null
// world know about it immediately. Otherwise, if another call site is correctly called
// Get() with a valid world before the incorrect call, the incorrect call would succeed
// (in spite of the null world), making the bug hard to track down.
return nullptr;
}
if (!Singleton.IsValid())
{
for (TActorIterator<ActorType> It(World); It; ++It)
{
if (!Singleton.IsValid())
{
Singleton = *It;
}
else
{
UE_LOG(
LogTemp,
Error,
TEXT("TWorldSingleton::Get found another actor of class %s named %s. The "
"actor being used as the singleton is %s. To fix, delete all but one "
"of the actors."),
*GetNameSafe(ActorType::StaticClass()),
*GetNameSafe(*It),
*GetNameSafe(Singleton.Get()));
}
}
}
return Singleton.Get();
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment