Unreal: Parties #
This tutorial uses Unreal Engine 5.3 with Pragma Engine 0.4.0 to demonstrate integrating Pragma Engine party functionality with a third-party game engine. This guide assumes you are proficient with Unreal Editor.
After creating a Party Plugin in Pragma Engine, you can build the corresponding frontend in Unreal Engine with help from the Pragma Party API.
In this section, we’ll expand the MyPlayerController.h
header file and MyPlayerController.cpp
source file we created in the Handle Login and Logout Unreal tutorial to implement party functionality. By the end of the tutorial, our game client will be able to create, join, and leave parties, as well as make game mode and character selections.
Update SDK #
Because there were changes to the ext protos, re-run the update script command from your Unreal Plugins folder:
update-pragma-sdk.sh
Create the party #
Goal: Allow a player to create a party from Unreal.
Upon party creation, parties are automatically assigned a unique party ID and invite code. In our example, we have the CreateParty()
function return the party ID and invite code for easy access.
Steps #
In
MyPlayerController.h
, declareCreateParty()
:public: UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void CreateParty();
In
MyPlayerController.cpp
, defineCreateParty()
to create the party and add the current player as the party leader:void AMyPlayerController::CreateParty() { Player->PartyApi().CreateParty( FPragma_Party_ExtCreateRequest{}, FPragma_Party_ExtPlayerJoinRequest{}, UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda( 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, Error, TEXT("MyGameClient -- Pragma unable to create party: %s"), *Result.GetErrorAsString()); } })); }
Our CreateParty()
function simply calls the Pragma PartyApi’s CreateParty()
function, which handles creating a party on the backend. Our example function does not accept any extra data for party creation, but you can add parameters to your CreateParty()
Unreal function and customize the ExtCreateRequest
and ExtPlayerJoinRequest
protos to allow for party customization during the time of creation.
Our function prints out the party’s invite code and party ID. These are values set on the party and can be distributed to allow others to join the party (see Join party with invite code or party ID).
Test #
To test this functionality using the Unreal in-game console, call CreateParty()
as a logged-in user. You should see “Pragma party created with code [Party join code].” in your Unreal output log. Record the party ID and invite code to use later.
To apply this functionality using Unreal Blueprints, create a button that calls your CreateParty()
function when clicked. Populate text boxes with the returned party ID and party invite code values.
Join party with invite code or party ID #
Goal: Allow a player to join a party using the party’s public invite code or party ID.
Upon party creation, parties are automatically assigned a unique party ID and invite code. To access these values, you can have the CreateParty()
function return the party invite code and store it locally, or access the code with a call to Player->PartyApi().GetPartyCache()->Party()->GetInviteCode()
.
Steps #
In
MyPlayerController.h
, declareJoinPartyWithInviteCode()
andJoinPartyWithPartyId()
:public: UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void JoinPartyWithInviteCode(const FString& InviteCode); UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void JoinPartyWithPartyId(const FString& PartyId);
In
MyPlayerController.cpp
, defineJoinPartyWithInviteCode()
andJoinPartyWithPartyId()
:void AMyPlayerController::JoinPartyWithInviteCode(const FString& InviteCode) { Player->PartyApi().JoinPartyWithInviteCode( FPragma_Party_ExtPlayerJoinRequest{}, InviteCode, UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda( this, [this, InviteCode](const TPragmaResult<> Result) { if (Result.IsSuccessful()) { UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Joined party using invite code %s"), *InviteCode); } else { UE_LOG(LogTemp, Error, TEXT("MyGameClient -- Unable to join party: %s"), *Result.GetErrorAsString()); } })); } void AMyPlayerController::JoinPartyWithPartyId(const FString& PartyId) { Player->PartyApi().JoinPartyWithId( FPragma_Party_ExtPlayerJoinRequest{}, PartyId, UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda( this, [this, PartyId](const TPragmaResult<> Result) { if (Result.IsSuccessful()) { UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Joined party using party ID %s"), *PartyId); } else { UE_LOG(LogTemp, Error, TEXT("MyGameClient -- Unable to join party: %s"), *Result.GetErrorAsString()); } })); }
Test #
To test this functionality using the Unreal in-game console:
Log in on two clients (you can use the accounts
test01
andtest02
).As
test01
, create a party and record the invite code and party ID.As
test02
, issueJoinPartyWithInviteCode [party invite code]
to jointest01
’s party.As
test03
, issueJoinPartyWithPartyId [party ID]
to jointest01
’s party.
To apply this functionality using Unreal Blueprints:
Create editable text boxes where a user can input a party invite code or a party ID.
Create buttons that calls your
JoinPartyWithInviteCode()
andJoinPartyWithPartyId
functions when clicked.Grab the text from the appropriate input box and plug it into the function.
Upon the second client successfully joining the party, you should see a success message in your output log.
Send party invite #
Goal: Allow a player to send a private party invite to another player using the player’s ID.
Steps #
In
MyPlayerController.h
, declareSendPartyInviteByPlayerId()
. Have the function accept a string for the invitee’s user ID.public: UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void SendPartyInviteByPlayerId(const FString& InviteeId);
In
MyPlayerController.cpp
, defineSendPartyInviteByPlayerId()
:void AMyPlayerController::SendPartyInviteByPlayerId(const FString& InviteeId) { Player->PartyApi().SendPartyInvite( InviteeId, UPragmaPartyApi::FOnInviteSentDelegate::CreateWeakLambda( 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, Error, TEXT( "MyGameClient -- Unable to send invite to player ID: %s Reason: %s" ), *InviteeId, *SendPartyInviteResult.GetErrorAsString()); } })); }
Our SendPartyInviteByPlayerId())
function accepts a string value representing the player ID of the invitee. Using this ID, the function calls the PartyApi’s SendPartyInvite()
function which facilitates sending an invite to the identified player. On success, our function logs a success message to the Unreal output log.
Test #
To test this functionality using the Unreal in-game console:
Log in on two clients (you can use the accounts
test01
andtest02
).As
test01
, create a party.As
test02
, issueGetPlayerId
(see Get party and player information) and record the value.As
test01
, useSendPartyInviteByPlayerId
with the ID from step 3.
You should see a success message in your output log.
To apply this functionality using Unreal Blueprints:
Create a button that calls your
GetPlayerId()
function when clicked. Pipe the return value to a text box so players can view their ID number.Create an editable text box where a user can input a player’s ID.
Create a button that calls your
SendPartyInviteByPlayerId()
function when clicked.Grab the text from the input box and plug it into the
SendPartyInviteByPlayerId
node.
View party invites #
Goal: Allow a player to fetch pending party invites.
Steps #
In
MyPlayerController.h
, declareGetPartyInvites()
to get a list of pending party invites for the active player:public: UFUNCTION(Exec, BlueprintCallable, Category="Pragma") TArray<FString> GetPartyInvites();
In
MyPlayerController.cpp
, defineGetPartyInvites()
:TArray<FString> AMyPlayerController::GetPartyInvites() { TSharedPtr<const TArray<FPragmaPartyInvite>> PartyInvites = Player->PartyApi(). GetReceivedPartyInvites(); TArray<FString> PartyInviteCodes; for (const FPragmaPartyInvite PartyInvite : PartyInvites) { FString PartyInviteCode = PartyInvite.GetInviteId(); UE_LOG(LogTemp, Display, TEXT("Party invite code: %s"), *PartyInviteCode); PartyInviteCodes.Add(PartyInviteCode); } return PartyInviteCodes; }
This function will return a
PartyInviteCode
for each pending party invite.
Test #
To test this functionality using the Unreal in-game console:
- As
test02
, callGetPartyInvites()
. The output log should show a party invite code for the party invitetest01
sent in the previous section. Record this value.
Accept or decline a party invite #
Goal: Allow a player to accept or reject an invite. You respond to a party invite using the party’s PartyInviteCode
, which is unique for each sent invite.
Steps #
In
MyPlayerController.h
, declare aAcceptPartyInvite()
and aDeclinePartyInvite()
method that accepts a party invite ID:public: UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void AcceptPartyInvite(const FString& PartyInviteId); UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void DeclinePartyInvite(const FString& PartyInviteId);
In
MyPlayerController.cpp
, defineAcceptPartyInvite()
and aDeclinePartyInvite()
:void AMyPlayerController::AcceptPartyInvite(const FString& PartyInviteId) { Player->PartyApi().AcceptPartyInvite( PartyInviteId, FPragma_Party_ExtPlayerJoinRequest{}, UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda( this, [this](const TPragmaResult<> Result) { if (Result.IsSuccessful()) { UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Accepted party invite")); } else { UE_LOG(LogTemp, Error, TEXT("MyGameClient -- Unable to accept invite: %s"), *Result.GetErrorAsString()); } })); } void AMyPlayerController::DeclinePartyInvite(const FString& PartyInviteId) { Player->PartyApi().DeclinePartyInvite( PartyInviteId, UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda( this, [this](const TPragmaResult<> Result) { if (Result.IsSuccessful()) { UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Declined party invite")); } else { UE_LOG(LogTemp, Error, TEXT("MyGameClient -- Unable to decline invite: %s"), *Result.GetErrorAsString()); } })); }
Our accept/decline functions use the provided PartyInviteCode
string to identify a pending party invite for the current player, and forwards that value to the PartyApi, which facilitates adding the invitee to the party if the invite is accepted.
Test #
To test this functionality using the Unreal in-game console:
As
test02
, callGetPartyInvites()
. The output log should show a party invite code for the party invitetest01
sent in the previous section. Record this value.As
test02
, callAcceptPartyInvite()
orDeclinePartyInvite()
with the party invite code you fetched in step 1.
You should see the appropriate message in your output log. If you accepted the party invite, you can verify you joined the party by selecting a character.
To apply this functionality using Unreal Blueprints:
Create a “Get party invites” button that calls your
GetPartyInvites()
function.Grab the results from the
GetPartyInvites()
function and display the strings on the player’s screen.Create an “Accept party invite” button and a “Decline party invite” button, along with an editable text box for the player to enter the invite code.
Have the accept button call your
AcceptPartyInvite()
function with the entered code.Have the reject button call your
DeclinePartyInvite()
function with the entered code.
Make game mode selections #
Goal: Allow party leaders to select a game mode.
Steps #
In
MyPlayerController.h
, declareSetGameModeSelection()
. Have the function accept a game mode value based on the enum we defined in Define party and player options:public: UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void SetGameMode(const EPragma_Party_GameMode& GameModeSelection);
In
MyPlayerController.cpp
, defineSetGameModeSelection()
to change a party’s game mode selection. You’ll notice we also added a check to verify the player setting the game mode is the party leader.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; } FPragma_Party_ExtUpdatePartyRequest Request; Request.Update.SetNewGameMode(GameModeSelection); Player->PartyApi().UpdateParty( Request, UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda( this, [this](const TPragmaResult<> Result) { if (Result.IsSuccessful()) { UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Changed game mode selection.")); } else { UE_LOG(LogTemp, Error, TEXT("MyGameClient -- Unable to change game mode: %s"), *Result.GetErrorAsString()); } })); }
Our SetGameMode()
function accepts one of the GameMode values that we defined and made available on the party via the ExtParty
proto (see Define party and player options). As long as the player is a party leader, the GameModeSelection
parameter is set as the game mode and sent to the PartyApi’s UpdateParty()
function with the new game mode as the ExtUpdatePartyRequest
payload. The UpdateParty()
function facilitates updating the party data on the backend.
Test #
To test this functionality using the Unreal in-game console, as the party leader issue the SetGameMode()
function with either CASUAL
or RANKED
. If your selection is valid, you’ll see a “Changed game mode selection to [your game mode selection]” in the Unreal output log.
To apply this functionality using Unreal Blueprints:
Create a “Casual” button and a “Ranked” button.
Have the “Casual” button call your
SetGameMode()
function with aEPragma Party Game Mode
variable defaulted toCASUAL
.Have the “Ranked” button call your
SetGameMode()
function with aEPragma Party Game Mode
variable defaulted toRANKED
.Output the selection to the player’s screen.
Make character selections #
Goal: Allow players to select characters.
In an actual game, there are many selections that players can make prior to getting in game. To keep our example simple, we’ll limit what the player can do to making a character selection.
Steps #
In
MyPlayerController.h
, declareSetCharacter()
. Have the function accept a character value based on the enum we defined in Define party and player options:public: UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void SetCharacter(const EPragma_Party_Character& CharacterSelection);
In
MyPlayerController.cpp
, defineSetCharacter()
to change a player’s character selection:void AMyPlayerController::SetCharacter(const EPragma_Party_Character& CharacterSelection) { FPragma_Party_ExtUpdatePartyPlayerRequest Request; Request.Update.SetNewCharacter(CharacterSelection); Player->PartyApi().UpdatePartyPlayer( Request, UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda( this, [this](const TPragmaResult<> Result) { if (Result.IsSuccessful()) { UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Changed character selection.")); } else { UE_LOG(LogTemp, Error, TEXT("MyGameClient -- Unable to change character: %s"), *Result.GetErrorAsString()); } })); }
Our SetCharacter()
function accepts one of the Character values that we defined and made available on the party via the ExtPartyPlayer
proto (see Define party and player options). The CharacterSelection
parameter is set as the player’s character and sent to the PartyApi’s UpdatePartyPlayer()
function with the new character as the ExtUpdatePartyPlayerRequest
payload. The UpdatePartyPlayer()
function facilitates updating the player data on the backend. In addition, the player’s isReady
value is automatically set to true
, which allows the player to enter matchmaking.
Test #
To test this functionality using the Unreal in-game console, as a player in a party, issue the SetCharacter()
function with either KNIGHT
, MAGE
, or ROGUE
. If your selection is valid, you’ll see a “Changed character selection to [your character selection]” in the Unreal output log.
To apply this functionality using Unreal Blueprints:
Create a button for each character option.
Have each button call your
SetGameMode()
function with aEPragma Party Game Mode
variable defaulted to the respective character choice (e.g. MAGE).Output the selection to the player’s screen.
Leave the party #
Goal: Allow players to voluntarily leave a party.
Steps #
In
MyPlayerController.h
, declareLeaveParty()
:public: UFUNCTION(Exec, BlueprintCallable, Category="Pragma") void LeaveParty();
In
MyPlayerController.cpp
, defineLeaveParty()
:void AMyPlayerController::LeaveParty() { Player->PartyApi().LeaveParty( UPragmaPartyApi::FOnCompleteDelegate::CreateWeakLambda( this, [this](const TPragmaResult<> Result) { if (Result.IsSuccessful()) { UE_LOG(LogTemp, Display, TEXT("MyGameClient -- Successfully left party.")); } else { UE_LOG(LogTemp, Error, TEXT("MyGameClient -- Unable to leave party: %s"), *Result.GetErrorAsString()); } })); }
Our LeaveParty()
function calls the Pragma PartyApi’s LeaveParty()
function, which facilitates removing the player from the party.
Test #
To test this functionality using the Unreal in-game console, as a player currently in a party, issue LeaveParty
. If successful, you’ll see a “Successfully left party.” message your the Unreal output log.
To apply this functionality using Unreal Blueprints, create a “Leave party” button that calls your LeaveParty()
function.
Next steps #
At this point, players can create and join parties, make party and character selections, and leave parties using the Unreal in-game console or Blueprint graph. Continue to the Matchmaking tutorial to learn how to implement sample matchmaking functionality.