Sample Unreal Files #

This page contains sample header and source files for the Party, Matchmaking, Social, and Game Server tutorials for Unreal.

Sample MyPlayerController.h header file
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "PragmaPtr.h"
#include "Dto/PragmaPartyRpcExtDto.h"
#include "MyPlayerController.generated.h"

struct FPragmaPartyInvite;
class FPragmaGameInstance;
class FPragmaPresence;

// Forward declares Pragma pointer types for Pragma::FPlayer.
PRAGMA_FWD(FPlayer);

UCLASS()
class UNREALTUTORIAL_API AMyPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	virtual void BeginPlay() override;

	// Login and Logout functions
	
	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void LogIn(const FString& Username);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void LogOut();
	
	// Initialization functions

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void InitializeServices();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void InitializeParty();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void InitializeGameInstance();
	
	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void InitializePresence();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void InitializeFriends();
	
	// Party functions
	
	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void CreateParty();
	
	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void JoinPartyWithInviteCode(const FString& InviteCode);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void JoinPartyWithPartyId(const FString& PartyId);
	
	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void SendPartyInviteByPlayerId(const FString& InviteeId);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void RespondToPartyInvite(const FString& PartyInviteId, const bool Response);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void SetGameMode(const EPragma_Party_GameMode& GameModeSelection);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void SetCharacter(const EPragma_Party_Character& CharacterSelection);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void LeaveParty();
	
	// Matchmaking functions

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void EnterMatchmaking();

	// Presence functions

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void SetPresenceToOnline();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void SetPresenceToAway();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void SetInShop(const bool IsInShop);

	// Friend functions

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void SendFriendInviteByUsername(const FString& FullUsername);
	
	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void SendFriendInviteBySocialId(const FString& SocialId);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void AcceptFriendInvite(const FString& InviterSocialId);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void DeclineFriendInvite(const FString& InviterSocialId);

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void RemoveFriend(const FString FriendSocialID);

	// Get functions

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	FString GetFullUsername();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	FString GetPlayerId();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	FString GetSocialId();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	FString GetPartyId();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	TArray<FString> GetPartyPlayers();

	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	void GetPresence();
	
	UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
	FString GetGameInstanceId();

	// Game server functions

	UFUNCTION(Client, Reliable, Category="Pragma")
	void TellGameClientItIsConnected();

	UFUNCTION(BlueprintCallable, Server, Reliable, Category="Pragma")
	void TellGameServerToEndGame();

private:
	Pragma::FPlayerPtr Player;
	
	void HandleOnPartyInviteReceived(const FPragmaPartyInvite& PartyInvite);
	void HandleOnAddedToGameInstance(const FPragmaGameInstance& GameInstance);
	void HandleOnHostConnectionDetailsReceived(const FPragmaGameInstance& GameInstance);
	void HandleOnPresenceChanged(const FPragmaPresence& Presence);
};
Sample MyPlayerController.cpp source file
// Fill out your copyright notice in the Description page of Project Settings.

#include "MyPlayerController.h"

#include "MyGameModeBase.h"
#include "PragmaLocalPlayerSubsystem.h"
#include "PragmaPlayer.h"
#include "Dto/PragmaAccountRpcDto.h"
#include "Dto/PragmaPartyRpcExtDto.h"
#include "Kismet/GameplayStatics.h"
#include "Pragma/Api/Player/PragmaFriendApi.h"
#include "Pragma/Common/Party/PragmaPartyInvite.h"
#include "Pragma/Common/Presence/PragmaPresence.h"
#include "Pragma/Api/Player/PragmaPresenceApi.h"
#include "Pragma/Common/Presence/PragmaPresenceCache.h"
#include "Pragma/Common/GameInstance/PragmaGameInstanceCache.h"


void AMyPlayerController::BeginPlay()
{
	Super::BeginPlay();

	if (IsRunningDedicatedServer())
	{
		return;
	}

	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Game client startup."));

	const auto* Subsystem = GetLocalPlayer()
		->GetSubsystem<UPragmaLocalPlayerSubsystem>();
	Player = Subsystem->Player();

	Player->PartyApi().OnPartyInviteReceived.AddUObject(
		this, &AMyPlayerController::HandleOnPartyInviteReceived);
	Player->GameInstanceApi().OnAddedToGameInstance.AddUObject(
		this, &AMyPlayerController::HandleOnAddedToGameInstance);
	Player->GameInstanceApi().OnHostConnectionDetailsReceived.AddUObject(
		this, &AMyPlayerController::HandleOnHostConnectionDetailsReceived);
	Player->PresenceApi().OnPresenceChanged.AddUObject(
		this, &AMyPlayerController::HandleOnPresenceChanged);
}

