Link Game Server and Game Instance #
Goal: Allow the game server to communicate with the Pragma backend and link to a game instance.
In this section we’ll be adding to the MyPlayerController.cpp
file and defining the following MyGameModeBase
methods:
- BeginPlay(): Kicks off the server connection process. This is automatically called as soon as GameServerLevel is started.
- RequestStartGame(): Requests the game start data from the Pragma backend once communication is established between the server and backend. Once called, Pragma Engine forwards the host details to the player clients via the
onHostConnectionDetailsReceived
event.
Restrict access to the player controller #
In the MyPlayerController.cpp
BeginPlay()
method, use GetNetMode()
to ensure that the code in the PlayerController
BeginPlay()
method is only run by the player client, and not a dedicated server.
void AMyPlayerController::BeginPlay()
{
Super::BeginPlay();
if (GetNetMode() == NM_DedicatedServer)
{
return;
}
//...
}
Set up the game mode base header file #
In
MyGameModeBase.h
, include the following imports and the Pragma server pointer forward declaration.#include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "PragmaPtr.h" #include "Dto/PragmaGameInstanceRpcDto.h" #include "MyGameModeBase.generated.h" // Forward declares Pragma pointer types for Pragma::FServer. PRAGMA_FWD(FServer);
Declare the following functions:
protected: virtual void BeginPlay() override; private: void RequestStartGame(FString GameInstanceId); void HandleGameStartDataReceived(FPragma_GameInstance_GameStart GameStartData);
We also want to declare the following variables.
Server
is a pointer to the Pragma server.StoredGameStartData
will be used to store game data sent to the player client when a game starts.private: Pragma::FServerPtr Server; TOptional<FPragma_GameInstance_GameStart> StoredGameStartData;
Connect server to the backend #
BeginPlay()
is automatically called as soon as the server is spun up and the default level (GameServerLevel) is loaded. In this tutorial, we’ll use BeginPlay()
to get the partner tokens and game instance ID from Pragma, and attempt to connect to the specific game instance via our RequestStartGame()
method.
Restrict access to the game mode base #
In the MyGameModeBase.cpp
BeginPlay()
method, use GetNetMode()
to ensure that the code in the MyGameModeBase
BeginPlay()
method is only run by the dedicated server.
void AMyGameModeBase::BeginPlay()
{
Super::BeginPlay();
if (GetNetMode() != NM_DedicatedServer)
{
return;
}
//...
}
Verify address and tokens #
The PragmaAddress, SocialToken, GameToken, and GameInstanceId will be provided by the LocalProcessGameServerProviderPlugin
as command line arguments.
In a later step we’ll provide the LocalProcessGameServerProviderPlugin
with the path to our dedicated server. For now, let’s set up our BeginPlay()
method to verify the address, tokens, and ID we’ll receive.
#include "MyGameModeBase.h"
#include "MyPlayerController.h"
#include "PragmaGameServerSubsystem.h"
#include "PragmaServer.h"
#include "PragmaRuntime.h"
#include "Dto/PragmaGameInstanceRpcDto.h"
void AMyGameModeBase ::BeginPlay()
{
Super::BeginPlay();
if (GetNetMode() != NM_DedicatedServer)
{
return;
}
UE_LOG(LogTemp, Display, TEXT("MyGameServer -- Game server startup."));
const auto * Subsystem = GetWorld ()->GetGameInstance()
->GetSubsystem<UPragmaGameServerSubsystem>();
auto Runtime = Subsystem->Runtime();
Server = Subsystem->Server();
FString PragmaAddress;
if (!FParse::Value(
FCommandLine::Get(), TEXT("-PragmaBackendAddress="),
PragmaAddress
)
) {
UE_LOG(LogTemp, Error, TEXT("MyGameServer -- No address found"));
ShutdownServer();
return;
}
FString SocialToken;
if (!FParse::Value(
FCommandLine::Get(), TEXT("-PragmaSocialToken="),
SocialToken
)
) {
UE_LOG(LogTemp, Error, TEXT("MyGameServer -- No social token found"));
ShutdownServer();
return;
}
FString GameToken;
if (!FParse::Value(
FCommandLine::Get(), TEXT("-PragmaGameToken="),
GameToken
)
) {
UE_LOG(LogTemp, Error, TEXT("MyGameServer -- No game token found"));
ShutdownServer();
return;
}
FString GameInstanceId;
if (!FParse::Value(
FCommandLine::Get(), TEXT("-PragmaGameInstanceId="),
GameInstanceId
)
) {
UE_LOG(LogTemp, Error, TEXT("MyGameServer -- No game instance ID found"));
ShutdownServer();
return;
}
Runtime->Config().PartnerBackendAddress = PragmaAddress;
Runtime->Config().PartnerSessionSocialAuthToken = SocialToken;
Runtime->Config().PartnerSessionGameAuthToken = GameToken;
//...
}
Attempt to connect to backend #
We will attempt to connect the game server to the Pragma backend and request the game start data. If the server is able to receive the data, the OnGameStart
event is fired.
By listening to the OnGameStart
event, we can call HandleGameStartDataReceived()
when OnGameStart
is fired. We’ll implement HandleGameStartDataReceived()
in the next section.
At the end of the
BeginPlay()
method, add the following:UE_LOG(LogTemp, Display, TEXT( "MyGameServer -- Attempting to connect to backend...")); Server->Connect( Pragma::FServer::FConnectedDelegate::CreateLambda( [this, GameInstanceId](const TPragmaResult<>& Result) { if (Result.IsFailure()) { UE_LOG(LogTemp, Error, TEXT( "MyGameServer -- Connect to backend failed.")); return; } UE_LOG(LogTemp, Display, TEXT( "MyGameServer -- Connect to backend succeeded.")); RequestStartGame(GameInstanceId); }));
Define the
RequestStartGame()
method:void AMyGameModeBase::RequestStartGame(FString GameInstanceId) { Server->MatchApi().OnGameStart.AddUObject(this, &AMyGameModeBase::HandleGameStartDataReceived); Server->MatchApi().OnGameStartFailed.AddWeakLambda(this,[this](const TPragmaResult<>& Error) { UE_LOG(LogTemp, Error, TEXT("MyGameServer -- Start game failed: %s"), *Error.ErrorCode()); ShutdownServer(); }); UE_LOG(LogTemp, Display, TEXT("MyGameServer -- Attempting to start game...")); Server->MatchApi().RequestStartGame(GameInstanceId); }