Skip to content

Asynchronous Multiplayer

Rather than playing out matches in real-time, asynchronous multiplayer games enable players to take their turns at a time that suits them, with most games allowing players to have several matches running in parallel.

Asynchronous multiplayer has become popular on mobile platforms - many mobile players use games in between other activities or during moments of down time, when travelling for example. In these cases, players may not have more than a minute or two available to play and may be interrupted or lose their internet connection at any moment - for these reasons, asynchronous style multiplayer is often preferred to real-time multiplayer.

ChilliConnect provides built in support for Asynchronous Multiplayer with support for various turn types, flexible match making and the ability to run your own server logic during matches. See our Tic Tac Toe tutorial for an example of using the Asynchronous Multiplayer feature with Unity.

Match Types

Match Types are used by ChilliConnect to define default parameters, available turn types and Match Properties for a particular category of game. A single game can have multiple match types. You can define Match Types from the Connect, Async Multplayer menu in your dashboard. Each Match Type has the following properties:

MatchTypes

Name Descriptive name that identifies the Match Type.
Key Key use to reference the Match Type in ChilliConnect API calls.
Description Optional description of the Match Type. Only displayed for reference in the Dashboard.
TurnType The TurnTypes supported by this Match Type.
Default Waiting Timeout The number of minutes that a match of this type can be in the WAITING or READY state before ChilliConnect automatically moves the match to the Timeout state
Default Turn Timeout The number of minutes that a match of this type will wait for a player turn to be submitted before ChilliConnect automatically moves the match to the TIMEOUT state. Note that for matches with the Parallel Turn Type, any submitted player turn is enough to reset the Timeout, the entire turn does not need to be completed.
Properties Match Properties are customisable attributes that can be assigned to a Match instance and used to search for matches during match making. See the Match Properties section for more details.
Custom Data Custom free-form JSON data. You can retrieve this custom data in your game at run time by using the GetMatchTypeDefinitions method. This allows you to add support for new game modes, or add additional data such as match rewards etc. without having to make new builds of your game.

Match State

Matches in ChilliConnect go through several states:

MatchProperties

Each of the states is described below:

Waiting The Match has been created with CreateMatch but is waiting for more players before it can start. Matches in the WAITING state can also be automatically started by calling StartMatch.
Ready The Match now has all required players, and is ready to start. The Match can be started through the StartMatch call. The READY state provides the opportunity to set player order and initialise the Match State Data. Matches can skip the READY state and move immediately to IN_PROGRESS by providing the AutoStart flag on CreateMatch.
In Progress The Match has now started and players can submit turns using the SubmitTurn method. The order in which players are allows to submit turns is determined by the TurnType parameter of the match. The Match remains in the In Progress state until it is either completed or timed out.
Complete The Match is finished and is no longer accepting turns. Matches can be completed by providing the completed flag to the SubmitTurn method. To record any final match state, such as the match winner for example, free form OutcomeData can also be provided to the SubmitTurn method.
Timeout The Match timed out, either waiting for players to join, waiting for a match in the READY state to start, or waiting for a player to submit a turn. Default Match timeouts can associated with a Match Type or provided to the CreateMatch call.

State Data

Match StateData is used to track the current state of a specific match. StateData is completely customisable and can be used store anything you want to track during the course of a Match. For example, in the ChilliConnect Tic Tac Toe tutorial, StateData is used to store what player is X, what player is O, and the current state of the board as a simple 9 character string:

{
    "PlayerX" : "123456",
    "PlayerY" : "789101",
    "BoardState" : "???X?O??"
}

StateData can be initialised either when CreateMatch is called, on StartMatch, as well as being updated on every turn by SubmitTurn.

Creating and Starting Matches

New matches are created with the CreateMatch call. The creating player will always be added to the match. Other players can join the match either directly through JoinMatch, if they have the MatchID, or via matchmaking through JoinAvailableMatch. By default, when a match reaches the maximum number of players, it will move in to the READY Match State and can be started by calling StartMatch, optionally providing initial StateData or player turn order. Even if the maximum number of players has not been reached, matches can be moved from WAITING to IN_PROGRESS at any time by calling StartMatch.

Matches can also be created with the AutoStart flag set to true - this will cause the match to immediately move in to the IN_PROGRESS state when enough players have joined.

Match Properties and Matchmaking

Match Properties are used to support Matchmaking. Match Properties are defined when creating Match Types. Each Match Type can have up to 5 properties defined and properties can be of type String, Int, Float, Boolean or DateTime. When matches are created with CreateMatch, you can specify a value for each property that can then be used by other players to search for appropriate matches. For example, in a golf game, you might define Match Properties for the selected course, the number of holes to be played, or the match type.

