Matchmaking Tasks #

Matchmaking features are built and customized using a combination of calls and plugin methods. This page describes common matchmaking operations, along with descriptions of SDK actions and related Matchmaking plugin methods.

Common matchmaking operations include:

For a full list of all available Matchmaking SDK and plugin function, see Matchmaking Reference.

Initialize the matchmaking process #

Perform any validation logic or party/player transformations before adding the party to a matchmaking queue.

Initialize matchmaking

The matchmaking process starts when parties enter the Matchmaking service from the Party service. The MatchmakingService.enterMatchmaking call, which is called as part of PartyService.enterMatchmaking, places the party into a Matchable object and invokes the initialize method.

interface MatchmakingPlugin {
  fun initialize(
    queueKey: MatchmakingQueueKey, 
    matchable: Matchmaking.Matchable
  ): NewGameInstance? { 
    // Custom logic to run before adding this matchable to a queue
  }
}

The Matchable passed to the initialize method will include an empty ExtMatchable. Use initialize to set data on the ExtMatchable before the Matchable enters the queue.

This method will have one of the following outcomes:

  • Matchable is added to the matchmaking queue: return null
  • Party in the Matchable is fast-tracked to the game instance: generate and return a NewGameInstance. For example, custom games for events like in-house tournaments may want to skip matchmaking and place players directly in a game instance regardless of skill level or other standard matchmaking data.
  • Matchable is prevented from joining the queue: an ExtException is thrown. The party leader will receive the PartyService_FailedToEnterMatchmaking error.

Related events:

Match parties #

Design logic to compare parties and form or update game instances.

The primary methods in the Matchmaking Plugin are matchParties and matchPartiesWithGame, which are used to perform matchmaking operations such as comparing players and moving them between Matchables.

Compare parties in the matchmaking queue #

Match parties

As part of the matchParties method, Matchables are compared using a set of developer-defined matchmaking data, such as skill level or preferred game server zones. Only two Matchables can be compared at once. One is considered the anchor Matchable, and the other is considered the other Matchable.

interface MatchmakingPlugin {
  fun matchParties(
    queueKey: MatchmakingQueueKey, 
    anchor: Matchable, 
    other: Matchable
  ): NewGameInstance? { 
    // Custom matchmaking logic 
  }
}

Build logic in the matchParties method to compare parties in the Matchables. The method can be used to do the following:

If the matchParties method throws an exception, the Matchmaking service logs an error and removes both the anchor Matchable and the other Matchable from the queue to allow for debugging. Players are notified via a SessionChangedV1Notification. The anchor position is then reset to the oldest Matchable in the queue.

Compare parties with an active game instance #

Add to game instance

The Matchmaking service uses Matchmaking Game Instances to allow game instances that have already been sent to a game server to accept new parties by entering matchmaking. When a game instance enters matchmaking to receive more parties, the Matchmaking Plugin’s matchPartiesWithGame method is called.

interface MatchmakingPlugin {
  fun matchPartiesWithGame(
    queueKey: MatchmakingQueueKey, 
    anchor: Matchable, 
    game: Matchmaking.GameInstance
  ): GameInstanceUpdate? { 
    // Custom matchmaking logic for active game instances
  }
}

Build logic in the matchPartiesWithGame method to determine if a party should be added to the game instance. The method can be used to do the following:

When adding new players to a Matchmaking Game Instance, an OnAddPlayers event is sent via WebSocket connection. To use this feature, your game server must be using WebSockets instead of HTTP to connect to Pragma Engine.

Comparison data #

When comparing Matchables, the following information is available to the Matchmaking Plugin for consideration in your matchmaking logic.

  • parties: list of parties in the Matchable
    • partyId: unique party ID
    • ext (ExtMatchmakingParty): custom party data to inform the matchmaking process
    • preferredGameServerZones: list of the party’s preferred game server zones
    • players: list of player objects within the party
    • playerCount: number of players in the party
    • secondsInQueue(): number of seconds the party has been in the matchmaking queue
  • players: list of all the players in the Matchable
    • playerId: unique player ID
    • socialId: player’s unique social ID
    • displayName: player’s unique display name
    • teamNumber: player’s team number
    • partyId: unique party ID for the party the player is in
    • gameServerZoneToPing: map of the player’s client-supplied ping map, keyed by gameServerZone ID
    • ext (ExtMatchmakingPlayer): custom player data to inform the matchmaking process
  • extMatchable (ExtMatchable): use this ext to store data calculated within the Matchmaking loop so you don’t have to recompute it on every matchParties call
  • matchmakingKey (ExtMatchmakingKey): custom data about the Matchable’s matchmaking queue
  • gameServerVersion: version of the game server the match would be played on

