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); }); } }
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); }
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); } }
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"); } }); }
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; }
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."); }
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); }); } }
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); }