Starting a match

To begin a turn-based match, your game can prompt players to select how they
want to be matched to other participants, or build the match using some default
criteria. Google Play games services uses the match configuration data from your
game to return a TurnBasedMatch
object to your game; this object is updated and shared asynchronously with all
participants over the lifecycle of the turn-based match.

To start a match, follow these steps:

In your app, gather specifications for the type of turn-based match that the
player wants to play and who can participate in the match.

Next, override the onActivityResult()
callback to construct a TurnBasedMatchConfig
object using the criteria provided by the user. The TurnBasedMatchConfig
object defines the characteristics of the match that the user wants to play. Google Play games services
uses this configuration data to determine whether to build a new match or to auto-match the user to
an existing game.

Optionally, you might want to ensure that only players who are interested in a
specific type of game variant are auto-matched together. If there are
different versions of your app, your game can also use variants to ensure that
only players who are on compatible versions are auto-matched.

To specify a variant when creating a turn-based match, use the
setVariant()
method. Your game can also use the exclusiveBitMask parameter in
createAutoMatchCriteria()
to pair auto-matched players who are interested in playing specific exclusive
roles in a game.

Taking the first turn

Before proceeding, remember to initialize the game data as needed by your game.
For example, you might need to initialize the starting positions for players in
a strategy game or initialize the first hand for players in a card game.

If the call returns a null value, this indicates that the game data is
uninitialized because no player has taken a turn yet (that is, the current
player is the first player in this match). Your game can initialize the game data and
store it in a byte array. The size of the game data must be less than the size
returned by TurnBasedMultiplayerClient.getMaxMatchDataSize().
The data size returned is guaranteed to be at least 128 KB.

If the call returns a non-null value, this indicates that the game has
already started and the game data is already initialized, so make sure your
game does not reinitialize the data.

Optionally, call TurnBasedMultiplayerClient.takeTurn()now. If your initial
state is based on a random value (for example, a card game where the player
starts with a random hand) and your game does not call
TurnBasedMultiplayerClient.takeTurn()to persist the
data to Google's servers, the player could keep restarting the first turn to
try to get a better starting position.

Let the player perform game actions, and if appropriate, update the byte
array containing the game data.

Save the game data to Google’s servers by calling
TurnBasedMultiplayerClient.takeTurn(). Your game can specify the next player's
participant ID, or specify null to let Google Play games services
find a player for auto-matching. Your game can let match participants take turns even
when not all invited players have joined or when there are auto-match slots
still available. To get players into gameplay faster, your game should let players
take their turn as soon as they join. When you call
TurnBasedMultiplayerClient.takeTurn(), Google Play games services sends a
notification to the pending participant and updates the turn
data on all participants' devices asynchronously.

When the next player takes a turn, make sure to load the initialized data
by calling getData()
before you let the player perform game actions.

Handling invitations

Once a player has signed in to your game, the player may receive invitations to
join a turn-based match created by another player. To save coding time and
provide users with a consistent UI for responding to match invitations across
applications, you can use the default match inbox UI provided by the SDK.

Note: If an invited participant declines an invitation without taking a
turn, the match is canceled. An auto-matched player can leave without
canceling the match as long as that player has not taken a turn.

Taking a turn

After the first player takes a turn, your game can let the same participant or
another participant take the next turn. Generally, turn-taking involves loading
the most recent match data from Google Play games services, letting the participant
interact with your game, and calling TurnBasedMultiplayerClient.takeTurn()to
update the match data and pass the turn to another participant.

Load the most recent match data from Google Play games services by calling
getData()
and render your game accordingly.

Let the user perform game actions and, if appropriate, persist the
updated game data to a byte array.

Determine the pending participant who should take the next turn. This is
usually dependent on the order of play specified by your game design. The
pending participant can be another player in the match or the current participant
whose turn it is. Your game can also pass the turn to the next player
joining by auto-match, by setting the pending participant to null.

