Real-Time Multiplayer

Your game can use the real-time multiplayer API in Play Games services to connect multiple players together in a single game session and transfer data messages between connected players. Using the real-time multiplayer API can help to simplify your game development effort because the API handles the following tasks on your behalf:

  • Manages network connections to create and maintain a real-time multiplayer room (a virtual constructor that enables network communication between multiple players in the same game session and lets players send data directly to each other).
  • Provides a player selection user interface (UI) to invite players to join a room, look for random players for auto-matching or a combination of both.
  • Stores participant and room state information on the Play Games services servers during the lifecycle of the real-time multiplayer game.
  • Sends room invitations and updates to players. Notifications appear on all devices on which the player is logged in (unless disabled).

Real-time multiplayer game basics

Before you design and implement your game using the real-time multiplayer API, you should familiarize yourself with the following concepts related to the typical lifecycle of a real-time multiplayer game.

Room initialization

Internally, the room sets up a peer-to-peer mesh network between participants where clients can communicate directly with each other, rather than through the Play Games services servers.

Before a real-time multiplayer game session can be initiated on a device, the device user must be signed in to your game. The local player (that is the user who is logged into the device where your game is running) can then initiate a multiplayer game session by inviting friends in that player's Google+ circles to join the game or requesting to be auto-matched.

If your game runs on a mobile device, the real-time multiplayer API provides a default player selection UI. The UI allows players to invite their friends or select a number of auto-match opponents. This simplifies your UI coding, but you can also choose to implement your player selection UI.

Based on the player selection and room configuration details (either entered by the local player through the UI or provided programmatically by your game), Play Games services will attempt to create a room for the real-time multiplayer game session.

If the room is created successfully, Play Games services notify your game through a callback (in Android) or delegate (in iOS) that is registered in your game. The local player is automatically joined as a participant in the room.

Room configuration

You must specify the number of players that you want to allow in your room. Currently, Games services support a maximum of eight players in a multiplayer game (including the player who is initiating the match).

Optionally, you might want to ensure that only players who are interested in a specific type of game variant are auto matched to the room. For example, in a racing game, you can auto-match players who only want to play a specific racing map or difficulty level. Variants can be used to auto-match players who are interested in different play styles, such as player-vs-player (PvP) or 'capture the flag' gameplay. If there are different versions of your app, you can also use variants to ensure that only players who are on compatible versions are auto-matched.

If you want to auto-match players who are interested in playing specific exclusive roles in a game, you can specify this using the bitMask parameter.



When players initiate a multiplayer game, they can choose to invite specific people or have Games services automatically select other participants randomly via auto-matching. They can also request a mix of the two (for example, one specific player from their circles, and two auto-matched players).

If players choose to invite a specific person to a game, the invitee can be any user with a Google+ account. However, if the inverter is using the default player selection UI to select invitees, the UI only lists people that are in the inverter's Google+ circles and people that invited recently played with. To invite players from outside the inverter's circles, the inverter can use the search function in the player selection UI.


An auto-match participant does not have to be a contact in the local player's circles. When auto-matching, Games services simply look for other participants at that time who are also initiating a game and requesting to be auto-matched. Auto-match participants do not receive notifications to join a game; from their perspective it appears as though they are individually initiating the game.