// ### Login and Logout functions ###

void AMyPlayerController::LogIn(const FString& Username)
{
	Player->LogIn(
		EPragma_Account_IdProvider::UNSAFE,
		Username,
		Pragma::FPlayer::FLoggedInDelegate::CreateWeakLambda(
			this, [=](const TPragmaResult<>& Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Logged in."));
				}
				else
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Login failed: %s"), *Result.ErrorCode());
				}
			}));
}

void AMyPlayerController::LogOut()
{
	Player->LogOut(
		Pragma::FPlayer::FLoggedOutDelegate::CreateWeakLambda(
			this, [=]
			{
				UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Logged out."));
			}));
}

// ### Initialization functions ###

void AMyPlayerController::InitializeServices()
{
	UPragmaPartyApi::FOnCompleteDelegate PartyInitializeDelegate;
	PartyInitializeDelegate.BindWeakLambda(this, [this](const TPragmaResult<>& PartyResult)
	{
		if (PartyResult.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Party service initialized."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Party service failed to initialize: %s"), *PartyResult.Error().ToString());
		}
	});

	UPragmaGameInstanceApi::FOnCompleteDelegate GameInstanceInitializeDelegate;
	GameInstanceInitializeDelegate.BindWeakLambda(this, [this](const TPragmaResult<>& GameResult)
	{
		if (GameResult.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Game instance service initialized."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Game instance failed to initialize: %s"), *GameResult.Error().ToString());
		}
	});

	UPragmaFriendApi::FOnCompleteDelegate FriendInitializeDelegate;
	FriendInitializeDelegate.BindWeakLambda(this, [this](const TPragmaResult<>& FriendResult)
	{
		if (FriendResult.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Friend service initialized."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Friend service failed to initialize: %s"), *FriendResult.Error().ToString());
		}
	});

	UPragmaPresenceApi::FOnCompleteDelegate PresenceInitializeDelegate;
	PresenceInitializeDelegate.BindWeakLambda(this, [this](const TPragmaResult<>& PresenceResult)
	{
		if (PresenceResult.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Presence service initialized."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Presence service failed to initialize: %s"), *PresenceResult.Error().ToString());
		}
	});

	Player->PartyApi().Initialize(PartyInitializeDelegate);
	Player->GameInstanceApi().Initialize(GameInstanceInitializeDelegate);
	Player->FriendApi().Initialize(FriendInitializeDelegate);
	Player->PresenceApi().Initialize(PresenceInitializeDelegate);
}

void AMyPlayerController::InitializeParty()
{
	Player->PartyApi().Initialize(
		UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [this](const TPragmaResult<>& Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Party service initialized."));
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Party service failed to initialize: %s"),
					       *Result.Error().ToString());
				}
			}));
}

void AMyPlayerController::InitializeGameInstance()
{
	Player->GameInstanceApi().Initialize(
		UPragmaGameInstanceApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [this](const TPragmaResult<>& Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Game Instance service initialized."));
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Game Instance service failed to initialize: %s"),
					       *Result.Error().ToString());
				}
			}));
}

void AMyPlayerController::InitializePresence()
{
	Player->PresenceApi().Initialize(
		UPragmaPresenceApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [this](const TPragmaResult<>& Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Presence service initialized."));
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Presence service failed to initialize: %s"),
					       *Result.Error().ToString());
				}
			}));
}

void AMyPlayerController::InitializeFriends()
{
	Player->FriendApi().Initialize(
		UPragmaFriendApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [this](const TPragmaResult<>& Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Friends service initialized."));
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Friends service failed to initialize: %s"),
					       *Result.Error().ToString());
				}
			}));
}

// ### Party functions ###

