Download

GameInstance is constructed three times

Hi,

I use GameInstance to hold some services and I thought it is constructed only once. But I see the GameInstance is actually constructed three times. Is this intended?

How should I approach this problem then? I want to initialize my services only once and I don’t like using singletons (but I will if there is not other way).

Thanks
Dredok

Being a UObject, GameInstance is constructed multiple times (CDO, Skel Blueprints, instances, etc.), this is normal. But you likely only have one instance being stored and used by the engine. In order to avoid unnecessary initialization on CDOs, you can check whether you’re dealing with a template object, i.e.:


UMyGameInstance::UMyGameInstance(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
	if( !HasAnyFlags( RF_ClassDefaultObject | RF_ArchetypeObject ) )
	{
		// initialize services here
	}
}

-Camille

Thanks cmartel, this is a step in a good direction!

Unfortunately this code leads to two initializations instead of three ! So I have still one extra initialization :confused:

Are you running this in the editor? I think it will get constructed by pie also. Maybe that’s your second one? Or you seeing two in a package also? I know one is for the default object but I think the code above takes care of that…

Nope, this is running in an Android device. I know is running twice because I got it from logs (and because the services are initialized twice).

Try outputting the object path (GetPathName()), it should help figuring out what’s being initialized.

hi,
I have tested this and here it goes:

01-09 15:59:36.007 1842 1870 D UE4 : [2015.01.09-14.59.36:011] 0]LogTemp: Initializing InventoryDB from GameInstance path ‘/Engine/Transient.GameEngine_0:STPGameInstance_0’
01-09 15:59:36.359 1842 1870 D UE4 : [2015.01.09-14.59.36:365] 0]LogTemp: Initializing InventoryDB from GameInstance path ‘/Engine/Transient.GameEngine_0:STPGameInstance_1’

Where STPGameInstance is my custom GameInstance class …

I think the path does not bring light here :frowning:

BTW. I add here the constructor code, is pretty simple



USTPGameInstance::USTPGameInstance(const class FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
	, bMusicEnabled{true}
	, bSoundsEnabled{ true }
	, bDebugProfileEnabled{false}
{
	InventoryDB = ObjectInitializer.CreateDefaultSubobject<UInventoryDB>(this, TEXT("IventoryDB"));

	if (!HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
	{
		UE_LOG(LogTemp, Log, TEXT("Initializing InventoryDB from GameInstance path '%s'"), *GetPathName());
		InventoryDB->Initialize();
	}
}

Well, at least we know it’s not the CDO, and that UGameEngine is constructing it. Engine Init is called in both FEngineLoop::PreInit and FEngineLoop::Init:


	GEngineLoop.PreInit(0, NULL, FCommandLine::Get());

	UE_LOG(LogAndroid, Display, TEXT("Passed PreInit()"));

	GLog->SetCurrentThreadAsMasterThread();

	GEngineLoop.Init();

I don’t really know why. It’s also entirely likely that although the game instance is constructed twice, only one is kept. You could work around this by moving your initialization call to a separate function and manually call that once you know you have the game instance you want to keep.

Could be possible to do the initialization after the FEngineLoop::Init ? how to detect if the GameInstance is being constructed in preinit or init? (i would like to avoid dirty tricks like using a static count of initializations and similar weirdiness). The idea is to initialize the services as soon as possible, because they start async requests and stuff.

Of course I could do the initialization from my Game when it starts but it would be ideal to do this as soon as possible (ie in engine initialization).

Any idea?

BTW. thanks for all the info so far !

GameSingleton might be a better candidate than GameInstance for what you’re trying to achieve here. It’s initialized even earlier, it is created even for non-game engines and I do believe it is created only once.

The GameInstance you want will be the second one being constructed since Init always follows PreInit. Odds are there’s some flag or state you can poll on GEngine to see which one it’s being constructed for. Try nosing around UEngine::Init and UGameEngine::Init, or maybe inspect GEngine in both cases using the debugger.