Design a FlexMatch rule set - Amazon GameLift

Design a FlexMatch rule set

At its most basic, a matchmaking rule set does two things: it lays out a match's team structure and size, and it tells the matchmaker how to evaluate players to find the best possible match. But it can do quite a bit more than that. For example, rule set is also where you address matchmaking issues such as these:

  • Optimize the matching algorithm for your game.

  • Trigger special match processing for large matches (>40 players).

  • Enforce minimum player latency requirements to protect the quality of gameplay.

  • Gradually relax team requirements or match rules if no match can be made.

  • Define special handling for match requests that contain multiple players (party aggregation).

This topic covers the basic structure of a rule set and how to use them for matches with up to 40 players. Matches for greater than 40 players require a different rule set structure, because FlexMatch uses a streamlined algorithm to quickly match large groups of players. Learn more about building large matches in Design a FlexMatch large-match rule set.

Related Topics

Define rule set components

All rule sets contain some or all of the components as described in the general rule set schema in FlexMatch rule set schema. This topic covers design issues for each rule set component:

Need a rule set to build matches which more than 40 players? Learn how to Design a FlexMatch large-match rule set.

Describe the rule set

Provide details for the rule set.

  • name (optional) – This is a descriptive label within the rule set syntax and is not used by Amazon GameLift in any meaningful way. Do not confuse this value with the rule set name, which is set, along with the rule set syntax, when you create a rule set.

  • ruleLanguageVersion (required) – This is the version of the property expression language used to create FlexMatch rules. The value must be equal to “1.0”.

Customize the match algorithm

You have the option to modify certain elements of the default matching algorithm. By design, the default algorithm is optimized for most games to process match requests quickly and efficiently, getting players into acceptable matches with minimal wait time. You can customize the algorithm and adjust match priorities to better suit the needs of your game.

The default FlexMatch matchmaking process is as follows:

  1. All open matchmaking tickets and backfill tickets are placed in a ticket pool.

  2. Tickets are randomly grouped into one or more batches for matching. Multiple batches are formed only when the ticket pool gets too large for optimal matching.

  3. Each batch is sorted by ticket age.

  4. Starting with the oldest ticket, all tickets in a batch are evaluated for acceptable matches.

The following suggested customizations impact different stages of the matchmaking process. To customize the match algorithm, add an algorithm component to your rule set schema. See FlexMatch rule set schema for the complete reference information.

Add pre-batch sorting

You can configure FlexMatch to sort the ticket pool before forming batches. This type of customization is most effective with games that tend to have very large tickets pools. Pre-batch sorting can be used to help speed up the matchmaking process, and it also tends to form matches with greater player uniformity in certain characteristics.

Pre-batch sorting methods are defined in the algorithm property batchingPreference. The default setting is "random", which indicates that no pre-sorting occurs.

Options for customizing pre-batch sorting include the following:

  • Sort by player attributes. Provide a list of player attributes to pre-sort the ticket pool on. This customization causes FlexMatch to create batches with more uniformity in the sorted attributes. For example, if you pre-sort the ticket pool by player skill, tickets with similar skill levels tend to be batched together. If your rule set also contains match rules based on player skill, pre-batch sorting can significantly boost matchmaking efficiency.

    To enable this customization, set the algorithm property batchingPreference to "sorted", and set the property sortByAttributes to the list of player attributes. Each attribute in the list much be declared in the playerAttributes component of the rule set.

    In the following example, FlexMatch sorts the ticket pool based first on players' preferred game map and then by player skill. The resulting batches are more likely to contain similarly skilled players who want to use the same map.

    "algorithm": { "batchingPreference": "sorted", "sortByAttributes": ["map", "player_skill"], "strategy": "exhaustiveSearch" },
  • Sort by latency. Choose between prioritizing one of the following: (1) put players in matches with the lowest available latency, or (2) quickly get players into matches with acceptable latency. This customization is suitable with rule sets for forming large matches (more than 40 players); the algorithm property strategy must be set to "balanced", which significantly limits the available types of rule statements. See Design a FlexMatch large-match rule set.

    This customization causes FlexMatch to pre-sort tickets based on reported latency data in one of the following ways:

    • Get players into lowest latency Regions. The ticket pool is pre-sorted by the Regions where players report their lowest latency values. This causes FlexMatch to batch tickets that report low latency in the same Regions, which tends to match players into their fastest Regions and overall better game play experiences. It also shrinks the number of tickets in each batch, so matches can take longer to complete. To enable this customization, set the algorithm property batchingPreference to the value "fastestRegion", as shown in the following example.

      "algorithm": { "batchingPreference": "fastestRegion", "strategy": "balanced" },
    • Get players into acceptable latency matches quickly. The ticket poll is pre-sorted by Regions where players report any acceptable latency value. This method tends to form fewer batches, each containing a large number of tickets that have acceptable latency in the same Regions. With more tickets in each batch, finding enough acceptable matches tends to be easier and faster. To enable this customization, set the property batchingPreference to the value "largestPopulation", as shown in the following example. (This method is the default behavior for rule sets that use the balanced strategy.)

      "algorithm": { "batchingPreference": "largestPopulation", "strategy": "balanced" },

