Where can I do some initialization before game starts but after level is loaded?

Hi!

I don’t know where to ask this, but I will do it in C++, so maybe here is the right place.

If I want to get some data form a SQLite 3 database and also connect to a RESTful web service before the game starts, but after the level load.

Where can I do this?

There is an Actor class to connect to the database and another Actor to connect to the RESTful service.

Where do I call the methods? In a GameMode method? Or maybe in a method in the Player’s Character.

Thanks!

for these type of tasks you can use the GameInstance.

1 Like

Thanks.

Now, I know where do I have to put the code.

But, when do I have to run it? In GameMode.BeginPlay? PlayerController.BeginPlay? Level Blueprint?

I’m asking this because I don’t know if there is something in the subsystem that it’s called automatically when the level loads.

Thanks.

You can delay pawn creation for player controllers on the GameMode until all initialization and validation is completed. I’ve done this type of thing in PreLogin and PostLogin method overloads (works for single or multiplayer). Once you’ve got the data you’ll need loaded, create the pawn in the game mode and fire an event to all player controllers to take control of their respective pawns. Then load the game UI (you can have a loading screen UI until this entire process is done).

Note: you’ll need to set the default pawn to None or Spectator in the game mode, and then create the pawn once you’ve got everything loaded. The Default pawn will be created otherwise.

1 Like

How can I do that? Calling the Super::PostLogin(NewPlayer); at the end of the method?

void ACustomGameModeBase::PostLogin(APlayerController* NewPlayer)
{
	// My code

	Super::PostLogin(NewPlayer);
	
}

Thanks!

Make sure your custom game mode does not have a default player pawn (or use a spectator pawn)

void YourGameMode::PostLogin(APlayerController* newPlayer)
{
    checkf(newPlayer, TEXT("PostLogin() was given a null player controller ptr"));

    Super::PostLogin(newPlayer);

    const auto controller = CastChecked<AYourPlayerControllerClass>(newPlayer);
	
	//custom function that automatically casts the player state to my custom player state class
    const auto playerState = controller->GetPlayerStateCast();
	
    if(!IsValid(playerState))
    {
        UE_LOG(LogTemp, Error, TEXT("PostLogin(): unable to get cast player state"));
        return;
    }


	//Track players that haven't been validated
	TArrayHoldingPendingValidations.Add(playerState);
	
	//perform any validation for your custom data
	Validate(playerState);

}

void YourGameMode::Validate(AYourPlayerState* state)
{
	// do your validation. I use a backend service called over a TCP socket.
	
	//When done, the socket data handler invokes HandlePlayerValidation() with a custom data payload
	
	// you can probably combine this into one step if you do validation/setup all in unreal)
}

//call back method invoked by Validate()
void YourGameMode::HandlePlayerValidation(const FValidationResultStruct& data)
{
    //Check for failure
    if(!data.success)
    {
		UE_LOG(LogTemp, Warning, TEXT("Rejected player validation."));
	        //you'll have to implement kickplayer()
		YourGameMode::KickPlayer(data);
        return;
    }

    //Validation was successful
	auto playerState = TArrayHoldingPendingValidations.Get(data.playerStatePtr);
	
	if(!playerState)
	{
		UE_LOG(LogTemp, Warning, TEXT("Unable to get player state from tracking array"));		
		YourGameMode::KickPlayer(data);
        return;
	}

    auto playerController = playerState->GetPlayerController();
	
    FTransform pawnTransform = data.startingTransform;
	
	//SpawnActor expects a UClass pointer and transform.
    auto playerPawn = GetWorld()->SpawnActor<AYourPlayerPawn>(PropertyThatHoldsYourUClassPointer, pawnTransform);
    checkf(playerPawn, TEXT("Unable to spawn player pawn during player validation."));
    playerPawn->InitFromValidationData(data);
	
	//This is where/when you spawn your player's pawn, replacing the spectator pawn if you're using one
    playerController->Possess(playerPawn);

    //Can send additional events etc if you need additional initialization.
    OnPlayerValidation(playerController);
   TArrayHoldingPendingValidations.Remove(data.playerStatePtr);
}

Might be some things to clean up, but this is the code flow how our current project does it (lots of unrelated stuff removed).