Setting Up Matchmaking #
The next part in building our game flow is enabling players to enter matchmaking.
Pragma Engine uses a Matchmaking Plugin to provide matchmaking functionality. You can build your own matchmaking plugins to customize matchmaking behavior to suit the unique needs of your game. As this is a simplified tutorial, we’ll be using a Pragma-provided matchmaking plugin that performs warm body matchmaking. This means the matchmaking plugin we’re using simply matches the first available players together until a complete match is formed.
For the front end, we’ll be making the necessary modifications by adding a start matchmaking button and outputting status information so that the party leader can start matchmaking and see when they are in a match.
Enable the Matchmaking Plugin #
For this example, we’ll be using the WarmBodyMatchmakingPlugin
. This plugin is a configurable implementation of the Matchmaking Plugin, meaning we can pass specific parameters in our configuration YAML to change its behavior. Enable the plugin by editing 5-ext/config/dev.yml
to add the following config:
game:
pluginConfigs:
MatchmakingService.matchmakingPlugin:
class: "pragma.matchmaking.WarmBodyMatchmakingPlugin"
config:
numberOfTeams: 1
playersPerTeam: 2
This configuration enables the WarmBodyMatchmakingPlugin
and tells it to create a two-player match where both players are on the same team.
Next, we need to implement two matchmaking-related functions in GameFlowTutorialPartyPlugin
:
override suspend fun buildMatchmakingKey(party: Party): ExtMatchmakingKey {
return ExtMatchmakingKey.getDefaultInstance()
}
override suspend fun buildExtMatchmakingParty(party: Party): ExtMatchmakingParty {
return ExtMatchmakingParty.getDefaultInstance()
}
Since we’ve implemented new functionality in our Party Plugin, we’ll need to rebuild 5-ext
. Run the following command in a terminal from the platform directory:
make ext pragma-sdks
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
.
Implement the enter matchmaking service call #
We’ve previously built the party flow up until the point players enter matchmaking: players can create a new party, invite other players, select their characters, and ready up. We’ll add a button to enter matchmaking, then have that button issue the service call to begin matchmaking.
Add a button to your Party screen to enter matchmaking, then add the following code:
Add the following to your header file under protected
:
UFUNCTION(BlueprintCallable, Category="Pragma")
void EnterMatchmaking();
Then add the corresponding function definition to your source file:
void APC_TutorialPlayerController::EnterMatchmaking()
{
Player->GameLoopApi().EnterMatchmaking();
}
Then hook up the EnterMatchmaking()
method to the button in Unreal Editor. While we won’t be implementing any client-side checks in this tutorial, the platform does perform validation and won’t enter parties into matchmaking unless they meet all criteria, such as all players being ready.
At this point, you can launch two clients and have them enter matchmaking. They can either be in the same party or they can enter matchmaking as two separate parties of one player. You’ll know matchmaking succeeded when you see the following line in the Unreal log (formatted for readability; the log isn’t pretty printed in Unreal Editor):
LogPragma: Verbose: RESPONSE 355 PartyRpc.EnterMatchmakingV1Response (seq: 35): Ok, message body: {
"sequenceNumber": 35,
"response": {
"requestId": 355,
"type": "PartyRpc.EnterMatchmakingV1Response",
"payload": {
"party": {
"extPartySelections": {},
"extPrivatePlayerSelections": {},
"partyId": "b11f0901-e794-4f04-8fb1-6be09414d3c7",
"partyMembers": [
{
"ext": {
"visibleCharacter": "KNIGHT",
"teamNumber": "0"
},
"playerId": "ff358871-e301-40ec-95ad-7c97ad2312ff",
"displayName": {
"displayName": "test01",
"discriminator": "4746"
},
"isReady": true,
"isLeader": true
}
],
"inviteCode": "B33RJ7",
"preferredGameServerZones": []
}
}
}
}.
However, this isn’t the most intuitive way to see that matchmaking has succeeded, so let’s add status messages to the UI and register the appropriate event handlers.
Add matchmaking event handlers to the client #
In production scenarios, it’s necessary to show players when they are in matchmaking and when a match has been found. In our simplified tutorial, we’ll be writing text to a multiline text box. In either case, the same event handlers apply.
First, let’s register the event handlers by adding the following lines to the header file. Under private
, add:
void HandleEnteredMatchmaking();
void HandleGameInstanceIdChanged(const FString GameInstanceId);
Then in your source file, add the following function definitions:
void APC_TutorialPlayerController::HandleEnteredMatchmaking()
{
AddStatusMessage("You are in matchmaking!");
UpdatePartyUI();
}
void ATutorialPlayerController::HandleGameInstanceIdChanged(const FString GameInstanceId)
{
UE_LOG(LogTemp, Display, TEXT("Match ID: %p"), *FString(GameInstanceId) );
FString Status;
(GameInstanceId.IsEmpty()) ? Status = "GameInstanceId is empty." : Status = "You are in a game! GameInstanceId: " + GameInstanceId;
AddStatusMessage(Status);
UpdatePartyUI();
}
These methods use a class variable PartyStatus
and a helper method AddStatusMessage()
, so let’s create those.
In your header file, add the following under private
:
UPROPERTY(BlueprintReadWrite, meta = (AllowPrivateAccess))
TArray<FString> PartyStatus;
Then add the function declaration for AddStatusMessage()
which also goes under private
:
void AddStatusMessage(FString StatusMessage);
Then in your source file, add the function definition:
void APC_TutorialPlayerController::AddStatusMessage(FString StatusMessage)
{
if (!StatusMessage.IsEmpty())
{
PartyStatus.Add(StatusMessage);
}
}
Lastly, we need to actually register these functions with the appropriate event handlers. In the source file under the Init()
function, add the following lines:
Player->GameLoopApi().OnEnteredMatchmaking.AddUObject(
this, &APC_TutorialPlayerController::HandleEnteredMatchmaking);
Player->GameLoopApi().OnMatchIdChanged.AddUObject(
this, &APC_TutorialPlayerController::HandleGameInstanceIdChanged);
Add a multiline text box to your UI, then create a ShowPartyStatus()
Blueprint Function that takes in the PartyStatus
string array and sets the multiline text box text with the contents of PartyStatus
. In your controller, make sure that your UI update function UpdatePartyUI()
calls this new ShowPartyStatus()
function.
You can now enter matchmaking after creating a party and selecting a character. When you have two players enter matchmaking, the matchmaker pairs them together. You should also see status messages upon entering matchmaking and when the matchmaker successfully finds a match.