Prioritize backfill tickets

If your game implements either auto-backfill or manual backfill, you can customize how FlexMatch processes matchmaking tickets based on request type (new match or backfill request). By default, both types of requests are treated equally. This customization causes FlexMatch to either try to fill backfill tickets first or only when new matches can't be made. It also has the potential to impact use of hosting resources – by either packing players into fewer game sessions or by creating more partially filled game sessions.

Backfill prioritization impacts how tickets are handled after they have been batched; it does not affect the ticket batching process. You can implement both pre-batch sorting and backfill prioritization as needed. Use backfill prioritization only with rule sets that use the exhaustive search strategy.

To change prioritization for backfill tickets, set the property backfillPriority as follows:

  • Match backfill tickets first. This option prompts FlexMatch to evaluate and try to complete backfill tickets before creating new matches. This means that incoming players have a higher chance of being slotted into an existing game. Set the property backfillPriority to "high".

    If your game is using auto-backfill, enable this customization as a best practice. Auto-backfill is most often used in games with short game session time frames and high player turnaround. Auto-backfill helps these games to quickly form minimum viable matches and get them started even as FlexMatch searches for more players to fill open slots. Trying to fill backfill tickets first helps to optimize this approach.

    "algorithm": { "backfillPriority": "high", "strategy": "exhaustiveSearch" },
  • Match backfill tickets last. This option prompts FlexMatch to ignore backfill tickets until all other tickets have been evaluated. This means that incoming players are only backfilled into existing games when they can't be matched into new games. Set the property backfillPriority to "low".

    This option is useful when you want to use backfill as a last-chance option to get players into a game, such as when there are too few players to form a new match. De-prioritizing backfill tickets should never be used with auto-backfill.

    "algorithm": { "backfillPriority": "low", "strategy": "exhaustiveSearch" },

Favor older tickets with expansions

Customize how FlexMatch applies expansion rules, which relax match criteria when matches are difficult to complete. GameLift applies expansion rules when tickets in a partially completed match reach a certain age. The creation timestamps of the tickets determine when the rules are applied; by default, FlexMatch tracks the timestamp of the most recently matched ticket.

To change when expansion rules are applied, set the property expansionAgeSelection as follows:

  • Expand based on newest tickets. This option applies expansion rules based on the newest ticket added to the potential match. Each time a new ticket is matched, the time clock is reset. With this option, it is more difficult to apply an expansion; resulting matches tend to be higher quality, but the wait time for players can be longer, and match requests might time out before completing. Set the property expansionAgeSelection to "newest" (this is the default).

  • Expand based on oldest tickets. This option applies expansion rules based on the oldest ticket in the potential match, which is usually (but not always) the first ticket added to the match. With this option, expansions tend to be applied faster, which improves wait times for the earliest matched players, but also lowers the match quality for all players. Set the property expansionAgeSelection to "oldest".

"algorithm": { "expansionAgeSelection": "oldest", "strategy": "exhaustiveSearch" },

Declare player attributes

Rules may choose players for matches based on individual player characteristics. If you create rules that rely on player attributes, they must be declared in this section. Values for declared player attributes should be included in every matchmaking request that is sent a matchmaker using this rule set.

You may also want to pass certain player attributes to the game session even if the rule set doesn't use them during player evaluation. For example, you might pass a player's character choice. To do this, declare your player attributes here, and include the attribute values for each player in your matchmaking requests.

When declaring a player attribute, include the following information:

  • name (required) – This value must be unique to the rule set.

  • type (required) – This is the data type of the attribute value. Valid data types are number, string, or string map.

  • default (optional) – Enter a default value to use when no value is provided for a player. If no default is declared and a player does not provide a value, the player cannot be matched.

Define match teams

Describe the structure and size of the teams for a match. Each match must have at least one team, and you can define as many teams as you want. Your teams can have the same number of players or be asymmetric. For example, you might define a single-player monster team and a hunters team with 10 players.

FlexMatch processes match requests as either small match or large match, based on how the rule set defines team sizes. Potential matches of up to 40 players are small matches, while matches with more than 40 players are large matches. To determine a rule set's potential match size, add up the maxPlayer settings for all teams defined in the rule set.

  • name (required) – Assign each team a unique name. This name is used in rules and expansions, and it is referenced in the matchmaking data that is used in the game session.

  • maxPlayers (required) – Specify the maximum number of players that can be assigned to the team.

  • minPlayers (required) – Specify the minimum number of players that must be assigned to the team before the match can succeed.

  • quantity (optional) – If you want FlexMatch to create more than one team based on this definition, specify how many. When FlexMatch creates a match, these teams are given the designated name with an appended number. For example "Red-Team_1", "Red-Team_2", "Red-Team_3", etc.

