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 calls and methods, see All Calls and Methods.

Initialize the matchmaking process #

The matchmaking process starts when parties enter the Matchmaking service from the Party service. The initialize method is called every time a new party enters the Matchmaking service via MatchmakingService.enterMatchmaking, which is called as part of PartyService.enterMatchmaking.

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

Add custom logic to the initialize method to determine one of the following outcomes:

  • Party is added to the matchmaking queue
  • Party is fast-tracked to the game instance
  • Party is prevented from joining the queue

If a party is successfully added to the matchmaking queue, the initialize method returns null and a Matchable is created for that party. This Matchable is like a train car, where there’s space for other parties to join until the car is full.

If a party contains all the players needed for a game instance, and the developer wants to enable fast-tracking the game instance and ignore any mismatches that would typically invalidate a matchup (such as skill disparity), initialize can generate a NewGameInstance directly. 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.

If the party cannot join the matchmaking queue due to validation errors, an ExtException is thrown. The party leader will receive the PartyService_FailedToEnterMatchmaking error.

Match parties #

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

Compare Matchables #

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 
  }
}

Within each queue, the oldest Matchable is selected as the anchor. All other Matchables in that queue are named other, and each of these are compared to the anchor to check viability of combining parties into one Matchable. The anchor Matchable begins comparison with the next oldest Matchable, and continues through all Matchables in the queue until it reaches the accepted state for a full Matchable and a NewGameInstance is returned.

Match Parties Logic

Add custom logic to the matchParties method to determine one of the following outcomes:

  • a NewGameInstance is generated and details are sent to the game server
  • matchParties is called again with a new other Matchable
  • endOfLoop is called and a new Matchable becomes the anchor

By default, if the end of the loop is reached and no NewGameInstance has been generated, the anchor position is moved to the next oldest Matchable in the queue. To add custom behavior at this stage, implement endOfLoop as described in Add custom behavior after matchmaking loop.

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.

For each comparison, the following information is available to the Matchmaking Plugin for consideration in your matchmaking logic. This data is stored on the Matchable object.

Match Comparison Data
  • parties - list of matchmaking parties
    • partyId: UUID
    • ext: ExtMatchmakingParty
    • preferredGameServerZones: List
    • players: List<Matchmaking.Player> - details for all players within that matchmaking party
    • playerCount: Int - count of players in this party
    • secondsInQueue(): Int
  • players - list of all players in match parties
    • playerId: UUID
    • socialId: UUID
    • displayName: PragmaDisplayName
    • teamNumber: Int
    • partyId: UUID
    • gameServerZoneToPing: Map<String, Int>
  • matchmakingKey: ExtMatchmakingKey - the ext data associated with the queue
  • gameServerVersion: String - the version of the game server the match would be played on

Move parties between Matchables #

When the matchmaking logic that compares Matchables determines that parties should be moved from one Matchable to another, they can be moved by invoking the takePartiesFrom method.

interface Matchable {
  fun takePartiesFrom(matchable: Matchable, parties: List<Matchmaking.Party>)
}
Moving parties between Matchables does not automatically update team numbers. Use the functions in the Teams section to change team numbers as necessary.

Add custom behavior after matchmaking loop #

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?

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 new game instance #

When a NewGameInstance is created and returned to the matchmaking service, all the data needed for a game instance to start on a game server is sent to the Game Instance service. Any parties included in the NewGameInstance are removed from their Matchable. If this results in an empty Matchable, the Matchable is removed from the matchmaking queue.

Assign teams #

Team numbers are assigned to players when their party is added to a NewGameInstance (NewGameInstance.addParties). If the team number is not specified, all players default to team 0.

To assign team numbers by player, use the NewGameInstance setTeamByPlayers method and specify one or more players to add to a team.

interface NewGameInstance { 
  fun setTeamByPlayers(players: List<Matchmaking.Player>, teamNumber: Int)
}

Send custom player and party data to the game instance #

When a NewGameInstance or a GameInstanceUpdate is created, you might need to set custom data about the player or party in that matchmaking result to send to the Game Instance Service, where it can be used to send custom data to the running game instance or incorporated into your end game result logic.

interface NewGameInstance {
  fun setExtGameParty(player: Matchmaking.Party, ext: ExtGameParty)
  fun setExtGamePlayer(player: Matchmaking.Player, ext: ExtGamePlayer)
}
interface GameInstanceUpdate {
  fun setExtGameParty(player: Matchmaking.Party, ext: ExtGameParty)
  fun setExtGamePlayer(player: Matchmaking.Player, ext: ExtGamePlayer)
}

Add parties and players to active game instances #

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

The matchPartiesWithGame method attempts to match Matchables in the matchmaking queue with the existing game instance (now considered a MatchmakingGameInstance) to add more parties to the game instance. The MatchmakingGameInstance passed to matchPartiesWithGame includes data stored in the ExtMatchmakingGameInstance, ExtMatchmakingGameParty, ExtMatchmakingGamePlayer protos.

fun matchPartiesWithGame(
  queueKey: MatchmakingQueueKey,
  anchor: Matchable,
  game: MatchmakingGameInstance
): 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. If so, return a Game Instance Update with the new party data. At this point, the parties and players will be converted from MatchmakingParties and MatchmakingPlayers to MatchmakingGameParties and MatchmakingGamePlayers, and added to the game instance.

While waiting for this data to arrive, the MatchmakingGameInstance object receiving the matches will be skipped over during matchmaking queue processing until it has been brought up to date by the engine. The number of MatchmakingGameInstances currently in this paused state is exposed to metrics as pragma.matchmaking.pausedGameInstancesInQueue.

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

Leave matchmaking #

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(). Game servers can also directly request to leave matchmaking by invoking MatchApi.LeaveMatchmaking.

The Game Instance service automatically removes the game instance from matchmaking if the game instance ends due to invoking GameInstanceRPC.EndGame, the game server timing out via the keep-alive heartbeat or the absolute timeout is reached.

Leave matchmaking as a player #

Players can request to leave matchmaking by invoking GameLoopApi.LeaveMatchmaking. This action removes their whole party from the matchmaking service.

Server->GameLoopApi()->LeaveMatchmaking(
  OnComplete
)
Server.GameLoopApi.LeaveMatchmaking(
  OnComplete
)

After the player and their party are removed from matchmaking, players receive a OnLeftMatchmaking event.

The LeaveMatchmaking call also triggers the Party Plugin’s returnFromMatchmaking method, which provides a way to handle parties leaving matchmaking. See Party Implementation: Return from Matchmaking for more information.

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 MatchmakingGameInstance.