void AMyPlayerController::CreateParty()
{
	UPragmaPartyApi::FOnCompleteDelegate OnPartyCreatedDelegate;
	OnPartyCreatedDelegate.BindWeakLambda(this, [this](const TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Pragma party created. \n Party ID: %s \n Invite code: %s"),
			       *Player->PartyApi().GetPartyCache()->Party()->GetId(),
			       *Player->PartyApi().GetPartyCache()->Party()->GetInviteCode());
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Pragma unable to create party: %s"), *Result.Error().ToString());
		}
	});

	Player->PartyApi().CreateParty(
		FPragma_Party_ExtCreateRequest{},
		FPragma_Party_ExtPlayerJoinRequest{},
		TArray<FString>(),
		TMap<FString, int32>(),
		OnPartyCreatedDelegate
	);
}

void AMyPlayerController::JoinPartyWithInviteCode(const FString& InviteCode)
{
	UPragmaPartyApi::FOnCompleteDelegate JoinWithInviteCodeDelegate;
	JoinWithInviteCodeDelegate.BindWeakLambda(this, [=](const TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Joined party using invite code %s"), *InviteCode);
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to join party: %s"), *Result.Error().ToString());
		}
	});

	Player->PartyApi().JoinPartyWithInviteCode(
		FPragma_Party_ExtPlayerJoinRequest{},
		InviteCode,
		JoinWithInviteCodeDelegate
	);
}

void AMyPlayerController::JoinPartyWithPartyId(const FString& PartyId)
{
	UPragmaPartyApi::FOnCompleteDelegate JoinWithPartyIdDelegate;
	JoinWithPartyIdDelegate.BindWeakLambda(this, [=](const TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Joined party using party ID %s"), *PartyId);
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to join party: %s"), *Result.Error().ToString());
		}
	});

	Player->PartyApi().JoinPartyWithId(
		FPragma_Party_ExtPlayerJoinRequest{},
		PartyId,
		JoinWithPartyIdDelegate
	);
}

void AMyPlayerController::SendPartyInviteByPlayerId(const FString& InviteeId)
{
	UPragmaPartyApi::FOnInviteSentDelegate SendPartyInviteDelegate;
	SendPartyInviteDelegate.BindWeakLambda(
		this, [this, InviteeId](const TPragmaResult<FString>& SendPartyInviteResult)
		{
			if (SendPartyInviteResult.IsSuccessful())
			{
				UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Party invite sent to player ID: %s"), *InviteeId);
			}
			else
			{
				UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to send invite to player ID: %s Reason: %s"), *InviteeId,
				       *SendPartyInviteResult.Error().ToString());
			}
		});

	Player->PartyApi().SendPartyInvite(
		InviteeId,
		SendPartyInviteDelegate
	);
}

void AMyPlayerController::RespondToPartyInvite(const FString& PartyInviteId, const bool Response)
{
	UPragmaPartyApi::FOnCompleteDelegate RespondInviteDelegate;
	RespondInviteDelegate.BindWeakLambda(this, [=](const TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			if (Response == true)
			{
				UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Accepted party invite. Party successfully joined."));
			}
			else
			{
				UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Declined party invite"));
			}
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to respond: %s"), *Result.Error().ToString());
		}
	});

	Player->PartyApi().RespondToPartyInvite(
		FPragma_Party_ExtPlayerJoinRequest{},
		PartyInviteId,
		Response,
		RespondInviteDelegate
	);
}

void AMyPlayerController::SetGameMode(const EPragma_Party_GameMode& GameModeSelection)
{
	if (!Player->PartyApi().GetPartyCache()->Party()->IsLeader(Player->Id()))
	{
		UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Only party leaders can select game mode"));
		return;
	}

	UPragmaPartyApi::FOnCompleteDelegate UpdatePartyDelegate;
	UpdatePartyDelegate.BindWeakLambda(this, [=](const TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Changed game mode selection to."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to change game mode: %s"), *Result.Error().ToString());
		}
	});

	FPragma_Party_ExtUpdatePartyRequest Request;
	Request.Update.SetNewGameMode(GameModeSelection);
	Player->PartyApi().UpdateParty(Request, UpdatePartyDelegate);
}

