Unreal: Social #

This tutorial uses Unreal Engine 5.3 with Pragma Engine 0.1.0. to demonstrate integrating Pragma Engine party functionality with a third-party game engine. This guide assumes you are proficient with Unreal Editor.

In this tutorial, we’ll expand the MyPlayerController.h header file and MyPlayerController.cpp source file to implement functionality related to the Pragma Engine Presence service. Specifically we will:

  • Allow a player to appear “online” or “offline” (basic presence)
  • Allow a player to appear “in shop” (rich presence)
  • Display a player’s current presence values

Note: We do not need a specific Unreal function for the “in party” presence, as that is automatically set by our Party Plugin (see Set Up Presence Features with Pragma Engine).

By the end of the tutorial, our player client and backend will be able to make and update basic and rich presence selections.

Get started #

To get started, re-run the update script command:

update-pragma-sdk.sh

Ensure you have a locally running Pragma Engine to test examples as you build each function.

How to use this tutorial #

The code presented in this tutorial is simplified to give you an introduction to the game flow. An actual game would have a more sophisticated design, and the player experience may differ significantly.

We’ve built this barebones social screen to help you visualize the functionality presented in this tutorial:

The functions in this tutorial are built as UFunctions with the Exec and BlueprintCallable specifiers, meaning they can be executed by the in-game console and in a Blueprint or Level Blueprint graph. The Exec specifier is useful for quickly testing your functions.

The example tests in each section are meant to ensure your C++ code is working properly and are unlikely to represent a completed game design. Adapt the organization and naming to suit your project’s needs.

For convenience, we’ve included sample C++ files that contain all the code from this tutorial as well as the login/logout functionality, party functionality, and matchmaking functionality.

Note that you may need to update your #include statements as you progress through the tutorial.

Implement the Initialize Presence function (required) #

Goal #

Implement a InitializePresence() function that initializes the Presence service and sets the player’s basic presence to Online. You can also choose to implement the following functionality into a general Initialize() function that also initializes the Party, Game Instance, and Friend services (see the relevant tutorials for examples).

Steps #

  1. Declare the InitializePresence() function in the public section of your MyPlayerController.h file:

    UFUNCTION(Exec, BlueprintCallable, meta=(Category="Pragma"))
    void InitializePresence();
    
  2. Define InitializePresence() in your MyPlayerController.cpp file:

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

Test #

To test this functionality using the Unreal in-game console, issue InitializePresence as each player client (e.g. test01 and test02).

To apply this functionality using Unreal Blueprints, you can call the InitializePresence() function as part of another operation, such as upon login.

When the service is successfully initialized, you should see “Presence service initialized.” in the Unreal output log, along with any on-screen functionality you defined in the Blueprints (such as populating a “Basic presence” text box).

Set player presence to online or offline #

Goal #

Implement a SetPresenceToOnline() function that sets the player’s basic presence to “Online”, and and SetPresenceToAway() function that sets the player’s basic presence to “Away”.

Steps #

  1. Declare the SetPresenceToOnline() and SetPresenceToAway() functions in the public section of your MyPlayerController.h file:

    UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
    void SetPresenceToOnline();
    
    UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
    void SetPresenceToAway();
    
  2. Define SetPresenceToOnline() and SetPresenceToAway() in your MyPlayerController.cpp file:

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

Our SetPresenceToOnline() calls the PresenceApi’s SetAsOnline() function, and our SetPresenceToAway() function calls the PresenceApi’s SetAsAway() function. The PresenceApi function facilitates setting the player’s basic presence to “Online” or “Away”.

Test #

To test this functionality using the Unreal in-game console, as a logged in player with social features initialized, issue SetAsOnline or SetAsAway.

If successful, you should see “Set presence to online succeeded.” or “Set presence to away succeeded.” in the Unreal output log.

To test this functionality using Unreal Blueprints, create a “Online” button that calls SetPresenceToOnline, and a “Away” button that calls SetPresenceToAway. As a logged in player with social features initialized, click each button.

If successful, you should see “Set presence to online succeeded.” or “Set presence to away succeeded.” in the Unreal output log along with any on-screen functionality you defined in the Blueprints (such as populating a “Basic presence” text box).

Set player presence to “in shop” #

Goal #

Implement a SetInShop() function that allows a player client to set or update a player’s rich presence in_shop value.

Steps #

  1. Declare the SetInShop() function in the public section of your MyPlayerController.h file. Have it accept a boolean value that represents whether the player is currently in the shop:

    UFUNCTION(Exec, BlueprintCallable, Category="Pragma")
    void SetInShop(const bool IsInShop);
    
  2. Define SetInShop() in your MyPlayerController.cpp file:

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

Our SetInShop() calls the PresenceApi’s SetRichPresence() function, providing the ExtRichPresencePlayerRequest value.

Test #

To test this functionality using the Unreal in-game console, as a logged in player with social features initialized, issue SetInShop true.

If successful, you should see “Set in shop to true.” in the Unreal output log.