In real-time multiplayer games auto-matched participants will appear as anonymous players to each other (even if the they are in each others' Google + circles).

Connected set

As players join or leave the room, Play Games services actively attempt to create a mesh of peer-to-peer connections between all participants. This forms a connected set of participants in the room, where every player in the connected set is fully connected to other players in the set. The connected set might consist of a subset of all players who have joined the room. If any player gets disconnected from another player in the connected set, the set is reduced to the remaining players who are still fully connected. It is up to your game to determine how to proceed if this happens.

When all the participants in a real-time room are fully connected, Play Games services notify through a callback (in Android) or delegate (in iOS). Your game can send messages to the participants who are connected to your room. This is described further in Sending game data.

In-game networking

The real-time multiplayer API is flexible enough that your game can use it to implement your own in-game network for participants over the underlying peer-to-peer network created by the Play Games services. For example, in your game, you might want to designate a single client to act as a 'host' to establish the authoritative game data first, then transmit this data to the other connected participants through data messaging. If auto-matching is used to create the room and your game logic relies on the existence of a 'host' or 'owner' of the game, you are responsible for implementing the logic to determine who the 'host' should be.


A mobile device user who is sent an invitation, will see a notification on devices where he is logged in. Invitations are sent by Play Games services via Google Cloud messaging to Android devices and through the Apple Push Notification service (APNS) to iOS devices.

Android device users can filter the invitations that they see by changing these settings:

  • Setting the access control list permissions for those who can notify them.
  • Muting the app.
  • Turning all mobile notifications off entirely.

iOS device users can filter the invitations that they see by changing these settings:

  • Setting the access control list permissions for those who can notify them.
  • Disabling iOS push notifications for the game.

If the player does not have the application installed on an Android device, he will be prompted to install the application from the Play Store. In that case the invitation is not consumed, and the player can accept it again after installing the game.

Play Games services notify your game about incoming invitations through a connection bundle (in Android) or delegate (in iOS). From the invitation object, provided by Play Games services, your game can retrieve additional details such as the invitation creation timestamp, the invitation ID and the player who sent the invitation.


Once the required number of participants for a room have been connected, the room is considered to be 'filled' and gameplay can begin. After participants join a room, your game can allow them to leave the room (effectively dropping them out of the game). However, no new players can join a room after it is 'filled' (not even to fill a spot that a participant has vacated).

In certain advanced scenarios your game might allow connected participants to start gameplay before all pending invitations have been accepted. If your game supports this mode of gameplay, make sure to handle any participants who join the room after the gameplay is underway. Take the following example: In a 3-player racing game your game session might start the race with two players. During the race, if a third player joins the room, your game can let the newly-joined participant observe the current race as a spectator but not play as a racer. After the race is over, your game can allow all three players to participate as racers in the next round.

Event notifications

As the status of the room, its participants or connection status of the participants change, Play Games services will send notifications to your game. Your game can use this information to display details about who joined the room (for example, while waiting for more participants to join), or to display an option for the local player to leave the room if Play Games services cannot find other players for auto-matching after a long wait.

Sending game data

You can use the Play Games services to broadcast data to participants in a room or allow participants to exchange messages with each other. Data messages can be sent using a reliable or unreliable messaging protocol provided by Play Games services. For finer-grain control of data communications in your Android game you can also implement socket-style messaging with Games services. Socket communication is not supported on iOS.

  • Reliable messaging. With reliable messaging, data delivery, integrity and ordering are guaranteed. You can choose to be notified of the delivery status by using a callback. Reliable messaging is suitable for sending non-time-sensitive data. You can also use reliable messaging to send large data sets where the data can be split into smaller segments, sent over the network, and then reassembled by the receiving client. Reliable messaging might have high latency. The maximum size of a reliable message that you can send is 1400 bytes.
  • Unreliable messaging. The game client sends the data only once ('fire-and-forget') with no guarantee of data delivery or data arriving in order. However, integrity is guaranteed, so there is no need to add a checksum. Unreliable messaging has low latency and is suitable for sending data that is time-sensitive. Your app is responsible for ensuring that the game behaves correctly if messages are dropped in transmission or received out of order. The maximum size for an unreliable message that you can send is 1168 bytes.

Sending messages

You can send messages to participants who are connected to the room. If your game is not connected to Play Games services or the recipient is not connected, the message will not be delivered.

To conserve message transmissions and avoid exceeding rate limits, follow these best practices for sending data:

  • Send messages only to the participants who require that information, rather than broadcasting to all participants. If you are sending a broadcast message, make sure to exclude the sender participant from the list of broadcast recipients.
  • If you are sending data using the reliable messaging protocol, try to keep the frequency of your message transmissions to around 50 or fewer messages per second. If you need to send data more frequently than this, we recommend to use unreliable messaging instead.

Receiving messages

A participant can only receive messages when connected to the room.

If your game uses socket-based messaging, note that it may receive data from more than one socket write operation at a time. It is up to your game to parse the inbound stream from the socket. To simplify this task, you can use a delimiter or implement the socket messages using a fixed field size.

Warning: Data that is sent using Games services is unencrypted. Since messages can originate from any peer client connected to the room, you should treat this data as untrusted. We recommend that you implement your own security checking to verify that inbound data does not compromise your app.

Room closure

Your game is responsible for leaving the room (that is, disconnecting the room from Play Games services servers) when a participant logs out of the game or exits the real-time portion of the game. Your game should also handle the scenario where all participants except the local player have left the room. When this happens, your game should disconnect the local player from the room immediately.

The room is considered 'closed' when all its participants have left the room. At this point your game should shut down any game currently in progress, and make sure to save game data appropriately.


Once the player is signed in and connected to play service, your game can start using the real-time multiplayer API.

GooglePlayConnection.State == GPConnectionState.STATE_CONNECTED

Starting a real-time multiplayer game

Your main screen is the player's primary entry point to start a real-time multiplayer game, invite other players or accept a pending invitation. We recommend that at minimum you implement these UI components on the main screen of your game:

  • Quick Game button - Lets the player play against randomly selected opponents (via auto-matching).
  • Invite Players button - Lets the player invite friends in their Google+ circles to join a game session or specify some number of random opponents for auto-matching.
  • Show Invitations button - Lets the player see any pending invitations sent by another player. Selecting this option should launch the invitation inbox as described in Handling invitations.

Note: You should adjust the button labels to best suit your game's context. For example, "Quick Game" could be renamed "Quick Race".

Quick Game option

When the player selects the Quick Game option, your game should create a virtual room object to join players, auto-match the player to randomly selected opponents without displaying the player picker UI, and immediately start the game. Use GooglePlayRTM class in your implementation.

private void findMatch() {
	int minPlayers = 1;
	int maxPlayers = 2;

	GooglePlayRTM.Instance.FindMatch(minPlayers, maxPlayers);

We can also provide our friends player id's who we like to invite to play a multiplayer match with us.


public void FindMatch(int minPlayers, int maxPlayers, params string[] playersToInvite)
public void FindMatch(int minPlayers, int maxPlayers, params GooglePlayerTemplate[] playersToInvite)

You might also be interested how to load friends list.

If your game has multiple player roles (such as farmer, archer, and wizard) and you want to restrict auto-matched games to one player of each role, add an exclusive bitmask to your room configuration. While auto-matching with this option players will only be considered for a match when the logical AND of their exclusive bit masks is equal to 0. The following example shows how to use the bit mask to perform auto matching with three exclusive roles:

private static int ROLE_FARMER = 0x1; // 001 in binary
private static int ROLE_ARCHER = 0x2; // 010 in binary
private static int ROLE_WIZARD = 0x4; // 100 in binary

private void findMatch() {

	GooglePlayRTM.Instance.SetExclusiveBitMask (ROLE_WIZARD);

	int minPlayers = 1;
	int maxPlayers = 2;

	GooglePlayRTM.Instance.FindMatch(minPlayers, maxPlayers);


You can also set the variant for the room. This is an optional, developer-controlled parameter describing the type of a game to play and is used for auto-matching criteria. Must be either a positive integer or ROOM_VARIANT_DEFAULT (the default) if not desired.

Note that variants must match exactly. Thus, if you do not specify a variant, only other rooms created withROOM_VARIANT_DEFAULT will be considered potential auto-matches.

private static int ROLE_FARMER = 0x1; // 001 in binary
private static int ROLE_ARCHER = 0x2; // 010 in binary
private static int ROLE_WIZARD = 0x4; // 100 in binary

private static int TRACK_1 = 1; // 100 in binary
private static int TRACK_2 = 2; // 100 in binary

private void findMatch() {

	GooglePlayRTM.Instance.SetExclusiveBitMask (ROLE_WIZARD);
	GooglePlayRTM.Instance.SetVariant (TRACK_1);

	int minPlayers = 1;
	int maxPlayers = 2;

	GooglePlayRTM.Instance.FindMatch(minPlayers, maxPlayers);


Invite Players option

When the Invite Players option is selected, your game should launch a player picker UI that prompts the initiating player to select friends to invite to a real-time game session or select a number of random players for auto-matching. Your game should create a virtual room object using the player's criteria, then start the session, once players are connected to the room.

To obtain the user's selection, your game can display the built-in player picker UI provided by Games services or a custom player picker UI. To launch the default player picker UI, call:

int minPlayers = 1;
int maxPlayers = 2;
GooglePlayRTM.Instance.OpenInvitationBoxUI(minPlayers, maxPlayers);

An example of the default player picker UI is shown below.


After all players are ready, a new game room will be created, and you should set up listeners to receive notifications of room status changes or incoming messages.

GooglePlayRTM.ActionRoomCreated += OnRoomCreated;
//networking event
GooglePlayRTM.ActionDataRecieved += OnGCDataReceived;

private void OnRoomCreated(GP_GamesStatusCodes code) {
	SA_StatusBar.text = "Room Create Result:  " + code.ToString();



The current room status is avaliable with GooglePlayRTM.Instance.currentRoom.status and is represented as GP_RTM_RoomStatus.

Handling room creation errors

To be notified of errors during the room creation, your game can use the Actions. If a room creation error has occurred, your game should display a message to notify players and return to the main screen.

public static Action ActionRoomAutomatching =  delegate{};
public static Action ActionRoomConnecting 	=  delegate{};
public static Action<GP_GamesStatusCodes> ActionJoinedRoom 	=  delegate{};
public static Action<GP_RTM_Result> ActionLeftRoom 	=  delegate{};
public static Action<GP_GamesStatusCodes> ActionRoomConnected =  delegate{};
public static Action<GP_GamesStatusCodes> ActionRoomCreated =  delegate{};

//add about room and participants

The room is represented as GP_RTM_Room class.

Note: The player ID is not the same as the participant ID. A player ID is a permanent identifier for a particular user and is consistent from game to game. A participant ID is a temporary identifier that is valid only for a particular room. Invitees from a player's circles have both a player ID and a participant ID. However, to preserve anonymity, players who joined the room via auto-match will only have a participant ID (and not a player ID).

The participant is represented as GP_Participant class and uses GP_RTM_ParticipantStatus enum.

Optional: Adding a waiting room UI

We recommend that your game use a "waiting room" UI so that players can see the current status of the room as participants join and get connected. Your game can display the default waiting room UI (shown in the figure below) or a custom UI.

To launch the default waiting room UI, call


Your game can launch the waiting room UI from the ActionRoomConnected and the ActionJoinedRoom callbacks.


When the waiting room UI or invitation UI is dismissed, your game receives the result in following actions:

public static Action<AndroidActivityResult> ActionInvitationBoxUIClosed =  delegate{};
public static Action<AndroidActivityResult> ActionWatingRoomIntentClosed =  delegate{};
  • AdroidActivityResultCodes.RESULT_OK - All invited players were successfully connected to the room.
  • AdroidActivityResultCodes.RESULT_CANCELED - The player pressed the Back button or the Up button on the Action Bar.


Starting the game before all players are connected

When creating the waiting room, your game can specify the minimum number of players required to start the game session. If the number of connected participants is more than or equal to the specified minimum to start the game, the system enables the Start Playing option in the waiting room UI. When a user clicks this option, the system dismisses the waiting room UI and delivers the AdroidActivityResultCodes.RESULT_OK result from code.

There is also an another way to get the current room status. You can simply monitor the current room state:

if(GooglePlayRTM.Instance.currentRoom.status!= GP_RTM_RoomStatus.ROOM_VARIANT_DEFAULT && GooglePlayRTM.Instance.currentRoom.status!= GP_RTM_RoomStatus.ROOM_STATUS_ACTIVE) {
	//We in the creation room process


if(GooglePlayRTM.Instance.currentRoom.status == GP_RTM_RoomStatus.ROOM_VARIANT_DEFAULT) {
  //No Room action

if(GooglePlayRTM.Instance.currentRoom.status == GP_RTM_RoomStatus.ROOM_STATUS_ACTIVE) {
  //Room is created, game started


Participant's statuses

  • STATUS_INVITED: The participant has been invited but has not acted on the invitation yet.
  • STATUS_DECLINED: The participant has declined the invitation.
  • STATUS_JOINED: The participant has joined the room.
  • STATUS_LEFT: The participants has left the room.

Make sure to construct your game logic carefully to take each participant's status and connectedness into account. For example, in a racing game, to determine if all racers have crossed the finish line, your game should only consider the participants who are connected. Your game should not wait for all players in the room cross the finish line, because not all participants might be connected (for example, one or more players might have left the room or declined the invitation).


Detecting when a player is disconnected

Your player might be disconnected from the room due to the network connectivity or server issues. To be notified when the player is disconnected from the room, implement Action:

public static Action ActionDisconnectedFromRoom 	=  delegate{};


Handling invitations


The invitation system is almost the same for the real-time and turn-based matches and described in this article.

Exchanging game data between clients

To send a message, your game can use:

string msg = "hello world";
System.Text.UTF8Encoding  encoding = new System.Text.UTF8Encoding();
byte[] data = encoding.GetBytes(msg);

GooglePlayRTM.instance.SendDataToAll(data, GP_RTM_PackageType.RELIABLE);


When your game receives a message(with GP_RTM_Network_Package type), it is notified by the ActionDataRecieved:

GooglePlayRTM.ActionDataRecieved += OnGCDataReceived;

private void OnGCDataReceived(GP_RTM_Network_Package package) {
	System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
	string str = enc.GetString(package.buffer);
	string name = package.ParticipantId;

	GP_Partisipant p =  GooglePlayRTM.Instance.currentRoom.GetPartisipantById(package.participantId);
	if(p != null) {
		GooglePlayerTemplate player = GooglePlayManager.Instance.GetPlayerById(p.PlayerId);
		if(player != null) {
			name = player.Name;

	AndroidMessage.Create("Data Eeceived", "player " + name + " \n " + "data: " + str);



The full implementation example can be found under the RTM_Example example scene.