void AMyPlayerController::SetCharacter(const EPragma_Party_Character& CharacterSelection)
{
	UPragmaPartyApi::FOnCompleteDelegate UpdatePartyPlayerDelegate;
	UpdatePartyPlayerDelegate.BindWeakLambda(this, [=](const TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Changed character selection."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to change character: %s"), *Result.Error().ToString());
		}
	});

	FPragma_Party_ExtUpdatePartyPlayerRequest Request;
	Request.Update.SetNewCharacter(CharacterSelection);
	Player->PartyApi().UpdatePartyPlayer(Request, UpdatePartyPlayerDelegate);
}

void AMyPlayerController::LeaveParty()
{
	UPragmaPartyApi::FOnCompleteDelegate LeavePartyDelegate;
	LeavePartyDelegate.BindWeakLambda(this, [this](const TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Successfully left party."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to leave party: %s"), *Result.Error().ToString());
		}
	});
	Player->PartyApi().LeaveParty(LeavePartyDelegate);
}

// ### Matchmaking functions ###

void AMyPlayerController::EnterMatchmaking()
{
	UPragmaPartyApi::FOnCompleteDelegate OnEnterMatchmakingDelegate;
	OnEnterMatchmakingDelegate.BindWeakLambda(this, [this](const TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Enter matchmaking success."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to enter matchmaking: %s"), *Result.Error().ToString());
		}
	});

	Player->PartyApi().EnterMatchmaking(OnEnterMatchmakingDelegate);
}

// ### Presence functions ###

void AMyPlayerController::SetPresenceToOnline()
{
	Player->PresenceApi().SetAsOnline(
		UPragmaPresenceApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [](const TPragmaResult<>& Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Set presence to online succeeded."));
				}
				else
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Set presence to online failed."));
				}
			}));
}

void AMyPlayerController::SetPresenceToAway()
{
	Player->PresenceApi().SetAsAway(
		UPragmaPresenceApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [this](const TPragmaResult<>& Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient --  Set presence to away succeeded."));
				}
				else
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient --  Set presence to away failed."));
				}
			}));
}

void AMyPlayerController::SetInShop(const bool IsInShop)
{
	FPragma_Presence_ExtRichPresencePlayerRequest Request;
	Request.Update.SetInShop(IsInShop);
	Player->PresenceApi().SetRichPresence(
		Request,
		UPragmaPresenceApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [](const TPragmaResult<> Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Set in shop success"));
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to set rich presence: %s"),
					       *Result.Error().ToString());
				}
			}));
}

// ### Friend functions ###

void AMyPlayerController::SendFriendInviteByUsername(const FString& FullUsername)
{
	FString DisplayName, Discriminator;
	FullUsername.Split("#", &DisplayName, &Discriminator);

	Player->FriendApi().SendFriendInviteByDisplayName(
		FPragma_Account_DisplayName{DisplayName, Discriminator},
		UPragmaFriendApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [DisplayName, Discriminator](const TPragmaResult<> Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Sent friend invite to display name: %s"),
					       *DisplayName);
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to send friend invite by display name. %s %s %s"),
					       *DisplayName, *Discriminator, *Result.Error().ToString());
				}
			}));
}

void AMyPlayerController::SendFriendInviteBySocialId(const FString& SocialId)
{
	Player->FriendApi().SendFriendInviteBySocialId(
		SocialId,
		UPragmaFriendApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [=](const TPragmaResult<> Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Sent friend invite to id: %s"),
					       *SocialId);
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to send friend invite by ID. %s"),
					       *Result.Error().ToString());
				}
			})
	);
}

void AMyPlayerController::AcceptFriendInvite(const FString& InviterSocialId)
{
	Player->FriendApi().AcceptFriendInvite(
		InviterSocialId,
		UPragmaFriendApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [=](const TPragmaResult<> Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Accepted friend invite from %s."),
					       *InviterSocialId)
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to accept friend invite: %s"),
					       *Result.Error().ToString());
				}
			})
	);
}

void AMyPlayerController::DeclineFriendInvite(const FString& InviterSocialId)
{
	Player->FriendApi().DeclineFriendInvite(
		InviterSocialId,
		UPragmaFriendApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [=](const TPragmaResult<> Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Declined friend invite from %s."),
					       *InviterSocialId)
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to decine friend invite: %s"),
					       *Result.Error().ToString());
				}
			})
	);
}