Related events:

Related errors:

Move parties #

Take parties from one Matchable and move them to another Matchable or Matchmaking.GameInstance.

Move parties between Matchables #

When the logic in the matchParties method determines that parties should be moved from one Matchable to another, they can be moved by invoking the Matchable.takePartiesFrom method. Both the anchor Matchable and the other Matchable can take parties from one another. When parties move between Matchables, that change persists for the life of the party unless the party is deliberately moved elsewhere.

interface Matchable {
  fun takePartiesFrom(matchable: Matchable, parties: List<Matchmaking.Party>)
}

Add parties to a game instance #

When the logic in the matchPartiesWithGame method determines that additional parties should be moved into the Matchmaking.GameInstance, they can be moved by invoking the GameInstanceUpdate.addParties method. Only the game MatchakingGameInstance can gain parties; the anchor Matchable cannot take parties from the Matchmaking.GameInstance. When parties are moved to an active game instance, that change persists for the life of the party unless the party is deliberately moved elsewhere.

interface GameInstanceUpdate {
  fun addParties(parties: List<Matchmaking.Party>, teamNumber: Int = 0) {
    setTeamByPlayers(parties.flatMap { it.players }, teamNumber)
    internalParties.addAll(parties.map { it as MatchmakingPartyImpl })
}

Related events:

Related errors:

Moving parties between Matchables does not automatically update team numbers. For existing game instances you can use the teamNumber parameter in the addParties method. Otherwise, use the functions in the Assign Teams section to change team numbers as necessary.

Add custom behavior after matchmaking loop #

Define what happens after an anchor Matchable exhausts the matchmaking queue.

If an anchor Matchable makes it through the entire queue without forming a complete match, the default behavior is that the anchor position is moved to the next oldest Matchable in the queue. Custom behavior can be added before the anchor position is moved by defining logic in the endOfLoop method:

fun endOfLoop(
  queueKey: MatchmakingQueueKey,
  anchor: Matchable
): NewGameInstance?
The endOfLoop method is also called if there is only one item in the matchmaking queue.

Example: Use this function to examine data such as match queue time and create a NewGameInstance immediately, even if the matchmaking process failed to build an ideal complete Matchable. This capability can be leveraged to build matches with a limited matchmaking pool, such as during testing.

Start a game instance #

Create a new game instance and send data to the game server.

New game instance

After successfully matching parties using the matchParties method, game instance data is communicated to the game server through the returned NewGameInstance object.

When returning a NewGameInstance:

  • Add parties to the game instance using addParties
  • Set team numbers using setTeamByPlayers (optional; default 0)
  • Use setExtGameParty to set/update the ExtGameParty payload for a given party in the game instance update. This data will be set on the NewGameInstance for the specified party.
  • Use setExtGamePlayer to set/update the ExtGamePlayer payload for a given player in the game instance update. This data will be set on the NewGameInstance for the specified player.
  • Call the continueMatchmaking method with a MatchmakingQueueKey if the NewGameInstance/GameInstanceUpdate should continue to find players
  • Set the NewGameInstance.ext (ExtGameInstance) and NewGameInstance.gameServerZone values using the constructor.

At this point, a new game instance is created. Added players are considered associated with the game instance and removed from matchmaking by exchanging the MATCHMAKING_ID on their sessions with a GAME_INSTANCE_ID.

If using the Pragma Fleet service, the Game Instance service then calls the Fleet service RPC StartGameInstanceV1Request to spin up a game server for a game instance. See Fleet Service Tasks for more information about how the Pragma Fleet service manages capacity and allocates game servers for game instances.

Related events:

Update a game instance #

Update an active game instance and send updated data to the game server.

After successfully finding parties to add to the existing game instance using the matchPartiesWithGame method, data about the game instance changes are communicated to the game server through the returned GameInstanceUpdate object.

When returning a GameInstanceUpdate:

