Building the Party Screen in Unreal Engine #
In this section, we’ll implement the Party screen. As we complete each section, our game client will be able to create, join, and leave parties, along with make character selections. Additionally, we’ll be able to see the character selection and ready state of the other player in our party.
Start a local instance of Pragma Engine #
We’ll need a locally running Pragma Engine in order to test our work as we build each piece of the Party screen.
Run Pragma Engine via one of the following methods.
Once the engine has started successfully, it prints the message [main] INFO main - Pragma server startup complete
.
Creating the party #
Let’s actually create the party. In your header, add the following:
protected:
UFUNCTION(BlueprintCallable, Category="Pragma")
void CreateParty();
Define the CreateParty()
function:
void APC_TutorialPlayerController::CreateParty()
{
UPragmaPartyService::FOnCompleteDelegate OnPartyCreatedDelegate;
OnPartyCreatedDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
{
if (Result.IsSuccessful())
{
UE_LOG(LogTemp, Display, TEXT("Pragma party created."));
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Pragma unable to create party: %s"), *Result.Error().ToString());
}
});
Session->Party().CreateParty(
FPragma_Party_ExtCreateRequest{},
FPragma_Party_ExtPlayerJoinRequest{},
TArray<FString>(),
TMap<FString, int32>(),
OnPartyCreatedDelegate
);
}
Remember that this function is a BlueprintCallable
. Do the necessary corresponding work in your blueprint to create a corresponding button and have it invoke this function when clicked. You should then be able to check your work by clicking the play button in Unreal Editor. Once you’ve logged in, clicking the create party button should successfully create a party with you as the party leader. You can confirm this by checking your Unreal log, where you should see the following output:
Registering the On Party Changed event listener #
Any given player in a party can cause the party’s state to change, so it’s not sufficient to only update the party UI when the local player makes changes. The Pragma SDK provides an event that fires every time the party’s state changes.
For now, let’s create a function that logs to the console whenever the party state changes. Add the following under private
to your header:
void HandlePartyUpdate(const UPragmaParty* Party);
And add the following to the source file:
void APC_TutorialPlayerController::HandlePartyUpdate(const UPragmaParty* Party)
{
UE_LOG(LogTemp, Display, TEXT("Party state updated."));
// You can handle updating your party UI here.
}
Then register an event handler for OnPartyChanged
that will call HandlePartyUpdate()
by adding the following line to the end of your Init()
function:
Session->Party().OnPartyChanged.AddUObject(this, &ATutorialPlayerController::HandlePartyUpdate);
Whenever your party’s state changes, you will see “Party state updated.” printed to your output log. Later, we will be revisiting this function in order to update the UI.
Joining the party #
So far, we’ve implemented creating and leaving parties, but we don’t have the ability for other players to join our party. Let’s fix that.
In your UI, make the following elements: a place to show the lobby invite code, a text box for players to input an invite code, and a join party button.
Upon party creation, parties are automatically assigned a unique invite code. To actually get the invite code, use the following function.
In your header under protected
:
UFUNCTION(BlueprintCallable, Category="Pragma")
FString GetInviteCode();
In your source file:
FString ATutorialPlayerController::GetInviteCode()
{
if (!Session->Party().GetParty())
{
return FString{};
}
return Session->Party().GetParty()->GetInviteCode();
}
This function returns the invite code. Display it in the party UI. Remember that you can use the Update Lobby UI event to trigger all your UI updates as this event fires whenever there is a state change to the party.
Next, create the JoinByInviteCode()
function.
In your header under protected
:
UFUNCTION(BlueprintCallable, Category="Pragma")
void JoinByInviteCode(const FString& InviteCode);
In your source file:
void APC_TutorialPlayerController::JoinByInviteCode(const FString& InviteCode)
{
UPragmaPartyService::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());
}
});
Session->Party().JoinWithInviteCode(
FPragma_Party_ExtPlayerJoinRequest {},
InviteCode,
JoinWithInviteCodeDelegate
);
}
Hook this up to the UI such that it gets its argument from the invite code text box and is called by the join button. Once you’ve done so, you should be able to verify that you can have another player join your party. You can test this by building a standalone client. Log in on two clients (you can use the accounts test01 and test02). Have one client create a party, then join the party using the invite code on the second client.
You should see the following in your output log upon the second client successfully joining the party:
Making character selections #
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.
Create a dropdown menu so that players can select their desired character.
Make the following declaration under protected
:
UFUNCTION(BlueprintCallable, Category="Pragma")
void SendCharacterSelection(const FString& CharacterSelection);
Then define the following function:
void APC_TutorialPlayerController::SendCharacterSelection(const FString& CharacterSelection)
{
const EPragma_Party_Character PartyCharacter = static_cast<EPragma_Party_Character>(
StaticEnum<EPragma_Party_Character>()->GetValueByNameString(CharacterSelection, EGetByNameFlags::None)
);
UE_LOG(LogTemp, Display, TEXT("character: %s."), *CharacterSelection);
UPragmaPartyService::FOnCompleteDelegate UpdatePlayerSelectionsDelegate;
UpdatePlayerSelectionsDelegate.BindWeakLambda(this, [=, this](TPragmaResult<> Result)
{
if (Result.IsSuccessful())
{
UE_LOG(LogTemp, Display, TEXT("Changed character selection to %s"), *CharacterSelection);
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Unable to change character: %s"), *Result.Error().ToString());
}
});
FPragma_Party_ExtUpdatePlayerSelectionsRequest Request;
Request.Update.SetNewCharacter(PartyCharacter);
Session->Party().UpdatePlayerSelections(Request, UpdatePlayerSelectionsDelegate);
}
In your UI blueprint’s graph, add a Pre Construct event. Iterate over the EPragma_Party_Character
enum and populate the character selection dropdown with each enum. Next, make it so that the SendCharacterSelection()
function is called On Selection Changed by the character selection dropdown.
If done successfully, when in a party, you should see that the character selection dropdown is populated by four values:
- UNSPECIFIED
- KNIGHT
- MAGE
- ROGUE
Additionally, we should see something similar to the following in our output log whenever we make a character selection.
Making the party state visible to players #
At this point, we’ve built out all the necessary party functionality but players cannot view the state of the party. Let’s build the UI so that the state of the party is visible.
In your Party UI blueprint, add a text box. We’ll use this to show the players in the party along with their respective roles and leader status.
Make the following protected
declarations:
UFUNCTION(BlueprintCallable, Category="Pragma")
FString GetDisplayName();
UFUNCTION(BlueprintCallable, Category="Pragma")
TArray<FString> GetPartyPlayerDisplayNames();
Add the following function to retrieve the player’s display name:
FString APC_TutorialPlayerController::GetDisplayName()
{
return Session->Account().GetDisplayName();
}
Then add the following function to populate the text box we just created:
TArray<FString> ATutorialPlayerController::GetPartyPlayerDisplayNames()
{
if (!Session->Party().GetParty())
{
return TArray<FString>{};
}
const TArray<UPragmaPartyPlayer*> PartyPlayers = Session->Party().GetParty()->GetPlayers();
TArray<FString> DisplayNames;
const FString YourPlayerId = Session->Account().GetPragmaId();
for (const UPragmaPartyPlayer* PartyPlayer : PartyPlayers)
{
FString DisplayName = PartyPlayer->GetDisplayName().DisplayName;
FString PlayerId = PartyPlayer->GetPlayerId();
if (PlayerId == YourPlayerId)
{
DisplayName += " (You)";
}
if (PartyPlayer->IsLeader())
{
DisplayName += " (Leader)";
}
if (PartyPlayer->IsReady())
{
DisplayName += " (Ready)";
}
DisplayNames.Add(DisplayName);
}
return DisplayNames;
}
GetPartyPlayerDisplayNames()
should be invoked by the Update Lobby UI event and its output inserted into the text box. While we’re merely concatenating strings here, this example shows you how to get the data you need to build a full UI.
You can now create a BlueprintImplementableEvent that gets called by HandlePartyUpdate()
. Add the following to the public
section of your header file:
UFUNCTION(BlueprintImplementableEvent, Category = "Widget")
void UpdatePartyUI();
Then have HandlePartyUpdate()
call UpdatePartyUI()
. Switch over to Unreal Editor and open your PC_TutorialPlayerController blueprint. You now have an UpdatePartyUI
event that you can use to call all your BlueprintCallable
C++ functions that update your party UI. This ensure that your party UI is always showing the latest information.
Leaving the party #
Next, let’s make it so that we can leave the party by creating the LeaveParty()
function. In your header under protected
, add:
UFUNCTION(BlueprintCallable, Category="Pragma")
void LeaveParty();
Then in your source file, add:
void APC_TutorialPlayerController::LeaveParty()
{
UPragmaPartyService::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());
}
});
Session->Party().LeaveParty(LeavePartyDelegate);
}
Create and hook up a leave party button in your UI blueprint. When you successfully leave a party, you should see the following in your output log:
LogPragma: Verbose: RESPONSE 54 PartyRpc.LeaveV1Response (seq: 25): Ok, payload: {}.
LogTemp: Display: Successfully left party.
At this point, you have Pragma set up with Parties and you have a corresponding Unreal game client that can log into Pragma with full Party functionality. Players can create and join parties, make character selections, and leave parties.