void AMyPlayerController::RemoveFriend(const FString FriendSocialID)
{
	Player->FriendApi().RemoveFriend(
		FriendSocialID,
		UPragmaFriendApi::FOnCompleteDelegate::CreateWeakLambda(
			this, [=](const TPragmaResult<> Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Removed friend: %s."),
					       *FriendSocialID)
				}
				else
				{
					UE_LOG(LogTemp, Warning, TEXT("MyGameClient -- Unable to remove friend: %s"),
					       *Result.Error().ToString());
				}
			})
	);
}

// ### Handler functions ###

void AMyPlayerController::HandleOnPartyInviteReceived(const FPragmaPartyInvite& PartyInvite)
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Party invite received. Respond using invite ID: %s"), *PartyInvite.GetInviteId());
}

void AMyPlayerController::HandleOnAddedToGameInstance(const FPragmaGameInstance& GameInstance)
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Game instance ID: %s"), *GameInstance.GetId());
}

void AMyPlayerController::HandleOnHostConnectionDetailsReceived(const FPragmaGameInstance& GameInstance)
{
	const FString ServerHostname = GameInstance.GetHostConnectionDetails()->GetHostName();
	const int ServerPort = GameInstance.GetHostConnectionDetails()->GetPort();
	const FString ServerAddress = ServerHostname + ":" + FString::FromInt(ServerPort);
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Received host connection details, attempting to connect to %s"),
	       *ServerAddress);
	UGameplayStatics::OpenLevel(GetWorld(), FName(*ServerAddress), true);
}

void AMyPlayerController::HandleOnPresenceChanged(const FPragmaPresence& Presence)
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Presence status changed."));
}

// ### GET FUNCTIONS NOT IN TUTORIAL ###

FString AMyPlayerController::GetFullUsername()
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Your full username: %s"), *Player->FullDisplayName());
	return Player->FullDisplayName();
}

FString AMyPlayerController::GetPlayerId()
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Your player ID: %s"), *Player->Id());
	return Player->Id();
}

FString AMyPlayerController::GetSocialId()
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Your social ID: %s"), *Player->SocialId());
	return Player->SocialId();
}

FString AMyPlayerController::GetPartyId()
{
	const auto Cache = Player->PartyApi().GetPartyCache();
	if (Cache && Cache->IsInParty())
	{
		const auto PartyId = Cache->Party()->GetId();
		UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Your party ID: %s"), *PartyId);
		return PartyId;
	}

	return "Not in a party";
}

TArray<FString> AMyPlayerController::GetPartyPlayers()
{
	auto PartyPlayers = Player->PartyApi().GetPartyCache()->Party()->GetPlayers();
	const FString& YourPlayerId = Player->Id();

	TArray<FString> DisplayNames;
	for (auto PartyPlayer : PartyPlayers)
	{
		FString DisplayName = PartyPlayer.GetDisplayName().DisplayName;
		FString PlayerId = PartyPlayer.GetPlayerId();
		FString SocialId = PartyPlayer.GetSocialId();

		if (PlayerId == YourPlayerId)
		{
			DisplayName += " (You)";
		}

		if (PartyPlayer.IsLeader())
		{
			DisplayName += " (Leader)";
		}

		if (PartyPlayer.IsReady())
		{
			DisplayName += " (Ready)";
		}

		DisplayNames.Add(DisplayName);

		UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Display name: %s, Player ID: %s, Social ID: %s"),
		       *DisplayName, *PlayerId, *SocialId);
	}

	return DisplayNames;
}

void AMyPlayerController::GetPresence()
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Presece ID: %s"),
	       *Player->PresenceApi().GetPresenceCache()->GetPresence()->GetId());
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Presence game shard ID: %s"),
	       *Player->PresenceApi().GetPresenceCache()->GetPresence()->GetGameShardId());
}

FString AMyPlayerController::GetGameInstanceId()
{
	const auto Cache = Player->GameInstanceApi().GetGameInstanceCache();
	if (Cache && Cache->IsInGame())
	{
		const auto GameInstanceId = Cache->GetGameInstance()->GetId();
		UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Your game instance ID: %s"), *GameInstanceId);
		return GameInstanceId;
	}

	return "Not in a game instance";
}

// ### Game server functions ###

void AMyPlayerController::TellGameClientItIsConnected_Implementation()
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Game server told me we are connected!"));
}

