Sulabh Deep Puri
Sulabh Deep Puri

Reputation: 33

Real-time Multiplayer Google Play Games Services peer gets disconnected when app goes in background

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

Answers (1)

Teyam
Teyam

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

Related Questions