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

            sInstance = new PlayGamesPlatform(configuration);
        }
Example #3
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());
 }
        // 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");
                }
            });
        }
 /// <summary>
 /// Calls a method on a java object while handling null return values.
 /// Sadly, it appears that calling a method that returns a null Object in Java so we work
 /// around this by catching null pointer exceptions a checking for the word "null".
 /// </summary>
 internal static AndroidJavaObject NullSafeCall(this AndroidJavaObject target,
                                                string methodName, params object[] args)
 {
     try {
         return(target.Call <AndroidJavaObject>(methodName, args));
     } catch (Exception ex) {
         if (ex.Message.Contains("null"))
         {
             // expected -- means method returned null
             return(null);
         }
         else
         {
             Logger.w("CallObjectMethod exception: " + ex);
             return(null);
         }
     }
 }
        // called from game thread
        public void LeaveRoom()
        {
            Logger.d("AndroidRtmpClient.LeaveRoom");

            // if we are setting up a room but haven't got the room yet, we can't
            // leave the room now, we have to defer it to a later time when we have the room
            if (mRtmpActive && mRoom == null)
            {
                Logger.w("AndroidRtmpClient.LeaveRoom: waiting for room; deferring leave request.");
                mLeaveRoomRequested = true;
            }
            else
            {
                mClient.CallClientApi("leave room", () => {
                    Clear("LeaveRoom called");
                }, null);
            }
        }
