Пример #1
0
        void PopulateUser(uint authGeneration, PlayerManager.FetchSelfResponse response)
        {
            Logger.d("Populating User");

            if (authGeneration != mAuthGeneration)
            {
                Logger.d("Received user callback after signout occurred, ignoring");
                return;
            }

            lock (AuthStateLock)
            {
                if (response.Status() != Status.ResponseStatus.VALID &&
                    response.Status() != Status.ResponseStatus.VALID_BUT_STALE)
                {
                    Logger.e("Error retrieving user, signing out");
                    var localCallbacks = mPendingAuthCallbacks;
                    mPendingAuthCallbacks = null;

                    if (localCallbacks != null)
                    {
                        InvokeCallbackOnGameThread(localCallbacks, false);
                    }
                    SignOut();
                    return;
                }

                mUser    = response.Self().AsPlayer();
                mFriends = null;
            }
            Logger.d("Found User: "******"Maybe finish for User");
            MaybeFinishAuthentication();
        }
Пример #2
0
        // called from game thread
        public void CreateWithInvitationScreen(int minOpponents, int maxOpponents, int variant,
                                               RealTimeMultiplayerListener listener)
        {
            Logger.d(string.Format("AndroidRtmpClient.CreateWithInvitationScreen, " +
                                   "opponents={0}-{1}, variant={2}", minOpponents, maxOpponents, variant));

            if (!PrepareToCreateRoom("CreateWithInvitationScreen", listener))
            {
                return;
            }

            mRtmpListener = listener;
            mVariant      = variant;
            mClient.CallClientApi("rtmp create with invitation screen", () => {
                AndroidJavaClass klass = JavaUtil.GetClass(
                    JavaConsts.SupportSelectOpponentsHelperActivity);
                mLaunchedExternalActivity = true;
                klass.CallStatic("launch", true, mClient.GetActivity(),
                                 new SelectOpponentsProxy(this), Logger.DebugLogEnabled,
                                 minOpponents, maxOpponents);
            }, (bool success) => {
                if (!success)
                {
                    FailRoomSetup("Failed to create game because GoogleApiClient was disconnected");
                }
            });
        }
Пример #3
0
        private void OnRealTimeMessageReceived(AndroidJavaObject message)
        {
            Logger.d("AndroidClient.OnRealTimeMessageReceived.");

            if (!CheckRtmpActive("OnRealTimeMessageReceived"))
            {
                return;
            }

            RealTimeMultiplayerListener listener = mRtmpListener;

            if (listener != null)
            {
                byte[] messageData;
                using (AndroidJavaObject messageBytes = message.Call <AndroidJavaObject>("getMessageData")) {
                    messageData = JavaUtil.ConvertByteArray(messageBytes);
                }
                bool   isReliable = message.Call <bool>("isReliable");
                string senderId   = message.Call <string>("getSenderParticipantId");

                Utils.PlayGamesHelperObject.RunOnGameThread(() => {
                    listener.OnRealTimeMessageReceived(isReliable, senderId, messageData);
                });
            }
            message.Dispose();
        }
Пример #4
0
        // called from game thread
        public Participant GetParticipant(string id)
        {
            Logger.d("AndroidRtmpClient.GetParticipant: " + id);

            if (!CheckConnectedRoom("GetParticipant"))
            {
                return(null);
            }

            List <Participant> allParticipants;

            lock (mParticipantListsLock) {
                allParticipants = mAllParticipants;
            }

            if (allParticipants == null)
            {
                Logger.e("RtmpGetParticipant called without a valid room!");
                return(null);
            }

            foreach (Participant p in allParticipants)
            {
                if (p.ParticipantId.Equals(id))
                {
                    return(p);
                }
            }

            Logger.e("Participant not found in room! id: " + id);
            return(null);
        }
 /// <summary>
 /// Activates the Play Games platform as the implementation of Social.Active.
 /// After calling this method, you can call methods on Social.Active. For
 /// example, <c>Social.Active.Authenticate()</c>.
 /// </summary>
 /// <returns>The singleton <see cref="PlayGamesPlatform" /> instance.</returns>
 public static PlayGamesPlatform Activate()
 {
     Logger.d("Activating PlayGamesPlatform.");
     Social.Active = PlayGamesPlatform.Instance;
     Logger.d("PlayGamesPlatform activated: " + Social.Active);
     return PlayGamesPlatform.Instance;
 }
