Integrate matchmaking (Unity)
This guide covers setting up matchmaking in a Unity game. If you're using Unreal Engine, refer to the Unreal matchmaking integration guide .
Overview
Matchmaking is the process by which two or more players can be evaluated for a match, and joined to a game session so they can play together. There are several components that AccelByte Gaming Services (AGS) Matchmaking interacts with during the matchmaking process.
Session Template: defines the characteristics a session will be created with. This includes joinability, what game server deployment to use, player requirements, team composition, etc.
Match Ticket: defines a request for matchmaking, either by a solo player or a party, with the player information attached for evaluation.
Backfill Ticket: similar to a match ticket, however, it is only created if auto-backfill is enabled in the match ruleset. In which case, when two or more players are matched, they will be joined to the session and a backfill ticket is submitted to AGS Matchmaking to continue to find matches until the minimum number of players have connected to the session.
Match Pool: defines a collection of match tickets that can be evaluated by the service for valid matches. Tickets end up in the same pool based on the selected game mode and preferences, if applicable.
Match Ruleset: defines the attributes and comparison criteria that will be used by the default match function to determine if tickets make a valid match. In the case that the match function has been overridden, the ruleset will still need to be configured with any attributes that are stored in AGS Statistics that are required for evaluation.
Match Function: defines the logic that the service will use to evaluate match tickets. By default, the service will use the criteria defined in the associated match ruleset.
This article will show you how to integrate AGS Matchmaking into your Unity game client using the Unity SDK plugin.
Goals
This article aims to provide you an understanding of the matchmaking player experience flow and show you how to integrate:
- Starting matchmaking for solo players and parties
- Canceling matchmaking before a match is found
- Listening for and handling match results
- Listening for game session invites and joining sessions
Prerequisites
To complete all the steps in this article, you will need:
- A familiarity with AGS Lobby, Session, and Matchmaking.
- An basic understanding of Unity.
- The AGS Game SDK installed into your Unity project and set up using its required client ID.
- Access to the AGS Admin Portal.
- A session template, match ruleset, and match pool created and configured.
- Your game client to have authenticated users with the AGS backend and connected to AGS Lobby.
Implementing the Matchmaking flow
Implementation follows the high level flow described in our overview of the matchmaking flow.
Listen to matchmaking-related notifications
Before proceeding with the matchmaking flow, ensure the player is logged in and authenticated. It is strongly advised to connect them to the Lobby service as soon as possible.
Listen to matchmaking-related notifications
// Connect to the Lobby service as soon as the user has successfully logged in or authenticated.
// This helps avoid race conditions with events and allows for accurate CCU metrics tracking.
// Use lobby.Connect() to establish the connection.
var lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
// Match started notification.
// This is only received when the user is part of a party and
// the party leader has successfully started matchmaking (MatchmakingV2.CreateMatchmakingTicket).
lobby.MatchmakingV2MatchmakingStarted += result =>
{
if (result.IsError)
{
// Do something if MatchmakingV2MatchmakingStarted fails
Debug.Log($"Error MatchmakingV2MatchmakingStarted, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if MatchmakingV2MatchmakingStarted is successfully received
};
// Match found notification.
// This is received when a match has been found for the party,
// usually when there are no available servers. This is received to
// notify that there is already a match and to wait for a spun-up DS to accommodate the game session.
lobby.MatchmakingV2MatchFound += result =>
{
if (result.IsError)
{
// Do something if MatchmakingV2MatchFound fails
Debug.Log($"Error MatchmakingV2MatchFound, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if MatchmakingV2MatchFound is successfully received
};
// Invited to session notification.
// This is received when there is a DS ready to accommodate the game session.
// It is safe to join the game session (Session.JoinGameSession) once the user receives this notification.
lobby.SessionV2InvitedUserToGameSession += result =>
{
if (result.IsError)
{
// Do something if SessionV2InvitedUserToGameSession fails
Debug.Log($"Error MatchmakingV2MatchFound, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if SessionV2InvitedUserToGameSession is successfully received
};
// Match timeout notification.
// This is received when the user's or party's matchmaking time has reached the set timeout value.
// Before restarting the matchmaking process, make sure that the expired ticket is already cleaned up
// (MatchmakingV2.DeleteMatchmakingTicket).
lobby.MatchmakingV2TicketExpired += result =>
{
if (result.IsError)
{
// Do something if MatchmakingV2TicketExpired fails
Debug.Log($"Error MatchmakingV2TicketExpired, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if MatchmakingV2TicketExpired is successfully received
};
Start matchmaking
var matchmaking = AccelByteSDK.GetClientRegistry().GetApi().GetMatchmakingV2();
// Start Matchmaking
string matchPool = "a-match-pool";
// Add any optional parameters if needed
var optionalParams = new MatchmakingV2CreateTicketRequestOptionalParams
{
// Set the custom attributes you need for matchmaking. Matchmaking will try to match the attributes.
// In this example, the map names as values for the custom parameter for matchmaking only to specified maps.
attributes = new Dictionary<string, object>()
{
{ "map_names", "map_01" }
},
// Latencies are used to give the Matchmaking service more information about the game clients latencies to all available servers region.
// It will only matchmake to specified regions.
// To get all latencies, use QosManager.GetAllServerLatencies.
latencies = new Dictionary<string, int>()
{
{"ap", 100},
{"eu", 90}
},
// If matchmaking is performed by the party leader, fill this with the party session ID.
// It will make all users in the party to be included in matchmaking and later will be notified when the match is found.
// You can retrieve the party session ID via Session.GetUserParties
sessionId = "party-session-id"
};
string matchTicketId = "";
matchmaking.CreateMatchmakingTicket(matchPool, optionalParams, result =>
{
if (result.IsError)
{
// Do something if CreateMatchmakingTicket fails
Debug.Log($"Error CreateMatchmakingTicket, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if CreateMatchmakingTicket succeeds
matchTicketId = result.Value.matchTicketId;
});
Join a game session
After matchmaking is completed, the game client will receive a game session invitation and can join the matched game session.
var session = AccelByteSDK.GetClientRegistry().GetApi().GetSession();
var lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
Result<SessionV2GameInvitationNotification> InvitedToGameSessionNotif;
lobby.SessionV2InvitedUserToGameSession += result =>
{
InvitedToGameSessionNotif = result;
if (result.IsError)
{
// Do something if SessionV2InvitedUserToGameSession fails
Debug.Log($"Error SessionV2InvitedUserToGameSession, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
Debug.Log($"Invited to game session {InvitedToGameSessionNotif.Value.sessionId}");
// Here, the game client can decide to join a game session or not
session.JoinGameSession(InvitedToGameSessionNotif.Value.sessionId, joinGameSessionResult =>
{
if (result.IsError)
{
// Do something if JoinGameSession fails
Debug.Log($"Error JoinGameSession, Error Code: {joinGameSessionResult.Error.Code} Error Message: {joinGameSessionResult.Error.Message}");
return;
}
Debug.Log($"Successfully joined a game session {joinGameSessionResult.Value.id}");
if (joinGameSessionResult.Value.dsInformation.status == SessionV2DsStatus.AVAILABLE)
{
string serverIP = joinGameSessionResult.Value.dsInformation.server.ip;
Debug.Log($"DS Ready, IP: {serverIP}");
}
});
};
Connect to a dedicated server
Game clients need to listen to the dedicated server (DS) update notification to check if the DS is ready or not. Alternatively, game clients can also check DS information after joining a game session.
var lobby = AccelByteSDK.GetClientRegistry().GetApi().GetLobby();
lobby.SessionV2DsStatusChanged += result =>
{
if (result.IsError)
{
// Do something if SessionV2DsStatusChanged fails
Debug.Log($"Error SessionV2DsStatusChanged, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
var status = result.Value.session.dsInformation.status;
if (status == SessionV2DsStatus.AVAILABLE)
{
string serverIP = result.Value.session.dsInformation.server.ip;
Debug.Log($"DS Ready, IP: {serverIP}");
}
};
Cancel matchmaking
If you need to cancel matchmaking before the process completes or timeout occurs, you can call following API:
var matchmaking = AccelByteSDK.GetClientRegistry().GetApi().GetMatchmakingV2();
// Obtain from start matchmaking result
string matchTicketId = "match-ticket-id";
matchmaking.DeleteMatchmakingTicket(matchTicketId, result =>
{
if (result.IsError)
{
// Do something if DeleteMatchmakingTicket fails
Debug.Log($"Error DeleteMatchmakingTicket, Error Code: {result.Error.Code} Error Message: {result.Error.Message}");
return;
}
// Do something if DeleteMatchmakingTicket succeeds
});
Troubleshoot issues
In this section, you can find common errors and issues that may occur when using the service, along with recommendations on how to resolve them.
OnMatchmakingTicketExpired notification from AGS Lobby
If you receive the OnMatchmakingTicketExpired notification from AGS Lobby, that means that the ticket reached the timeout limit and the player has been removed from matchmaking. This often happens if the timeout defined in the match pool configuration is too short or the match ruleset doesn't allow enough rule flexing to enable the player to match with others. To resolve:
- Review the match pool configuration to determine if the match or backfill ticket timeout is too short.
- Review the match ruleset to make sure if the minimum player or team requirements have been set correctly.