To test this functionality using Unreal Blueprints, create a “Enter shop” button that calls SetInShop with the true value, and a “Leave shop” button that calls SetInShop with the false value. As a logged in player with social features initialized, click each button.

If successful, you should see “Set in shop to true.” in the Unreal output log along with any on-screen functionality you defined in the Blueprints (such as populating a “Rich presence” text box).

Handle presence changes #

Goal #

Implement a HandleOnPresenceChanged() function that listens to the OnPresenceChanged event.

The Pragma SDK provides an OnPresenceChanged event that fires every time a player’s basic or rich presence is changed. We can use this event to trigger a handler function for updates in Unreal. For now, our HandleOnPresenceChanged() function simply print an Unreal log entry that displays the player’s presence values.

Steps #

  1. Declare HandleOnPresenceChanged()in the private section of your MyPlayerController.h file:

    void HandleOnPresenceChanged(const FPragmaPresence& MyPresence);
    
  2. Define HandleOnPresenceChanged() in MyPlayerController.cpp:

    void AMyPlayerController::HandleOnPresenceChanged(const FPragmaPresence& MyPresence)
    {
    	UE_LOG(LogTemp, Display, TEXT("Presence status changed: "
    			"\n Basic: %s, \n Rich: %s, %s"), *UEnum::GetValueAsString<EBasicPresence>(MyPresence.GetBasicPresence()),
    		MyPresence.GetExt().InShop ? TEXT("In shop") : TEXT("Not in shop"),
    		MyPresence.GetExt().InParty ? TEXT("In party") : TEXT("Not in party"));
    }
    
  3. Register the event handler. Add the following to the end of your BeginPlay() function in your MyPlayerController.cpp file:

    Player->PresenceApi().OnPresenceChanged.AddUObject(
    	this, &AMyPlayerController::HandleOnPresenceChanged);
    

Test #

To test this functionality using the Unreal in-game console, as a logged in player with social features initialized, change your presence.

If successful, you should see the “Presence status changed …” message in the Unreal output log, along with any on-screen functionality you defined in the Blueprints (such as populating a “Rich presence” text box).

Test backend presence changes #

Because we modified the OnAddPlayer and OnRemovePlayer methods in Automatically set player to “in party” to update a player’s rich presence based on party state, we don’t need to do any additional work in the Unreal files.

To test the functionality defined in the plugin using Unreal, as a logged in player with social features initialized, create, join, or leave a party. You should see the message defined in your HandleOnPresenceChanged function in the Unreal output log.

Sample header and source files #

The following sample files combine the code blocks from this tutorial, along with the functions from the Handle Login and Logout tutorial, the Unreal: Parties tutorial, and the Unreal: Matchmaking tutorial.

Sample MyPlayerController.h header file
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "PragmaPtr.h"
#include "PragmaGameInstanceSubsystem.h"
#include "PragmaResult.h"
#include "Dto/PragmaPartyRpcExtDto.h"
#include "Services/Party/PragmaPartyInvite.h"
#include "MyPlayerController.generated.h"
using FFriendList = TMap<FString, FPragmaFriend>;