Пример #6
0
        private void OnRoomConnected(int statusCode, AndroidJavaObject room)
        {
            Logger.d("AndroidClient.OnRoomConnected, status " + statusCode);

            if (!CheckRtmpActive("OnRoomConnected"))
            {
                return;
            }

            mRoom = room;
            UpdateRoom();
            if (statusCode != 0)
            {
                FailRoomSetup("OnRoomConnected error code " + statusCode);
            }
            else
            {
                Logger.d("AndroidClient.OnRoomConnected: room setup succeeded!");
                RealTimeMultiplayerListener listener = mRtmpListener;
                if (listener != null)
                {
                    Logger.d("Invoking callback OnRoomConnected(true) to report success.");
                    Utils.PlayGamesHelperObject.RunOnGameThread(() => {
                        mDeliveredRoomConnected = true;
                        listener.OnRoomConnected(true);
                    });
                }
            }
        }
Пример #7
0
            public void ChooseMetadata(ISavedGameMetadata chosenMetadata)
            {
                var convertedMetadata = chosenMetadata as AndroidSnapshotMetadata;

                if (convertedMetadata != mOriginal && convertedMetadata != mUnmerged)
                {
                    Logger.e("Caller attempted to choose a version of the metadata that was not part " +
                             "of the conflict");
                    mCompleteCallback(SavedGameRequestStatus.BadInputError, null);
                    return;
                }

                using (var task = mSnapshotsClient.Call <AndroidJavaObject>(
                           "resolveConflict", mConflict.Call <string>("getConflictId"), convertedMetadata.JavaSnapshot))
                {
                    AndroidTaskUtils.AddOnSuccessListener <AndroidJavaObject>(
                        task,
                        dataOrConflict => mRetryFileOpen());

                    mAndroidSavedGameClient.AddOnFailureListenerWithSignOut(
                        task,
                        exception =>
                    {
                        Logger.d("ChooseMetadata failed: " + exception.Call <string>("toString"));
                        var status = mAndroidSavedGameClient.mAndroidClient.IsAuthenticated()
                                ? SavedGameRequestStatus.InternalError
                                : SavedGameRequestStatus.AuthenticationError;
                        mCompleteCallback(status, null);
                    }
                        );
                }
            }
Пример #8
0
        void MaybeFinishAuthentication()
        {
            Action <bool> localCallbacks = null;

            lock (AuthStateLock)
            {
                // Only proceed if both the fetch-self and fetch-achievements callback have
                // completed.
                if (mUser == null || mAchievements == null)
                {
                    Logger.d("Auth not finished. User="******" achievements=" + mAchievements);
                    return;
                }

                Logger.d("Auth finished. Proceeding.");
                // Null out the pending callbacks - we will be invoking any pending ones.
                localCallbacks        = mPendingAuthCallbacks;
                mPendingAuthCallbacks = null;
                mAuthState            = AuthState.Authenticated;
            }

            if (localCallbacks != null)
            {
                Logger.d("Invoking Callbacks: " + localCallbacks);
                InvokeCallbackOnGameThread(localCallbacks, true);
            }
        }
Пример #9
0
        private void DeliverRoomSetupProgressUpdate()
        {
            Logger.d("AndroidRtmpClient: DeliverRoomSetupProgressUpdate");
            if (!mRtmpActive || mRoom == null || mDeliveredRoomConnected)
            {
                // no need to deliver progress
                return;
            }

            float progress = CalcRoomSetupPercentage();

            if (progress < mLastReportedProgress)
            {
                progress = mLastReportedProgress;
            }
            else
            {
                mLastReportedProgress = progress;
            }

            Logger.d("room setup progress: " + progress + "%");
            if (mRtmpListener != null)
            {
                Logger.d("Delivering progress to callback.");
                Utils.PlayGamesHelperObject.RunOnGameThread(() => {
                    mRtmpListener.OnRoomSetupProgress(progress);
                });
            }
        }