  • Add new parties to the game instance using addParties
  • Update team numbers using setTeamByPlayers
  • Use setExtGameParty to update the ExtGameParty payload for a given party in the game instance update. This data will be set on the GameInstanceUpdate for the specified party.
  • Use setExtGamePlayer to update the ExtGamePlayer payload for a given player in the game instance update. This data will be set on the GameInstanceUpdate for the specified player.
  • Call stopMatchmaking if the GameInstanceUpdate should be removed from matchmaking

Continue matchmaking #

Continue matchmaking process after creating or updating a game.

Continue matchmaking

After you create a NewGameInstance or GameInstanceUpdate from the matchmaking process, you have the option to keep the game instance in the matchmaking queue to continue accepting new players/parties. Game instances remain in matchmaking as long as their continueMatchmaking property is true.

By default, NewGameInstance.continueMatchmaking is false, meaning the new game instance will exit the matchmaking process as soon as it is created. If you want a new game instance to continue accepting new players/parties, call NewGameInstance.continueMatchmaking with the appropriate matchmaking queue key. When called, the continueMatchmaking boolean is set to true and the game instance will be added to the matchmaking queue.

Because GameInstanceUpdate objects are created with the express purpose of entering matchmaking, the GameInstanceUpdate.continueMatchmaking value defaults to true.

Leave matchmaking #

Exit the matchmaking process.

Leave matchmaking as a player #

Player leaves matchmaking

Players can request to leave matchmaking by invoking PartyApi.LeaveMatchmaking (Unreal) or GameLoopApi.LeaveMatchmaking (Unity). This action removes their whole party from the matchmaking service.

Player->PartyApi()->LeaveMatchmaking(
OnComplete
)
player.GameLoopApi.LeaveMatchmaking(
OnComplete
)
{
  "requestId": 15,
  "type": "matchmakingRpc.LeaveMatchmakingV2Request",
  "payload": {
  }
}

After the player and their party are removed from matchmaking, players receive a OnLeftMatchmaking event. TheLeaveMatchmaking() function also triggers the Party Plugin’s returnFromMatchmaking() method, which provides a way to handle players and parties leaving matchmaking. See Party Service Tasks: Return from Matchmaking for more information.

Leave matchmaking as a game instance #

If, after creating a Game Instance Update object, you want the Matchmaking Game Instance to leave matchmaking, use GameInstanceUpdate.stopMatchmaking.

interface GameInstanceUpdate {
  fun stopMatchmaking() {
    continueMatchmaking = false
  }
}

Game servers can also directly request to leave matchmaking by invoking MatchApi.LeaveMatchmaking.

Player->MatchApi()->LeaveMatchmaking(
  gameInstanceId,
  Delegate
)
player.MatchApi.LeaveMatchmaking(
  gameInstanceId,
  callback
)
{
  "requestId": 16,
  "type": "matchmakingRpc.LeaveMatchmakingV2Request",
  "payload": {
  }
}

Related events:

Related errors:

Customize queue names for reporting #

Customize queue names for metrics/logging

For purposes of viewing metrics and logs, you might want to group various matchmaking queues into one metric/log entry. Using the Matchmaking Plugin’s getQueueName() function, you can generate a queue name based on a queue’s ExtMatchmakingKey property.

For example, say your ExtMatchmakingKey contains a game mode, along with various other parameters needed for matchmaking purposes (region, difficulty, etc.). For reporting purposes, you might want matchmaking queues with the same game mode to appear as one metric. To do so, customize the getQueueName() function in your implementation of the Matchmaking Plugin:

fun getQueueName(extMatchmakingKey: ExtMatchmakingKey): String {
      
    return extMatchmakingKey.gameMode;
}

The getQueueName() function is called during instantiation of a new matchmaking queue or when a metric/log requires a queue name and doesn’t already have access to the queue. In our example, all queues with the same game mode will get the same queue name and be presented as one for metric/logging purposes.

If you don’t customize the getQueueName function, the function returns “undefinedqueueName” by default.

Examples #

Example: Party enters matchmaking service #

When a party enters the matchmaking service it joins the matchmaking queue as a Matchable object. The matchmaking service uses logic defined in the Matchmaking Plugin’s matchParties method to compare Matchable objects. During this matchmaking process, parties may be added to or removed from Matchable objects. If the matchParties method determines that two Matchables are a match, a NewGameInstance is generated and the Matchable is sent to the game server.

Example: Game Instance enters matchmaking #

Depending on your settings, a game instance can enter the matchmaking service and accept additional parties. For example, a battle royale mode may keep all players in a pre-game lobby where they can interact with each other before the full game has been built. This lobby exists on a game server, and this game requires the use of a Matchmaking Game Instance. The matchPartiesWithGame method is called when a Matchmaking Game Instance enters the matchmaking process. Like the matchParties function compares a queued Matchable to an anchor Matchable, the matchPartiesWithGame function compares an anchor Matchable with the Matchmaking.GameInstance.