Reputation: 33
I am building a real time multiplayer game using 'Google Play Games Services'. My question is that when peers are connected to a room and playing the game, and one of them puts their application in background that peer gets disconnected from room, and other peers receives callback of that peer leaving the room, is their a way to prevent this from happening.
For testing purpose fragment does not call to leave that room in any of its life cycle methods.
I've added code snippets to provide better understanding.
@Override
public void onStop() {
super.onStop();
// if (mRoomId!=null && !mRoomId.isEmpty()) {
// Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, mRoomId);
// }
// getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// mPlaying = false;
}
@Override
public void onActivityResult(int request, int response, Intent data) {
if (request == RC_SELECT_PLAYERS) {
if (response != Activity.RESULT_OK) {
// user canceled
return;
}
// get the invitee list
Bundle extras = data.getExtras();
final ArrayList<String> invitees =
data.getStringArrayListExtra(Games.EXTRA_PLAYER_IDS);
// get auto-match criteria
Bundle autoMatchCriteria = null;
int minAutoMatchPlayers =
data.getIntExtra(Multiplayer.EXTRA_MIN_AUTOMATCH_PLAYERS, 0);
int maxAutoMatchPlayers =
data.getIntExtra(Multiplayer.EXTRA_MAX_AUTOMATCH_PLAYERS, 0);
if (minAutoMatchPlayers > 0) {
autoMatchCriteria = RoomConfig.createAutoMatchCriteria(
minAutoMatchPlayers, maxAutoMatchPlayers, 0);
} else {
autoMatchCriteria = null;
}
// create the room and specify a variant if appropriate
RoomConfig.Builder roomConfigBuilder = makeBasicRoomConfigBuilder();
roomConfigBuilder.addPlayersToInvite(invitees);
if (autoMatchCriteria != null) {
roomConfigBuilder.setAutoMatchCriteria(autoMatchCriteria);
}
RoomConfig roomConfig = roomConfigBuilder.build();
Games.RealTimeMultiplayer.create(((MainActivity) getActivity()).getGoogleApiClient(), roomConfig);
// prevent screen from sleeping during handshake
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
if (request == RC_WAITING_ROOM) {
if (mWaitingRoomFinishedFromCode) return;
if (response == Activity.RESULT_OK) {
// (start game)
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (getContext()!=null) {
Player[] players = getParticipantPlayers();
if (players!=null && players.length>0) {
startGame(players);
}
}
}
}, 1000);
}
else if (response == Activity.RESULT_CANCELED) {
// Waiting room was dismissed with the back button. The meaning of this
// action is up to the game. You may choose to leave the room and cancel the
// match, or do something else like minimize the waiting room and
// continue to connect in the background.
// in this example, we take the simple approach and just leave the room:
Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, mRoomId);
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
else if (response == GamesActivityResultCodes.RESULT_LEFT_ROOM) {
// player wants to leave the room.
Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, mRoomId);
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
}
private RoomUpdateListener roomUpdateListener = new RoomUpdateListener() {
@Override
public void onJoinedRoom(int statusCode, Room room) {
if (getContext()!=null) {
roomCreatorId = room.getCreatorId();
mRoomId = room.getRoomId();
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
// setCurrentPlayerParticipantId();
if (statusCode != GamesStatusCodes.STATUS_OK) {
// let screen go to sleep
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// show error message, return to main screen.
Toast.makeText(getContext(), "Error while joining room.", Toast.LENGTH_SHORT).show();
showRoomUi();
}
// get waiting room intent
Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(((MainActivity) getActivity()).getGoogleApiClient(), room, MIN_PLAYERS);
startActivityForResult(i, RC_WAITING_ROOM);
}
}
@Override
public void onRoomCreated(int statusCode, Room room) {
if (getContext()!=null) {
roomCreatorId = room.getCreatorId();
mRoomId = room.getRoomId();
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
// setCurrentPlayerParticipantId();
if (statusCode != GamesStatusCodes.STATUS_OK) {
// let screen go to sleep
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// show error message, return to main screen.
Toast.makeText(getContext(), "Error creating room.", Toast.LENGTH_SHORT).show();
showRoomUi();
}
// get waiting room intent
Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(((MainActivity) getActivity()).getGoogleApiClient(), room, MIN_PLAYERS);
startActivityForResult(i, RC_WAITING_ROOM);
}
}
@Override
public void onLeftRoom(int i, String s) {
if (getContext()!=null) {
// remove the flag that keeps the screen on
mRoomId = null;
}
}
@Override
public void onRoomConnected(int statusCode, Room room) {
if (getContext()!=null) {
roomCreatorId = room.getCreatorId();
mRoomId = room.getRoomId();
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
// setCurrentPlayerParticipantId();
if (statusCode != GamesStatusCodes.STATUS_OK) {
// let screen go to sleep
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// show error message, return to main screen.
Toast.makeText(getContext(), "Error connecting to room.", Toast.LENGTH_SHORT).show();
showRoomUi();
}
}
}
};
private RoomStatusUpdateListener roomStatusUpdateListener = new RoomStatusUpdateListener() {
@Override
public void onRoomConnecting(Room room) {
if (getContext()!=null) {
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
}
}
@Override
public void onRoomAutoMatching(Room room) {
if (getContext()!=null) {
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
}
}
@Override
public void onPeerInvitedToRoom(Room room, List<String> list) {
if (getContext()!=null) {
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
}
}
@Override
public void onPeerJoined(Room room, List<String> list) {
if (getContext()!=null) {
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
}
}
@Override
public void onConnectedToRoom(Room room) {
if (getContext()!=null) {
mMyId = room.getParticipantId(Games.Players.getCurrentPlayerId(((MainActivity) getActivity()).getGoogleApiClient()));
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
}
}
@Override
public void onDisconnectedFromRoom(Room room) {
if (getContext()!=null) {
// leave the room
Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, room.getRoomId());
// clear the flag that keeps the screen on
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// show error message and return to main screen
Toast.makeText(getContext(), "Network error.", Toast.LENGTH_SHORT).show();
showRoomUi();
}
}
@Override
public void onP2PConnected(String s) {
}
@Override
public void onP2PDisconnected(String s) {
}
@Override
public void onPeersConnected(Room room, List<String> peers) {
if (getContext()!=null) {
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
if (mPlaying) {
// add new player to an ongoing game
} else if (shouldStartGame(room)) {
// start game!
}
}
}
@Override
public void onPeersDisconnected(Room room, List<String> peers) {
if (getContext()!=null) {
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
if (mPlaying) {
// do game-specific handling of this -- remove player's avatar
// from the screen, etc. If not enough players are left for
// the game to go on, end the game and leave the room.
}
else if (shouldCancelGame(room)) {
// cancel the game
Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, room.getRoomId());
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
showRoomUi();
}
}
}
@Override
public void onPeerLeft(Room room, List<String> peers) {
if (getContext()!=null) {
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
// peer left -- see if game should be canceled
if (!mPlaying && shouldCancelGame(room)) {
Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, room.getRoomId());
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
showRoomUi();
}
}
}
@Override
public void onPeerDeclined(Room room, List<String> peers) {
if (getContext()!=null) {
mParticipants.clear();
mParticipants.addAll(room.getParticipants());
// peer declined invitation -- see if game should be canceled
if (!mPlaying && shouldCancelGame(room)) {
Games.RealTimeMultiplayer.leave(((MainActivity) getActivity()).getGoogleApiClient(), roomUpdateListener, room.getRoomId());
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
showRoomUi();
}
}
}
};
private RealTimeMessageReceivedListener realTimeMessageReceivedListener = new RealTimeMessageReceivedListener() {
@Override
public void onRealTimeMessageReceived(RealTimeMessage realTimeMessage) {
if (getContext()!=null) {
if (realTimeMessage.isReliable()) {
handleReliableMessages(realTimeMessage.getMessageData());
}
}
}
};
Any help is appreciated. Thank you.
Upvotes: 3
Views: 565
Reputation: 8112
AFAIK, that's just how the API was designed and is working as intended.
As mentioned in this documentation, you should leave the active room whenever your game goes into the background.
For additional insights (from Bruno Oliveira), you may want to see these related SO posts:
Though, you may also opt to try this suggested solution. Try editing BaseGameActivity.onStop()
and remove gamehelper.onStop()
. With this, gamesclient
will only stopped in onDestroy
. It might be a good option but I haven't actually tried it.
Upvotes: 1