Пример #10
0
        // called from game thread
        public void CreateQuickGame(int minOpponents, int maxOpponents, int variant,
                                    RealTimeMultiplayerListener listener)
        {
            Logger.d(string.Format("AndroidRtmpClient.CreateQuickGame, opponents={0}-{1}, " +
                                   "variant={2}", minOpponents, maxOpponents, variant));

            if (!PrepareToCreateRoom("CreateQuickGame", listener))
            {
                return;
            }

            mRtmpListener = listener;
            mVariant      = variant;
            mClient.CallClientApi("rtmp create quick game", () => {
                AndroidJavaClass rtmpUtil = JavaUtil.GetClass(JavaConsts.SupportRtmpUtilsClass);
                rtmpUtil.CallStatic("createQuickGame", mClient.GHManager.GetApiClient(),
                                    minOpponents, maxOpponents, variant,
                                    new RoomUpdateProxy(this), new RoomStatusUpdateProxy(this),
                                    new RealTimeMessageReceivedProxy(this));
            }, (bool success) => {
                if (!success)
                {
                    FailRoomSetup("Failed to create game because GoogleApiClient was disconnected");
                }
            });
        }
Пример #11
0
 private bool CheckRtmpActive(string method)
 {
     if (!mRtmpActive)
     {
         Logger.d("Got call to " + method + " with RTMP inactive. Ignoring.");
         return(false);
     }
     return(true);
 }
Пример #12
0
 ConflictCallback ToOnGameThread(ConflictCallback conflictCallback)
 {
     return((resolver, original, originalData, unmerged, unmergedData) =>
     {
         Logger.d("Invoking conflict callback");
         PlayGamesHelperObject.RunOnGameThread(() =>
                                               conflictCallback(resolver, original, originalData, unmerged, unmergedData));
     });
 }
Пример #13
0
        // called from UI thread
        private void Clear(string reason)
        {
            Logger.d("RtmpClear: clearing RTMP (reason: " + reason + ").");

            // leave the room, if we have one
            if (mRoom != null)
            {
                Logger.d("RtmpClear: Room still active, so leaving room.");
                string roomId = mRoom.Call <string>("getRoomId");
                Logger.d("RtmpClear: room id to leave is " + roomId);

                // TODO: we are not specifying the callback from this API call to get
                // notified of when we *actually* leave the room. Perhaps we should do that,
                // in order to prevent the case where the developer tries to create a room
                // too soon after leaving the previous room, resulting in errors.
                mClient.GHManager.CallGmsApi("games.Games", "RealTimeMultiplayer", "leave",
                                             new NoopProxy(JavaConsts.RoomUpdateListenerClass), roomId);
                Logger.d("RtmpClear: left room.");
                mRoom = null;
            }
            else
            {
                Logger.d("RtmpClear: no room active.");
            }

            // call the OnLeftRoom() callback if needed
            if (mDeliveredRoomConnected)
            {
                Logger.d("RtmpClear: looks like we must call the OnLeftRoom() callback.");
                RealTimeMultiplayerListener listener = mRtmpListener;
                if (listener != null)
                {
                    Logger.d("Calling OnLeftRoom() callback.");
                    Utils.PlayGamesHelperObject.RunOnGameThread(() => {
                        listener.OnLeftRoom();
                    });
                }
            }
            else
            {
                Logger.d("RtmpClear: no need to call OnLeftRoom() callback.");
            }

            mLeaveRoomRequested     = false;
            mDeliveredRoomConnected = false;
            mRoom = null;
            mConnectedParticipants = null;
            mAllParticipants       = null;
            mSelf                     = null;
            mRtmpListener             = null;
            mVariant                  = 0;
            mRtmpActive               = false;
            mAccumulatedProgress      = 0.0f;
            mLastReportedProgress     = 0.0f;
            mLaunchedExternalActivity = false;
            Logger.d("RtmpClear: RTMP cleared.");
        }
Пример #14
0
        // called from game thread
        public void SendMessage(bool reliable, string participantId, byte[] data,
                                int offset, int length)
        {
            Logger.d(string.Format("AndroidRtmpClient.SendMessage, reliable={0}, " +
                                   "participantId={1}, data[]={2} bytes, offset={3}, length={4}",
                                   reliable, participantId, data.Length, offset, length));

            if (!CheckConnectedRoom("SendMessage"))
            {
                return;
            }

            if (mSelf != null && mSelf.ParticipantId.Equals(participantId))
            {
                Logger.d("Ignoring request to send message to self, " + participantId);
                return;
            }

            // Since we don't yet have API support for buffer/offset/length, convert
            // to a regular byte[] buffer:
            byte[] dataToSend = Misc.GetSubsetBytes(data, offset, length);

            if (participantId == null)
            {
                // this means "send to all"
                List <Participant> participants = GetConnectedParticipants();
                foreach (Participant p in participants)
                {
                    if (p.ParticipantId != null && !p.Equals(mSelf))
                    {
                        SendMessage(reliable, p.ParticipantId, dataToSend, 0, dataToSend.Length);
                    }
                }
                return;
            }

            mClient.CallClientApi("send message to " + participantId, () => {
                if (mRoom != null)
                {
                    string roomId = mRoom.Call <string>("getRoomId");
                    if (reliable)
                    {
                        mClient.GHManager.CallGmsApi <int>("games.Games", "RealTimeMultiplayer",
                                                           "sendReliableMessage", null, dataToSend, roomId, participantId);
                    }
                    else
                    {
                        mClient.GHManager.CallGmsApi <int>("games.Games", "RealTimeMultiplayer",
                                                           "sendUnreliableMessage", dataToSend, roomId, participantId);
                    }
                }
                else
                {
                    Logger.w("Not sending message because real-time room was torn down.");
                }
            }, null);
        }
