// called from game thread public bool HasInvitationFromNotification() { bool has = mInvitationFromNotification != null; Logger.d("AndroidClient.HasInvitationFromNotification, returning " + has); return(has); }
// called on game thread public void CreateWithInvitationScreen(int minOpponents, int maxOpponents, int variant, Action <bool, TurnBasedMatch> callback) { Logger.d(string.Format("AndroidTbmpClient.CreateWithInvitationScreen, " + "opponents {0}-{1}, variant {2}", minOpponents, maxOpponents, variant)); mClient.CallClientApi("tbmp launch invitation screen", () => { AndroidJavaClass klass = JavaUtil.GetClass( JavaConsts.SupportSelectOpponentsHelperActivity); klass.CallStatic("launch", false, mClient.GetActivity(), new SelectOpponentsProxy(this, callback, variant), Logger.DebugLogEnabled, minOpponents, maxOpponents); }, (bool success) => { if (!success) { Logger.w("Failed to create tbmp w/ invite screen: client disconnected."); if (callback != null) { callback.Invoke(false, null); } } }); }
// called on game thread public void CreateQuickMatch(int minOpponents, int maxOpponents, int variant, Action <bool, TurnBasedMatch> callback) { Logger.d(string.Format("AndroidTbmpClient.CreateQuickMatch, opponents {0}-{1}, var {2}", minOpponents, maxOpponents, variant)); mClient.CallClientApi("tbmp create quick game", () => { ResultProxy proxy = new ResultProxy(this, "createMatch"); proxy.SetMatchCallback(callback); AndroidJavaClass tbmpUtil = JavaUtil.GetClass(JavaConsts.SupportTbmpUtilsClass); using (AndroidJavaObject pendingResult = tbmpUtil.CallStatic <AndroidJavaObject>( "createQuickMatch", mClient.GHManager.GetApiClient(), minOpponents, maxOpponents, variant)) { pendingResult.Call("setResultCallback", proxy); } }, (bool success) => { if (!success) { Logger.w("Failed to create tbmp quick match: client disconnected."); if (callback != null) { callback.Invoke(false, null); } } }); }
private void OnAuthenticated() { GooglePlayGames.OurUtils.PlayGamesHelperObject.RunOnGameThread( () => { cloudOnceEvents.RaiseOnSignedInChanged(true); Logger.d("Successfully signed in to Google Play Game Services. Player: " + PlayerDisplayName); IsGuestUserDefault = false; GetPlayerImage(); if (playerIdCache != null && !string.Equals(playerIdCache, PlayerID, StringComparison.InvariantCulture)) { // Switching user foreach (var achievement in Achievements.All) { achievement.ResetLocalState(); } if (cloudSaveEnabled) { GooglePlayGamesCloudSaveWrapper.LoadDataString(OnDataStringLoaded); } } else if (autoLoadEnabled && cloudSaveEnabled) { Cloud.Storage.Load(); } playerIdCache = PlayerID; if (Achievements.All.Length > 0) { PlayGamesPlatform.Instance.LoadAchievements(UpdateAchievementsData); } }); }
// called from game thread public void UnlockAchievement(string achId, Action <bool> callback) { // if the local cache says it's unlocked, we don't have to do anything Logger.d("AndroidClient.UnlockAchievement: " + achId); Achievement a = GetAchievement(achId); if (a != null && a.IsUnlocked) { Logger.d("...was already unlocked, so no-op."); if (callback != null) { callback.Invoke(true); } return; } CallClientApi("unlock ach " + achId, () => { mGHManager.CallGmsApi("games.Games", "Achievements", "unlock", achId); }, callback); // update local cache a = GetAchievement(achId); if (a != null) { a.IsUnlocked = a.IsRevealed = true; } }
internal void CallClientApi(string desc, Action call, Action <bool> callback) { Logger.d("Requesting API call: " + desc); RunWhenConnectionStable(() => { // we got a stable connection state to the games service // (either connected or disconnected, but not in progress). if (mGHManager.IsConnected()) { // we are connected, so make the API call Logger.d("Connected! Calling API: " + desc); call.Invoke(); if (callback != null) { PlayGamesHelperObject.RunOnGameThread(() => { callback.Invoke(true); }); } } else { // we are not connected, so fail the API call Logger.w("Not connected! Failed to call API :" + desc); if (callback != null) { PlayGamesHelperObject.RunOnGameThread(() => { callback.Invoke(false); }); } } }); }
// called from game thread public void RevealAchievement(string achId, Action <bool> callback) { Logger.d("AndroidClient.RevealAchievement: " + achId); Achievement a = GetAchievement(achId); if (a != null && a.IsRevealed) { Logger.d("...was already revealed, so no-op."); if (callback != null) { callback.Invoke(true); } return; } CallClientApi("reveal ach " + achId, () => { mGHManager.CallGmsApi("games.Games", "Achievements", "reveal", achId); }, callback); // update local cache a = GetAchievement(achId); if (a != null) { a.IsRevealed = true; } }
// called (on the UI thread) by GameHelperManager to notify us that sign in succeeded internal void OnSignInSucceeded() { Logger.d("AndroidClient got OnSignInSucceeded."); RetrieveUserInfo(); if (mAuthState == AuthState.AuthPending || mAuthState == AuthState.InProgress) { Logger.d("AUTH: Auth succeeded. Proceeding to achievement loading."); DoInitialAchievementLoad(); } else if (mAuthState == AuthState.LoadingAchs) { Logger.w("AUTH: Got OnSignInSucceeded() while in achievement loading phase (unexpected)."); Logger.w("AUTH: Trying to fix by issuing a new achievement load call."); DoInitialAchievementLoad(); } else { // we will hit this case during the normal lifecycle (for example, Activity // was brought to the foreground and sign in has succeeded even though // we were not in an auth flow). Logger.d("Normal lifecycle OnSignInSucceeded received."); RunPendingActions(); // check for invitations that may have arrived via notification CheckForConnectionExtras(); // inform the RTMP client that sign-in has suceeded mRtmpClient.OnSignInSucceeded(); mTbmpClient.OnSignInSucceeded(); } }
// called from game thread public void RegisterInvitationDelegate(InvitationReceivedDelegate deleg) { Logger.d("AndroidClient.RegisterInvitationDelegate"); if (deleg == null) { Logger.w("AndroidClient.RegisterInvitationDelegate called w/ null argument."); return; } mInvitationDelegate = deleg; // install invitation listener, if we don't have one yet if (!mRegisteredInvitationListener) { Logger.d("Registering an invitation listener."); RegisterInvitationListener(); } if (mInvitationFromNotification != null) { Logger.d("Delivering pending invitation from notification now."); Invitation inv = mInvitationFromNotification; mInvitationFromNotification = null; PlayGamesHelperObject.RunOnGameThread(() => { if (mInvitationDelegate != null) { mInvitationDelegate.Invoke(inv, true); } }); } }
/// <summary> /// Used internally when switching user. /// </summary> /// <param name="onDataLoaded">Action to invoke when data has been loaded.</param> public static void LoadDataString(UnityAction <string> onDataLoaded) { #if CLOUDONCE_DEBUG Logger.d("Switching user. Loading default save game."); #endif PlayGamesPlatform.Instance.SavedGame.OpenWithAutomaticConflictResolution( saveGameFileName, DataSource.ReadCacheOrNetwork, ConflictResolutionStrategy.UseLongestPlaytime, (status, metadata) => { if (status == SavedGameRequestStatus.Success) { PlayGamesPlatform.Instance.SavedGame.ReadBinaryData( metadata, (requestStatus, bytes) => { if (requestStatus == SavedGameRequestStatus.Success) { s_timeWhenCloudSaveWasLoaded = Time.realtimeSinceStartup; var dataString = GetDataString(bytes); onDataLoaded.Invoke(dataString); } else { onDataLoaded.Invoke(null); } }); } else { onDataLoaded.Invoke(null); } }); }
public void Finish(string matchId, byte[] data, MatchOutcome outcome, Action <bool> callback) { Logger.d(string.Format("AndroidTbmpClient.Finish matchId={0}, data={1} outcome={2}", matchId, data == null ? "(null)" : data.Length + " bytes", outcome)); Logger.d("Preparing list of participant results as Android ArrayList."); AndroidJavaObject participantResults = new AndroidJavaObject("java.util.ArrayList"); if (outcome != null) { foreach (string pid in outcome.ParticipantIds) { Logger.d("Converting participant result to Android object: " + pid); AndroidJavaObject thisParticipantResult = new AndroidJavaObject( JavaConsts.ParticipantResultClass, pid, JavaUtil.GetAndroidParticipantResult(outcome.GetResultFor(pid)), outcome.GetPlacementFor(pid)); // (yes, the return type of ArrayList.add is bool, strangely) Logger.d("Adding participant result to Android ArrayList."); participantResults.Call <bool>("add", thisParticipantResult); thisParticipantResult.Dispose(); } } TbmpApiCall("tbmp finish w/ outcome", "finishMatch", callback, null, matchId, data, participantResults); }
/// <summary> /// Initializes Google Play Game Services. /// </summary> /// <param name="activateCloudSave">Whether or not Cloud Saving should be activated.</param> /// <param name="autoSignIn"> /// Whether or not <see cref="SignIn"/> will be called automatically once Google Play Game Services is initialized. /// </param> /// <param name="autoCloudLoad"> /// Whether or not cloud data should be loaded automatically if the user is successfully signed in. /// Ignored if Cloud Saving is deactivated or the user fails to sign in. /// </param> public override void Initialize(bool activateCloudSave = true, bool autoSignIn = true, bool autoCloudLoad = true) { if (initializing) { return; } #if CLOUDONCE_DEBUG Debug.Log("Initializing Google Play Game Services."); #endif initializing = true; cloudSaveEnabled = activateCloudSave; #if CLOUDONCE_DEBUG Debug.Log("Saved Games support " + (activateCloudSave ? "enabled." : "disabled.")); #endif var config = new PlayGamesClientConfiguration.Builder(); if (activateCloudSave) { config.EnableSavedGames(); CloudSaveInitialized = true; } PlayGamesPlatform.InitializeInstance(config.Build()); SubscribeOnAuthenticatedEvent(); #if CLOUDONCE_DEBUG // Enable/disable logs on the PlayGamesPlatform PlayGamesPlatform.DebugLogEnabled = true; Debug.Log("PlayGamesPlatform debug logs enabled."); #else PlayGamesPlatform.DebugLogEnabled = false; Debug.Log("PlayGamesPlatform debug logs disabled."); #endif IsGpgsInitialized = true; if (!IsGuestUserDefault && autoSignIn) { var onSignedIn = new UnityAction <bool>(arg0 => { cloudOnceEvents.RaiseOnInitializeComplete(); initializing = false; }); SignIn(autoCloudLoad, onSignedIn); } else { if (IsGuestUserDefault && autoSignIn) { Logger.d("Guest user mode active, ignoring auto sign-in. Please call SignIn directly."); } if (autoCloudLoad) { cloudOnceEvents.RaiseOnCloudLoadComplete(false); } cloudOnceEvents.RaiseOnInitializeComplete(); initializing = false; } }
/// <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); }
private Invitation ConvertInvitation(AndroidJavaObject invObj) { Logger.d("Converting Android invitation to our Invitation object."); string invitationId = invObj.Call <string>("getInvitationId"); int invType = invObj.Call <int>("getInvitationType"); Participant inviter; using (AndroidJavaObject inviterObj = invObj.Call <AndroidJavaObject>("getInviter")) { inviter = JavaUtil.ConvertParticipant(inviterObj); } int variant = invObj.Call <int>("getVariant"); Invitation.InvType type; switch (invType) { case JavaConsts.INVITATION_TYPE_REAL_TIME: type = Invitation.InvType.RealTime; break; case JavaConsts.INVITATION_TYPE_TURN_BASED: type = Invitation.InvType.TurnBased; break; default: Logger.e("Unknown invitation type " + invType); type = Invitation.InvType.Unknown; break; } Invitation result = new Invitation(type, invitationId, inviter, variant); Logger.d("Converted invitation: " + result.ToString()); return(result); }
// called from game thread public Invitation GetInvitationFromNotification() { Logger.d("AndroidClient.GetInvitationFromNotification"); Logger.d("Returning invitation: " + ((mInvitationFromNotification == null) ? "(null)" : mInvitationFromNotification.ToString())); return(mInvitationFromNotification); }
public static void ShowSelectSnapshotUI(bool showCreateSaveUI, bool showDeleteSaveUI, int maxDisplayedSavedGames, string uiTitle, Action <SelectUIStatus, ISavedGameMetadata> cb) { using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) using (var task = helperFragment.CallStatic <AndroidJavaObject>("showSelectSnapshotUi", GetActivity(), uiTitle, showCreateSaveUI, showDeleteSaveUI, maxDisplayedSavedGames)) { AndroidTaskUtils.AddOnSuccessListener <AndroidJavaObject>( task, result => { var status = (SelectUIStatus)result.Get <int>("status"); Logger.d("ShowSelectSnapshotUI result " + status); var javaMetadata = result.Get <AndroidJavaObject>("metadata"); var metadata = javaMetadata == null ? null : new AndroidSnapshotMetadata(javaMetadata, /* contents= */ null); cb.Invoke(status, metadata); }); AndroidTaskUtils.AddOnFailureListener( task, exception => { Logger.e("ShowSelectSnapshotUI failed with exception"); cb.Invoke(SelectUIStatus.InternalError, null); }); } }
public void LeaveDuringTurn(string matchId, string pendingParticipantId, Action <bool> callback) { Logger.d("AndroidTbmpClient.LeaveDuringTurn, matchId=" + matchId + ", pending=" + pendingParticipantId); TbmpApiCall("tbmp leave during turn", "leaveMatchDuringTurn", callback, null, matchId, pendingParticipantId); }
// called on UI thread public void OnSignInSucceeded() { Logger.d("AndroidTbmpClient.OnSignInSucceeded"); Logger.d("Querying for max match data size..."); mMaxMatchDataSize = mClient.GHManager.CallGmsApi <int>("games.Games", "TurnBasedMultiplayer", "getMaxMatchDataSize"); Logger.d("Max match data size: " + mMaxMatchDataSize); }
// call from UI thread only! private void DoInitialAchievementLoad() { Logger.d("AUTH: Now performing initial achievement load..."); mAuthState = AuthState.LoadingAchs; mGHManager.CallGmsApiWithResult("games.Games", "Achievements", "load", new OnAchievementsLoadedResultProxy(this), false); Logger.d("AUTH: Initial achievement load call made."); }
// called from game thread public void SubmitScore(string lbId, long score, Action <bool> callback) { Logger.d("AndroidClient.SubmitScore, lb=" + lbId + ", score=" + score); CallClientApi("submit score " + score + ", lb " + lbId, () => { mGHManager.CallGmsApi("games.Games", "Leaderboards", "submitScore", lbId, score); }, callback); }
/// <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; }
// called from game thread public void LoadState(int slot, OnStateLoadedListener listener) { Logger.d("AndroidClient.LoadState, slot=" + slot); CallClientApi("load state slot=" + slot, () => { OnStateResultProxy proxy = new OnStateResultProxy(this, listener); mGHManager.CallGmsApiWithResult("appstate.AppStateManager", null, "load", proxy, slot); }, null); }
private void RegisterInvitationListener() { Logger.d("AndroidClient.RegisterInvitationListener"); CallClientApi("register invitation listener", () => { mGHManager.CallGmsApi("games.Games", "Invitations", "registerInvitationListener", new OnInvitationReceivedProxy(this)); }, null); mRegisteredInvitationListener = true; }
// called from game thread. This is ONLY called internally (OnStateLoadedProxy // calls this). This is not part of the IPlayGamesClient interface. internal void ResolveState(int slot, string resolvedVersion, byte[] resolvedData, OnStateLoadedListener listener) { Logger.d(string.Format("AndroidClient.ResolveState, slot={0}, ver={1}, " + "data={2}", slot, resolvedVersion, resolvedData)); CallClientApi("resolve state slot=" + slot, () => { mGHManager.CallGmsApiWithResult("appstate.AppStateManager", null, "resolve", new OnStateResultProxy(this, listener), slot, resolvedVersion, resolvedData); }, null); }
/// <summary> /// Shows the standard Google Play Games leaderboards user interface, /// which allows the player to browse their leaderboards. If you have /// configured a specific leaderboard as the default through a call to /// <see cref="SetDefaultLeaderboardForUi" />, the UI will show that /// specific leaderboard only. Otherwise, a list of all the leaderboards /// will be shown. /// </summary> public void ShowLeaderboardUI() { if (!IsAuthenticated()) { Logger.e("ShowLeaderboardUI can only be called after authentication."); return; } Logger.d("ShowLeaderboardUI"); mClient.ShowLeaderboardUI(MapId(mDefaultLbUi)); }
internal void ClearInvitationIfFromNotification(string invitationId) { Logger.d("AndroidClient.ClearInvitationIfFromNotification: " + invitationId); if (mInvitationFromNotification != null && mInvitationFromNotification.InvitationId.Equals(invitationId)) { Logger.d("Clearing invitation from notification: " + invitationId); mInvitationFromNotification = null; } }
public static void Create(Action <INearbyConnectionClient> callback) { if (Application.isEditor) { Logger.d("Creating INearbyConnection in editor, using DummyClient."); callback.Invoke(new DummyNearbyConnectionClient()); } callback.Invoke(new AndroidNearbyConnectionClient()); }
/// <summary> /// Shows the standard Google Play Games achievements user interface, /// which allows the player to browse their achievements. /// </summary> public void ShowAchievementsUI() { if (!IsAuthenticated()) { Logger.e("ShowAchievementsUI can only be called after authentication."); return; } Logger.d("ShowAchievementsUI"); mClient.ShowAchievementsUI(); }
/// <summary> /// Signs in to Google Play Game Services. /// </summary> /// <param name="autoCloudLoad"> /// Whether or not cloud data should be loaded automatically if the user is successfully signed in. /// Ignored if Cloud Saving is deactivated or the user fails to sign in. /// </param> /// <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> public override void SignIn(bool autoCloudLoad = true, UnityAction <bool> callback = null) { if (!IsGpgsInitialized) { Debug.LogWarning("SignIn called, but Google Play Game Services has not been initialized. Ignoring call."); CloudOnceUtils.SafeInvoke(callback, false); return; } if (autoCloudLoad) { SetUpAutoCloudLoad(); } IsGuestUserDefault = false; Logger.d("Attempting to sign in to Google Play Game Services."); PlayGamesPlatform.Instance.Authenticate(success => { // Success is handled by OnAutenticated method if (!success) { Logger.w("Failed to sign in to Google Play Game Services."); bool hasNoInternet; try { hasNoInternet = InternetConnectionUtils.GetConnectionStatus() != InternetConnectionStatus.Connected; } catch (NotSupportedException) { hasNoInternet = Application.internetReachability == NetworkReachability.NotReachable; } if (hasNoInternet) { Logger.d("Failure seems to be due to lack of Internet. Will try to connect again next time."); } else { Logger.d("Must assume the failure is due to player opting out" + " of the sign-in process, setting guest user as default"); IsGuestUserDefault = true; } cloudOnceEvents.RaiseOnSignInFailed(); if (autoCloudLoad) { cloudOnceEvents.RaiseOnCloudLoadComplete(false); } } CloudOnceUtils.SafeInvoke(callback, success); }); }
// called on game thread public void TakeTurn(string matchId, byte[] data, string pendingParticipantId, Action <bool> callback) { Logger.d(string.Format("AndroidTbmpClient.TakeTurn matchId={0}, data={1}, " + "pending={2}", matchId, (data == null ? "(null)" : "[" + data.Length + "bytes]"), pendingParticipantId)); TbmpApiCall("tbmp take turn", "takeTurn", callback, null, matchId, data, pendingParticipantId); }