Skill Ratings
The IMS Matchmaker is capable of using player 'skill' values to match players together for more balanced, competitive matches.
To use this feature, your game must use either:
- Use PlayFab authentication and store your player's skill data in PlayFab player data objects, or
- Use AccelByte authentication and store your player's skill data in AccelByte CloudSave data objects.
Te IMS Matchmaker will only read data from your chosen backend; your game server (or backend) will be responsible for updating these player data at the end of each match with new values depending on whether they win or lose.
Overview
The goal of any skill-based matchmaking system is to estimate each player's individual skill level within as few matches as possible, allowing players of like skill to be matched with one another.
Skill-based matchmaking relies on two values being stored and tracked for every user:
mu
- this value describes the measured skill of the player, such that two players with the samemu
value are considered to be of equal 'skill'.sigma
- this value describes the level confidence in themu
value, whereby a small value indicates high confidence, and a large value implies less confidence.
Every time a player wins a game, the mu
value typically increases by a constant amount, indicating that their skill appears to be higher than previously measured. Conversely, every time a player loses a game, their mu
value is typically decreased by the same amount.
The sigma
value typically changes depending on whom the player was competing against. A player that consistently beats lower-skilled players and loses to higher-skilled values will see their sigma
value reduce, as it indicates that the mu
value is accurate. Conversely, when the player loses to a lower-skilled player, or beats a higher-skilled player, their sigma
value will typically increase, indicating a decreased confidence in their mu
skill rating.
We recommend using a default value of 30 for mu
, and 10 for sigma
, and using our rating calculation endpoint to calculate new values for players at the end of each match.
(For more information on skill-based matchmaking, we strongly recommend reading 'Computing Your Skill' by Jeff Moser.)
PlayFab Configuration
Your title should store a PlayFab Read-Only data object for each player, and this object will need to specify two numeric values - a mu
(average skill) value, and a sigma
(skill confidence) value.
The below Queue configuration assumes you are using a PlayFab data object named Ratings
with the following JSON structure:
{
"ranked": {
"mu": 30,
"sigma": 10
}
}
Queue Configuration
Your Queue will need to specify two additional data blocks in order to first read the rating data (see dataSource
), and second process it (see dataPoints
).
{
"name": "projects/speedy-racer-1999/queues/ranked",
"id": "speedy-racer-1999.ranked",
"title": "Solo Queue",
"active": true,
"simple": {
"playerSettings": {
"maxPlayers": 2
},
"startSettings": {
"playersToAllocate": 2
}
},
"dataSource": {
"playFab": {
"ranked_rating.mu": {
"default": 30,
"readOnlyDataKey": "Ratings",
"valuePath": "ranked.mu"
},
"ranked_rating.sigma": {
"default": 10,
"readOnlyDataKey": "Ratings",
"valuePath": "ranked.sigma"
}
}
},
"dataPoints": [
{
"config": {
"musigma": {
"path": "ranked_rating",
"mu": 30,
"sigma": 10,
"beta": 5,
"maxMuWeight": 2,
"medMuWeight": 1,
"ordinalDeviations": 3
}
},
"extension": "musigma",
"floor": 0.5,
"name": "Skill",
"weight": 1
}
]
}
The dataSource.playFab
keys pull the ranked_rating.mu
and ranked_rating.sigma
values from the user's PlayFab Ratings
object via keys ranked.mu
and ranked.sigma
, respectively.
Note: the ranked_rating
object keys within dataPoints
must be named mu
and sigma
for skill-based matchmaking to work.
Defaults are also provided for the mu
and sigma
values - these will be used if the object or keys are missing (for instance, if this is player's first match.)
AccelByte Configuration
Your title should store rating data in a CloudSave AdminPlayerRecord
for each player, and this object will need to specify two numeric values - a mu
(average skill) value, and a sigma
(skill confidence) value.
The below Queue configuration assumes you are using a CloudSave record named Ratings
with the following JSON structure:
{
"ranked": {
"mu": 30,
"sigma": 10
}
}
Queue Configuration
Your Queue will need to specify two additional data blocks in order to first read the rating data (see dataSource
), and second process it (see dataPoints
).
{
"name": "projects/speedy-racer-1999/queues/ranked",
"id": "speedy-racer-1999.ranked",
"title": "Solo Queue",
"active": true,
"simple": {
"playerSettings": {
"maxPlayers": 2
},
"startSettings": {
"playersToAllocate": 2
}
},
"dataSource": {
"accelByte": {
"ranked_rating.mu": {
"default": 30,
"adminPlayerRecordKey": "Ratings",
"valuePath": "ranked.mu"
},
"ranked_rating.sigma": {
"default": 10,
"adminPlayerRecordKey": "Ratings",
"valuePath": "ranked.sigma"
}
}
},
"dataPoints": [
{
"config": {
"musigma": {
"path": "ranked_rating",
"mu": 30,
"sigma": 10,
"beta": 5,
"maxMuWeight": 2,
"medMuWeight": 1,
"ordinalDeviations": 3
}
},
"extension": "musigma",
"floor": 0.5,
"name": "Skill",
"weight": 1
}
]
}
The dataSource.accelByte
keys pull the ranked_rating.mu
and ranked_rating.sigma
values from the user's AccelByte AdminPlayerRecord
with the name Ratings
via the keys ranked.mu
and ranked.sigma
, respectively.
Note: the ranked_rating
object keys within dataPoints
must be named mu
and sigma
for skill-based matchmaking to work.
Defaults are also provided for the mu
and sigma
values - these will be used if the object or keys are missing (for instance, if this is player's first match.)
Musigma Data Point
The Data Point block configures the Matchmaker to use the ranked_rating.mu
and ranked_rating.sigma
values provided by the configured Data Source.
Data Points extensions allow us to add behaviour to the matchmaker. In this case, we want to use the musigma
extension, which do by using the following parameters:
name
- the name of this data block, we suggest something descriptive likeSkill
to indicate this block is responsible for skill-based matchmaking, as this will be emitted to the metrics backend.extension
- enable support for skill-based matchmaking - this must be set tomusigma
.floor
- the minimum score that this data point must return for the match to be accepted, and can be reduced to permit looser matching (and therefore shorter queue times) -0.5
is a good starting value.weight
- when using multiple data points, this determines how much influence skill-based matching has. (Since we're only defining one data point, a value of1
is ideal.)config
- the matching criteria to use, which are described in more detail in Tuning.
Here's an example with recommended values for the extension:
{
"config": {
"musigma": {
"path": "ranked_rating",
"mu": 30,
"sigma": 10,
"beta": 5,
"maxMuWeight": 2,
"medMuWeight": 1,
"ordinalDeviations": 3
}
},
"extension": "musigma",
"floor": 0.5,
"name": "Skill",
"weight": 1
}
Tuning
The default values listed above are a good starting point, but you will want to adjust them through testing.
The musigma
block nested within config
is where most configuration is done:
path
- where to retrieve themu
andsigma
values from - this should beranked_rating
if using the example provided in Queue Configurationmu
- the default Mu value (skill rating) to use for players if one is not available - we suggest30
sigma
- the default Sigma value (confidence rating) to use for players if one is not available - we suggest using a third ofmu
, i.e.10
beta
- defines the maximum permitted skill disparity (i.e. difference inmu
values) to allow - we suggest half ofsigma
, i.e.5
maxMuWeight
- the weight to apply to the highest-skilled member of a party - a value above1
will increase their influence on the party's estimated skillmedMuWeight
- the weight to apply to the median mu value of a party - a value below1
will decrease their influence on the party's estimated skillordinalDeviations
- the modifier affecting how much sigma factors into final skill estimation for a team. Increasing this value will mean the matchmaker treats players with a higher sigma value as less skilled, thereby increasing the confidence that they are at that skill rating or better at the cost of potentially matching them against weaker players. We suggest starting with a value of3
.
We recommend not changing the mu
value at all, but you may want to reduce sigma
slightly if new players are being put into matches that are too challenging for them.
The beta
value can be decreased to make the matchmaker favour players of more similar skill levels (although this may mean players have to queue a little longer), or increased to loosen the criteria (which typically means they queue for less time.) For a more detailed breakdown, refer to Beta Tuning.
If it is more likely for a highly-skilled player to 'carry' their party to victory, you may want to increase the maxMuWeight
value above 1
, so they have a greater impact on their overall party's estimated rating.
Finally, you may want to increase the ordinalDeviations
such that parties with a low overall rating confidence are more likely to be matched with lower-skilled teams. This can help reduce the likelihood of new players (with default - and therefore typically higher - Sigma values indicating lower confidence in their reported skill rating) being repeatedly beaten by higher-skilled teams.
Match Finding
In order to generate matches, we first have to reduce the mu
and sigma
numbers for each teams into something that can be compared.
First, for each player we rate them within the range of possible skill levels they may be at based on the queue configuration. This is calculated simply by taking their current mu
value and subtracting sigma
times the queue's ordinalDeviations
setting. For example, if a player has the default mu
of 30 and a sigma
value of 10, using the default ordinalDeviations
setting of 3 would result in their final rating being 0 - in other words, the rating at which we are nearly 100% certain they are that skilled (or better.)
As players continue to play matches and their sigma value shrinks, eventually this will result in their adjusted rating being closer to their actual mu
value. Players who queue individually are scored this way, while parties work slightly differently.
Players who queue together as a party are rated based on the queue configuration - queues can be tuned so that parties of players will be scored based on their best player (using the maxMuWeight
setting) or their median player (using the medMuWeight
setting). In the case of teams with an even number of players, the median player will be the average mu
of the middle most skilled players. The weights for each setting are relative, so setting a 2-to-1 ratio of max to med weight would result the most skilled player representing 66% of the final base rating for the team, while the median player would account for 33% of the final value. Once a mu value has been estimated for the party, it is reduced by the average of the sigma
values for each party member times the ordinalDeviations
setting.
Once individual players and parties have been rated, the scoring function determines which players would be a good match for one another by finding individuals and parties whose rating delta is less than the beta
setting for the queue. These individuals and parties are organized into teams based on the configured team size in the queue, which are then organized into matches.
Buckets
Typically, you will only match players together if they have skill values that are similar - however, you can configure the Matchmaker to be increasingly tolerant of higher skill disparities as time passes to prevent players from being stuck in the queue forever. This ensures that at busy periods when players of similar skill are more likely to be queuing, they will be matched together, but at less busy periods players can still get matched.
This can be configured using the maxBeta
, bucket
and bucketDuration
keys:
{
"config": {
"musigma": {
"path": "ranked_rating",
"mu": 30,
"sigma": 10,
"maxMuWeight": 2,
"medMuWeight": 1,
"ordinalDeviations": 3,
"maxBeta": 20,
"buckets": 5,
"bucketDuration": 10
}
},
"extension": "musigma",
"floor": 0.5,
"name": "Skill",
"weight": 1
}
Note how the beta
value is absent and has been replaced by maxBeta
, which will dynamically increase the beta value used by the calculation depending on how long a player has been queued for.
maxBeta
- the maximum beta value to scale up to.buckets
- the number of steps in which the beta value will be scaled as time passes.bucketDuration
- how long the first bucket will last, defined in seconds - subsequent buckets scale longer against a square exponential series.
In the above example, the 'beta' value used by the calculation (which defines the maximum skill difference permitted between players) will scale up to 20 in 5 separate buckets:
- First 10 seconds - a beta value of
4
- Next 40 seconds - a beta value of
8
- Next 90 seconds - a beta value of
12
- Next 160 seconds - a beta value of
16
- Beyond 160 seconds - a beta value of
20
Note how the beta value increases over time, such that the matchmaker will try to match players with a similar skill initially, but widens the search criteria as time passes to increase the chance of the user being matched, albeit with players that may be of higher/lower skill.
Rating Calculation
When a match ends, it is the responsibility of your game server or backend to ensure that the skill ratings of players are updated depending on the outcome of the game and whether they were on the winning/losing team.
The IMS Matchmaker Developer API provides an endpoint that can perform this calculation for you.
You should issue a JSON POST request to the https://prd.matchmaker.os.i8e.io/v1/admin/rate
endpoint, with your skill rating settings and a list of teams and players, ranked by their finishing position. For example:
{
"config": {
"modelId": "PLACKETT_LUCE",
"beta": 5,
"epsilon": 0.001,
"mu": 30,
"sigma": 10
},
"teams": [
{
"rank": 0,
"team": {
"teamId": "red",
"players": [
{ "playerId": "player1", "mu": 35.0, "sigma": 5.1 },
{ "playerId": "player2", "mu": 32.1, "sigma": 2.9 }
]
}
},
{
"rank": 1,
"team": {
"teamId": "blue",
"players": [
{ "playerId": "player3", "mu": 30.5, "sigma": 4.4 },
{ "playerId": "player4", "mu": 29.5, "sigma": 9.4 }
]
}
}
]
}
In the above example, the following parameters can be configured:
modelId
- the type of skill estimation model to use - currently only Plackett-Luce is supported.beta
- the beta value to apply to the adjustment, which should match the value defined by the data point.epsilon
- the minimum adjustment to make tosigma
values regardless of the outcome of the calculation. This needs to be a small, non-zero value and is necessary to prevent sigma values from zeroing out.mu
- the default Mu value to use, which should match the value defined by the data point.sigma
- the default Sigma value to use, which should match the value defined by the data point.
Additionally, the teams
block specifies the IDs and ratings of players before the match started, along with their respective ranks when the game ended. In this case, team red
(rank 0) beat team blue
(rank 1). Had the game resulted in a draw, both teams would have been given the same rank
value.
The endpoint will return with a set of new ratings for each player, based on the Plackett-Luce algorithm when applied with the supplied values. You should update your player's data with these values, such that next time they queue for a match, their updated skill values will be used, and they'll be placed in a more appropriate game.
{
"teams": [
{
"teamId": "red",
"players": [
{
"playerId": "player1",
"mu": 35.703050324698204,
"sigma": 5.065653319815339
},
{
"playerId": "player2",
"mu": 32.32732230798585,
"sigma": 2.8936994946797667
}
]
},
{
"teamId": "blue",
"players": [
{
"playerId": "player3",
"mu": 29.976699181616407,
"sigma": 4.360939109491974
},
{
"playerId": "player4",
"mu": 27.111629116096374,
"sigma": 9.012856163163935
}
]
}
]
}
Beta Tuning
One of the most important parts of the matchmaking algorithm that needs to be customized to each game is the beta
value. Assigning this number correctly will help the score update function converge on player skill faster and more accurately while also helping avoid player assignment to matches they stand little chance of winning.
The beta
value should reflect one standard deviation (or approximately an 80% chance of victory) based on player skill. This number can vary a lot based on how much of a factor skill is in your game, or even a particular match type, and really needs to be dialed in as you accumulate match data.
In order to be able to dial this number in, we recommend recording the results of matches along with player information that can be resolved into skill ratings. With this information in hand, we can create a simple scatter plot as follows:
- For each match, approximate the rating for each team. This should be consistent with the same scale your default musigma values use.
- Find the delta in rating between the teams.
- If the favored (higher rated) team won, plot that as a 1 or, if they lost, as a 0.
- Find the line of best fit for the graph, and check what delta mu the line intercepts 0.8 at - this should be a decent value for your
beta
.
The 80% chance of victory beta
value is what should be used when calling the rating calculator - you may want to use a different beta
for the actual datapoint configuration (possibly closer to the 50% value) to create more even matches.
FAQ
How should skill updates work with backfill?
There is no way to take into account a player who was dropped midway through a match when adjusting skill ratings, or new players being introduced. It is likely best initially to not update the skill of players in backfilled matches.
Is there a way to account for lopsided victories?
The basic skill calculation only concerns itself with who won, who lost, and how surprising that result was (based on the relative disparity between player skill). As a result a quick and decisive victory will produce the same results as a protracted and hard-fought one.
If you only use the maximum and median player skills for matchmaking, does that mean that the least skilled player is not considered at all?
For the purpose of estimating the skill of a team yes, but for the purpose of estimating our uncertainty about their skill no. The sigma
value of the least skilled players are a factor in the party's average sigma
value, which should affect their final rating.
When the matchfinding algorithm rates players and then filters them based on the configured beta, doesn't that mean that you could technically have a match including one player who is -beta and another who is +beta relative to the pivot player?
Yes, in theory this is possible - however, this would give the match a low score in the matchmaking function, and so it would only be made if no other matches were possible.