Announcement

Collapse
No announcement yet.

GameInstance is constructed three times

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    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
    WIP Save the princess !
    https://twitter.com/stp_the_game

    #2
    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.:

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

    Comment


      #3
      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 :/
      WIP Save the princess !
      https://twitter.com/stp_the_game

      Comment


        #4
        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...

        Comment


          #5
          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).
          WIP Save the princess !
          https://twitter.com/stp_the_game

          Comment


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

            Comment


              #7
              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


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

              Code:
              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();
              	}
              }
              Last edited by Dredok; 01-09-2015, 11:06 AM.
              WIP Save the princess !
              https://twitter.com/stp_the_game

              Comment


                #8
                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:

                Code:
                	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.

                Comment


                  #9
                  Originally posted by cmartel View Post
                  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:

                  Code:
                  	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 !
                  WIP Save the princess !
                  https://twitter.com/stp_the_game

                  Comment


                    #10
                    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.

                    Comment

                    Working...
                    X