To find matches that fit a certain criteria and are available to join, the QueryAvailableMatches method can be used. This accepts a query string in the same format as the QueryCollection method, where the prefix "Properties" is used to . For example, assuming a golf game with the below match properties:

MatchProperties

We could run the below queries:

  • Find all matches that are 9 holes
Properties.Holes = 9
  • Find all matches that are 18 holes and MatchPlay
Properties.Holes = 9 AND Properties.GameType = "MatchPlay"
  • Find all matches for a particular set of courses
Properties.Course IN ("St Andrews", "Pebble Beach")

QueryAvailableMatches will return a list of matches that can then be presented to the player. Individual matches can be joined by calling JoinMatch with the MatchID.

To automatically join a match, rather than requiring the player to select a match, JoinAvailableMatch can be used used. JoinAvailableMatch accepts up to 3 separate queries that will be executed one after the other until a match is found, allowing specific match criteria to attempted first before falling back to broader queries. In this way, you can try to find an exact skill match for a player, but then fall back to a specific range. The FallbackToAny flag can also be set to true to instruct ChilliConnect to join any match if all queries fail.

See the Tic Tac Toe tutorial for a detailed example of how to implement match making.

Private Matches

In some cases, you may not want matches to be visible to Match Making - for example, if you are creating a 1v1 match and sending invites using the ChilliConnect Messaging system. To prevent other players from finding a match via Match Making, you can set the Private flag to true when calling CreateMatch.

Turns

Once a Match is IN_PROGRESS, turns can be submitted using the SubmitTurn method. Each turn can specify updated StateData which should reflect the state of the match after the players turn, and also optional TurnData which can be used to capture specific actions that were taken by the player. ChilliConnect will automatically take a snapshot of the Match StateData before and after each turn.

The order in which turns can be taken is determined by the TurnType. Available TurnTypes are described below:

Any ChilliConnect does not enforce any turn order. Turns can be submitted by players at any time and each match turn will contain turn data a single player.
Sequential Turns must be submitted in a strict order. ChilliConnect will enforce that only one player at a time can submit a turn. The order of players can be controlled through the `TurnOrderType` parameter when creating the match.

A type of `RANDOM` will cause ChilliConnect to randomise the turn order of players. `ORDERED` will use the order in which players joined the match. `EXPLCIIT` requires that the turn order is specified in the `StartMatch` call.
Parallel Each turn within a match must contain a turn submission by every player. This is for games where players submit their turns at the same time, and the outcome for a turn is only calculated once all turn data has been received. For example, in Rock Paper Scissors, both players should submit their turns together before working out the winner.

If using `Parallel`, the SubmitTurn call will only accept updated Match `StateData` from the last player to move within a turn. To ensure that two or more players do not submit their turn simultaneously (and cause your game to miss the opportunity to provide updated `StateData`) the `WriteLock` value should be provided to SubmitTurn.

For Sequential and Parallel turn types, the next player(s) to submit turns can be retrieved from the CurrentTurn property of the match.

Updating out of Turn

In some cases, you might want to override the enforced turn behaviour and update Match StateData or complete a match without going through the usual turn order. This can be done by calling the UpdateMatch method. By default, this method is only available via CloudCode scripts. Note that any direct updates to a match via UpdateMatch do not create match turns. This means that if you are using the GetMatchTurns method to replay matches in anyway, you should make sure that your game code can handle any potential "missing" turn data.

Loading Matches

Individual matches can be loaded through the GetMatch call. To get a list of matches that a player is part of or has recently been part of, the GetPlayerMatches method can be used. This will return an abbreviated match response that includes the latest match state, the match turn number and also a boolean flag, CanSubmitTurn, that indicates if the currently logged in player is able to submit a turn for the match.

Timeouts

Matches in ChilliConnect are automatically timed out when there has been no activity on them for a set period of time. Matches have two timeout settings - the waiting timeout, that defines how long the match can be in the waiting state, and the turn timeout, that defines how long the match should wait for a player to submit a turn. Default values for these timeouts can be set when creating the Match Type, but they can also be overridden in the CreateMatch call.

To add in specific game logic when ChilliConnect times out a match (for example, sending a push notification or awarding a win to the last player to submit a turn), you can create an Event Cloud Script that can trigger when a match is going to time or has timed out. For matches that are going to timeout, you can call UpdateMatch within your script to reset the timeouts and extend the match, or even use the AsPlayer method to automatically submit turn data for missing players. The available Asynchronous Multiplayer script events are below:

Match Waiting Timed Out A match in the `WAITING` state has been timed out.
Match Waiting Timing Out A match in the `WAITING` state is about to be timed out.
Match Turn Timed Out A match in the `IN_PROGRESS` state has been timed out.
Match Turn Timing Out A match in the `IN_PROGRESS` state is about to be timed out.