// 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;

	// Weak pointer to our Pragma Player owned by the PragmaLocalPlayerSubsystem.
	Pragma::FRuntimePtr Runtime;
	Pragma::FPlayerPtr Player;

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

	UFUNCTION(Exec, BlueprintCallable, meta=(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();

	
	//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, meta=(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, meta=(Category="Pragma"))
	void SetCharacter(const EPragma_Party_Character& CharacterSelection);

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

	UFUNCTION(Exec, BlueprintCallable, meta=(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);

	
private:
	void HandleLoggedIn(const TPragmaResult<>& Result);
	void HandleLoggedOut();
	void HandleOnPartyInviteReceived(const FPragmaPartyInvite& MyPartyInvite);
	void HandleOnAddedToGameInstance(const FPragmaGameInstance& MyGameInstance);
	void HandleOnPresenceChanged(const FPragmaPresence& MyPresence);
};
Sample MyPlayerController.cpp source file
#include "MyPlayerController.h"
#include "PragmaPlayer.h"
#include "Dto/PragmaAccountRpcDto.h"
#include "Dto/PragmaPartyRpcExtDto.h"
#include "Pragma/Api/Player/PragmaFriendApi.h"
#include "Services/Party/PragmaPartyInvite.h"
#include "Pragma/Common/Friend/PragmaPresence.h"
#include "Pragma/Api/Player/PragmaPresenceApi.h"
#include "PragmaLocalPlayerSubsystem.h"

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

	UE_LOG(LogTemp, Display, TEXT("Initializing") );
	
	const auto* Subsystem = GetLocalPlayer()->GetSubsystem<UPragmaLocalPlayerSubsystem>();

	// The UPragmaLocalPlayerSubsystem is automatically initialized
	// with a Pragma Player object for every LocalPlayer.
	Player = Subsystem->Player();
	
	Player->PartyApi().OnPartyInviteReceived.AddUObject(
	this, &AMyPlayerController::HandleOnPartyInviteReceived);

	Player->GameInstanceApi().OnAddedToGameInstance.AddUObject(
	this, &AMyPlayerController::HandleOnAddedToGameInstance);
}

//Login and Logout functions

void AMyPlayerController::LogIn(const FString& Username)
{
    Player->LogIn(
        EPragma_Account_IdProvider::UNSAFE,
        Username,
        Pragma::FPlayer::FLoggedInDelegate::CreateUObject(
            this, &AMyPlayerController::HandleLoggedIn));
}

void AMyPlayerController::LogOut()
{
    Player->LogOut(Pragma::FPlayer::FLoggedOutDelegate::CreateUObject(
        this, &AMyPlayerController::HandleLoggedOut));
}

//Initialization functions

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

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

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

//Party functions

void AMyPlayerController::CreateParty()
{
	UPragmaPartyApi::FOnCompleteDelegate OnPartyCreatedDelegate;
	OnPartyCreatedDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("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("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, [=, this](TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("Joined party using invite code %s"), *InviteCode);
		}
		else
		{
			UE_LOG(LogTemp, Warning,
				TEXT("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, [=, this](TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("Joined party using party ID %s"), *PartyId);
		}
		else
		{
			UE_LOG(LogTemp, Warning,
				TEXT("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("Party invite sent to player ID: %s"), *InviteeId);
		}
		else
		{
			UE_LOG(LogTemp, Warning,
				TEXT("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, [=, this](TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			if (Response==true)
			{
				UE_LOG(LogTemp, Display, TEXT("Accepted party invite. Party successfully joined."));
			}
			else
			{
				UE_LOG(LogTemp, Display, TEXT("Declined party invite"));
			}
		}
		else
		{
			UE_LOG(LogTemp, Warning,
				TEXT("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())==true)
	{
		FPragma_Party_ExtUpdatePartyRequest Request;
		Request.Update.SetNewGameMode(GameModeSelection);

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

		Player->PartyApi().UpdateParty(Request, UpdatePartyDelegate);
	}
	else
	{
		UE_LOG(LogTemp, Display,TEXT("Only party leaders can select game mode"));
	}
}

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

	FPragma_Party_ExtUpdatePartyPlayerRequest Request;
	Request.Update.SetNewCharacter(CharacterSelection);

	Player->PartyApi().UpdatePartyPlayer(Request, UpdatePartyPlayerDelegate);
}

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

//Matchmaking functions

void AMyPlayerController::EnterMatchmaking()
{
	UPragmaPartyApi::FOnCompleteDelegate OnEnterMatchmakingDelegate;
	OnEnterMatchmakingDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display, TEXT("Enter matchmaking success."));
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("Pragma 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("Set presence to online succeeded."));
			}
			else
			{
				UE_LOG(LogTemp, Display, TEXT("Set presence to online failed."));
			}
		}));
}

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

void AMyPlayerController::SetInShop(const bool IsInShop)
{

	FPragma_Presence_ExtRichPresencePlayerRequest Request;
	Request.Update.SetInShop(IsInShop);

	UPragmaPresenceApi::FOnCompleteDelegate SetRichPresenceDelegate;

	SetRichPresenceDelegate.BindWeakLambda(this, [IsInShop](TPragmaResult<> Result)
	{
		if (Result.IsSuccessful())
		{
			UE_LOG(LogTemp, Display,
				TEXT("Set in shop to %s"), IsInShop ? TEXT("true") : TEXT("false"));
		}
		else
		{
			UE_LOG(LogTemp, Warning,
				TEXT("Unable to set rich presence: %s"), *Result.Error().ToString());
		}
	});

	Player->PresenceApi().SetRichPresence(Request, SetRichPresenceDelegate);
}

//Handler functions

void AMyPlayerController::HandleLoggedIn(const TPragmaResult<>& Result)
{
    if (Result.IsFailure())
    {
        UE_LOG(LogTemp, Display, TEXT("Pragma -- Login failed: %s"), *Result.ErrorCode());
    }
    UE_LOG(LogTemp, Display, TEXT("Pragma -- Logged in."));
}

void AMyPlayerController::HandleLoggedOut()
{
    UE_LOG(LogTemp, Display, TEXT("Pragma -- Logged out."));
}

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

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

void AMyPlayerController::HandleOnPresenceChanged(const FPragmaPresence& MyPresence)
{
	UE_LOG(LogTemp, Display, TEXT("Presence status changed: "
			"\n Basic: %s, \n Rich: %s, %s"), *UEnum::GetValueAsString<EBasicPresence>(MyPresence.GetBasicPresence()),
		MyPresence.GetExt().InShop ? TEXT("In shop") : TEXT("Not in shop"),
		MyPresence.GetExt().InParty ? TEXT("In party") : TEXT("Not in party"));
}

Next steps #

Congratulations! You now have a custom Unreal implementation of the Pragma Engine Presence service. Continue to the Unreal: Friends tutorial to see how to apply the Friends services in Unreal.