Created
December 31, 2020 22:37
-
-
Save drichardson/51544ebe014b129d435d5bbd9d725fc4 to your computer and use it in GitHub Desktop.
UE4 World Singleton
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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