Matchmaking Plugin #
The Matchmaking Plugin provides the following methods that allow for a wide variety of matchmaking implementations:
method | description |
---|---|
initialize | Handles initial steps for parties that enter the Matchmaking service. |
matchParties | Attempts to match an anchor Matchable with another Matchable in the queue. If a match is made, a NewGameInstance is returned. |
buildMatch | Attempts to match an Active Match with another Matchable in the matchmaking service. |
endOfLoop | Returns a NewGameInstance or null at end of the matchmaking loop to either create a new game instance with the anchor Matchable, or exit the matchmaking process. |
Initializing the matchmaking process #
At this stage of the matchmaking flow, parties enter 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 potential match 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 match, and the developer wants to enable fast-tracking the match and ignore any mismatches that would typically invalidate a matchup (such as skill disparity), initialize
can generate a NewGameInstance
. For example, custom games for events like in-house tournaments may want to skip matchmaking and place players directly in a match 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.
Matching 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 matches #
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 classified as 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.
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 newother
MatchableendOfLoop
is called and a new Matchable becomes theanchor
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 complete 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.
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 {
takePartiesFrom(
matchable: Matchable,
parties: List<Matchmaking.Party>
)
}
You cannot take parties from an Active Match.
Moving parties between Matchables does not automatically update team number. 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 using the Matchmaking Plugin endOfLoop
method:
fun endOfLoop {
queueKey: MatchmakingQueueKey,
anchor: Matchable
): NewGameInstance?
Example: Use this function to examine data like match queue time and create a NewGameInstance
immediately even if the matchmaking process failed to build an ideal complete Matchable. This can be leveraged to build matches with a limited matchmaking pool, such as during testing.
Starting a new game instance #
When a NewGameInstance
is created all the data needed for a game instance to start on a game server is sent to the Match Lifecycle service. The Matchable that triggered the new game instance is then removed from the matchmaking queue.
Adding parties to game instances #
The Active Matches feature allows game instances that have already been sent to a game server to accept new players. New game instances that are configured to allow for continued matchmaking can use logic in the buildMatch
method to find additional parties.
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 match requires the use of a Matchmaking game instance.
To use the Active Match feature, the buildMatch
function for Active Matches must be implemented in addition to the matchParties
method.
interface MatchmakingPlugin {
...
fun buildMatch(
queueKey: MatchmakingQueueKey,
activeMatch: ActiveMatch,
matchable: Matchable
) {
// Custom matchmaking logic for active matches
}
}
To add new players to an Active Match, information is sent via WebSocket connection using the MatchMorePlayersFoundV1Notification
. If you want to use this feature, you must be using WebSockets instead of HTTP.
Active Matches contain a list of removedPlayers
that represents all players that were previously removed from the game instance. This can be used during the buildMatch
step to prevent players from being placed in a game instance they’ve already left.
The Active Match’s players
and removedPlayers
lists are updated when players join or are removed from the game instance on the game server. This allows the Matchmaking Plugin to rely on information being up-to-date within a few seconds.
To remove an Active Match from matchmaking once the match has enough players, use activeMatch.stopMatchmaking()
. Game servers can also directly request to leave matchmaking by invoking the endpoint MatchLifecycleRpc.LeaveMatchmaking
. The Match Lifecycle service automatically removes the match from matchmaking if the game instance ends due to invoking MatchLifecycleRpc.MatchEnd
, the game server timing out with the KeepAliveV1
, or if the MatchAbsoluteTimeout
is reached.
The game server receives updates on its matchmaking status, and the following SDK-level events exist to monitor changes.
GetSession()->MatchLifecycle().OnEnteredMatchmakingEvent
GetSession()->MatchLifecycle().OnLeftMatchmakingEvent
Session.GetService<MatchLifecycleService>().OnEnteredMatchmaking
Session.GetService<MatchLifecycleService>().OnLeftMatchmaking
Matchmaking Service Calls #
The table below contains a full list of all the Matchmaking service calls. Optionally, use the calls in the verification call column to perform additional verification for the respective calls.
Call | section | verification call |
---|---|---|
enterMatchmaking | CanEnterMatchmaking | |
enterMatchmakingWithMatchV1 | - | |
leaveMatchmakingServiceV1 | - | |
leaveMatchmaking | CanLeaveMatchmaking | |
onSessionReconnected | - | |
onSessionTerminated | - | |
removeGameServerVersionV1 | - |
Example workflow #
In this example, we have a queue of Matchable objects (represented by rectangles) waiting to be matched with other Matchable objects so a NewGameInstance
can be generated. Each Matchable object contains one or more parties (represented by a rounded square). Each party contains one or more players (represented by a circle). In our example, we’re basing our matchmaking logic on a player’s MMR (represented by the number in the player’s circle).
Additional 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 reenters matchmaking #
Depending on your settings, an Active Match can reenter the matchmaking service and accept additional parties. The buildMatch
method is called when an Active Match reenters the matchmaking process. Like the matchParties
function compares a queued Matchable to an anchor Matchable, the buildMatch
function compares queued Matchable with the Active Match.