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);
                });
            }
        }
Example #2
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();
        }
 void DoGetAnotherServerAuthCode(bool reAuthenticateIfNeeded, Action <string> callback)
 {
     try
     {
         using (var bridgeClass = new AndroidJavaClass(HelperFragmentClass))
             using (var currentActivity = AndroidHelperFragment.GetActivity())
                 using (var pendingResult = bridgeClass.CallStatic <AndroidJavaObject>(
                            "fetchToken",
                            currentActivity,
                            /* silent= */ reAuthenticateIfNeeded,
                            /* requestAuthCode= */ true,
                            /* requestEmail= */ false,
                            /* requestIdToken= */ false,
                            webClientId,
                            /* forceRefresh= */ false,
                            oauthScopes.ToArray(),
                            /* hidePopups= */ true,
                            /* accountName= */ ""))
                 {
                     pendingResult.Call("setResultCallback", new ResultCallbackProxy(
                                            tokenResult => { callback(tokenResult.Call <string>("getAuthCode")); }));
                 }
     }
     catch (Exception e)
     {
         Logger.e("Exception launching token request: " + e.Message);
         Logger.e(e.ToString());
     }
 }
        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();
        }
        // 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);
        }
Example #6
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);
            }
        }
Example #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);
                    }
                        );
                }
            }
        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);
                    });
                }
            }
        }
        // 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");
                }
            });
        }
Example #10
0
        public void ReadBinaryData(ISavedGameMetadata metadata,
                                   Action <SavedGameRequestStatus, byte[]> completedCallback)
        {
            Misc.CheckNotNull(metadata);
            Misc.CheckNotNull(completedCallback);
            completedCallback = ToOnGameThread(completedCallback);

            var convertedMetadata = metadata as AndroidSnapshotMetadata;

            if (convertedMetadata == null)
            {
                Logger.e("Encountered metadata that was not generated by this ISavedGameClient");
                completedCallback(SavedGameRequestStatus.BadInputError, null);
                return;
            }

            if (!convertedMetadata.IsOpen)
            {
                Logger.e("This method requires an open ISavedGameMetadata.");
                completedCallback(SavedGameRequestStatus.BadInputError, null);
                return;
            }

            var data = convertedMetadata.JavaContents.Call <byte[]>("readFully");

            if (data == null)
            {
                completedCallback(SavedGameRequestStatus.BadInputError, null);
            }
            else
            {
                completedCallback(SavedGameRequestStatus.Success, data);
            }
        }
        // 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");
                }
            });
        }
 /// <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;
 }
Example #13
0
        public void OpenWithAutomaticConflictResolution(string filename, DataSource source,
                                                        ConflictResolutionStrategy resolutionStrategy,
                                                        Action <SavedGameRequestStatus, ISavedGameMetadata> completedCallback)
        {
            Misc.CheckNotNull(filename);
            Misc.CheckNotNull(completedCallback);
            var prefetchDataOnConflict        = false;
            ConflictCallback conflictCallback = null;

            completedCallback = ToOnGameThread(completedCallback);

            if (conflictCallback == null)
            {
                conflictCallback = (resolver, original, originalData, unmerged, unmergedData) =>
                {
                    switch (resolutionStrategy)
                    {
                    case ConflictResolutionStrategy.UseOriginal:
                        resolver.ChooseMetadata(original);
                        return;

                    case ConflictResolutionStrategy.UseUnmerged:
                        resolver.ChooseMetadata(unmerged);
                        return;

                    case ConflictResolutionStrategy.UseLongestPlaytime:
                        if (original.TotalTimePlayed >= unmerged.TotalTimePlayed)
                        {
                            resolver.ChooseMetadata(original);
                        }
                        else
                        {
                            resolver.ChooseMetadata(unmerged);
                        }

                        return;

                    default:
                        Logger.e("Unhandled strategy " + resolutionStrategy);
                        completedCallback(SavedGameRequestStatus.InternalError, null);
                        return;
                    }
                }
            }
            ;

            conflictCallback = ToOnGameThread(conflictCallback);

            if (!IsValidFilename(filename))
            {
                Logger.e("Received invalid filename: " + filename);
                completedCallback(SavedGameRequestStatus.BadInputError, null);
                return;
            }

            InternalOpen(filename, source, resolutionStrategy, prefetchDataOnConflict, conflictCallback,
                         completedCallback);
        }
 private bool CheckRtmpActive(string method)
 {
     if (!mRtmpActive)
     {
         Logger.d("Got call to " + method + " with RTMP inactive. Ignoring.");
         return(false);
     }
     return(true);
 }
        // 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.");
        }