FlexMatch always tries to fill teams to the maximum player size but does create teams with fewer players when the minimum player size allows it. If you want all teams in the match to be equally sized, you can create a rule for that. See the FlexMatch rule set examples topic for an example of an "EqualTeamSizes" rule.

Set rules for player matching

Create a set of rule statements that define how to evaluate players for acceptance in to a match. Rules might set requirements that apply to individual players, teams, or an entire match. When GameLift processes a match request, it starts with the oldest player in the pool of available players and builds a match around that player.

  • name (required) – This is a meaningful name that uniquely identifies the rule within a rule set. Rule names are also referenced in event logs and metrics that track activity related to this rule.

  • description (optional) – Use this element to attach a free-form text description. This information is not used by the matchmaker.

  • type (required) – The type element identifies the operation to use when processing the rule. Each rule type requires a set of additional properties. For example, several rule types need a reference value to measure a player's attributes against. See a list of valid rule types and properties in FlexMatch rules language.

  • Rule type property (may be required) – Depending on the type of rule being defined, you may need to set certain rule properties. For example, with distance and comparison rules, you must specify which player attribute to measure. Learn more about properties and how to use the FlexMatch property expression language in FlexMatch rules language.

Allow requirements to relax over time

Expansions allow you to relax match criteria over time when a match can't be completed. This feature ensures that a "best available" match can be made when a perfect match is not possible. You might use an expansion to relax a player skill requirement, increase acceptable player latency levels, or decrease the minimum number of players required in a team. By relaxing your rules with an expansion, you gradually expand the pool of players that are an acceptable match.

Expansions are triggered by when the age of the newest ticket in the incomplete match matches an expansion wait time. When a new ticket is added to the match, the expansion wait time clock may be reset. You can customize how expansions are triggered in the algorithm section of the rule set. Keep in mind that expansion step wait times in are absolute, they do not compound on each other. So, if you have two steps, one set at 15 and one set at 30, the second step will trigger 15 seconds after the first step.

Here's an example of an expansion that gradually increases the minimum skill level required for the match. The rule set uses a distance rule statement, named "SkillDelta" to require that all players in a match be within 5 skill levels of each other. If no new matches are made for fifteen seconds, this expansion allows for a skill level difference of 10, and then ten seconds later allows for a difference of 20.

"expansions": [{ "target": "rules[SkillDelta].maxDistance", "steps": [{ "waitTimeSeconds": 15, "value": 10 }, { "waitTimeSeconds": 25, "value": 20 }] }]

With matchmakers that have automatic backfill enabled, don't relax your player count requirements too quickly. It takes a few seconds for the new game session to start up and begin automatic backfill. If you have very short wait times in your expansion steps, FlexMatch is likely to create a lot of partially-filled matches before newly launched game sessions send backfill requests. A better approach is to trigger your expansion only after automatic backfill tends to kicks in for your games. This helps FlexMatch get players into games (new or existing) faster and more efficiently. Expansion timing varies depending on your team composition, so expect to do some testing to find the best expansion strategy for your game.

Design a FlexMatch large-match rule set

If your rule set creates matches that allow 41 to 200 players, you need to make some adjustments to your rule set configuration. These adjustments optimize the match algorithm so that it can build viable large matches while also keeping player wait times short. As a result, large match rule sets replace time-consuming custom rules with standard solutions that are optimized for common matchmaking priorities.

Here's how to determine if you need to optimize your rule set for large matches:

  1. For each team defined in your rule set, get the value of maxPlayer,

  2. Add up all the maxPlayer values. If the total exceeds 40, you've got a large match rule set.

To optimize your rule set for large matches, make the adjustments described as follows. See the schema for a large match rule set in Rule set schema for large matches and rule set examples in Example 7: Create a large match.

Customize match algorithm for large matches