Call TurnBasedMultiplayerClient.takeTurn()to update the
Google Play games services with the latest game data and pass the turn
to the pending participant. If the update is successful, Google Play games services
sends a notification to the pending participant to inform them that it's their
turn.

Saving game state

You can use the turn-based multiplayer API to manage your game state if your
game state data fits within the allowed size. The data size limit can be
retrieved by calling
TurnBasedMultiplayerClient.getMaxMatchDataSize(). The data size returned is
guaranteed to be at least 128 KB.

Warning: Using the Saved Games API
together with the turn-based multiplayer API could cause version conflicts
because the save game and match data are not updated synchronously. To avoid
these conflicts in your game, pick and use just one API to save your game state.

Your game should try to save game data for a partially-finished
turn whenever a player's turn is interrupted and the player has to temporarily
leave the game (for example, because of an incoming phone call). To do this,
override your activity's
onStop()
method to call TurnBasedMultiplayerClient.takeTurn(). Make sure to specify
the current player as the pending participant by using the same participant ID
as in the last call to TurnBasedMultiplayerClient.takeTurn(). If successful,
the call stores the game data in Google’s servers but does not generate a new
turn notification.

Completing a match

When the match has been played to completion (for example, a user has won the
game), your game should call TurnBasedMultiplayerClient.finishMatch()
to upload the user’s game data and signal to the other participants that the
match is over. When your game invokes this method for the first time during a match,
it must be during the user's turn. The match then appears under the
Completed Matches category in the user's match list UI.

Once a player calls TurnBasedMultiplayerClient.finishMatch()
for the first time in the match, your game cannot call
TurnBasedMultiplayerClient.takeTurn()again in this match.
Google Play games services sends a notification to all other
match participants to inform them that the match is over. These participants
see this match under Your Turn category in their respective match list UIs.
At this point, your game can call TurnBasedMultiplayerClient.finishMatch()
for these participants to save their final game data. Invoking this method also
moves the match to the Completed Matches category in the participant’s match
list UI.

There is one remaining participant and at least one empty auto-match slot
available.

Otherwise, the match is canceled.

In general, when a participant leaves a match, another player cannot join and
take that participant’s place. One exception is when a player who joined by
auto-match and who has not taken a turn calls
TurnBasedMultiplayerClient.leaveMatchDuringTurn(). In this case, the match
reverts to the MATCH_STATUS_AUTO_MATCHING state and another player can take over the
place of the participant who left.

Dismissing a match

Your game can let users dismiss a turn or invitation so that they do not have to see
the match again. This hides the match from the dismisser's match list UI and
causes the match to eventually expire. Other match participants can continue to
play until the dismissed match expires after two weeks, or until the match is
played to completion or canceled (whichever happens first). To other
participants, the dismisser still appears as a participant in the match. Another
player cannot take the dismisser's place.

Tracking match expiration

A match can expire if a player does not respond to a match or turn notification
for two weeks (for example, after a player whose turn it is selects Dismiss
in the default match list UI).

You can use the following approach on the game client to identify which player
caused a game to expire:

Load a list of the currently signed-in player’s list of games by calling TurnBasedMultiplayerClient.loadMatchesByStatus().

If a match participant has STATUS_UNRESPONSIVE
state, it indicates that this player has let the game expire.

Implementing a rematch

When a match is over, a participant may want to play a rematch with the same
set of invited and auto-match opponents. Your game can initiate a rematch by
invoking TurnBasedMultiplayerClient.rematch().
Your game can only invoke this method when the match state is
MATCH_STATUS_COMPLETE and no other participants have requested a rematch. If the call is successful,
Google Play games services sends invitation notifications to all rematched opponents.

If your game uses the default match inbox UI, players can also initiate rematches
from that UI. When a player initiates a rematch from the match inbox UI,
Google Play games services returns a new match object as an
Intent extra in the onActivityResult() callback of the match inbox activity. If your game
needs to initialize game data for the new match, make sure to use the match
object returned in the
onActivityResult() callback.