For each of these events, the ChilliConnect.Event.Data.MatchID property will contain the ID of the match that is either timing our or timed out. For example, the below script can be added on the Match Turn Timing Out event to send a push notification to the next player to move and reset the timeout.

/** Get the Match ID from the Event Data */
var matchId = ChilliConnect.Event.Data.MatchId;

ChilliConnect.Logger.info("Match Timing Out: " + matchId);

try {

    /** Load the match */
    var match = ChilliConnect.AsyncMultiplayer.getMatch(matchId);

    /**
     * If a match has been running for more than a day, then allow it 
     * to timeout
     */ 
    if(shouldTimeOut(match)) {
        ChilliConnect.Logger.info("Allowed to Time Out.");
        return;
    }

    /**
     * Update match - this will reset the turn timeout 
     */
    ChilliConnect.AsyncMultiplayer.updateMatch(matchId);

    var chilliConnectIds = [];
    for(var i = 0; i < match.Match.CurrentTurn.PlayersWaitingFor.length; i++) {
        chilliConnectIds.push(match.Match.CurrentTurn.PlayersWaitingFor[i].ChilliConnectID);
    }

    ChilliConnect.PushNotifications.sendToChilliConnectIds(chilliConnectIds, 
        "Your match is going to timeout!");
}
catch(e)
{
    ChilliConnect.Logger.error("Error:" + e );
}

function shouldTimeOut(match) {
    var millisecondDiff = Date.now() - Date.parse(match.Match.DateCreated);
    var cutOff = 24 * 3600000; //24 hours in milliseconds
    return millisecondDiff > cutOff;
}

Completing a Match

Matches are completed by specifying the Completed flag as true in the SubmitTurn call. To store any final match data, such as the winner of the match or rewards allocated to players, free form OutcomeData can be also specified in the SubmitTurn call.

Outcome Attachment Data

Similar to the OutcomeData, when a Match is completed via supplying the Completed flag in either the SubmitTurn call or the UpdateMatch call, you have the option of including an OutcomeAttachment as well. This is very similar to OutcomeData but is intended to hold larger amounts of data, such as replay data for Matches, or generic binary data.

If a Match has an OutcomeAttachment it will have the property HasOutcomeAttachment set to true. And to get the OutcomeAttachment data call GetOutcomeAttachment endpoint with the MatchID. An OutcomeAttachment can be up to 1Mb in size.

Server Authoritative Games

By default, the Asynchronous Multiplayer feature of ChilliConnect is client authoritative. To implement server side validation of submitted turn data, the SubmitTurn method can be disabled from the API Access Control list on the Game View. Rather than call SubmitTurn directly, your game can instead call a Cloud Code script that first validates the submitted turn data. For example, the below code provides a template script that loads the current match data and submits the turn only if the call to matchTurnIsValid returns true:

var matchId = ChilliConnect.Request.MatchID;
var turnData = ChilliConnect.Request.TurnData;

/** Load the existing match **/
var match = ChilliConnect.AsyncMultiplayer.getMatch(matchId);

/** Get the existing state data **/
var stateData = match.StateData;

/** Check submitted turn data against state data */
if (!matchTurnIsValid(turnData, stateData)) {
    return {"Status": "Error", "Message" : "Invalid Turn Data"};
}

ChilliConnect.AsyncMultiplayer.submitTurn( matchId, null, turnData );
return {"Status": "OK"};

Push Notifications

A common pattern for Asynchronous Multiplayer games is to send a Push Notification to a player when it is their turn. This can be done in ChilliConnect using a Event Cloud Code Script. From the dashboard, select "Cloud Code" and "Add Script". Define the Type as "Event", and "Event Type" as "AsyncMultiplayer.submitTurn":

This will create a Cloud Code script that will be automatically called by ChilliConnect whenever the SubmitTurn API call is invoked. Paste in the below code:

/**
 * Get the updated match from the Request data
 */
var updatedMatchId = ChilliConnect.Event.Request.MatchID;

ChilliConnect.Logger.info( "Turn submitted for match:" + updatedMatchId );

/**
 * Get the updated match data from the Response data
 */ 
var updatedMatch = ChilliConnect.Event.Response.Match;

/**
 * Check updated state if match is still in progress
 */ 
var updatedState = updatedMatch.State;
if (updatedState == "IN_PROGRESS") { 

    /**
     * Get the next player
     */ 
    var nextPlayer = updatedMatch.CurrentTurn.PlayersWaitingFor[0].ChilliConnectID;

    ChilliConnect.PushNotifications.sendToChilliConnectIds( 
        [nextPlayer], "It's your turn!", null, "Match Updated");

    ChilliConnect.Logger.info( "Sent Push Notification to Player:" + nextPlayer);
}

This script will check the returned Match object to first ensure that the match is still in progress, and then send a Push Notification to the next player.