Add an algorithm component to the rule set, if one doesn't already exist. Set the following properties.

  • strategy (required) – Set the strategy property to “balanced”. This setting triggers FlexMatch to do additional post-match checks to find the optimal team balance based on a specified player attribute. Set the player attribute using the balancedAttribute property. The balanced strategy replaces the need for custom rules to build evenly matched teams.

  • balancedAttribute (required) – Identify a player attribute to use when balancing the teams in a match. This attribute must have a numerical data type (double or integer). For example, if you choose to balance on player skill, FlexMatch tries to assign players so that all teams have aggregate skill levels that are as evenly matched as possible. The balancing attribute must be declared in the rule set's player attributes.

  • batchingPreference (optional) – Choose how much emphasis you want to put on forming the lowest latency matches possible for your players. This setting affects how match tickets are sorted prior to building matches. Options include:

    • Largest population. FlexMatch allows matches using all tickets in the pool that have acceptable latency values in at least one Region in common. As a result, the potential ticket pool tends to be large, which makes it easier to fill matches more quickly. Players may be placed in games with acceptable, but not always optimal, latency. If this property isn't set, this is the default behavior when strategy is set to "balanced".

    • Fastest Region. FlexMatch pre-sorts all tickets in the pool based on where they report the lowest latency values. As a result, matches tend to be formed with players that report low latency in the same Regions. At the same time, the potential ticket pool for each match is smaller, which can increase the time needed to fill a match. In addition, since a higher priority is placed on latency, players in matches may vary more widely with regard to the balancing attribute.

The following example configures the match algorithm to behave as follows: (1) Pre-sort the ticket pool to group tickets by Region where they have acceptable latency values; (2) Form batches of sorted tickets for matching; (3) Create matches with tickets in a batch and balance the teams to even out the average player skill.

"algorithm": { "strategy": "balanced", "balancedAttribute": "player_skill", "batchingPreference": "largestPopulation" },

Declare player attributes

Make sure that you declare the player attribute that is used as a balancing attribute in the rule set algorithm. This attribute should be included for each player in a matchmaking request. You can provide a default value for the player attribute, but attribute balancing works best when player-specific values are provided.

Define teams

The process of defining team size and structure is the same as with small matches, but the way FlexMatch fills the teams is different. This affects how matches are likely to look like when only partially filled. You may want to alter your minimum team sizes in response.

FlexMatch uses the following rules when assigning a player to a team. First: look for teams that haven't yet reached their minimum player requirement. Second: of those teams, find the one with the most open slots.

For matches that define multiple equally sized teams, players are added sequentially to each team until full. As a result, teams in a match always have a nearly equal number of players, even when the match is not full. There is currently no way to force equally sized teams in large matches. For matches with asymmetrically sized teams, the process is a bit more complex. In this scenario, players are initially assigned to the largest teams that have the most open slots. As the number of open slots become more evenly distributed across all teams, players are slotted into the smaller teams.

For example, let's say you have a rule set with three teams. The Red and Blue teams are both set to maxPlayers=10, minPlayers=5. The Green team is set to maxPlayers=3, minPlayers=2. Here's the fill sequence:

  1. No team has reached minPlayers. Red and Blue teams have 10 open slots, while Green has 3. The first 10 players are assigned (5 each) to the Red and Blue teams. Both teams have now reached minPlayers.

  2. Green team has not yet reached minPlayers. The next 2 players are assigned to the Green team. The Green team has now reached minPlayers.

  3. With all teams now at minPlayers, additional players are now assigned based on the number of open slots. The Red and Blue teams each have 5 open slots, while the Green team has 1. The next 8 players are assigned (4 each) to the Red and Blue teams. All teams now have 1 open slot.

  4. The remaining 3 player slots are assigned (1 each) to teams in no particular order.

Set latency rule for large matches

Matchmaking for large matches relies primarily on the balancing strategy and latency batching optimizations. Most custom rules are not available. However, you can create a rule that sets a hard limit on player latency.

To create this rule, use the latency rule type with the property maxLatency. Here's an example that sets maximum player latency to 200 milliseconds:

"rules": [{ "name": "player-latency", "type": "latency", "maxLatency": 200 }],

Relax large match requirements

As with small matches, you can use expansions to relax match requirements over time when no valid matches are possible. With large matches, you have the option to relax either the latency rules or the team player counts.

If you're using automatic match backfill for large matches, avoid relaxing your team player counts too quickly. FlexMatch starts generating backfill requests only after a game session starts, which may not happen for several seconds after a match is created. During that time, FlexMatch can create multiple partially filled new game sessions, especially when the player count rules are lowered. As a result, you end up with more game sessions than you need and players spread too thinly across them. Best practice is to give the first step in your player count expansion a longer wait time, long enough for your game session to start. Since backfill requests are given higher priority with large matches, incoming players will be slotted into existing games before new game are started. You may need to experiment to find the ideal wait time for your game.

Here's an example that gradually lowers the Yellow team's player count, with a longer initial wait time. Keep in mind that wait times in rule set expansions are absolute, not compounded. So the first expansion occurs at five seconds, and the second expansion occurs five seconds later, at ten seconds.

"expansions": [{ "target": "teams[Yellow].minPlayers", "steps": [{ "waitTimeSeconds": 5, "value": 8 }, { "waitTimeSeconds": 10, "value": 5 }] }]