Example #16
0
        public void CommitUpdate(ISavedGameMetadata metadata, SavedGameMetadataUpdate updateForMetadata,
                                 byte[] updatedBinaryData, Action <SavedGameRequestStatus, ISavedGameMetadata> callback)
        {
            Misc.CheckNotNull(metadata);
            Misc.CheckNotNull(updatedBinaryData);
            Misc.CheckNotNull(callback);

            callback = ToOnGameThread(callback);

            var convertedMetadata = metadata as AndroidSnapshotMetadata;

            if (convertedMetadata == null)
            {
                Logger.e("Encountered metadata that was not generated by this ISavedGameClient");
                callback(SavedGameRequestStatus.BadInputError, null);
                return;
            }

            if (!convertedMetadata.IsOpen)
            {
                Logger.e("This method requires an open ISavedGameMetadata.");
                callback(SavedGameRequestStatus.BadInputError, null);
                return;
            }

            if (!convertedMetadata.JavaContents.Call <bool>("writeBytes", updatedBinaryData))
            {
                Logger.e("This method requires an open ISavedGameMetadata.");
                callback(SavedGameRequestStatus.BadInputError, null);
            }

            using (var convertedMetadataChange = AsMetadataChange(updateForMetadata))
                using (var task = mSnapshotsClient.Call <AndroidJavaObject>("commitAndClose", convertedMetadata.JavaSnapshot,
                                                                            convertedMetadataChange))
                {
                    AndroidTaskUtils.AddOnSuccessListener <AndroidJavaObject>(
                        task,
                        /* disposeResult= */ false,
                        snapshotMetadata =>
                    {
                        Debug.Log("commitAndClose.succeed");
                        callback(SavedGameRequestStatus.Success,
                                 new AndroidSnapshotMetadata(snapshotMetadata, /* contents= */ null));
                    });

                    AddOnFailureListenerWithSignOut(
                        task,
                        exception =>
                    {
                        Debug.Log("commitAndClose.failed: " + exception.Call <string>("toString"));
                        var status = mAndroidClient.IsAuthenticated()
                            ? SavedGameRequestStatus.InternalError
                            : SavedGameRequestStatus.AuthenticationError;
                        callback(status, null);
                    });
                }
        }
Example #17
0
 ConflictCallback ToOnGameThread(ConflictCallback conflictCallback)
 {
     return((resolver, original, originalData, unmerged, unmergedData) =>
     {
         Logger.d("Invoking conflict callback");
         PlayGamesHelperObject.RunOnGameThread(() =>
                                               conflictCallback(resolver, original, originalData, unmerged, unmergedData));
     });
 }
        // 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);
        }
        private void OnLeftRoom(int statusCode, AndroidJavaObject room)
        {
            Logger.d("AndroidClient.OnLeftRoom, status " + statusCode);
            if (!CheckRtmpActive("OnLeftRoom"))
            {
                return;
            }

            Clear("Got OnLeftRoom " + statusCode);
        }
        /// <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;
        }
        public static void InitializeInstance(PlayGamesClientConfiguration configuration)
        {
            if (sInstance != null)
            {
                Logger.w("PlayGamesPlatform already initialized. Ignoring this call.");
                return;
            }

            sInstance = new PlayGamesPlatform(configuration);
        }
        /// <summary>
        /// Returns the user's avatar URL if they have one.
        /// </summary>
        /// <returns>
        /// The URL, or <code>null</code> if the user is not authenticated or does not have
        /// an avatar.
        /// </returns>
        public string GetUserImageUrl()
        {
            if (!IsAuthenticated())
            {
                Logger.e("GetUserImageUrl can only be called after authentication.");
                return null;
            }

            return mClient.GetUserImageUrl();
        }
        /// <summary>
        /// Returns the user's display name.
        /// </summary>
        /// <returns>
        /// The user display name (e.g. "Bruno Oliveira")
        /// </returns>
        public string GetUserDisplayName()
        {
            if (!IsAuthenticated())
            {
                Logger.e("GetUserDisplayName can only be called after authentication.");
                return string.Empty;
            }

            return mClient.GetUserDisplayName();
        }
        /// <summary>
        /// Returns the achievement corresponding to the passed achievement identifier.
        /// </summary>
        /// <returns>
        /// The achievement corresponding to the identifer. <code>null</code> if no such
        /// achievement is found or if the user is not authenticated.
        /// </returns>
        /// <param name="achievementId">
        /// The identifier of the achievement.
        /// </param>
        public Achievement GetAchievement(string achievementId)
        {
            if (!IsAuthenticated())
            {
                Logger.e("GetAchievement can only be called after authentication.");
                return null;
            }

            return mClient.GetAchievement(achievementId);
        }
        internal IUserProfile[] GetFriends()
        {
            if (!IsAuthenticated())
            {
                Logger.d("Cannot get friends when not authenticated!");
                return new IUserProfile[0];
            }

            return mClient.GetFriends();
        }
        /// <summary>
        /// Loads the user information if available.
        /// <param name="userIds">The user ids to look up</param>
        /// <param name="callback">The callback</param>
        /// </summary>
        public void LoadUsers(string[] userIds, Action<IUserProfile[]> callback)
        {
            if (!IsAuthenticated())
            {
                Logger.e("GetUserId() can only be called after authentication.");
                callback(new IUserProfile[0]);
            }

            mClient.LoadUsers(userIds, callback);
        }
        /// <summary>
        /// Returns the user's Google ID.
        /// </summary>
        /// <returns>
        /// The user's Google ID. No guarantees are made as to the meaning or format of
        /// this identifier except that it is unique to the user who is signed in.
        /// </returns>
        public string GetUserId()
        {
            if (!IsAuthenticated())
            {
                Logger.e("GetUserId() can only be called after authentication.");
                return "0";
            }

            return mClient.GetUserId();
        }
        private void OnP2PDisconnected(string participantId)
        {
            Logger.d("AndroidClient.OnP2PDisconnected: " + participantId);

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

            UpdateRoom();
        }
        private void OnDisconnectedFromRoom(AndroidJavaObject room)
        {
            Logger.d("AndroidClient.OnDisconnectedFromRoom");

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

            Clear("Got OnDisconnectedFromRoom");
        }
        /// <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);
        }