Пример #15
0
        private void OnLeftRoom(int statusCode, AndroidJavaObject room)
        {
            Logger.d("AndroidClient.OnLeftRoom, status " + statusCode);
            if (!CheckRtmpActive("OnLeftRoom"))
            {
                return;
            }

            Clear("Got OnLeftRoom " + statusCode);
        }
        internal IUserProfile[] GetFriends()
        {
            if (!IsAuthenticated())
            {
                Logger.d("Cannot get friends when not authenticated!");
                return new IUserProfile[0];
            }

            return mClient.GetFriends();
        }
        /// <summary>
        /// Sets the default leaderboard for the leaderboard UI. After calling this
        /// method, a call to <see cref="ShowLeaderboardUI" /> will show only the specified
        /// leaderboard instead of showing the list of all leaderboards.
        /// </summary>
        /// <param name='lbid'>
        /// The ID of the leaderboard to display on the default UI. This may be a raw
        /// Google Play Games leaderboard ID or an alias configured through a call to
        /// <see cref="AddIdMapping" />.
        /// </param>
        public void SetDefaultLeaderboardForUI(string lbid)
        {
            Logger.d("SetDefaultLeaderboardForUI: " + lbid);
            if (lbid != null)
            {
                lbid = MapId(lbid);
            }

            mDefaultLbUi = lbid;
        }
        /// <summary>
        /// Shows the standard Google Play Games achievements user interface,
        /// which allows the player to browse their achievements.
        /// </summary>
        /// <param name="callback">If non-null, the callback is invoked when
        /// the achievement UI is dismissed</param>
        public void ShowAchievementsUI(Action<UIStatus> callback)
        {
            if (!IsAuthenticated())
            {
                Logger.e("ShowAchievementsUI can only be called after authentication.");
                return;
            }

            Logger.d("ShowAchievementsUI callback is "  + callback);
            mClient.ShowAchievementsUI(callback);
        }
Пример #19
0
        private void OnDisconnectedFromRoom(AndroidJavaObject room)
        {
            Logger.d("AndroidClient.OnDisconnectedFromRoom");

            if (!CheckRtmpActive("OnDisconnectedFromRoom"))
            {
                return;
            }

            Clear("Got OnDisconnectedFromRoom");
        }
Пример #20
0
        private void OnP2PDisconnected(string participantId)
        {
            Logger.d("AndroidClient.OnP2PDisconnected: " + participantId);

            if (!CheckRtmpActive("OnP2PDisconnected"))
            {
                return;
            }

            UpdateRoom();
        }
        /// <summary>
        /// Authenticate the local user with the Google Play Games service.
        /// </summary>
        /// <param name='callback'>
        /// The callback to call when authentication finishes. It will be called
        /// with <c>true</c> if authentication was successful, <c>false</c>
        /// otherwise.
        /// </param>
        /// <param name='silent'>
        /// Indicates whether authentication should be silent. If <c>false</c>,
        /// authentication may show popups and interact with the user to obtain
        /// authorization. If <c>true</c>, there will be no popups or interaction with
        /// the user, and the authentication will fail instead if such interaction
        /// is required. A typical pattern is to try silent authentication on startup
        /// and, if that fails, present the user with a "Sign in" button that then
        /// triggers normal (not silent) authentication.
        /// </param>
        public void Authenticate(Action<bool> callback, bool silent)
        {
            // make a platform-specific Play Games client
            if (mClient == null)
            {
                Logger.d("Creating platform-specific Play Games client.");
                mClient = PlayGamesClientFactory.GetPlatformPlayGamesClient(mConfiguration);
            }

            // authenticate!
            mClient.Authenticate(callback, silent);
        }