Example #7
0
        private static InitializationStatus ToStatus(S.InitializationStatus status)
        {
            switch (status)
            {
            case S.InitializationStatus.VALID:
                return(InitializationStatus.Success);

            case S.InitializationStatus.ERROR_INTERNAL:
                return(InitializationStatus.InternalError);

            case S.InitializationStatus.ERROR_VERSION_UPDATE_REQUIRED:
                return(InitializationStatus.VersionUpdateRequired);

            default:
                Logger.w("Unknown initialization status: " + status);
                return(InitializationStatus.InternalError);
            }
        }
        private void OnInvitationInboxResult(bool success, string invitationId)
        {
            Logger.d("AndroidRtmpClient.OnInvitationInboxResult, " +
                     "success=" + success + ", invitationId=" + invitationId);

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

            // we now do not have an external Activity that we launched
            mLaunchedExternalActivity = false;

            if (!success || invitationId == null || invitationId.Length == 0)
            {
                Logger.w("Failed to setup room because invitation inbox UI failed.");
                FailRoomSetup("Invitation inbox UI failed.");
                return;
            }

            mClient.ClearInvitationIfFromNotification(invitationId);

            // we use CallClientApi instead of calling the API directly because we need
            // to make sure that we call it when the GoogleApiClient is connected, which is
            // not necessarily true at this point (we just came back from an external
            // activity)
            mClient.CallClientApi("accept invite from inbox", () => {
                Logger.d("Accepting invite from inbox via support lib.");
                AndroidJavaClass rtmpUtil = JavaUtil.GetClass(JavaConsts.SupportRtmpUtilsClass);
                rtmpUtil.CallStatic("accept", mClient.GHManager.GetApiClient(), invitationId,
                                    new RoomUpdateProxy(this), new RoomStatusUpdateProxy(this),
                                    new RealTimeMessageReceivedProxy(this));
            }, (bool ok) => {
                if (!ok)
                {
                    FailRoomSetup("GoogleApiClient lost connection.");
                }
            });
        }
        private void OnSelectOpponentsResult(bool success, AndroidJavaObject opponents,
                                             bool hasAutoMatch, AndroidJavaObject autoMatchCriteria)
        {
            Logger.d("AndroidRtmpClient.OnSelectOpponentsResult, success=" + success);

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

            // we now do not have an external Activity that we launched
            mLaunchedExternalActivity = false;

            if (!success)
            {
                Logger.w("Room setup failed because select-opponents UI failed.");
                FailRoomSetup("Select opponents UI failed.");
                return;
            }

            // at this point, we have to create the room -- but we have to make sure that
            // our GoogleApiClient is connected before we do that. It might NOT be connected
            // right now because we just came back from calling an external Activity.
            // So we use CallClientApi to make sure we are only doing this at the right time:
            mClient.CallClientApi("creating room w/ select-opponents result", () => {
                Logger.d("Creating room via support lib's RtmpUtil.");
                AndroidJavaClass rtmpUtil = JavaUtil.GetClass(JavaConsts.SupportRtmpUtilsClass);
                rtmpUtil.CallStatic("create", mClient.GHManager.GetApiClient(),
                                    opponents, mVariant, hasAutoMatch ? autoMatchCriteria : null,
                                    new RoomUpdateProxy(this), new RoomStatusUpdateProxy(this),
                                    new RealTimeMessageReceivedProxy(this));
            }, (bool ok) => {
                if (!ok)
                {
                    FailRoomSetup("GoogleApiClient lost connection");
                }
            });
        }
        /// <summary>
        /// Reports the progress of an achievement (reveal, unlock or increment). This method attempts
        /// to implement the expected behavior of ISocialPlatform.ReportProgress as closely as possible,
        /// as described below. Although this method works with incremental achievements for compatibility
        /// purposes, calling this method for incremental achievements is not recommended,
        /// since the Play Games API exposes incremental achievements in a very different way
        /// than the interface presented by ISocialPlatform.ReportProgress. The implementation of this
        /// method for incremental achievements attempts to produce the correct result, but may be
        /// imprecise. If possible, call <see cref="IncrementAchievement" /> instead.
        /// </summary>
        /// <param name='achievementID'>
        /// The ID of the achievement to unlock, reveal or increment. This can be a raw Google Play
        /// Games achievement ID (alphanumeric string), or an alias that was previously configured
        /// by a call to <see cref="AddIdMapping" />.
        /// </param>
        /// <param name='progress'>
        /// Progress of the achievement. If the achievement is standard (not incremental), then
        /// a progress of 0.0 will reveal the achievement and 100.0 will unlock it. Behavior of other
        /// values is undefined. If the achievement is incremental, then this value is interpreted
        /// as the total percentage of the achievement's progress that the player should have
        /// as a result of this call (regardless of the progress they had before). So if the
        /// player's previous progress was 30% and this call specifies 50.0, the new progress will
        /// be 50% (not 80%).
        /// </param>
        /// <param name='callback'>
        /// Callback that will be called to report the result of the operation: <c>true</c> on
        /// success, <c>false</c> otherwise.
        /// </param>
        public void ReportProgress(string achievementID, double progress, Action<bool> callback)
        {
            if (!IsAuthenticated())
            {
                Logger.e("ReportProgress can only be called after authentication.");
                if (callback != null)
                {
                    callback.Invoke(false);
                }

                return;
            }

            // map ID, if it's in the dictionary
            Logger.d("ReportProgress, " + achievementID + ", " + progress);
            achievementID = MapId(achievementID);

            // if progress is 0.0, we just want to reveal it
            if (progress < 0.000001)
            {
                Logger.d("Progress 0.00 interpreted as request to reveal.");
                mClient.RevealAchievement(achievementID, callback);
                return;
            }

            // figure out if it's a standard or incremental achievement
            bool isIncremental = false;
            int curSteps = 0, totalSteps = 0;
            Achievement ach = mClient.GetAchievement(achievementID);
            if (ach == null)
            {
                Logger.w("Unable to locate achievement " + achievementID);
                Logger.w("As a quick fix, assuming it's standard.");
                isIncremental = false;
            }
            else
            {
                isIncremental = ach.IsIncremental;
                curSteps = ach.CurrentSteps;
                totalSteps = ach.TotalSteps;
                Logger.d("Achievement is " + (isIncremental ? "INCREMENTAL" : "STANDARD"));
                if (isIncremental)
                {
                    Logger.d("Current steps: " + curSteps + "/" + totalSteps);
                }
            }

            // do the right thing depending on the achievement type
            if (isIncremental)
            {
                // increment it to the target percentage (approximate)
                Logger.d("Progress " + progress +
                    " interpreted as incremental target (approximate).");
                if (progress >= 0.0 && progress <= 1.0)
                {
                    // in a previous version, incremental progress was reported by using the range [0-1]
                    Logger.w("Progress " + progress + " is less than or equal to 1. You might be trying to use values in the range of [0,1], while values are expected to be within the range [0,100]. If you are using the latter, you can safely ignore this message.");
                }

                int targetSteps = (int)((progress / 100) * totalSteps);
                int numSteps = targetSteps - curSteps;
                Logger.d("Target steps: " + targetSteps + ", cur steps:" + curSteps);
                Logger.d("Steps to increment: " + numSteps);
                if (numSteps > 0)
                {
                    mClient.IncrementAchievement(achievementID, numSteps, callback);
                }
            }
            else if (progress >= 100)
            {
                // unlock it!
                Logger.d("Progress " + progress + " interpreted as UNLOCK.");
                mClient.UnlockAchievement(achievementID, callback);
            }
            else
            {
                // not enough to unlock
                Logger.d("Progress " + progress + " not enough to unlock non-incremental achievement.");
            }
        }