void AMyPlayerController::TellGameServerToEndGame_Implementation()
{
	UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Telling game server to end the game..."));
	Cast<AMyGameModeBase>(GetWorld()->GetAuthGameMode())->EndGame();
}
Sample MyGameBaseMode.h header file
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

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

UCLASS(Config=Game)
class UNREALTUTORIAL_API AMyGameModeBase : public AGameModeBase
{
	GENERATED_BODY()

protected:
	virtual void BeginPlay() override;
	virtual void PostLogin(APlayerController* NewPlayer) override;

private:
	Pragma::FServerPtr Server;
	
	TOptional<FPragma_GameInstance_GameStart> StoredGameStartData;

	void RequestStartGame(FString GameInstanceId);
	void HandleGameStartDataReceived(FPragma_GameInstance_GameStart GameStartData);
	static void ShutdownServer();

public:
	void EndGame();
};
Sample MyGameBaseMode.cpp source file
// Fill out your copyright notice in the Description page of Project Settings.

#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 (!GetWorld()->IsNetMode(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;
	
	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);
			}));
}

void AMyGameModeBase::PostLogin(APlayerController* NewPlayer)
{
	Super::PostLogin(NewPlayer);

	UE_LOG(LogTemp, Display, TEXT("MyGameServer -- Player client connected."));
	Cast<AMyPlayerController>(NewPlayer)->TellGameClientItIsConnected();
}

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);
}

void AMyGameModeBase::HandleGameStartDataReceived(FPragma_GameInstance_GameStart GameStartData)
{
	UE_LOG(LogTemp, Display, TEXT("MyGameServer -- Start game succeeded."));
	StoredGameStartData = GameStartData;
	
	const auto Hostname = "127.0.0.1";
	constexpr auto Port = 7777;
	
	TArray<FPragma_GameInstance_PlayerConnectionDetails> PlayerConnectionDetails;
	for (const auto& Player : GameStartData.Players)
	{
		auto i = PlayerConnectionDetails.Emplace();
		PlayerConnectionDetails[i].PlayerId = Player.PlayerId;
		// PlayerConnectionDetails[i].ExtPlayerConnectionDetails = TEXT("your player-specific data here");
	}

	UE_LOG(LogTemp, Display, TEXT("MyGameServer -- Attempting to connect players..."));
	Server->MatchApi().ConnectPlayers(
		GameStartData.GameInstanceId,
		PlayerConnectionDetails,
		Hostname,
		Port,
		UPragmaMatchApi::FOnCompleteDelegate::CreateLambda(
			[this](const TPragmaResult<>& Result)
			{
				if (Result.IsFailure())
				{
					UE_LOG(LogTemp, Error, TEXT("MyGameServer -- Connect players failed."));
					ShutdownServer();
				}
				else
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameServer -- Connect players succeeded."));
				}
			})
	);
}

void AMyGameModeBase::EndGame()
{
	if (!StoredGameStartData.IsSet())
	{
		UE_LOG(LogTemp, Error, TEXT("MyGameServer -- No match data when trying to end game."))
		ShutdownServer();
		return;
	}
	
	TArray<FPragma_GameInstance_PlayerGameResult> PlayerGameResults;
	for (const auto& Player : StoredGameStartData->Players)
	{
		auto i = PlayerGameResults.Emplace();
		PlayerGameResults[i].PlayerId = Player.PlayerId;
		// PlayerGameResults[i].Ext = TEXT("your player-specific data here");
	}

	UE_LOG(LogTemp, Display, TEXT("MyGameServer -- Attempting to end game..."));
	Server->MatchApi().EndGame(
		StoredGameStartData->GameInstanceId,
		PlayerGameResults,
		FPragma_GameInstance_ExtEndGameRequest{},
		UPragmaMatchApi::FOnCompleteDelegate::CreateLambda(
			[this](const TPragmaResult<>& Result)
			{
				if (Result.IsSuccessful())
				{
					UE_LOG(LogTemp, Display, TEXT("MyGameServer -- End game succeeded."));
				}
				else
				{
					UE_LOG(LogTemp, Error, TEXT("MyGameServer -- End game failed."));
				}
				ShutdownServer();
			})
	);
}

void AMyGameModeBase::ShutdownServer()
{
	FGenericPlatformMisc::RequestExit(false);
}