Пример #22
0
        private void OnPeersDisconnected(AndroidJavaObject room, AndroidJavaObject participantIds)
        {
            Logger.d("AndroidClient.OnPeersDisconnected.");

            if (!CheckRtmpActive("OnPeersDisconnected"))
            {
                return;
            }

            mRoom = room;
            UpdateRoom();
        }
Пример #23
0
        private void OnRoomConnecting(AndroidJavaObject room)
        {
            Logger.d("AndroidClient.OnRoomConnecting.");

            if (!CheckRtmpActive("OnRoomConnecting"))
            {
                return;
            }

            mRoom = room;
            UpdateRoom();
        }
Пример #24
0
        private static void InvokeCallbackOnGameThread <T>(Action <T> callback, T data)
        {
            if (callback == null)
            {
                return;
            }

            PlayGamesHelperObject.RunOnGameThread(() =>
            {
                Logger.d("Invoking user callback on game thread");
                callback(data);
            });
        }
Пример #25
0
        private void OnConnectedToRoom(AndroidJavaObject room)
        {
            Logger.d("AndroidClient.OnConnectedToRoom");

            if (!CheckRtmpActive("OnConnectedToRoom"))
            {
                return;
            }

            mAccumulatedProgress += 10.0f;
            mRoom = room;
            UpdateRoom();
        }
        /// <summary>
        /// Shows the leaderboard UI and calls the specified callback upon
        /// completion.
        /// </summary>
        /// <param name="lbId">leaderboard ID, can be null meaning all leaderboards.</param>
        /// <param name="span">Timespan to display scores in the leaderboard.</param>
        /// <param name="callback">Callback to call.  If null, nothing is called.</param>
        public void ShowLeaderboardUI(string lbId, LeaderboardTimeSpan span,
            Action<UIStatus> callback)
        {
            if (!IsAuthenticated())
            {
                Logger.e("ShowLeaderboardUI can only be called after authentication.");
                callback(UIStatus.NotAuthorized);
                return;
            }

            Logger.d("ShowLeaderboardUI, lbId=" + lbId + " callback is " + callback);
            mClient.ShowLeaderboardUI(lbId, span, callback);
        }
Пример #27
0
 // called from UI thread, on onStop
 public void OnStop()
 {
     // if we launched an external activity (like the "select opponents" UI) as part of
     // the process, we should NOT clear our RTMP state on OnStop because we will get
     // OnStop when that Activity launches.
     if (mLaunchedExternalActivity)
     {
         Logger.d("OnStop: EXTERNAL ACTIVITY is pending, so not clearing RTMP.");
     }
     else
     {
         Clear("leaving room because game is stopping.");
     }
 }
Пример #28
0
 public IUserProfile[] GetFriends()
 {
     if (mFriends == null && !friendsLoading)
     {
         Logger.w("Getting friends before they are loaded!!!");
         friendsLoading = true;
         LoadFriends((ok) =>
         {
             Logger.d("loading: " + ok);
             friendsLoading = false;
         });
     }
     return((mFriends == null) ? new IUserProfile[0] : mFriends.ToArray());
 }
Пример #29
0
        // called from the game thread
        public void DeclineInvitation(string invitationId)
        {
            Logger.d("AndroidRtmpClient.DeclineInvitation " + invitationId);

            mClient.ClearInvitationIfFromNotification(invitationId);
            mClient.CallClientApi("rtmp decline invitation", () => {
                mClient.GHManager.CallGmsApi("games.Games", "RealTimeMultiplayer",
                                             "declineInvitation", invitationId);
            }, (bool success) => {
                if (!success)
                {
                    Logger.w("Failed to decline invitation. GoogleApiClient was disconnected");
                }
            });
        }
Пример #30
0
        // called from UI thread
        private void FailRoomSetup(string reason)
        {
            Logger.d("Failing room setup: " + reason);
            RealTimeMultiplayerListener listener = mRtmpListener;

            Clear("Room setup failed: " + reason);

            if (listener != null)
            {
                Logger.d("Invoking callback OnRoomConnected(false) to signal failure.");
                Utils.PlayGamesHelperObject.RunOnGameThread(() => {
                    listener.OnRoomConnected(false);
                });
            }
        }