callback);
+
+ ///
+ /// Returns whether or not user is authenticated.
+ ///
+ /// true if the user is authenticated; otherwise, false.
+ bool IsAuthenticated();
+
+ ///
+ /// Requests server-side access to Player Games Services for the currently signed in player.
+ ///
+ /// When requested an authorization code is returned that can be used by your game-server to
+ /// exchange for an access token and conditionally a refresh token (when {@code forceRefreshToken}
+ /// is true). The access token may then be used by your game-server to access the Play Games
+ /// Services web APIs. This is commonly used to complete a sign-in flow by verifying the Play Games
+ /// Services player id.
+ ///
+ /// If {@code forceRefreshToken} is true, when exchanging the authorization code a refresh token
+ /// will be returned in addition to the access token. The refresh token allows the game-server to
+ /// request additional access tokens, allowing your game-server to continue accesses Play Games
+ /// Services while the user is not actively playing your app.
+ ///
+ ///
+ ///
+ /// If {@code true} when the returned authorization code is exchanged a
+ /// refresh token will be included in addition to an access token.
+ ///
+ void RequestServerSideAccess(bool forceRefreshToken, Action callback);
+
+ ///
+ /// Returns the authenticated user's ID. Note that this value may change if a user signs
+ /// on and signs in with a different account.
+ ///
+ /// The user's ID, null
if the user is not logged in.
+ string GetUserId();
+
+ ///
+ /// Loads friends of the authenticated user. This loads the entire list of friends.
+ ///
+ /// Callback invoked when complete. bool argument
+ /// indicates success.
+ void LoadFriends(Action callback);
+
+ ///
+ /// Returns a human readable name for the user, if they are logged in.
+ ///
+ /// The user's human-readable name. null
if they are not logged
+ /// in
+ string GetUserDisplayName();
+
+ ///
+ /// Returns the user's avatar url, if they are logged in and have an avatar.
+ ///
+ /// The URL to load the avatar image. null
if they are not logged
+ /// in
+ string GetUserImageUrl();
+
+ /// Gets the player stats.
+ /// Callback for response.
+ void GetPlayerStats(Action callback);
+
+ ///
+ /// Loads the users specified. This is mainly used by the leaderboard
+ /// APIs to get the information of a high scorer.
+ ///
+ /// User identifiers.
+ /// Callback.
+ void LoadUsers(string[] userIds, Action callback);
+
+ ///
+ /// Loads the achievements for the current signed in user and invokes
+ /// the callback.
+ ///
+ void LoadAchievements(Action callback);
+
+ ///
+ /// Unlocks the achievement with the passed identifier.
+ ///
+ /// If the operation succeeds, the callback
+ /// will be invoked on the game thread with true
. If the operation fails, the
+ /// callback will be invoked with false
. This operation will immediately fail if
+ /// the user is not authenticated (i.e. the callback will immediately be invoked with
+ /// false
). If the achievement is already unlocked, this call will
+ /// succeed immediately.
+ ///
+ /// The ID of the achievement to unlock.
+ /// Callback used to indicate whether the operation
+ /// succeeded or failed.
+ void UnlockAchievement(string achievementId, Action successOrFailureCalllback);
+
+ ///
+ /// Reveals the achievement with the passed identifier.
+ ///
+ /// If the operation succeeds, the callback
+ /// will be invoked on the game thread with true
. If the operation fails, the
+ /// callback will be invoked with false
. This operation will immediately fail if
+ /// the user is not authenticated (i.e. the callback will immediately be invoked with
+ /// false
). If the achievement is already in a revealed state, this call will
+ /// succeed immediately.
+ ///
+ /// The ID of the achievement to reveal.
+ /// Callback used to indicate whether the operation
+ /// succeeded or failed.
+ void RevealAchievement(string achievementId, Action successOrFailureCalllback);
+
+ ///
+ /// Increments the achievement with the passed identifier.
+ ///
+ /// If the operation succeeds, the
+ /// callback will be invoked on the game thread with true
. If the operation
+ /// fails, the callback will be invoked with false
. This operation will
+ /// immediately fail if the user is not authenticated (i.e. the callback will immediately be
+ /// invoked with false
).
+ ///
+ /// The ID of the achievement to increment.
+ /// The number of steps to increment by.
+ /// Callback used to indicate whether the operation
+ /// succeeded or failed.
+ void IncrementAchievement(string achievementId, int steps,
+ Action successOrFailureCalllback);
+
+ ///
+ /// Set an achievement to have at least the given number of steps completed.
+ ///
+ ///
+ /// Calling this method while the achievement already has more steps than
+ /// the provided value is a no-op. Once the achievement reaches the
+ /// maximum number of steps, the achievement is automatically unlocked,
+ /// and any further mutation operations are ignored.
+ ///
+ /// Ach identifier.
+ /// Steps.
+ /// Callback.
+ void SetStepsAtLeast(string achId, int steps, Action callback);
+
+ ///
+ /// Shows the appropriate platform-specific achievements UI.
+ /// The callback to invoke when complete. If null,
+ /// no callback is called.
+ ///
+ void ShowAchievementsUI(Action callback);
+
+ ///
+ /// Shows the appropriate platform-specific friends sharing UI.
+ /// The callback to invoke when complete. If null,
+ /// no callback is called.
+ ///
+ void AskForLoadFriendsResolution(Action callback);
+
+ ///
+ /// Returns the latest LoadFriendsStatus obtained from loading friends.
+ ///
+ LoadFriendsStatus GetLastLoadFriendsStatus();
+
+ ///
+ /// Shows the Play Games Player Profile UI for a specific user identifier.
+ ///
+ /// User Identifier.
+ ///
+ /// The game's own display name of the player referred to by userId.
+ ///
+ ///
+ /// The game's own display name of the current player.
+ ///
+ /// Callback invoked upon completion.
+ void ShowCompareProfileWithAlternativeNameHintsUI(
+ string otherUserId, string otherPlayerInGameName, string currentPlayerInGameName,
+ Action callback);
+
+ ///
+ /// Returns if the user has allowed permission for the game to access the friends list.
+ ///
+ /// If true, this call will clear any locally cached data and
+ /// attempt to fetch the latest data from the server. Normally, this should be set to {@code
+ /// false} to gain advantages of data caching. Callback
+ /// invoked upon completion.
+ void GetFriendsListVisibility(bool forceReload, Action callback);
+
+ ///
+ /// Loads the first page of the user's friends
+ ///
+ ///
+ /// The number of entries to request for this initial page. Note that if cached
+ /// data already exists, the returned buffer may contain more than this size, but it is
+ /// guaranteed to contain at least this many if the collection contains enough records.
+ ///
+ ///
+ /// If true, this call will clear any locally cached data and attempt to
+ /// fetch the latest data from the server. This would commonly be used for something like a
+ /// user-initiated refresh. Normally, this should be set to {@code false} to gain advantages
+ /// of data caching.
+ /// Callback invoked upon completion.
+ void LoadFriends(int pageSize, bool forceReload, Action callback);
+
+ ///
+ /// Loads the friends list page
+ ///
+ ///
+ /// The number of entries to request for this page. Note that if cached data already
+ /// exists, the returned buffer may contain more than this size, but it is guaranteed
+ /// to contain at least this many if the collection contains enough records.
+ ///
+ ///
+ void LoadMoreFriends(int pageSize, Action callback);
+
+ ///
+ /// Shows the leaderboard UI for a specific leaderboard.
+ ///
+ /// If the passed ID is null
, all leaderboards are displayed.
+ ///
+ /// The leaderboard to display. null
to display
+ /// all.
+ /// Timespan to display for the leaderboard
+ /// If non-null, the callback to invoke when the
+ /// leaderboard is dismissed.
+ ///
+ void ShowLeaderboardUI(string leaderboardId, LeaderboardTimeSpan span,
+ Action callback);
+
+ ///
+ /// Loads the score data for the given leaderboard.
+ ///
+ /// Leaderboard identifier.
+ /// Start indicating the top scores or player centric
+ /// max number of scores to return. non-positive indicates
+ /// no rows should be returned. This causes only the summary info to
+ /// be loaded. This can be limited
+ /// by the SDK.
+ /// leaderboard collection: public or social
+ /// leaderboard timespan
+ /// callback with the scores, and a page token.
+ /// The token can be used to load next/prev pages.
+ void LoadScores(string leaderboardId, LeaderboardStart start, int rowCount,
+ LeaderboardCollection collection, LeaderboardTimeSpan timeSpan,
+ Action callback);
+
+ ///
+ /// Loads the more scores for the leaderboard.
+ ///
+ /// The token is accessed
+ /// by calling LoadScores() with a positive row count.
+ ///
+ /// Token for tracking the score loading.
+ /// max number of scores to return.
+ /// This can be limited by the SDK.
+ /// Callback.
+ void LoadMoreScores(ScorePageToken token, int rowCount,
+ Action callback);
+
+ ///
+ /// Returns the max number of scores returned per call.
+ ///
+ /// The max results.
+ int LeaderboardMaxResults();
+
+ ///
+ /// Submits the passed score to the passed leaderboard.
+ ///
+ /// This operation will immediately fail
+ /// if the user is not authenticated (i.e. the callback will immediately be invoked with
+ /// false
).
+ ///
+ /// Leaderboard identifier.
+ /// Score.
+ /// Callback used to indicate whether the operation
+ /// succeeded or failed.
+ void SubmitScore(string leaderboardId, long score, Action successOrFailureCalllback);
+
+ ///
+ /// Submits the score for the currently signed-in player.
+ ///
+ /// Score.
+ /// leaderboard id.
+ /// metadata about the score.
+ /// Callback upon completion.
+ void SubmitScore(string leaderboardId, long score, string metadata,
+ Action successOrFailureCalllback);
+
+ ///
+ /// Gets the saved game client.
+ ///
+ /// The saved game client.
+ SavedGame.ISavedGameClient GetSavedGameClient();
+
+ ///
+ /// Gets the events client.
+ ///
+ /// The events client.
+ Events.IEventsClient GetEventsClient();
+
+ IUserProfile[] GetFriends();
+ }
+}
+#endif
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs.meta
new file mode 100644
index 0000000..21ffabe
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 9138e04e4459148c680055b40ad324c0
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs
new file mode 100644
index 0000000..1c80761
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs
@@ -0,0 +1,129 @@
+//
+// Copyright (C) 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames.BasicApi
+{
+ using System.Collections.Generic;
+ using UnityEngine.SocialPlatforms;
+
+ ///
+ /// Leaderboard score data. This is the callback data
+ /// when loading leaderboard scores. There are several SDK
+ /// API calls needed to be made to collect all the required data,
+ /// so this class is used to simplify the response.
+ ///
+ public class LeaderboardScoreData
+ {
+ private string mId;
+ private ResponseStatus mStatus;
+ private ulong mApproxCount;
+ private string mTitle;
+ private IScore mPlayerScore;
+ private ScorePageToken mPrevPage;
+ private ScorePageToken mNextPage;
+ private List mScores = new List();
+
+ internal LeaderboardScoreData(string leaderboardId)
+ {
+ mId = leaderboardId;
+ }
+
+ internal LeaderboardScoreData(string leaderboardId, ResponseStatus status)
+ {
+ mId = leaderboardId;
+ mStatus = status;
+ }
+
+ public bool Valid
+ {
+ get
+ {
+ return mStatus == ResponseStatus.Success ||
+ mStatus == ResponseStatus.SuccessWithStale;
+ }
+ }
+
+ public ResponseStatus Status
+ {
+ get { return mStatus; }
+
+ internal set { mStatus = value; }
+ }
+
+ public ulong ApproximateCount
+ {
+ get { return mApproxCount; }
+
+ internal set { mApproxCount = value; }
+ }
+
+ public string Title
+ {
+ get { return mTitle; }
+
+ internal set { mTitle = value; }
+ }
+
+ public string Id
+ {
+ get { return mId; }
+
+ internal set { mId = value; }
+ }
+
+ public IScore PlayerScore
+ {
+ get { return mPlayerScore; }
+
+ internal set { mPlayerScore = value; }
+ }
+
+ public IScore[] Scores
+ {
+ get { return mScores.ToArray(); }
+ }
+
+ internal int AddScore(PlayGamesScore score)
+ {
+ mScores.Add(score);
+ return mScores.Count;
+ }
+
+ public ScorePageToken PrevPageToken
+ {
+ get { return mPrevPage; }
+
+ internal set { mPrevPage = value; }
+ }
+
+ public ScorePageToken NextPageToken
+ {
+ get { return mNextPage; }
+
+ internal set { mNextPage = value; }
+ }
+
+ public override string ToString()
+ {
+ return string.Format("[LeaderboardScoreData: mId={0}, " +
+ " mStatus={1}, mApproxCount={2}, mTitle={3}]",
+ mId, mStatus, mApproxCount, mTitle);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs.meta
new file mode 100644
index 0000000..1fb80aa
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 8e369c64e8c9f4571a8847f37848c37e
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby.meta
new file mode 100644
index 0000000..0286871
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: c980790a380df4850b17a208e544d062
+folderAsset: yes
+timeCreated: 1435699549
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs
new file mode 100644
index 0000000..1220501
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.Nearby
+{
+ using System;
+ using System.Collections.Generic;
+ using GooglePlayGames.OurUtils;
+
+ public struct AdvertisingResult
+ {
+ private readonly ResponseStatus mStatus;
+ private readonly string mLocalEndpointName;
+
+ public AdvertisingResult(ResponseStatus status, string localEndpointName)
+ {
+ this.mStatus = status;
+ this.mLocalEndpointName = Misc.CheckNotNull(localEndpointName);
+ }
+
+ public bool Succeeded
+ {
+ get { return mStatus == ResponseStatus.Success; }
+ }
+
+ public ResponseStatus Status
+ {
+ get { return mStatus; }
+ }
+
+ public string LocalEndpointName
+ {
+ get { return mLocalEndpointName; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs.meta
new file mode 100644
index 0000000..4d1472e
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 941324a6338664af6a9faf5b88cad408
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs
new file mode 100644
index 0000000..e7183af
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.Nearby
+{
+ using GooglePlayGames.OurUtils;
+
+ public struct ConnectionRequest
+ {
+ private readonly EndpointDetails mRemoteEndpoint;
+ private readonly byte[] mPayload;
+
+ public ConnectionRequest(string remoteEndpointId,
+ string remoteEndpointName, string serviceId, byte[] payload)
+ {
+ Logger.d("Constructing ConnectionRequest");
+ mRemoteEndpoint = new EndpointDetails(remoteEndpointId, remoteEndpointName, serviceId);
+ this.mPayload = Misc.CheckNotNull(payload);
+ }
+
+ public EndpointDetails RemoteEndpoint
+ {
+ get { return mRemoteEndpoint; }
+ }
+
+ public byte[] Payload
+ {
+ get { return mPayload; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs.meta
new file mode 100644
index 0000000..04b0414
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: c7f9bb6b249224f99ad05a87d3e4ee34
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs
new file mode 100644
index 0000000..4a915ad
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs
@@ -0,0 +1,108 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.Nearby
+{
+ using GooglePlayGames.OurUtils;
+
+ public struct ConnectionResponse
+ {
+ private static readonly byte[] EmptyPayload = new byte[0];
+
+ public enum Status
+ {
+ Accepted,
+ Rejected,
+ ErrorInternal,
+ ErrorNetworkNotConnected,
+ ErrorEndpointNotConnected,
+ ErrorAlreadyConnected
+ }
+
+ private readonly long mLocalClientId;
+ private readonly string mRemoteEndpointId;
+ private readonly Status mResponseStatus;
+ private readonly byte[] mPayload;
+
+ private ConnectionResponse(long localClientId, string remoteEndpointId, Status code,
+ byte[] payload)
+ {
+ this.mLocalClientId = localClientId;
+ this.mRemoteEndpointId = Misc.CheckNotNull(remoteEndpointId);
+ this.mResponseStatus = code;
+ this.mPayload = Misc.CheckNotNull(payload);
+ }
+
+ public long LocalClientId
+ {
+ get { return mLocalClientId; }
+ }
+
+ public string RemoteEndpointId
+ {
+ get { return mRemoteEndpointId; }
+ }
+
+ public Status ResponseStatus
+ {
+ get { return mResponseStatus; }
+ }
+
+ public byte[] Payload
+ {
+ get { return mPayload; }
+ }
+
+ public static ConnectionResponse Rejected(long localClientId, string remoteEndpointId)
+ {
+ return new ConnectionResponse(localClientId, remoteEndpointId, Status.Rejected,
+ EmptyPayload);
+ }
+
+ public static ConnectionResponse NetworkNotConnected(long localClientId, string remoteEndpointId)
+ {
+ return new ConnectionResponse(localClientId, remoteEndpointId, Status.ErrorNetworkNotConnected,
+ EmptyPayload);
+ }
+
+ public static ConnectionResponse InternalError(long localClientId, string remoteEndpointId)
+ {
+ return new ConnectionResponse(localClientId, remoteEndpointId, Status.ErrorInternal,
+ EmptyPayload);
+ }
+
+ public static ConnectionResponse EndpointNotConnected(long localClientId, string remoteEndpointId)
+ {
+ return new ConnectionResponse(localClientId, remoteEndpointId, Status.ErrorEndpointNotConnected,
+ EmptyPayload);
+ }
+
+ public static ConnectionResponse Accepted(long localClientId, string remoteEndpointId,
+ byte[] payload)
+ {
+ return new ConnectionResponse(localClientId, remoteEndpointId, Status.Accepted,
+ payload);
+ }
+
+ public static ConnectionResponse AlreadyConnected(long localClientId,
+ string remoteEndpointId)
+ {
+ return new ConnectionResponse(localClientId, remoteEndpointId,
+ Status.ErrorAlreadyConnected,
+ EmptyPayload);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs.meta
new file mode 100644
index 0000000..1f22253
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: ad6611af8d0204d0d8922a327d3d9ec0
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs
new file mode 100644
index 0000000..af90358
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs
@@ -0,0 +1,121 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames.BasicApi.Nearby
+{
+ using UnityEngine;
+
+ public class DummyNearbyConnectionClient : INearbyConnectionClient
+ {
+ public int MaxUnreliableMessagePayloadLength()
+ {
+ return NearbyConnectionConfiguration.MaxUnreliableMessagePayloadLength;
+ }
+
+ public int MaxReliableMessagePayloadLength()
+ {
+ return NearbyConnectionConfiguration.MaxReliableMessagePayloadLength;
+ }
+
+ public void SendReliable(System.Collections.Generic.List recipientEndpointIds, byte[] payload)
+ {
+ OurUtils.Logger.d("SendReliable called from dummy implementation");
+ }
+
+ public void SendUnreliable(System.Collections.Generic.List recipientEndpointIds, byte[] payload)
+ {
+ OurUtils.Logger.d("SendUnreliable called from dummy implementation");
+ }
+
+ public void StartAdvertising(string name, System.Collections.Generic.List appIdentifiers,
+ System.TimeSpan? advertisingDuration, System.Action resultCallback,
+ System.Action connectionRequestCallback)
+ {
+ AdvertisingResult obj = new AdvertisingResult(ResponseStatus.LicenseCheckFailed, string.Empty);
+ resultCallback.Invoke(obj);
+ }
+
+ public void StopAdvertising()
+ {
+ OurUtils.Logger.d("StopAvertising in dummy implementation called");
+ }
+
+ public void SendConnectionRequest(string name, string remoteEndpointId, byte[] payload,
+ System.Action responseCallback, IMessageListener listener)
+ {
+ OurUtils.Logger.d("SendConnectionRequest called from dummy implementation");
+
+ if (responseCallback != null)
+ {
+ ConnectionResponse obj = ConnectionResponse.Rejected(0, string.Empty);
+ responseCallback.Invoke(obj);
+ }
+ }
+
+ public void AcceptConnectionRequest(string remoteEndpointId, byte[] payload, IMessageListener listener)
+ {
+ OurUtils.Logger.d("AcceptConnectionRequest in dummy implementation called");
+ }
+
+ public void StartDiscovery(string serviceId, System.TimeSpan? advertisingTimeout, IDiscoveryListener listener)
+ {
+ OurUtils.Logger.d("StartDiscovery in dummy implementation called");
+ }
+
+ public void StopDiscovery(string serviceId)
+ {
+ OurUtils.Logger.d("StopDiscovery in dummy implementation called");
+ }
+
+ public void RejectConnectionRequest(string requestingEndpointId)
+ {
+ OurUtils.Logger.d("RejectConnectionRequest in dummy implementation called");
+ }
+
+ public void DisconnectFromEndpoint(string remoteEndpointId)
+ {
+ OurUtils.Logger.d("DisconnectFromEndpoint in dummy implementation called");
+ }
+
+ public void StopAllConnections()
+ {
+ OurUtils.Logger.d("StopAllConnections in dummy implementation called");
+ }
+
+ public string LocalEndpointId()
+ {
+ return string.Empty;
+ }
+
+ public string LocalDeviceId()
+ {
+ return "DummyDevice";
+ }
+
+ public string GetAppBundleId()
+ {
+ return "dummy.bundle.id";
+ }
+
+ public string GetServiceId()
+ {
+ return "dummy.service.id";
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs.meta
new file mode 100644
index 0000000..cfee748
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 9b3f34a2bba13428789d02b53fd89a47
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs
new file mode 100644
index 0000000..84d5c5d
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.Nearby
+{
+ using GooglePlayGames.OurUtils;
+
+ public struct EndpointDetails
+ {
+ private readonly string mEndpointId;
+ private readonly string mName;
+ private readonly string mServiceId;
+
+ public EndpointDetails(string endpointId, string name, string serviceId)
+ {
+ this.mEndpointId = Misc.CheckNotNull(endpointId);
+ this.mName = Misc.CheckNotNull(name);
+ this.mServiceId = Misc.CheckNotNull(serviceId);
+ }
+
+ public string EndpointId
+ {
+ get { return mEndpointId; }
+ }
+
+ public string Name
+ {
+ get { return mName; }
+ }
+
+ public string ServiceId
+ {
+ get { return mServiceId; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs.meta
new file mode 100644
index 0000000..6dd55d9
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 9d9a087b0e20d4752b24f33a4a2bf977
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs
new file mode 100644
index 0000000..c25e519
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.Nearby
+{
+ using System;
+ using System.Collections.Generic;
+
+ // move this inside IMessageListener and IDiscoveryListener are always declared.
+#if UNITY_ANDROID
+
+ public interface INearbyConnectionClient
+ {
+ int MaxUnreliableMessagePayloadLength();
+
+ int MaxReliableMessagePayloadLength();
+
+ void SendReliable(List recipientEndpointIds, byte[] payload);
+
+ void SendUnreliable(List recipientEndpointIds, byte[] payload);
+
+ void StartAdvertising(string name, List appIdentifiers,
+ TimeSpan? advertisingDuration, Action resultCallback,
+ Action connectionRequestCallback);
+
+ void StopAdvertising();
+
+ void SendConnectionRequest(string name, string remoteEndpointId, byte[] payload,
+ Action responseCallback, IMessageListener listener);
+
+ void AcceptConnectionRequest(string remoteEndpointId, byte[] payload,
+ IMessageListener listener);
+
+ void StartDiscovery(string serviceId, TimeSpan? advertisingTimeout,
+ IDiscoveryListener listener);
+
+ void StopDiscovery(string serviceId);
+
+ void RejectConnectionRequest(string requestingEndpointId);
+
+ void DisconnectFromEndpoint(string remoteEndpointId);
+
+ void StopAllConnections();
+
+ string GetAppBundleId();
+
+ string GetServiceId();
+ }
+#endif
+
+ public interface IMessageListener
+ {
+ void OnMessageReceived(string remoteEndpointId, byte[] data,
+ bool isReliableMessage);
+
+ void OnRemoteEndpointDisconnected(string remoteEndpointId);
+ }
+
+ public interface IDiscoveryListener
+ {
+ void OnEndpointFound(EndpointDetails discoveredEndpoint);
+
+ void OnEndpointLost(string lostEndpointId);
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs.meta
new file mode 100644
index 0000000..e54bb65
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: cb64b5b444dd34de5bd308c7eed6e509
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs
new file mode 100644
index 0000000..e789630
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.Nearby
+{
+ using System;
+ using GooglePlayGames.OurUtils;
+
+ public enum InitializationStatus
+ {
+ Success,
+ VersionUpdateRequired,
+ InternalError
+ }
+
+ public struct NearbyConnectionConfiguration
+ {
+ public const int MaxUnreliableMessagePayloadLength = 1168;
+ public const int MaxReliableMessagePayloadLength = 4096;
+
+ private readonly Action mInitializationCallback;
+ private readonly long mLocalClientId;
+
+ public NearbyConnectionConfiguration(Action callback,
+ long localClientId)
+ {
+ this.mInitializationCallback = Misc.CheckNotNull(callback);
+ this.mLocalClientId = localClientId;
+ }
+
+ public long LocalClientId
+ {
+ get { return mLocalClientId; }
+ }
+
+ public Action InitializationCallback
+ {
+ get { return mInitializationCallback; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs.meta
new file mode 100644
index 0000000..2c54d2d
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 968ac90e4a9094a4a92df9da1ee1f884
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs
new file mode 100644
index 0000000..094645f
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#if UNITY_ANDROID
+namespace GooglePlayGames.BasicApi
+{
+ ///
+ /// Represents a player. A player is different from a participant! The participant is
+ /// an entity that takes part in a particular match; a Player is a real-world person
+ /// (tied to a Games account). The player exists across matches, the Participant
+ /// only exists in the context of a particular match.
+ ///
+ public class Player : PlayGamesUserProfile
+ {
+ internal Player(string displayName, string playerId, string avatarUrl)
+ : base(displayName, playerId, avatarUrl)
+ {
+ }
+ }
+}
+#endif
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs.meta
new file mode 100644
index 0000000..d338234
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: a6dfb529ed3bfc58ea80e1e100af33fd
+labels:
+- gvh
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs
new file mode 100644
index 0000000..fae6b68
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames.BasicApi
+{
+ ///
+ /// Represents a player, a real-world person (tied to a Games account).
+ ///
+ public class PlayerProfile : PlayGamesUserProfile
+ {
+ internal PlayerProfile(string displayName, string playerId, string avatarUrl, bool isFriend) : base(displayName,
+ playerId, avatarUrl, isFriend)
+ {
+ }
+ }
+}
+#endif
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs.meta
new file mode 100644
index 0000000..800ecfa
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs.meta
@@ -0,0 +1,13 @@
+fileFormatVersion: 2
+guid: 12cfec295ecf76a6fb0d0d48f59d374c
+labels:
+- gvh
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs
new file mode 100644
index 0000000..a7e8c5f
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs
@@ -0,0 +1,268 @@
+//
+// Copyright (C) 2015 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames.BasicApi
+{
+ using System;
+
+ ///
+ /// Player stats. See https://developers.google.com/games/services/android/stats
+ ///
+ public class PlayerStats
+ {
+ private static float UNSET_VALUE = -1.0f;
+
+ public PlayerStats(
+ int numberOfPurchases,
+ float avgSessionLength,
+ int daysSinceLastPlayed,
+ int numberOfSessions,
+ float sessPercentile,
+ float spendPercentile,
+ float spendProbability,
+ float churnProbability,
+ float highSpenderProbability,
+ float totalSpendNext28Days)
+ {
+ mValid = true;
+ mNumberOfPurchases = numberOfPurchases;
+ mAvgSessionLength = avgSessionLength;
+ mDaysSinceLastPlayed = daysSinceLastPlayed;
+ mNumberOfSessions = numberOfSessions;
+ mSessPercentile = sessPercentile;
+ mSpendPercentile = spendPercentile;
+ mSpendProbability = spendProbability;
+ mChurnProbability = churnProbability;
+ mHighSpenderProbability = highSpenderProbability;
+ mTotalSpendNext28Days = totalSpendNext28Days;
+ }
+
+ public PlayerStats()
+ {
+ mValid = false;
+ }
+
+ private bool mValid;
+ private int mNumberOfPurchases;
+ private float mAvgSessionLength;
+ private int mDaysSinceLastPlayed;
+ private int mNumberOfSessions;
+ private float mSessPercentile;
+ private float mSpendPercentile;
+ private float mSpendProbability;
+ private float mChurnProbability;
+ private float mHighSpenderProbability;
+ private float mTotalSpendNext28Days;
+
+ ///
+ /// If this PlayerStats object is valid (i.e. successfully retrieved from games services).
+ ///
+ ///
+ /// Note that a PlayerStats with all stats unset may still be valid.
+ ///
+ public bool Valid
+ {
+ get { return mValid; }
+ }
+
+ ///
+ /// The number of in-app purchases.
+ ///
+ public int NumberOfPurchases
+ {
+ get { return mNumberOfPurchases; }
+ }
+
+ ///
+ /// The length of the avg session in minutes.
+ ///
+ public float AvgSessionLength
+ {
+ get { return mAvgSessionLength; }
+ }
+
+ ///
+ /// The days since last played.
+ ///
+ public int DaysSinceLastPlayed
+ {
+ get { return mDaysSinceLastPlayed; }
+ }
+
+ ///
+ /// The number of sessions based on sign-ins.
+ ///
+ public int NumberOfSessions
+ {
+ get { return mNumberOfSessions; }
+ }
+
+ ///
+ /// The approximation of sessions percentile for the player.
+ ///
+ ///
+ /// This value is given as a decimal value between 0 and 1 (inclusive).
+ /// It indicates how many sessions the current player has
+ /// played in comparison to the rest of this game's player base.
+ /// Higher numbers indicate that this player has played more sessions.
+ /// A return value less than zero indicates this value is not available.
+ ///
+ public float SessPercentile
+ {
+ get { return mSessPercentile; }
+ }
+
+ ///
+ /// The approximate spend percentile of the player.
+ ///
+ ///
+ /// This value is given as a decimal value between 0 and 1 (inclusive).
+ /// It indicates how much the current player has spent in
+ /// comparison to the rest of this game's player base. Higher
+ /// numbers indicate that this player has spent more.
+ /// A return value less than zero indicates this value is not available.
+ ///
+ public float SpendPercentile
+ {
+ get { return mSpendPercentile; }
+ }
+
+ ///
+ /// The approximate probability of the player choosing to spend in this game.
+ ///
+ ///
+ /// This value is given as a decimal value between 0 and 1 (inclusive).
+ /// Higher values indicate that a player is more likely to spend.
+ /// A return value less than zero indicates this value is not available.
+ ///
+ public float SpendProbability
+ {
+ get { return mSpendProbability; }
+ }
+
+ ///
+ /// The approximate probability of the player not returning to play the game.
+ ///
+ ///
+ /// Higher values indicate that a player is less likely to return.
+ /// A return value less than zero indicates this value is not available.
+ ///
+ public float ChurnProbability
+ {
+ get { return mChurnProbability; }
+ }
+
+ ///
+ /// The high spender probability of this player.
+ ///
+ public float HighSpenderProbability
+ {
+ get { return mHighSpenderProbability; }
+ }
+
+ ///
+ /// The predicted total spend of this player over the next 28 days.
+ ///
+ public float TotalSpendNext28Days
+ {
+ get { return mTotalSpendNext28Days; }
+ }
+
+ ///
+ /// Determines whether this instance has NumberOfPurchases.
+ ///
+ /// true if this instance has NumberOfPurchases; otherwise, false.
+ public bool HasNumberOfPurchases()
+ {
+ return NumberOfPurchases != (int) UNSET_VALUE;
+ }
+
+ ///
+ /// Determines whether this instance has AvgSessionLength.
+ ///
+ /// true if this instance has AvgSessionLength; otherwise, false.
+ public bool HasAvgSessionLength()
+ {
+ return AvgSessionLength != UNSET_VALUE;
+ }
+
+ ///
+ /// Determines whether this instance has DaysSinceLastPlayed.
+ ///
+ /// true if this instance has DaysSinceLastPlayed; otherwise, false.
+ public bool HasDaysSinceLastPlayed()
+ {
+ return DaysSinceLastPlayed != (int) UNSET_VALUE;
+ }
+
+ ///
+ /// Determines whether this instance has NumberOfSessions.
+ ///
+ /// true if this instance has NumberOfSessions; otherwise, false.
+ public bool HasNumberOfSessions()
+ {
+ return NumberOfSessions != (int) UNSET_VALUE;
+ }
+
+ ///
+ /// Determines whether this instance has SessPercentile.
+ ///
+ /// true if this instance has SessPercentile; otherwise, false.
+ public bool HasSessPercentile()
+ {
+ return SessPercentile != UNSET_VALUE;
+ }
+
+ ///
+ /// Determines whether this instance has SpendPercentile.
+ ///
+ /// true if this instance has SpendPercentile; otherwise, false.
+ public bool HasSpendPercentile()
+ {
+ return SpendPercentile != UNSET_VALUE;
+ }
+
+ ///
+ /// Determines whether this instance has ChurnProbability.
+ ///
+ /// true if this instance has ChurnProbability; otherwise, false.
+ public bool HasChurnProbability()
+ {
+ return ChurnProbability != UNSET_VALUE;
+ }
+
+ ///
+ /// Determines whether this instance has HighSpenderProbability.
+ ///
+ /// true if this instance has HighSpenderProbability; otherwise, false.
+ public bool HasHighSpenderProbability()
+ {
+ return HighSpenderProbability != UNSET_VALUE;
+ }
+
+ ///
+ /// Determines whether this instance has TotalSpendNext28Days.
+ ///
+ /// true if this instance has TotalSpendNext28Days; otherwise, false.
+ public bool HasTotalSpendNext28Days()
+ {
+ return TotalSpendNext28Days != UNSET_VALUE;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs.meta
new file mode 100644
index 0000000..f39fae4
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 0cf73f44d6d524deab1717d6e71e2c6d
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame.meta
new file mode 100644
index 0000000..599cdc6
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 1bc47bd5631b849f88f2785c2d44019b
+folderAsset: yes
+timeCreated: 1435699548
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs
new file mode 100644
index 0000000..f7391a6
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs
@@ -0,0 +1,373 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.SavedGame
+{
+ using System;
+ using System.Collections.Generic;
+
+ ///
+ /// An enum for the different strategies that can be used to resolve saved game conflicts (i.e.
+ /// conflicts produced by two or more separate writes to the same saved game at once).
+ ///
+ public enum ConflictResolutionStrategy
+ {
+ ///
+ /// Choose which saved game should be used on the basis of which one has the longest recorded
+ /// play time. In other words, in the case of a conflicting write, the saved game with the
+ /// longest play time will be considered cannonical. If play time has not been provided by the
+ /// developer, or in the case of two saved games with equal play times,
+ /// will be used instead.
+ ///
+ UseLongestPlaytime,
+
+ ///
+ /// Choose the version of the saved game that existed before any conflicting write occurred.
+ /// Consider the following case:
+ /// - An initial version of a save game ("X") is written from a device ("Dev_A")
+ /// - The save game X is downloaded by another device ("Dev_B").
+ /// - Dev_A writes a new version of the save game to the cloud ("Y")
+ /// - Dev_B does not see the new save game Y, and attempts to write a new save game ("Z").
+ /// - Since Dev_B is performing a write using out of date information, a conflict is generated.
+ ///
+ /// In this situation, we can resolve the conflict by declaring either keeping Y as the
+ /// canonical version of the saved game (i.e. choose "original" aka ),
+ /// or by overwriting it with conflicting value, Z (i.e. choose "unmerged" aka
+ /// ).
+ ///
+ ///
+ UseOriginal,
+
+ ///
+ /// See the documentation for
+ ///
+ UseUnmerged,
+
+ ///
+ /// Manual resolution, no automatic resolution is attempted.
+ ///
+ UseManual,
+
+ ///
+ /// The use last known good snapshot to resolve conflicts automatically.
+ ///
+ UseLastKnownGood,
+
+ ///
+ /// The use most recently saved snapshot to resolve conflicts automatically.
+ ///
+ UseMostRecentlySaved
+ }
+
+ public enum SavedGameRequestStatus
+ {
+ Success = 1,
+
+ ///
+ /// The request failed due to a timeout.
+ ///
+ ///
+ TimeoutError = -1,
+
+ ///
+ /// An unexpected internal error. Check the log for error messages.
+ ///
+ ///
+ InternalError = -2,
+
+ ///
+ /// A error related to authentication. This is probably due to the user being signed out
+ /// before the request could be issued.
+ ///
+ ///
+ AuthenticationError = -3,
+
+ ///
+ /// The request failed because it was given bad input (e.g. a filename with 200 characters).
+ ///
+ ///
+ BadInputError = -4
+ }
+
+ public enum SelectUIStatus
+ {
+ ///
+ /// The user selected a saved game.
+ ///
+ SavedGameSelected = 1,
+
+ ///
+ /// The user closed the UI without selecting a saved game.
+ ///
+ ///
+ UserClosedUI = 2,
+
+ ///
+ /// An unexpected internal error. Check the log for error messages.
+ ///
+ ///
+ InternalError = -1,
+
+ ///
+ /// There was a timeout while displaying the UI.
+ ///
+ ///
+ TimeoutError = -2,
+
+ ///
+ /// A error related to authentication. This is probably due to the user being signed out
+ /// before the request could be issued.
+ ///
+ ///
+ AuthenticationError = -3,
+
+ ///
+ /// The request failed because it was given bad input (e.g. a filename with 200 characters).
+ ///
+ ///
+ BadInputError = -4,
+
+ UiBusy = -5
+ }
+
+ ///
+ ///
+ /// A delegate that is invoked when we encounter a conflict during execution of
+ /// . The caller must resolve the
+ /// conflict using the passed . All passed metadata is open.
+ /// If was invoked with
+ /// prefetchDataOnConflict set to true, the and
+ /// will be equal to the binary data of the "original" and
+ /// "unmerged" saved game respectively (and null otherwise). Since conflict files may be generated
+ /// by other clients, it is possible that neither of the passed saved games were originally written
+ /// by the current device. Consequently, any conflict resolution strategy should not rely on local
+ /// data that is not part of the binary data of the passed saved games - this data will not be
+ /// present if conflict resolution occurs on a different device. In addition, since a given saved
+ /// game may have multiple conflicts, this callback must be designed to handle multiple invocations.
+ ///
+ public delegate void ConflictCallback(IConflictResolver resolver, ISavedGameMetadata original,
+ byte[] originalData, ISavedGameMetadata unmerged, byte[] unmergedData);
+
+ ///
+ /// The main entry point for interacting with saved games. Saved games are persisted in the cloud
+ /// along with several game-specific properties ( for more
+ /// information). There are several core concepts involved with saved games:
+ ///
+ /// Filenames - act as unique identifiers for saved games. Two devices
+ /// performing a read or write using the same filename will end up reading or modifying the same
+ /// file (i.e. filenames are not device specific).
+ ///
+ ///
+ /// Saved Game Metadata are represented by .
+ /// The instances allow access to metadata properties about the underlying saved game (e.g.
+ /// description). In addition, metadata functions as a handle that are required to read and
+ /// manipulate saved game contents. Lastly, metadata may be "Open". Open metadata instances are
+ /// required to manipulate the underlying binary data of the saved game. See method comments to
+ /// determine whether a specific method requires or returns an open saved game.
+ ///
+ ///
+ /// Conflicts occur when multiple devices attempt to write to the same file
+ /// at the same time. The saved game system guarantees that no conflicting writes will be lost or
+ /// silently overwritten. Instead, they must be handled the next time the file with a conflict is
+ /// Opened. Conflicts can be handled automatically (
+ /// ) or can be manuallyhandled by the developer
+ /// (). See the Open methods for more discussion.
+ ///
+ ///
+ /// Saved games will generally be used in the following workflow:
+ ///
+ /// - Determine which saved game to use (either using a hardcoded filename or
+ /// ShowSelectSavedGameUI)
+ /// - Open the file using OpenWithManualConflictResolution or
+ /// OpenWithAutomaticConflictResolution
+ /// - Read the binary data of the saved game using ReadBinaryData handle it
+ /// as appropriate for your game.
+ /// - When you have updates, persist them in the cloud using CommitUpdate. Note
+ /// that writing to the cloud is relatively expensive, and shouldn't be done frequently.
+ ///
+ ///
+ ///
+ /// See online
+ /// documentation for Saved Games for more information.
+ ///
+ public interface ISavedGameClient
+ {
+ ///
+ /// Opens the file with the indicated name and data source. If the file has an outstanding
+ /// conflict, it will be resolved using the specified conflict resolution strategy. The
+ /// metadata returned by this method will be "Open" - it can be used as a parameter for
+ /// and .
+ ///
+ /// The name of the file to open. Filenames must consist of
+ /// only non-URL reserved characters (i.e. a-z, A-Z, 0-9, or the symbols "-", ".", "_", or "~")
+ /// be between 1 and 100 characters in length (inclusive).
+ /// The data source to use. for a description
+ /// of the available options here.
+ /// The conflict resolution that should be used if any
+ /// conflicts are encountered while opening the file.
+ /// for a description of these strategies.
+ /// The callback that is invoked when this operation finishes. The
+ /// returned metadata will only be non-null if the open succeeded. This callback will always
+ /// execute on the game thread and the returned metadata (if any) will be "Open".
+ void OpenWithAutomaticConflictResolution(string filename, DataSource source,
+ ConflictResolutionStrategy resolutionStrategy,
+ Action callback);
+
+ ///
+ /// Opens the file with the indicated name and data source. If there is a conflict that
+ /// requires resolution, it will be resolved manually using the passed conflict callback. Once
+ /// all pending conflicts are resolved, the completed callback will be invoked with the
+ /// retrieved data. In the event of an error, the completed callback will be invoked with the
+ /// corresponding error status. All callbacks will be executed on the game thread.
+ ///
+ /// The name of the file to open. Filenames must consist of
+ /// only non-URL reserved characters (i.e. a-z, A-Z, 0-9, or the symbols "-", ".", "_", or "~")
+ /// be between 1 and 100 characters in length (inclusive).
+ /// The data source to use. for a description
+ /// of the available options here.
+ /// If set to true, the data for the two
+ /// conflicting files will be automatically retrieved and passed as parameters in
+ /// . If set to false, null binary data
+ /// will be passed into and the caller will have to fetch
+ /// it themselves.
+ /// The callback that will be invoked if one or more conflict is
+ /// encountered while executing this method. Note that more than one conflict may be present
+ /// and that this callback might be executed more than once to resolve multiple conflicts.
+ /// This callback is always executed on the game thread.
+ /// The callback that is invoked when this operation finishes.
+ /// The returned metadata will only be non-null if the open succeeded. If an error is
+ /// encountered during conflict resolution, that error will be reflected here. This callback
+ /// will always execute on the game thread and the returned metadata (if any) will be "Open".
+ ///
+ void OpenWithManualConflictResolution(string filename, DataSource source,
+ bool prefetchDataOnConflict, ConflictCallback conflictCallback,
+ Action completedCallback);
+
+ ///
+ /// Reads the binary data of the passed saved game. The passed metadata must be opened (i.e.
+ /// returns true). The callback will always be executed
+ /// on the game thread.
+ ///
+ /// The metadata for the saved game whose binary data we want to read.
+ /// This metadata must be open. If it is not open, the method will immediately fail with status
+ /// .
+ ///
+ /// The callback that is invoked when the read finishes. If the
+ /// read completed without error, the passed status will be and the passed
+ /// bytes will correspond to the binary data for the file. In the case of
+ ///
+ void ReadBinaryData(ISavedGameMetadata metadata,
+ Action completedCallback);
+
+ ///
+ /// Shows the select saved game UI with the indicated configuration. If the user selects a
+ /// saved game in that UI, it will be returned in the passed callback. This metadata will be
+ /// unopened and must be passed to either or
+ /// in order to retrieve the binary data.
+ /// The callback will always be executed on the game thread.
+ ///
+ /// The user-visible title of the displayed selection UI.
+ /// The maximum number of saved games the UI may display.
+ /// This value must be greater than 0.
+ /// If set to true, show UI that will allow the user to
+ /// create a new saved game.
+ /// If set to true show UI that will allow the user to
+ /// delete a saved game.
+ /// The callback that is invoked when an error occurs or if the user
+ /// finishes interacting with the UI. If the user selected a saved game, this will be passed
+ /// into the callback along with the status. This saved game
+ /// will not be Open, and must be opened before it can be written to or its binary data can be
+ /// read. If the user backs out of the UI without selecting a saved game, this callback will
+ /// receive and a null saved game. This callback will always execute
+ /// on the game thread.
+ void ShowSelectSavedGameUI(string uiTitle, uint maxDisplayedSavedGames, bool showCreateSaveUI,
+ bool showDeleteSaveUI, Action callback);
+
+ ///
+ /// Durably commits an update to the passed saved game. When this method returns successfully,
+ /// the data is durably persisted to disk and will eventually be uploaded to the cloud (in
+ /// practice, this will happen very quickly unless the device does not have a network
+ /// connection). If an update to the saved game has occurred after the metadata was retrieved
+ /// from the cloud, this update will produce a conflict (this commonly occurs if two different
+ /// devices are writing to the cloud at the same time). All conflicts must be handled the next
+ /// time this saved game is opened. See and
+ /// for more information.
+ ///
+ /// The metadata for the saved game to update. This metadata must be
+ /// Open (i.e. returns true)."/> If it is not open, the
+ /// method will immediately fail with status
+ /// All updates that should be applied to the saved game
+ /// metadata.
+ /// The new binary content of the saved game
+ /// The callback that is invoked when this operation finishes.
+ /// The returned metadata will only be non-null if the commit succeeded. If an error is
+ /// encountered during conflict resolution, that error will be reflected here. This callback
+ /// will always execute on the game thread and the returned metadata (if any) will NOT be
+ /// "Open" (i.e. commiting an update closes the metadata).
+ void CommitUpdate(ISavedGameMetadata metadata, SavedGameMetadataUpdate updateForMetadata,
+ byte[] updatedBinaryData, Action callback);
+
+ ///
+ /// Returns the metadata for all known saved games for this game. All returned saved games are
+ /// not open, and must be opened before they can be used for writes or binary data reads. The
+ /// callback will always occur on the game thread.
+ ///
+ /// The data source to use. for a description
+ /// of the available options here.
+ /// The callback that is invoked when this operation finishes.
+ /// The returned metadata will only be non-empty if the commit succeeded. If an error is
+ /// encountered during the fetch, that error will be reflected here. This callback
+ /// will always execute on the game thread and the returned metadata (if any) will NOT be
+ /// "Open".
+ void FetchAllSavedGames(DataSource source,
+ Action> callback);
+
+ ///
+ /// Delete the specified snapshot.
+ /// This will delete the data of the snapshot locally and on the server.
+ ///
+ /// the saved game metadata identifying the data to
+ /// delete.
+ void Delete(ISavedGameMetadata metadata);
+ }
+
+ ///
+ /// An interface that allows developers to resolve metadata conflicts that may be encountered while
+ /// opening saved games.
+ ///
+ public interface IConflictResolver
+ {
+ ///
+ /// Resolves the conflict by choosing the passed metadata to be canonical. The passed metadata
+ /// must be one of the two instances passed as parameters into -
+ /// this instance will be kept as the cannonical value in the cloud.
+ ///
+ /// The chosen metadata. This metadata must be open. If it is not
+ /// open, the invokation of that produced this
+ /// ConflictResolver will immediately fail with .
+ void ChooseMetadata(ISavedGameMetadata chosenMetadata);
+
+ ///
+ /// Resolves the conflict and updates the data.
+ ///
+ /// Metadata for the chosen version. This is either the
+ /// original or unmerged metadata provided when the callback is invoked.
+ /// Metadata update, same as when committing changes.
+ /// Updated data to use when resolving the conflict.
+ void ResolveConflict(ISavedGameMetadata chosenMetadata, SavedGameMetadataUpdate metadataUpdate,
+ byte[] updatedData);
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs.meta
new file mode 100644
index 0000000..9d9606b
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 5d4ff89980bdd4c9780aa3ceee54a51b
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs
new file mode 100644
index 0000000..7b80eac
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs
@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.SavedGame
+{
+ using System;
+
+ ///
+ /// Interface representing the metadata for a saved game. These instances are also used as handles
+ /// for reading and writing the content of the underlying file.
+ ///
+ public interface ISavedGameMetadata
+ {
+ ///
+ /// Returns true if this metadata can be used for operations related to raw file data (i.e.
+ /// the binary data contained in the underlying file). Metadata returned by Open operations
+ /// will be "Open". After an update to the file is committed or the metadata is used to resolve
+ /// a conflict, the corresponding Metadata is closed, and IsOpen will return false.
+ ///
+ ///
+ /// true if this instance is open; otherwise, false.
+ bool IsOpen { get; }
+
+ ///
+ /// Returns the filename for this saved game. A saved game filename will only consist of
+ /// non-URL reserved characters (i.e. a-z, A-Z, 0-9, or the symbols "-", ".", "_", or "~")
+ /// and will between 1 and 100 characters in length (inclusive).
+ ///
+ /// The filename.
+ string Filename { get; }
+
+ ///
+ /// Returns a human-readable description of what the saved game contains. This may be null.
+ ///
+ /// The description.
+ string Description { get; }
+
+ ///
+ /// A URL corresponding to the PNG-encoded image corresponding to this saved game. null if
+ /// the saved game does not have a cover image.
+ ///
+ /// The cover image URL.
+ string CoverImageURL { get; }
+
+ ///
+ /// Returns the total time played by the player for this saved game. This value is
+ /// developer-specified and may be tracked in any way that is appropriate to the game. Note
+ /// that this value is specific to this specific saved game (unless the developer intentionally
+ /// sets the same value on all saved games). If the value was not set, this will be equal to
+ /// TimeSpan.FromMilliseconds(0)
+ ///
+ /// The total time played.
+ TimeSpan TotalTimePlayed { get; }
+
+ ///
+ /// A timestamp corresponding to the last modification to the underlying saved game. If the
+ /// saved game is newly created, this value will correspond to the time the first Open
+ /// occurred. Otherwise, this corresponds to time the last successful write occurred (either by
+ /// CommitUpdate or Resolve methods).
+ ///
+ /// The last modified timestamp.
+ DateTime LastModifiedTimestamp { get; }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs.meta
new file mode 100644
index 0000000..1c141d2
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: a94650f478358403ea166d374b2a950c
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs
new file mode 100644
index 0000000..7d84a84
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs
@@ -0,0 +1,115 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.BasicApi.SavedGame
+{
+ using System;
+ using GooglePlayGames.OurUtils;
+
+ ///
+ /// A struct representing the mutation of saved game metadata. Fields can either have a new value
+ /// or be untouched (in which case the corresponding field in the saved game metadata will be
+ /// untouched). Instances must be built using
+ /// and once created, these instances are immutable and threadsafe.
+ ///
+ public struct SavedGameMetadataUpdate
+ {
+ private readonly bool mDescriptionUpdated;
+ private readonly string mNewDescription;
+ private readonly bool mCoverImageUpdated;
+ private readonly byte[] mNewPngCoverImage;
+ private readonly TimeSpan? mNewPlayedTime;
+
+ private SavedGameMetadataUpdate(Builder builder)
+ {
+ mDescriptionUpdated = builder.mDescriptionUpdated;
+ mNewDescription = builder.mNewDescription;
+ mCoverImageUpdated = builder.mCoverImageUpdated;
+ mNewPngCoverImage = builder.mNewPngCoverImage;
+ mNewPlayedTime = builder.mNewPlayedTime;
+ }
+
+ public bool IsDescriptionUpdated
+ {
+ get { return mDescriptionUpdated; }
+ }
+
+ public string UpdatedDescription
+ {
+ get { return mNewDescription; }
+ }
+
+ public bool IsCoverImageUpdated
+ {
+ get { return mCoverImageUpdated; }
+ }
+
+ public byte[] UpdatedPngCoverImage
+ {
+ get { return mNewPngCoverImage; }
+ }
+
+ public bool IsPlayedTimeUpdated
+ {
+ get { return mNewPlayedTime.HasValue; }
+ }
+
+ public TimeSpan? UpdatedPlayedTime
+ {
+ get { return mNewPlayedTime; }
+ }
+
+ public struct Builder
+ {
+ internal bool mDescriptionUpdated;
+ internal string mNewDescription;
+ internal bool mCoverImageUpdated;
+ internal byte[] mNewPngCoverImage;
+ internal TimeSpan? mNewPlayedTime;
+
+ public Builder WithUpdatedDescription(string description)
+ {
+ mNewDescription = Misc.CheckNotNull(description);
+ mDescriptionUpdated = true;
+ return this;
+ }
+
+ public Builder WithUpdatedPngCoverImage(byte[] newPngCoverImage)
+ {
+ mCoverImageUpdated = true;
+ mNewPngCoverImage = newPngCoverImage;
+ return this;
+ }
+
+ public Builder WithUpdatedPlayedTime(TimeSpan newPlayedTime)
+ {
+ if (newPlayedTime.TotalMilliseconds > ulong.MaxValue)
+ {
+ throw new InvalidOperationException("Timespans longer than ulong.MaxValue " +
+ "milliseconds are not allowed");
+ }
+
+ mNewPlayedTime = newPlayedTime;
+ return this;
+ }
+
+ public SavedGameMetadataUpdate Build()
+ {
+ return new SavedGameMetadataUpdate(this);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs.meta
new file mode 100644
index 0000000..631b9b5
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 602d9e1c90f0144e79536115f3614478
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs
new file mode 100644
index 0000000..b4ab076
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames.BasicApi
+{
+ public enum ScorePageDirection
+ {
+ Forward = 1,
+ Backward = 2,
+ }
+
+ ///
+ /// Score page token. This holds the internal token used
+ /// to page through the score pages. The id, collection, and
+ /// timespan are added as a convience, and not actually part of the
+ /// page token returned from the SDK.
+ ///
+ public class ScorePageToken
+ {
+ private string mId;
+ private object mInternalObject;
+ private LeaderboardCollection mCollection;
+ private LeaderboardTimeSpan mTimespan;
+ private ScorePageDirection mDirection;
+
+ internal ScorePageToken(object internalObject, string id,
+ LeaderboardCollection collection, LeaderboardTimeSpan timespan,
+ ScorePageDirection direction)
+ {
+ mInternalObject = internalObject;
+ mId = id;
+ mCollection = collection;
+ mTimespan = timespan;
+ mDirection = direction;
+ }
+
+ public LeaderboardCollection Collection
+ {
+ get { return mCollection; }
+ }
+
+ public LeaderboardTimeSpan TimeSpan
+ {
+ get { return mTimespan; }
+ }
+
+ public ScorePageDirection Direction
+ {
+ get { return mDirection; }
+ }
+
+ public string LeaderboardId
+ {
+ get { return mId; }
+ }
+
+ internal object InternalObject
+ {
+ get { return mInternalObject; }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs.meta
new file mode 100644
index 0000000..9f270dd
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 3eade9d49f3e341ddb2ba8209e7ddf42
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs
new file mode 100644
index 0000000..d6d48e2
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs
@@ -0,0 +1,26 @@
+namespace GooglePlayGames.BasicApi
+{
+ public enum SignInInteractivity
+ {
+ /// no UIs will be shown (if UIs are needed, it will fail rather than show them).
+ NoPrompt,
+
+ ///
+ /// This may show UIs, consent dialogs, etc.
+ /// At the end of the process, callback will be invoked to notify of the result.
+ /// Once the callback returns true, the user is considered to be authenticated.
+ ///
+ CanPromptAlways,
+
+ /// When this is selected, PlayGamesPlatform.Authenticate does the followings in order:
+ /// 1. Attempt to silent sign in.
+ /// 2. If silent sign in fails, check if user has previously declined to sign in and don’t prompt interactive
+ /// sign in if they have.
+ /// 3. Check the internet connection and fail with NO_INTERNET_CONNECTION if there is no internet connection.
+ /// 4. Prompt interactive sign in.
+ /// 5. If the interactive sign in is not successful (user declines or cancels), then
+ /// remember this for step 2 the next time the user opens the game and don’t ask for sign-in.
+ ///
+ CanPromptOnce
+ }
+}
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs.meta
new file mode 100644
index 0000000..c0a5467
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: f5c7733064f2b09dc8df0009b3bbb1d6
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs
new file mode 100644
index 0000000..159f49b
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs
@@ -0,0 +1,14 @@
+namespace GooglePlayGames.BasicApi
+{
+ public enum SignInStatus
+ {
+ /// The operation was successful.
+ Success,
+
+ /// An internal error occurred.
+ InternalError,
+
+ /// The sign in was canceled.
+ Canceled,
+ }
+}
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs.meta
new file mode 100644
index 0000000..ab20fbf
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 0992bc2597d741e59dc3f8c963a3ca25
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs
new file mode 100644
index 0000000..f9e238f
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#if UNITY_ANDROID
+
+namespace GooglePlayGames {
+ ///
+ /// This file is automatically generated DO NOT EDIT!
+ ///
+ /// These are the constants defined in the Play Games Console for Game Services
+ /// Resources.
+ ///
+ ///
+ /// File containing information about the game. This is automatically updated by running the
+ /// platform-appropriate setup commands in the Unity editor (which does a simple search / replace
+ /// on the IDs in the form "__ID__"). We can check whether any particular field has been updated
+ /// by checking whether it still retains its initial value - we prevent the constants from being
+ /// replaced in the aforementioned search/replace by stripping off the leading and trailing "__".
+ ///
+ public static class GameInfo {
+
+ private const string UnescapedApplicationId = "APP_ID";
+ private const string UnescapedIosClientId = "IOS_CLIENTID";
+ private const string UnescapedWebClientId = "WEB_CLIENTID";
+ private const string UnescapedNearbyServiceId = "NEARBY_SERVICE_ID";
+
+ public const string ApplicationId = "1045293753265"; // Filled in automatically
+ public const string IosClientId = "__IOS_CLIENTID__"; // Filled in automatically
+ public const string WebClientId = "1045293753265-ejh4ifdimiqfqhj2msj2c3h7oib9r7aq.apps.googleusercontent.com"; // Filled in automatically
+ public const string NearbyConnectionServiceId = "";
+
+ public static bool ApplicationIdInitialized() {
+ return !string.IsNullOrEmpty(ApplicationId) && !ApplicationId.Equals(ToEscapedToken(UnescapedApplicationId));
+ }
+
+ public static bool IosClientIdInitialized() {
+ return !string.IsNullOrEmpty(IosClientId) && !IosClientId.Equals(ToEscapedToken(UnescapedIosClientId));
+ }
+
+ public static bool WebClientIdInitialized() {
+ return !string.IsNullOrEmpty(WebClientId) && !WebClientId.Equals(ToEscapedToken(UnescapedWebClientId));
+ }
+
+ public static bool NearbyConnectionsInitialized() {
+ return !string.IsNullOrEmpty(NearbyConnectionServiceId) &&
+ !NearbyConnectionServiceId.Equals(ToEscapedToken(UnescapedNearbyServiceId));
+ }
+
+ ///
+ /// Returns an escaped token (i.e. one flanked with "__") for the passed token
+ ///
+ /// The escaped token.
+ /// The Token
+ private static string ToEscapedToken(string token) {
+ return string.Format("__{0}__", token);
+ }
+ }
+}
+#endif
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs.meta
new file mode 100644
index 0000000..c814181
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: a722d413080904cc1bd07f4db21e1af1
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform.meta
new file mode 100644
index 0000000..b7673b5
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform.meta
@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: ef66268ee929544fb82bbef6ac13bafe
+folderAsset: yes
+DefaultImporter:
+ userData:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs
new file mode 100644
index 0000000..278535d
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs
@@ -0,0 +1,286 @@
+//
+// Copyright (C) 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames
+{
+ using System;
+ using GooglePlayGames.BasicApi;
+ using UnityEngine;
+#if UNITY_2017_1_OR_NEWER
+ using UnityEngine.Networking;
+#endif
+ using UnityEngine.SocialPlatforms;
+
+ internal delegate void ReportProgress(string id, double progress, Action callback);
+
+ ///
+ /// Represents a Google Play Games achievement. It can be used to report an achievement
+ /// to the API, offering identical functionality as .
+ ///
+ internal class PlayGamesAchievement : IAchievement, IAchievementDescription
+ {
+ private readonly ReportProgress mProgressCallback;
+ private string mId = string.Empty;
+ private bool mIsIncremental = false;
+ private int mCurrentSteps = 0;
+ private int mTotalSteps = 0;
+ private double mPercentComplete = 0.0;
+ private bool mCompleted = false;
+ private bool mHidden = false;
+ private DateTime mLastModifiedTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
+ private string mTitle = string.Empty;
+ private string mRevealedImageUrl = string.Empty;
+ private string mUnlockedImageUrl = string.Empty;
+#if UNITY_2017_1_OR_NEWER
+ private UnityWebRequest mImageFetcher = null;
+#else
+ private WWW mImageFetcher = null;
+#endif
+ private Texture2D mImage = null;
+ private string mDescription = string.Empty;
+ private ulong mPoints = 0;
+
+ internal PlayGamesAchievement()
+ : this(PlayGamesPlatform.Instance.ReportProgress)
+ {
+ }
+
+ internal PlayGamesAchievement(ReportProgress progressCallback)
+ {
+ mProgressCallback = progressCallback;
+ }
+
+ internal PlayGamesAchievement(Achievement ach) : this()
+ {
+ this.mId = ach.Id;
+ this.mIsIncremental = ach.IsIncremental;
+ this.mCurrentSteps = ach.CurrentSteps;
+ this.mTotalSteps = ach.TotalSteps;
+ if (ach.IsIncremental)
+ {
+ if (ach.TotalSteps > 0)
+ {
+ this.mPercentComplete =
+ ((double) ach.CurrentSteps / (double) ach.TotalSteps) * 100.0;
+ }
+ else
+ {
+ this.mPercentComplete = 0.0;
+ }
+ }
+ else
+ {
+ this.mPercentComplete = ach.IsUnlocked ? 100.0 : 0.0;
+ }
+
+ this.mCompleted = ach.IsUnlocked;
+ this.mHidden = !ach.IsRevealed;
+ this.mLastModifiedTime = ach.LastModifiedTime;
+ this.mTitle = ach.Name;
+ this.mDescription = ach.Description;
+ this.mPoints = ach.Points;
+ this.mRevealedImageUrl = ach.RevealedImageUrl;
+ this.mUnlockedImageUrl = ach.UnlockedImageUrl;
+ }
+
+ ///
+ /// Reveals, unlocks or increment achievement.
+ ///
+ ///
+ /// Call after setting , ,
+ /// as well as and
+ /// for incremental achievements. Equivalent to calling
+ /// .
+ ///
+ public void ReportProgress(Action callback)
+ {
+ mProgressCallback.Invoke(mId, mPercentComplete, callback);
+ }
+
+ ///
+ /// Loads the local user's image from the url. Loading urls
+ /// is asynchronous so the return from this call is fast,
+ /// the image is returned once it is loaded. null is returned
+ /// up to that point.
+ ///
+ private Texture2D LoadImage()
+ {
+ if (hidden)
+ {
+ // return null, we dont have images for hidden achievements.
+ return null;
+ }
+
+ string url = completed ? mUnlockedImageUrl : mRevealedImageUrl;
+
+ // the url can be null if the image is not configured.
+ if (!string.IsNullOrEmpty(url))
+ {
+ if (mImageFetcher == null || mImageFetcher.url != url)
+ {
+#if UNITY_2017_1_OR_NEWER
+ mImageFetcher = UnityWebRequestTexture.GetTexture(url);
+#else
+ mImageFetcher = new WWW(url);
+#endif
+ mImage = null;
+ }
+
+ // if we have the texture, just return, this avoids excessive
+ // memory usage calling www.texture repeatedly.
+ if (mImage != null)
+ {
+ return mImage;
+ }
+
+ if (mImageFetcher.isDone)
+ {
+#if UNITY_2017_1_OR_NEWER
+ mImage = DownloadHandlerTexture.GetContent(mImageFetcher);
+#else
+ mImage = mImageFetcher.texture;
+#endif
+ return mImage;
+ }
+ }
+
+ // if there is no url, always return null.
+ return null;
+ }
+
+
+ ///
+ /// Gets or sets the id of this achievement.
+ ///
+ ///
+ /// The identifier.
+ ///
+ public string id
+ {
+ get { return mId; }
+
+ set { mId = value; }
+ }
+
+ ///
+ /// Gets a value indicating whether this achievement is incremental.
+ ///
+ ///
+ /// This value is only set by PlayGamesPlatform.LoadAchievements
+ ///
+ /// true if incremental; otherwise, false.
+ public bool isIncremental
+ {
+ get { return mIsIncremental; }
+ }
+
+ ///
+ /// Gets the current steps completed of this achievement.
+ ///
+ ///
+ /// Undefined for standard (i.e. non-incremental) achievements.
+ /// This value is only set by PlayGamesPlatform.LoadAchievements, changing the
+ /// percentComplete will not affect this.
+ ///
+ /// The current steps.
+ public int currentSteps
+ {
+ get { return mCurrentSteps; }
+ }
+
+ ///
+ /// Gets the total steps of this achievement.
+ ///
+ ///
+ /// Undefined for standard (i.e. non-incremental) achievements.
+ /// This value is only set by PlayGamesPlatform.LoadAchievements, changing the
+ /// percentComplete will not affect this.
+ ///
+ /// The total steps.
+ public int totalSteps
+ {
+ get { return mTotalSteps; }
+ }
+
+ ///
+ /// Gets or sets the percent completed.
+ ///
+ ///
+ /// The percent completed.
+ ///
+ public double percentCompleted
+ {
+ get { return mPercentComplete; }
+
+ set { mPercentComplete = value; }
+ }
+
+ ///
+ /// Gets a value indicating whether this achievement is completed.
+ ///
+ ///
+ /// This value is only set by PlayGamesPlatform.LoadAchievements, changing the
+ /// percentComplete will not affect this.
+ ///
+ /// true if completed; otherwise, false.
+ public bool completed
+ {
+ get { return this.mCompleted; }
+ }
+
+ ///
+ /// Gets a value indicating whether this achievement is hidden.
+ ///
+ /// true if hidden; otherwise, false.
+ public bool hidden
+ {
+ get { return this.mHidden; }
+ }
+
+ public DateTime lastReportedDate
+ {
+ get { return mLastModifiedTime; }
+ }
+
+ public String title
+ {
+ get { return mTitle; }
+ }
+
+ public Texture2D image
+ {
+ get { return LoadImage(); }
+ }
+
+ public string achievedDescription
+ {
+ get { return mDescription; }
+ }
+
+ public string unachievedDescription
+ {
+ get { return mDescription; }
+ }
+
+ public int points
+ {
+ get { return (int) mPoints; }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs.meta
new file mode 100644
index 0000000..f9ae214
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: e5354c32a5dc64372ba5102f7f787adf
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs
new file mode 100644
index 0000000..7659217
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs
@@ -0,0 +1,180 @@
+//
+// Copyright (C) 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames
+{
+ using System.Collections.Generic;
+ using GooglePlayGames.BasicApi;
+ using UnityEngine;
+ using UnityEngine.SocialPlatforms;
+
+ public class PlayGamesLeaderboard : ILeaderboard
+ {
+ private string mId;
+ private UserScope mUserScope;
+ private Range mRange;
+ private TimeScope mTimeScope;
+ private string[] mFilteredUserIds;
+ private bool mLoading;
+
+ private IScore mLocalUserScore;
+ private uint mMaxRange;
+ private List mScoreList = new List();
+ private string mTitle;
+
+ public PlayGamesLeaderboard(string id)
+ {
+ mId = id;
+ }
+
+ #region ILeaderboard implementation
+
+ public void SetUserFilter(string[] userIDs)
+ {
+ mFilteredUserIds = userIDs;
+ }
+
+ public void LoadScores(System.Action callback)
+ {
+ PlayGamesPlatform.Instance.LoadScores(this, callback);
+ }
+
+ public bool loading
+ {
+ get { return mLoading; }
+ internal set { mLoading = value; }
+ }
+
+ public string id
+ {
+ get { return mId; }
+ set { mId = value; }
+ }
+
+ public UserScope userScope
+ {
+ get { return mUserScope; }
+ set { mUserScope = value; }
+ }
+
+ public Range range
+ {
+ get { return mRange; }
+ set { mRange = value; }
+ }
+
+ public TimeScope timeScope
+ {
+ get { return mTimeScope; }
+ set { mTimeScope = value; }
+ }
+
+ public IScore localUserScore
+ {
+ get { return mLocalUserScore; }
+ }
+
+ public uint maxRange
+ {
+ get { return mMaxRange; }
+ }
+
+ public IScore[] scores
+ {
+ get
+ {
+ PlayGamesScore[] arr = new PlayGamesScore[mScoreList.Count];
+ mScoreList.CopyTo(arr);
+ return arr;
+ }
+ }
+
+ public string title
+ {
+ get { return mTitle; }
+ }
+
+ #endregion
+
+ internal bool SetFromData(LeaderboardScoreData data)
+ {
+ if (data.Valid)
+ {
+ OurUtils.Logger.d("Setting leaderboard from: " + data);
+ SetMaxRange(data.ApproximateCount);
+ SetTitle(data.Title);
+ SetLocalUserScore((PlayGamesScore) data.PlayerScore);
+ foreach (IScore score in data.Scores)
+ {
+ AddScore((PlayGamesScore) score);
+ }
+
+ mLoading = data.Scores.Length == 0 || HasAllScores();
+ }
+
+ return data.Valid;
+ }
+
+ internal void SetMaxRange(ulong val)
+ {
+ mMaxRange = (uint) val;
+ }
+
+ internal void SetTitle(string value)
+ {
+ mTitle = value;
+ }
+
+ internal void SetLocalUserScore(PlayGamesScore score)
+ {
+ mLocalUserScore = score;
+ }
+
+ internal int AddScore(PlayGamesScore score)
+ {
+ if (mFilteredUserIds == null || mFilteredUserIds.Length == 0)
+ {
+ mScoreList.Add(score);
+ }
+ else
+ {
+ foreach (string fid in mFilteredUserIds)
+ {
+ if (fid.Equals(score.userID))
+ {
+ mScoreList.Add(score);
+ break;
+ }
+ }
+ }
+
+ return mScoreList.Count;
+ }
+
+ public int ScoreCount
+ {
+ get { return mScoreList.Count; }
+ }
+
+ internal bool HasAllScores()
+ {
+ return mScoreList.Count >= mRange.count || mScoreList.Count >= maxRange;
+ }
+ }
+}
+#endif
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs.meta
new file mode 100644
index 0000000..4d18c03
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: a027e4767bd0f41509b9ef6bd2f6080e
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs
new file mode 100644
index 0000000..1a76760
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs
@@ -0,0 +1,207 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames
+{
+ using System;
+ using GooglePlayGames.BasicApi;
+ using UnityEngine.SocialPlatforms;
+
+ ///
+ /// Represents the Google Play Games local user.
+ ///
+ public class PlayGamesLocalUser : PlayGamesUserProfile, ILocalUser
+ {
+ internal PlayGamesPlatform mPlatform;
+
+ private PlayerStats mStats;
+
+ internal PlayGamesLocalUser(PlayGamesPlatform plaf)
+ : base("localUser", string.Empty, string.Empty)
+ {
+ mPlatform = plaf;
+ mStats = null;
+ }
+
+ ///
+ /// Authenticates the local user. Equivalent to calling
+ /// .
+ ///
+ public void Authenticate(Action callback)
+ {
+ mPlatform.Authenticate(status => callback(status == SignInStatus.Success));
+ }
+
+ ///
+ /// Authenticates the local user. Equivalent to calling
+ /// .
+ ///
+ public void Authenticate(Action callback)
+ {
+ mPlatform.Authenticate(status => callback(status == SignInStatus.Success, status.ToString()));
+ }
+
+ ///
+ /// Loads all friends of the authenticated user.
+ ///
+ public void LoadFriends(Action callback)
+ {
+ mPlatform.LoadFriends(this, callback);
+ }
+
+ ///
+ /// Synchronous version of friends, returns null until loaded.
+ ///
+ public IUserProfile[] friends
+ {
+ get { return mPlatform.GetFriends(); }
+ }
+
+ ///
+ /// Returns whether or not the local user is authenticated to Google Play Games.
+ ///
+ ///
+ /// true if authenticated; otherwise, false.
+ ///
+ public bool authenticated
+ {
+ get { return mPlatform.IsAuthenticated(); }
+ }
+
+ ///
+ /// Not implemented. As safety placeholder, returns true.
+ ///
+ public bool underage
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Gets the display name of the user.
+ ///
+ ///
+ /// The display name of the user.
+ ///
+ public new string userName
+ {
+ get
+ {
+ string retval = string.Empty;
+ if (authenticated)
+ {
+ retval = mPlatform.GetUserDisplayName();
+ if (!base.userName.Equals(retval))
+ {
+ ResetIdentity(retval, mPlatform.GetUserId(), mPlatform.GetUserImageUrl());
+ }
+ }
+
+ return retval;
+ }
+ }
+
+ ///
+ /// Gets the user's Google id.
+ ///
+ /// This id is persistent and uniquely identifies the user
+ /// across all games that use Google Play Game Services. It is
+ /// the preferred method of uniquely identifying a player instead
+ /// of email address.
+ ///
+ ///
+ /// The user's Google id.
+ ///
+ public new string id
+ {
+ get
+ {
+ string retval = string.Empty;
+ if (authenticated)
+ {
+ retval = mPlatform.GetUserId();
+ if (!base.id.Equals(retval))
+ {
+ ResetIdentity(mPlatform.GetUserDisplayName(), retval, mPlatform.GetUserImageUrl());
+ }
+ }
+
+ return retval;
+ }
+ }
+
+
+ ///
+ /// Returns true (since this is the local user).
+ ///
+ public new bool isFriend
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Gets the local user's state. This is always UserState.Online for
+ /// the local user.
+ ///
+ public new UserState state
+ {
+ get { return UserState.Online; }
+ }
+
+
+ public new string AvatarURL
+ {
+ get
+ {
+ string retval = string.Empty;
+ if (authenticated)
+ {
+ retval = mPlatform.GetUserImageUrl();
+ if (!base.id.Equals(retval))
+ {
+ ResetIdentity(mPlatform.GetUserDisplayName(),
+ mPlatform.GetUserId(), retval);
+ }
+ }
+
+ return retval;
+ }
+ }
+
+ ///
+ /// Gets the player's stats.
+ ///
+ /// Callback when they are available.
+ public void GetStats(Action callback)
+ {
+ if (mStats == null || !mStats.Valid)
+ {
+ mPlatform.GetPlayerStats((rc, stats) =>
+ {
+ mStats = stats;
+ callback(rc, stats);
+ });
+ }
+ else
+ {
+ // 0 = success
+ callback(CommonStatusCodes.Success, mStats);
+ }
+ }
+ }
+}
+#endif
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs.meta
new file mode 100644
index 0000000..26e6de2
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 3b5f03fe051cb4a41a3b5489bd63c24c
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs
new file mode 100644
index 0000000..3e519f1
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs
@@ -0,0 +1,1358 @@
+//
+// Copyright (C) 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames
+{
+ using System;
+ using System.Collections.Generic;
+ using GooglePlayGames.BasicApi;
+ using GooglePlayGames.BasicApi.Events;
+ using GooglePlayGames.BasicApi.Nearby;
+ using GooglePlayGames.BasicApi.SavedGame;
+ using GooglePlayGames.OurUtils;
+ using UnityEngine;
+ using UnityEngine.SocialPlatforms;
+
+ ///
+ /// Provides access to the Google Play Games platform. This is an implementation of
+ /// UnityEngine.SocialPlatforms.ISocialPlatform. Activate this platform by calling
+ /// the method, then authenticate by calling
+ /// the method. After authentication
+ /// completes, you may call the other methods of this class. This is not a complete
+ /// implementation of the ISocialPlatform interface. Methods lacking an implementation
+ /// or whose behavior is at variance with the standard are noted as such.
+ ///
+ public class PlayGamesPlatform : ISocialPlatform
+ {
+ /// Singleton instance
+ private static volatile PlayGamesPlatform sInstance = null;
+
+ /// status of nearby connection initialization.
+ private static volatile bool sNearbyInitializePending;
+
+ /// Reference to the nearby client.
+ /// This is static since it can be used without using play game services.
+ private static volatile INearbyConnectionClient sNearbyConnectionClient;
+
+ /// The local user.
+ private PlayGamesLocalUser mLocalUser = null;
+
+ /// Reference to the platform specific implementation.
+ private IPlayGamesClient mClient = null;
+
+ /// the default leaderboard we show on ShowLeaderboardUI
+ private string mDefaultLbUi = null;
+
+ /// the mapping table from alias to leaderboard/achievement id.
+ private Dictionary mIdMap = new Dictionary();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Implementation client to use for this instance.
+ internal PlayGamesPlatform(IPlayGamesClient client)
+ {
+ this.mClient = Misc.CheckNotNull(client);
+ this.mLocalUser = new PlayGamesLocalUser(this);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ private PlayGamesPlatform()
+ {
+ GooglePlayGames.OurUtils.Logger.d("Creating new PlayGamesPlatform");
+ this.mLocalUser = new PlayGamesLocalUser(this);
+ }
+
+ ///
+ /// Gets or sets a value indicating whether debug logs are enabled. This property
+ /// may be set before calling method.
+ ///
+ ///
+ /// true if debug log enabled; otherwise, false.
+ ///
+ public static bool DebugLogEnabled
+ {
+ get { return GooglePlayGames.OurUtils.Logger.DebugLogEnabled; }
+
+ set { GooglePlayGames.OurUtils.Logger.DebugLogEnabled = value; }
+ }
+
+ ///
+ /// Gets the singleton instance of the Play Games platform.
+ ///
+ ///
+ /// The instance.
+ ///
+ public static PlayGamesPlatform Instance
+ {
+ get
+ {
+ if (sInstance == null)
+ {
+ OurUtils.Logger.d("Initializing the PlayGamesPlatform instance.");
+ sInstance =
+ new PlayGamesPlatform(PlayGamesClientFactory.GetPlatformPlayGamesClient());
+ }
+
+ return sInstance;
+ }
+ }
+
+ ///
+ /// Gets the nearby connection client. NOTE: Can be null until the nearby client
+ /// is initialized. Call InitializeNearby to use callback to be notified when initialization
+ /// is complete.
+ ///
+ /// The nearby.
+ public static INearbyConnectionClient Nearby
+ {
+ get
+ {
+ if (sNearbyConnectionClient == null && !sNearbyInitializePending)
+ {
+ sNearbyInitializePending = true;
+ InitializeNearby(null);
+ }
+
+ return sNearbyConnectionClient;
+ }
+ }
+
+ /// Gets the saved game client object.
+ /// The saved game client.
+ public ISavedGameClient SavedGame
+ {
+ get { return mClient.GetSavedGameClient(); }
+ }
+
+ /// Gets the events client object.
+ /// The events client.
+ public IEventsClient Events
+ {
+ get { return mClient.GetEventsClient(); }
+ }
+
+ ///
+ /// Gets the local user.
+ ///
+ ///
+ /// The local user.
+ ///
+ public ILocalUser localUser
+ {
+ get { return mLocalUser; }
+ }
+
+ ///
+ /// Initializes the nearby connection platform.
+ ///
+ /// This call initializes the nearby connection platform. This
+ /// is independent of the Play Game Services initialization. Multiple
+ /// calls to this method are ignored.
+ ///
+ /// Callback invoked when complete.
+ public static void InitializeNearby(Action callback)
+ {
+ OurUtils.Logger.d("Calling InitializeNearby!");
+ if (sNearbyConnectionClient == null)
+ {
+#if UNITY_ANDROID && !UNITY_EDITOR
+ NearbyConnectionClientFactory.Create(client => {
+ OurUtils.Logger.d("Nearby Client Created!!");
+ sNearbyConnectionClient = client;
+ if (callback != null) {
+ callback.Invoke(client);
+ }
+ else {
+ OurUtils.Logger.d("Initialize Nearby callback is null");
+ }
+ });
+#else
+ sNearbyConnectionClient = new DummyNearbyConnectionClient();
+ if (callback != null)
+ {
+ callback.Invoke(sNearbyConnectionClient);
+ }
+
+#endif
+ }
+ else if (callback != null)
+ {
+ OurUtils.Logger.d("Nearby Already initialized: calling callback directly");
+ callback.Invoke(sNearbyConnectionClient);
+ }
+ else
+ {
+ OurUtils.Logger.d("Nearby Already initialized");
+ }
+ }
+
+ ///
+ /// Activates the Play Games platform as the implementation of Social.Active.
+ /// After calling this method, you can call methods on Social.Active. For
+ /// example, Social.Active.Authenticate().
+ ///
+ /// The singleton instance.
+ public static PlayGamesPlatform Activate()
+ {
+ GooglePlayGames.OurUtils.Logger.d("Activating PlayGamesPlatform.");
+
+ Social.Active = PlayGamesPlatform.Instance;
+ GooglePlayGames.OurUtils.Logger.d(
+ "PlayGamesPlatform activated: " + Social.Active);
+ return PlayGamesPlatform.Instance;
+ }
+
+ ///
+ /// Specifies that the ID fromId should be implicitly replaced by toId
+ /// on any calls that take a leaderboard or achievement ID.
+ ///
+ /// After a mapping is
+ /// registered, you can use fromId instead of toId when making a call.
+ /// For example, the following two snippets are equivalent:
+ ///
+ /// ReportProgress("Cfiwjew894_AQ", 100.0, callback);
+ ///
+ /// ...is equivalent to:
+ ///
+ /// AddIdMapping("super-combo", "Cfiwjew894_AQ");
+ /// ReportProgress("super-combo", 100.0, callback);
+ ///
+ ///
+ ///
+ /// The identifier to map.
+ ///
+ ///
+ /// The identifier that fromId will be mapped to.
+ ///
+ public void AddIdMapping(string fromId, string toId)
+ {
+ mIdMap[fromId] = toId;
+ }
+
+ ///
+ /// Returns the result of the automatic sign-in attempt. Play Games SDK automatically
+ /// prompts users to sign in when the game is started. This API is useful for understanding
+ /// if your game has access to Play Games Services and should be used when your game is
+ /// started in order to conditionally enable or disable your Play Games Services
+ /// integration.
+ ///
+ /// The callback to call when authentication finishes.
+ public void Authenticate(Action callback)
+ {
+ mClient.Authenticate(callback);
+ }
+
+ ///
+ /// Provided for compatibility with ISocialPlatform.
+ ///
+ ///
+ /// Unused parameter for this implementation.
+ /// Callback invoked when complete.
+ public void Authenticate(ILocalUser unused, Action callback)
+ {
+ Authenticate(status => callback(status == SignInStatus.Success));
+ }
+
+ ///
+ /// Provided for compatibility with ISocialPlatform.
+ ///
+ ///
+ /// Unused parameter for this implementation.
+ /// Callback invoked when complete.
+ public void Authenticate(ILocalUser unused, Action callback)
+ {
+ Authenticate(status => callback(status == SignInStatus.Success, status.ToString()));
+ }
+
+ ///
+ /// Manually requests that your game performs sign in with Play Games Services.
+ ///
+ ///
+ /// Note that a sign-in attempt will be made automatically when your game's application
+ /// started. For this reason most games will not need to manually request to perform sign-in
+ /// unless the automatic sign-in attempt failed and your game requires access to Play Games
+ /// Services.
+ ///
+ ///
+ public void ManuallyAuthenticate(Action callback) {
+ mClient.ManuallyAuthenticate(callback);
+ }
+
+ ///
+ /// Determines whether the user is authenticated.
+ ///
+ ///
+ /// true if the user is authenticated; otherwise, false.
+ ///
+ public bool IsAuthenticated()
+ {
+ return mClient != null && mClient.IsAuthenticated();
+ }
+
+ ///
+ /// Requests server-side access to Player Games Services for the currently signed in player.
+ ///
+ /// When requested an authorization code is returned that can be used by your game-server to
+ /// exchange for an access token and conditionally a refresh token (when {@code
+ /// forceRefreshToken} is true). The access token may then be used by your game-server to
+ /// access the Play Games Services web APIs. This is commonly used to complete a sign-in flow
+ /// by verifying the Play Games Services player id.
+ ///
+ /// If {@code forceRefreshToken} is true, when exchanging the authorization code a refresh
+ /// token will be returned in addition to the access token. The refresh token allows the
+ /// game-server to request additional access tokens, allowing your game-server to continue
+ /// accesses Play Games Services while the user is not actively playing your app.
+ ///
+ ///
+ /// If {@code true} when the returned authorization code is
+ /// exchanged a refresh token will be included in addition to an access token.
+ public void RequestServerSideAccess(bool forceRefreshToken, Action callback)
+ {
+ Misc.CheckNotNull(callback);
+
+ if (!IsAuthenticated())
+ {
+ OurUtils.Logger.e("RequestServerSideAccess() can only be called after authentication.");
+ InvokeCallbackOnGameThread(callback, null);
+ return;
+ }
+
+ mClient.RequestServerSideAccess(forceRefreshToken, callback);
+ }
+
+ ///
+ /// Loads the users.
+ ///
+ /// User identifiers.
+ /// Callback invoked when complete.
+ public void LoadUsers(string[] userIds, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "GetUserId() can only be called after authentication.");
+ callback(new IUserProfile[0]);
+
+ return;
+ }
+
+ mClient.LoadUsers(userIds, callback);
+ }
+
+ ///
+ /// Returns the user's Google ID.
+ ///
+ ///
+ /// 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.
+ ///
+ public string GetUserId()
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "GetUserId() can only be called after authentication.");
+ return "0";
+ }
+
+ return mClient.GetUserId();
+ }
+
+ ///
+ /// Gets the player stats.
+ ///
+ /// Callback invoked when completed.
+ public void GetPlayerStats(Action callback)
+ {
+ if (mClient != null && mClient.IsAuthenticated())
+ {
+ mClient.GetPlayerStats(callback);
+ }
+ else
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "GetPlayerStats can only be called after authentication.");
+
+ callback(CommonStatusCodes.SignInRequired, new PlayerStats());
+ }
+ }
+
+ ///
+ /// Returns the user's display name.
+ ///
+ ///
+ /// The user display name (e.g. "Bruno Oliveira")
+ ///
+ public string GetUserDisplayName()
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "GetUserDisplayName can only be called after authentication.");
+ return string.Empty;
+ }
+
+ return mClient.GetUserDisplayName();
+ }
+
+ ///
+ /// Returns the user's avatar URL if they have one.
+ ///
+ ///
+ /// The URL, or null
if the user is not authenticated or does not have
+ /// an avatar.
+ ///
+ public string GetUserImageUrl()
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "GetUserImageUrl can only be called after authentication.");
+ return null;
+ }
+
+ return mClient.GetUserImageUrl();
+ }
+
+ ///
+ /// 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 instead.
+ ///
+ ///
+ /// 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 .
+ ///
+ ///
+ /// 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%).
+ ///
+ ///
+ /// Callback that will be called to report the result of the operation: true on
+ /// success, false otherwise.
+ ///
+ public void ReportProgress(string achievementID, double progress, Action callback)
+ {
+ callback = ToOnGameThread(callback);
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "ReportProgress can only be called after authentication.");
+ callback.Invoke(false);
+
+ return;
+ }
+
+ // map ID, if it's in the dictionary
+ GooglePlayGames.OurUtils.Logger.d("ReportProgress, " + achievementID + ", " + progress);
+ achievementID = MapId(achievementID);
+
+ // if progress is 0.0, we just want to reveal it
+ if (progress < 0.000001)
+ {
+ GooglePlayGames.OurUtils.Logger.d(
+ "Progress 0.00 interpreted as request to reveal.");
+ mClient.RevealAchievement(achievementID, callback);
+ return;
+ }
+
+ mClient.LoadAchievements(ach =>
+ {
+ for (int i = 0; i < ach.Length; i++)
+ {
+ if (ach[i].Id == achievementID)
+ {
+ if (ach[i].IsIncremental)
+ {
+ GooglePlayGames.OurUtils.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]
+ GooglePlayGames.OurUtils.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.");
+ }
+
+ mClient.SetStepsAtLeast(achievementID, progressToSteps(progress, ach[i].TotalSteps), callback);
+ }
+ else
+ {
+ if (progress >= 100)
+ {
+ // unlock it!
+ GooglePlayGames.OurUtils.Logger.d("Progress " + progress + " interpreted as UNLOCK.");
+ mClient.UnlockAchievement(achievementID, callback);
+ }
+ else
+ {
+ // not enough to unlock
+ GooglePlayGames.OurUtils.Logger.d(
+ "Progress " + progress + " not enough to unlock non-incremental achievement.");
+ callback.Invoke(false);
+ }
+ }
+
+ return;
+ }
+ }
+
+ // Achievement not found
+ GooglePlayGames.OurUtils.Logger.e("Unable to locate achievement " + achievementID);
+ callback.Invoke(false);
+ });
+ }
+
+ internal static int progressToSteps(double progress, int totalSteps) {
+ return (progress >= 100.0) ? totalSteps : (int) (progress * totalSteps / 100.0);
+ }
+
+ ///
+ /// Reveals the achievement with the passed identifier. This is a Play Games extension of the ISocialPlatform API.
+ ///
+ /// If the operation succeeds, the callback
+ /// will be invoked on the game thread with true
. If the operation fails, the
+ /// callback will be invoked with false
. This operation will immediately fail if
+ /// the user is not authenticated (i.e. the callback will immediately be invoked with
+ /// false
). If the achievement is already in a revealed state, this call will
+ /// succeed immediately.
+ ///
+ ///
+ /// The ID of the achievement to increment. This can be a raw Google Play
+ /// Games achievement ID (alphanumeric string), or an alias that was previously configured
+ /// by a call to .
+ ///
+ ///
+ /// The callback to call to report the success or failure of the operation. The callback
+ /// will be called with true to indicate success or false for failure.
+ ///
+ public void RevealAchievement(string achievementID, Action callback = null)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "RevealAchievement can only be called after authentication.");
+ if (callback != null)
+ {
+ callback.Invoke(false);
+ }
+
+ return;
+ }
+
+ // map ID, if it's in the dictionary
+ GooglePlayGames.OurUtils.Logger.d(
+ "RevealAchievement: " + achievementID);
+ achievementID = MapId(achievementID);
+ mClient.RevealAchievement(achievementID, callback);
+ }
+
+ ///
+ /// Unlocks the achievement with the passed identifier. This is a Play Games extension of the ISocialPlatform API.
+ ///
+ /// If the operation succeeds, the callback
+ /// will be invoked on the game thread with true
. If the operation fails, the
+ /// callback will be invoked with false
. This operation will immediately fail if
+ /// the user is not authenticated (i.e. the callback will immediately be invoked with
+ /// false
). If the achievement is already unlocked, this call will
+ /// succeed immediately.
+ ///
+ ///
+ /// The ID of the achievement to increment. This can be a raw Google Play
+ /// Games achievement ID (alphanumeric string), or an alias that was previously configured
+ /// by a call to .
+ ///
+ ///
+ /// The callback to call to report the success or failure of the operation. The callback
+ /// will be called with true to indicate success or false for failure.
+ ///
+ public void UnlockAchievement(string achievementID, Action callback = null)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "UnlockAchievement can only be called after authentication.");
+ if (callback != null)
+ {
+ callback.Invoke(false);
+ }
+
+ return;
+ }
+
+ // map ID, if it's in the dictionary
+ GooglePlayGames.OurUtils.Logger.d(
+ "UnlockAchievement: " + achievementID);
+ achievementID = MapId(achievementID);
+ mClient.UnlockAchievement(achievementID, callback);
+ }
+
+ ///
+ /// Increments an achievement. This is a Play Games extension of the ISocialPlatform API.
+ ///
+ ///
+ /// The ID of the achievement to increment. This can be a raw Google Play
+ /// Games achievement ID (alphanumeric string), or an alias that was previously configured
+ /// by a call to .
+ ///
+ ///
+ /// The number of steps to increment the achievement by.
+ ///
+ ///
+ /// The callback to call to report the success or failure of the operation. The callback
+ /// will be called with true to indicate success or false for failure.
+ ///
+ public void IncrementAchievement(string achievementID, int steps, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "IncrementAchievement can only be called after authentication.");
+ if (callback != null)
+ {
+ callback.Invoke(false);
+ }
+
+ return;
+ }
+
+ // map ID, if it's in the dictionary
+ GooglePlayGames.OurUtils.Logger.d(
+ "IncrementAchievement: " + achievementID + ", steps " + steps);
+ achievementID = MapId(achievementID);
+ mClient.IncrementAchievement(achievementID, steps, callback);
+ }
+
+ ///
+ /// Set an achievement to have at least the given number of steps completed.
+ /// Calling this method while the achievement already has more steps than
+ /// the provided value is a no-op. Once the achievement reaches the
+ /// maximum number of steps, the achievement is automatically unlocked,
+ /// and any further mutation operations are ignored.
+ ///
+ ///
+ /// The ID of the achievement to increment. This can be a raw Google Play
+ /// Games achievement ID (alphanumeric string), or an alias that was previously configured
+ /// by a call to .
+ ///
+ ///
+ /// The number of steps to increment the achievement by.
+ ///
+ ///
+ /// The callback to call to report the success or failure of the operation. The callback
+ /// will be called with true to indicate success or false for failure.
+ ///
+ public void SetStepsAtLeast(string achievementID, int steps, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "SetStepsAtLeast can only be called after authentication.");
+ if (callback != null)
+ {
+ callback.Invoke(false);
+ }
+
+ return;
+ }
+
+ // map ID, if it's in the dictionary
+ GooglePlayGames.OurUtils.Logger.d(
+ "SetStepsAtLeast: " + achievementID + ", steps " + steps);
+ achievementID = MapId(achievementID);
+ mClient.SetStepsAtLeast(achievementID, steps, callback);
+ }
+
+ ///
+ /// Loads the Achievement descriptions.
+ ///
+ /// The callback to receive the descriptions
+ public void LoadAchievementDescriptions(Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "LoadAchievementDescriptions can only be called after authentication.");
+ if (callback != null)
+ {
+ callback.Invoke(null);
+ }
+
+ return;
+ }
+
+ mClient.LoadAchievements(ach =>
+ {
+ IAchievementDescription[] data = new IAchievementDescription[ach.Length];
+ for (int i = 0; i < data.Length; i++)
+ {
+ data[i] = new PlayGamesAchievement(ach[i]);
+ }
+
+ callback.Invoke(data);
+ });
+ }
+
+ ///
+ /// Loads the achievement state for the current user.
+ ///
+ /// The callback to receive the achievements
+ public void LoadAchievements(Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e("LoadAchievements can only be called after authentication.");
+ callback.Invoke(null);
+
+ return;
+ }
+
+ mClient.LoadAchievements(ach =>
+ {
+ IAchievement[] data = new IAchievement[ach.Length];
+ for (int i = 0; i < data.Length; i++)
+ {
+ data[i] = new PlayGamesAchievement(ach[i]);
+ }
+
+ callback.Invoke(data);
+ });
+ }
+
+ ///
+ /// Creates an achievement object which may be subsequently used to report an
+ /// achievement.
+ ///
+ ///
+ /// The achievement object.
+ ///
+ public IAchievement CreateAchievement()
+ {
+ return new PlayGamesAchievement();
+ }
+
+ ///
+ /// Reports a score to a leaderboard.
+ ///
+ ///
+ /// The score to report.
+ ///
+ ///
+ /// The ID of the leaderboard on which the score is to be posted. This may be a raw
+ /// Google Play Games leaderboard ID or an alias configured through a call to
+ /// .
+ ///
+ ///
+ /// The callback to call to report the success or failure of the operation. The callback
+ /// will be called with true to indicate success or false for failure.
+ ///
+ public void ReportScore(long score, string board, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e("ReportScore can only be called after authentication.");
+ if (callback != null)
+ {
+ callback.Invoke(false);
+ }
+
+ return;
+ }
+
+ GooglePlayGames.OurUtils.Logger.d("ReportScore: score=" + score + ", board=" + board);
+ string leaderboardId = MapId(board);
+ mClient.SubmitScore(leaderboardId, score, callback);
+ }
+
+ ///
+ /// Submits the score for the currently signed-in player
+ /// to the leaderboard associated with a specific id
+ /// and metadata (such as something the player did to earn the score).
+ ///
+ /// Score to report.
+ /// leaderboard id.
+ /// metadata about the score.
+ /// Callback invoked upon completion.
+ public void ReportScore(long score, string board, string metadata, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e("ReportScore can only be called after authentication.");
+ if (callback != null)
+ {
+ callback.Invoke(false);
+ }
+
+ return;
+ }
+
+ GooglePlayGames.OurUtils.Logger.d("ReportScore: score=" + score +
+ ", board=" + board +
+ " metadata=" + metadata);
+ string leaderboardId = MapId(board);
+ mClient.SubmitScore(leaderboardId, score, metadata, callback);
+ }
+
+ ///
+ /// Loads the scores relative the player.
+ ///
+ /// This returns the 25
+ /// (which is the max results returned by the SDK per call) scores
+ /// that are around the player's score on the Public, all time leaderboard.
+ /// Use the overloaded methods which are specific to GPGS to modify these
+ /// parameters.
+ ///
+ /// Leaderboard Id
+ /// Callback to invoke when completed.
+ public void LoadScores(string leaderboardId, Action callback)
+ {
+ LoadScores(
+ leaderboardId,
+ LeaderboardStart.PlayerCentered,
+ mClient.LeaderboardMaxResults(),
+ LeaderboardCollection.Public,
+ LeaderboardTimeSpan.AllTime,
+ (scoreData) => callback(scoreData.Scores));
+ }
+
+ ///
+ /// Loads the scores using the provided parameters. This call may fail when trying to load friends with
+ /// ResponseCode.ResolutionRequired if the user has not share the friends list with the game. In this case, use
+ /// AskForLoadFriendsResolution to request access.
+ ///
+ /// Leaderboard identifier.
+ /// Start either top scores, or player centered.
+ /// Row count. the number of rows to return.
+ /// Collection. social or public
+ /// Time span. daily, weekly, all-time
+ /// Callback to invoke when completed.
+ public void LoadScores(
+ string leaderboardId,
+ LeaderboardStart start,
+ int rowCount,
+ LeaderboardCollection collection,
+ LeaderboardTimeSpan timeSpan,
+ Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e("LoadScores can only be called after authentication.");
+ callback(new LeaderboardScoreData(
+ leaderboardId,
+ ResponseStatus.NotAuthorized));
+ return;
+ }
+
+ mClient.LoadScores(
+ leaderboardId,
+ start,
+ rowCount,
+ collection,
+ timeSpan,
+ callback);
+ }
+
+ ///
+ /// Loads more scores. This call may fail when trying to load friends with
+ /// ResponseCode.ResolutionRequired if the user has not share the friends list with the game. In this case, use
+ /// AskForLoadFriendsResolution to request access.
+ ///
+ /// This is used to load the next "page" of scores.
+ /// Token used to recording the loading.
+ /// Row count.
+ /// Callback invoked when complete.
+ public void LoadMoreScores(
+ ScorePageToken token,
+ int rowCount,
+ Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e("LoadMoreScores can only be called after authentication.");
+ callback(
+ new LeaderboardScoreData(
+ token.LeaderboardId,
+ ResponseStatus.NotAuthorized));
+ return;
+ }
+
+ mClient.LoadMoreScores(token, rowCount, callback);
+ }
+
+ ///
+ /// Returns a leaderboard object that can be configured to
+ /// load scores.
+ ///
+ /// The leaderboard object.
+ public ILeaderboard CreateLeaderboard()
+ {
+ return new PlayGamesLeaderboard(mDefaultLbUi);
+ }
+
+ ///
+ /// Shows the standard Google Play Games achievements user interface,
+ /// which allows the player to browse their achievements.
+ ///
+ public void ShowAchievementsUI()
+ {
+ ShowAchievementsUI(null);
+ }
+
+ ///
+ /// Shows the standard Google Play Games achievements user interface,
+ /// which allows the player to browse their achievements.
+ ///
+ /// If non-null, the callback is invoked when
+ /// the achievement UI is dismissed
+ public void ShowAchievementsUI(Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e("ShowAchievementsUI can only be called after authentication.");
+ return;
+ }
+
+ GooglePlayGames.OurUtils.Logger.d("ShowAchievementsUI callback is " + callback);
+ mClient.ShowAchievementsUI(callback);
+ }
+
+ ///
+ /// 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
+ /// , the UI will show that
+ /// specific leaderboard only. Otherwise, a list of all the leaderboards
+ /// will be shown.
+ ///
+ public void ShowLeaderboardUI()
+ {
+ GooglePlayGames.OurUtils.Logger.d("ShowLeaderboardUI with default ID");
+ ShowLeaderboardUI(MapId(mDefaultLbUi), null);
+ }
+
+ ///
+ /// Shows the standard Google Play Games leaderboard UI for the given
+ /// leaderboard.
+ ///
+ ///
+ /// The ID of the leaderboard to display. This may be a raw
+ /// Google Play Games leaderboard ID or an alias configured through a call to
+ /// .
+ ///
+ public void ShowLeaderboardUI(string leaderboardId)
+ {
+ if (leaderboardId != null)
+ {
+ leaderboardId = MapId(leaderboardId);
+ }
+
+ ShowLeaderboardUI(leaderboardId, LeaderboardTimeSpan.AllTime, null);
+ }
+
+ ///
+ /// Shows the leaderboard UI and calls the specified callback upon
+ /// completion.
+ ///
+ /// leaderboard ID, can be null meaning all leaderboards.
+ /// Callback to call. If null, nothing is called.
+ public void ShowLeaderboardUI(string leaderboardId, Action callback)
+ {
+ ShowLeaderboardUI(leaderboardId, LeaderboardTimeSpan.AllTime, callback);
+ }
+
+ ///
+ /// Shows the leaderboard UI and calls the specified callback upon
+ /// completion.
+ ///
+ /// leaderboard ID, can be null meaning all leaderboards.
+ /// Timespan to display scores in the leaderboard.
+ /// Callback to call. If null, nothing is called.
+ public void ShowLeaderboardUI(
+ string leaderboardId,
+ LeaderboardTimeSpan span,
+ Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e("ShowLeaderboardUI can only be called after authentication.");
+ if (callback != null)
+ {
+ callback(UIStatus.NotAuthorized);
+ }
+
+ return;
+ }
+
+ GooglePlayGames.OurUtils.Logger.d("ShowLeaderboardUI, lbId=" +
+ leaderboardId + " callback is " + callback);
+ mClient.ShowLeaderboardUI(leaderboardId, span, callback);
+ }
+
+ ///
+ /// Sets the default leaderboard for the leaderboard UI. After calling this
+ /// method, a call to will show only the specified
+ /// leaderboard instead of showing the list of all leaderboards.
+ ///
+ ///
+ /// 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
+ /// .
+ ///
+ public void SetDefaultLeaderboardForUI(string lbid)
+ {
+ GooglePlayGames.OurUtils.Logger.d("SetDefaultLeaderboardForUI: " + lbid);
+ if (lbid != null)
+ {
+ lbid = MapId(lbid);
+ }
+
+ mDefaultLbUi = lbid;
+ }
+
+ ///
+ /// Loads the friends that also play this game. See loadConnectedPlayers.
+ ///
+ /// This is a callback variant of LoadFriends. When completed,
+ /// the friends list set in the user object, so they can accessed via the
+ /// friends property as needed.
+ ///
+ /// The current local user
+ /// Callback invoked when complete.
+ public void LoadFriends(ILocalUser user, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "LoadScores can only be called after authentication.");
+ if (callback != null)
+ {
+ callback(false);
+ }
+
+ return;
+ }
+
+ mClient.LoadFriends(callback);
+ }
+
+ ///
+ /// Loads the leaderboard based on the constraints in the leaderboard
+ /// object.
+ ///
+ /// The leaderboard object. This is created by
+ /// calling CreateLeaderboard(), and then initialized appropriately.
+ /// Callback invoked when complete.
+ public void LoadScores(ILeaderboard board, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e("LoadScores can only be called after authentication.");
+ if (callback != null)
+ {
+ callback(false);
+ }
+
+ return;
+ }
+
+ LeaderboardTimeSpan timeSpan;
+ switch (board.timeScope)
+ {
+ case TimeScope.AllTime:
+ timeSpan = LeaderboardTimeSpan.AllTime;
+ break;
+ case TimeScope.Week:
+ timeSpan = LeaderboardTimeSpan.Weekly;
+ break;
+ case TimeScope.Today:
+ timeSpan = LeaderboardTimeSpan.Daily;
+ break;
+ default:
+ timeSpan = LeaderboardTimeSpan.AllTime;
+ break;
+ }
+
+ ((PlayGamesLeaderboard) board).loading = true;
+ GooglePlayGames.OurUtils.Logger.d("LoadScores, board=" + board +
+ " callback is " + callback);
+ mClient.LoadScores(
+ board.id,
+ LeaderboardStart.PlayerCentered,
+ board.range.count > 0 ? board.range.count : mClient.LeaderboardMaxResults(),
+ board.userScope == UserScope.FriendsOnly ? LeaderboardCollection.Social : LeaderboardCollection.Public,
+ timeSpan,
+ (scoreData) => HandleLoadingScores(
+ (PlayGamesLeaderboard) board, scoreData, callback));
+ }
+
+ ///
+ /// Check if the leaderboard is currently loading.
+ ///
+ /// true, if loading was gotten, false otherwise.
+ /// The leaderboard to check for loading in progress
+ public bool GetLoading(ILeaderboard board)
+ {
+ return board != null && board.loading;
+ }
+
+ ///
+ /// Shows the Player Profile UI for the given user identifier.
+ ///
+ /// User Identifier.
+ ///
+ /// The game's own display name of the player referred to by userId.
+ ///
+ ///
+ /// The game's own display name of the current player.
+ ///
+ /// Callback invoked upon completion.
+ public void ShowCompareProfileWithAlternativeNameHintsUI(string userId,
+ string otherPlayerInGameName,
+ string currentPlayerInGameName,
+ Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "ShowCompareProfileWithAlternativeNameHintsUI can only be called after authentication.");
+ InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized);
+
+ return;
+ }
+
+ GooglePlayGames.OurUtils.Logger.d(
+ "ShowCompareProfileWithAlternativeNameHintsUI, userId=" + userId + " callback is " +
+ callback);
+ mClient.ShowCompareProfileWithAlternativeNameHintsUI(userId, otherPlayerInGameName,
+ currentPlayerInGameName, callback);
+ }
+
+ ///
+ /// Returns if the user has allowed permission for the game to access the friends list.
+ ///
+ /// If true, this call will clear any locally cached data and
+ /// attempt to fetch the latest data from the server. Normally, this should be set to {@code
+ /// false} to gain advantages of data caching.
+ /// Callback invoked upon completion.
+ public void GetFriendsListVisibility(bool forceReload,
+ Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "GetFriendsListVisibility can only be called after authentication.");
+ InvokeCallbackOnGameThread(callback, FriendsListVisibilityStatus.NotAuthorized);
+ return;
+ }
+
+ GooglePlayGames.OurUtils.Logger.d("GetFriendsListVisibility, callback is " + callback);
+ mClient.GetFriendsListVisibility(forceReload, callback);
+ }
+
+ ///
+ /// Shows the appropriate platform-specific friends sharing UI.
+ /// The callback to invoke when complete. If null,
+ /// no callback is called.
+ ///
+ public void AskForLoadFriendsResolution(Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "AskForLoadFriendsResolution can only be called after authentication.");
+ InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized);
+ return;
+ }
+
+ GooglePlayGames.OurUtils.Logger.d("AskForLoadFriendsResolution callback is " + callback);
+ mClient.AskForLoadFriendsResolution(callback);
+ }
+
+ ///
+ /// Gets status of the last call to load friends.
+ ///
+ public LoadFriendsStatus GetLastLoadFriendsStatus()
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "GetLastLoadFriendsStatus can only be called after authentication.");
+ return LoadFriendsStatus.NotAuthorized;
+ }
+
+ return mClient.GetLastLoadFriendsStatus();
+ }
+
+ ///
+ /// Loads the first page of the user's friends
+ ///
+ ///
+ /// The number of entries to request for this initial page. Note that if cached
+ /// data already exists, the returned buffer may contain more than this size, but it is
+ /// guaranteed to contain at least this many if the collection contains enough records.
+ ///
+ ///
+ /// If true, this call will clear any locally cached data and attempt to
+ /// fetch the latest data from the server. This would commonly be used for something like a
+ /// user-initiated refresh. Normally, this should be set to {@code false} to gain advantages
+ /// of data caching. Callback invoked upon
+ /// completion.
+ public void LoadFriends(int pageSize, bool forceReload,
+ Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "LoadFriends can only be called after authentication.");
+ InvokeCallbackOnGameThread(callback, LoadFriendsStatus.NotAuthorized);
+ return;
+ }
+
+ mClient.LoadFriends(pageSize, forceReload, callback);
+ }
+
+ ///
+ /// Loads the friends list page
+ ///
+ ///
+ /// The number of entries to request for this initial page. Note that if cached
+ /// data already exists, the returned buffer may contain more than this size, but it is
+ /// guaranteed to contain at least this many if the collection contains enough records.
+ ///
+ ///
+ public void LoadMoreFriends(int pageSize, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.e(
+ "LoadMoreFriends can only be called after authentication.");
+ InvokeCallbackOnGameThread(callback, LoadFriendsStatus.NotAuthorized);
+ return;
+ }
+
+ mClient.LoadMoreFriends(pageSize, callback);
+ }
+
+ ///
+ /// Handles the processing of scores during loading.
+ ///
+ /// leaderboard being loaded
+ /// Score data.
+ /// Callback invoked when complete.
+ internal void HandleLoadingScores(
+ PlayGamesLeaderboard board,
+ LeaderboardScoreData scoreData,
+ Action callback)
+ {
+ bool ok = board.SetFromData(scoreData);
+ if (ok && !board.HasAllScores() && scoreData.NextPageToken != null)
+ {
+ int rowCount = board.range.count - board.ScoreCount;
+
+ // need to load more scores
+ mClient.LoadMoreScores(
+ scoreData.NextPageToken,
+ rowCount,
+ (nextScoreData) =>
+ HandleLoadingScores(board, nextScoreData, callback));
+ }
+ else
+ {
+ callback(ok);
+ }
+ }
+
+ ///
+ /// Internal implmentation of getFriends.Gets the friends.
+ ///
+ /// The friends.
+ internal IUserProfile[] GetFriends()
+ {
+ if (!IsAuthenticated())
+ {
+ GooglePlayGames.OurUtils.Logger.d("Cannot get friends when not authenticated!");
+ return new IUserProfile[0];
+ }
+
+ return mClient.GetFriends();
+ }
+
+ ///
+ /// Maps the alias to the identifier.
+ ///
+ /// This maps an aliased ID to the actual id. The intent of
+ /// this method is to allow easy to read constants to be used instead of
+ /// the generated ids.
+ ///
+ /// The identifier, or null if not found.
+ /// Alias to map
+ private string MapId(string id)
+ {
+ if (id == null)
+ {
+ return null;
+ }
+
+ if (mIdMap.ContainsKey(id))
+ {
+ string result = mIdMap[id];
+ GooglePlayGames.OurUtils.Logger.d("Mapping alias " + id + " to ID " + result);
+ return result;
+ }
+
+ return id;
+ }
+
+ private static void InvokeCallbackOnGameThread(Action callback, T data)
+ {
+ if (callback == null)
+ {
+ return;
+ }
+
+ PlayGamesHelperObject.RunOnGameThread(() => { callback(data); });
+ }
+
+ private static Action ToOnGameThread(Action toConvert)
+ {
+ if (toConvert == null)
+ {
+ return delegate { };
+ }
+
+ return (val) => PlayGamesHelperObject.RunOnGameThread(() => toConvert(val));
+ }
+ }
+}
+#endif
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs.meta
new file mode 100644
index 0000000..b448e45
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: c1de7754a6e7f4fb08b76780a184b3ca
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs
new file mode 100644
index 0000000..d44dfba
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs
@@ -0,0 +1,126 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames
+{
+ using System;
+ using UnityEngine.SocialPlatforms;
+
+ ///
+ /// Represents a Google Play Games score that can be sent to a leaderboard.
+ ///
+ public class PlayGamesScore : IScore
+ {
+ private string mLbId = null;
+ private long mValue = 0;
+ private ulong mRank = 0;
+ private string mPlayerId = string.Empty;
+ private string mMetadata = string.Empty;
+
+ private DateTime mDate = new DateTime(1970, 1, 1, 0, 0, 0);
+
+ internal PlayGamesScore(DateTime date, string leaderboardId,
+ ulong rank, string playerId, ulong value, string metadata)
+ {
+ this.mDate = date;
+ mLbId = leaderboardID;
+ this.mRank = rank;
+ this.mPlayerId = playerId;
+ this.mValue = (long) value;
+ this.mMetadata = metadata;
+ }
+
+ ///
+ /// Reports the score. Equivalent to .
+ ///
+ public void ReportScore(Action callback)
+ {
+ PlayGamesPlatform.Instance.ReportScore(mValue, mLbId, mMetadata, callback);
+ }
+
+ ///
+ /// Gets or sets the leaderboard id.
+ ///
+ ///
+ /// The leaderboard id.
+ ///
+ public string leaderboardID
+ {
+ get { return mLbId; }
+
+ set { mLbId = value; }
+ }
+
+ ///
+ /// Gets or sets the score value.
+ ///
+ ///
+ /// The value.
+ ///
+ public long value
+ {
+ get { return mValue; }
+
+ set { mValue = value; }
+ }
+
+ ///
+ /// Not implemented. Returns Jan 01, 1970, 00:00:00
+ ///
+ public DateTime date
+ {
+ get { return mDate; }
+ }
+
+ ///
+ /// Not implemented. Returns the value converted to a string, unformatted.
+ ///
+ public string formattedValue
+ {
+ get { return mValue.ToString(); }
+ }
+
+ ///
+ /// Not implemented. Returns the empty string.
+ ///
+ public string userID
+ {
+ get { return mPlayerId; }
+ }
+
+ ///
+ /// Not implemented. Returns 1.
+ ///
+ public int rank
+ {
+ get { return (int) mRank; }
+ }
+
+ ///
+ /// Gets the metaData (scoreTag).
+ ///
+ ///
+ /// The metaData.
+ ///
+ public string metaData
+ {
+ get { return mMetadata; }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs.meta
new file mode 100644
index 0000000..1168228
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 2a6e2425305ab455a91061b1eb955b38
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs
new file mode 100644
index 0000000..62820e4
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs
@@ -0,0 +1,217 @@
+//
+// Copyright (C) 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+
+namespace GooglePlayGames
+{
+ using System;
+ using System.Collections;
+ using GooglePlayGames.OurUtils;
+ using UnityEngine;
+#if UNITY_2017_2_OR_NEWER
+ using UnityEngine.Networking;
+#endif
+ using UnityEngine.SocialPlatforms;
+
+ ///
+ /// Represents a Google Play Games user profile. In the current implementation,
+ /// this is only used as a base class of
+ /// and should not be used directly.
+ ///
+ public class PlayGamesUserProfile : IUserProfile
+ {
+ private string mDisplayName;
+ private string mPlayerId;
+ private string mAvatarUrl;
+ private bool mIsFriend;
+
+ private volatile bool mImageLoading = false;
+ private Texture2D mImage;
+
+ internal PlayGamesUserProfile(string displayName, string playerId,
+ string avatarUrl)
+ {
+ mDisplayName = displayName;
+ mPlayerId = playerId;
+ setAvatarUrl(avatarUrl);
+ mImageLoading = false;
+ mIsFriend = false;
+ }
+
+ internal PlayGamesUserProfile(string displayName, string playerId, string avatarUrl,
+ bool isFriend)
+ {
+ mDisplayName = displayName;
+ mPlayerId = playerId;
+ mAvatarUrl = avatarUrl;
+ mImageLoading = false;
+ mIsFriend = isFriend;
+ }
+
+ protected void ResetIdentity(string displayName, string playerId,
+ string avatarUrl)
+ {
+ mDisplayName = displayName;
+ mPlayerId = playerId;
+ mIsFriend = false;
+ if (mAvatarUrl != avatarUrl)
+ {
+ mImage = null;
+ setAvatarUrl(avatarUrl);
+ }
+
+ mImageLoading = false;
+ }
+
+ #region IUserProfile implementation
+
+ public string userName
+ {
+ get { return mDisplayName; }
+ }
+
+ public string id
+ {
+ get { return mPlayerId; }
+ }
+
+ public string gameId
+ {
+ get { return mPlayerId; }
+ }
+
+ public bool isFriend
+ {
+ get { return mIsFriend; }
+ }
+
+ public UserState state
+ {
+ get { return UserState.Online; }
+ }
+
+ public Texture2D image
+ {
+ get
+ {
+ if (!mImageLoading && mImage == null && !string.IsNullOrEmpty(AvatarURL))
+ {
+ OurUtils.Logger.d("Starting to load image: " + AvatarURL);
+ mImageLoading = true;
+ PlayGamesHelperObject.RunCoroutine(LoadImage());
+ }
+
+ return mImage;
+ }
+ }
+
+ #endregion
+
+ public string AvatarURL
+ {
+ get { return mAvatarUrl; }
+ }
+
+ ///
+ /// Loads the local user's image from the url. Loading urls
+ /// is asynchronous so the return from this call is fast,
+ /// the image is returned once it is loaded. null is returned
+ /// up to that point.
+ ///
+ internal IEnumerator LoadImage()
+ {
+ // the url can be null if the user does not have an
+ // avatar configured.
+ if (!string.IsNullOrEmpty(AvatarURL))
+ {
+#if UNITY_2017_2_OR_NEWER
+ UnityWebRequest www = UnityWebRequestTexture.GetTexture(AvatarURL);
+ www.SendWebRequest();
+#else
+ WWW www = new WWW(AvatarURL);
+#endif
+ while (!www.isDone)
+ {
+ yield return null;
+ }
+
+ if (www.error == null)
+ {
+#if UNITY_2017_2_OR_NEWER
+ this.mImage = DownloadHandlerTexture.GetContent(www);
+#else
+ this.mImage = www.texture;
+#endif
+ }
+ else
+ {
+ mImage = Texture2D.blackTexture;
+ OurUtils.Logger.e("Error downloading image: " + www.error);
+ }
+
+ mImageLoading = false;
+ }
+ else
+ {
+ OurUtils.Logger.e("No URL found.");
+ mImage = Texture2D.blackTexture;
+ mImageLoading = false;
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+
+ if (ReferenceEquals(this, obj))
+ {
+ return true;
+ }
+
+ PlayGamesUserProfile other = obj as PlayGamesUserProfile;
+ if (other == null)
+ {
+ return false;
+ }
+
+ return StringComparer.Ordinal.Equals(mPlayerId, other.mPlayerId);
+ }
+
+ public override int GetHashCode()
+ {
+ return typeof(PlayGamesUserProfile).GetHashCode() ^ mPlayerId.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return string.Format("[Player: '{0}' (id {1})]", mDisplayName, mPlayerId);
+ }
+
+ private void setAvatarUrl(string avatarUrl)
+ {
+ mAvatarUrl = avatarUrl;
+ if (!avatarUrl.StartsWith("https") && avatarUrl.StartsWith("http"))
+ {
+ mAvatarUrl = avatarUrl.Insert(4, "s");
+ }
+ }
+ }
+}
+#endif
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs.meta
new file mode 100644
index 0000000..b5bc517
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: ab1b90315f37e498a849765260dd436c
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils.meta
new file mode 100644
index 0000000..01304aa
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils.meta
@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: dc34e4ac2f7e6420da72898e7b511098
+folderAsset: yes
+DefaultImporter:
+ userData:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs
new file mode 100644
index 0000000..af8b8c3
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs
@@ -0,0 +1,92 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.OurUtils
+{
+ using System;
+ using UnityEngine;
+
+ public class Logger
+ {
+ private static bool debugLogEnabled = false;
+
+ public static bool DebugLogEnabled
+ {
+ get { return debugLogEnabled; }
+
+ set { debugLogEnabled = value; }
+ }
+
+ private static bool warningLogEnabled = true;
+
+ public static bool WarningLogEnabled
+ {
+ get { return warningLogEnabled; }
+
+ set { warningLogEnabled = value; }
+ }
+
+ public static void d(string msg)
+ {
+ if (debugLogEnabled)
+ {
+ PlayGamesHelperObject.RunOnGameThread(() =>
+ Debug.Log(ToLogMessage(string.Empty, "DEBUG", msg)));
+ }
+ }
+
+ public static void w(string msg)
+ {
+ if (warningLogEnabled)
+ {
+ PlayGamesHelperObject.RunOnGameThread(() =>
+ Debug.LogWarning(ToLogMessage("!!!", "WARNING", msg)));
+ }
+ }
+
+ public static void e(string msg)
+ {
+ if (warningLogEnabled)
+ {
+ PlayGamesHelperObject.RunOnGameThread(() =>
+ Debug.LogWarning(ToLogMessage("***", "ERROR", msg)));
+ }
+ }
+
+ public static string describe(byte[] b)
+ {
+ return b == null ? "(null)" : "byte[" + b.Length + "]";
+ }
+
+ private static string ToLogMessage(string prefix, string logType, string msg)
+ {
+ string timeString = null;
+ try
+ {
+ timeString = DateTime.Now.ToString("MM/dd/yy H:mm:ss zzz");
+ }
+ catch (Exception)
+ {
+ PlayGamesHelperObject.RunOnGameThread(() =>
+ Debug.LogWarning("*** [Play Games Plugin " + PluginVersion.VersionString + "] ERROR: Failed to format DateTime.Now"));
+ timeString = string.Empty;
+ }
+
+ return string.Format("{0} [Play Games Plugin " + PluginVersion.VersionString+ "] {1} {2}: {3}",
+ prefix, timeString, logType, msg);
+ }
+ }
+}
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs.meta
new file mode 100644
index 0000000..ab9a2a2
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: cde7cfd197b4a47edac2efe305e22e78
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs
new file mode 100644
index 0000000..8af6ea8
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs
@@ -0,0 +1,100 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.OurUtils
+{
+ using System;
+
+ public static class Misc
+ {
+ public static bool BuffersAreIdentical(byte[] a, byte[] b)
+ {
+ if (a == b)
+ {
+ // not only identical but the very same!
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ // one of them is null, the other one isn't
+ return false;
+ }
+
+ if (a.Length != b.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < a.Length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static byte[] GetSubsetBytes(byte[] array, int offset, int length)
+ {
+ if (array == null)
+ {
+ throw new ArgumentNullException("array");
+ }
+
+ if (offset < 0 || offset >= array.Length)
+ {
+ throw new ArgumentOutOfRangeException("offset");
+ }
+
+ if (length < 0 || (array.Length - offset) < length)
+ {
+ throw new ArgumentOutOfRangeException("length");
+ }
+
+ if (offset == 0 && length == array.Length)
+ {
+ return array;
+ }
+
+ byte[] piece = new byte[length];
+ Array.Copy(array, offset, piece, 0, length);
+ return piece;
+ }
+
+ public static T CheckNotNull(T value)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException();
+ }
+
+ return value;
+ }
+
+ public static T CheckNotNull(T value, string paramName)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(paramName);
+ }
+
+ return value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs.meta
new file mode 100644
index 0000000..b340ef4
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: ee52269f55933442fa5ea52e688ebec2
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs
new file mode 100644
index 0000000..3b09327
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs
@@ -0,0 +1,104 @@
+#if UNITY_ANDROID
+
+namespace GooglePlayGames.OurUtils
+{
+ using BasicApi.Nearby;
+ using System;
+ using UnityEngine;
+
+ public class NearbyHelperObject : MonoBehaviour
+ {
+ // our (singleton) instance
+ private static NearbyHelperObject instance = null;
+
+ // timers to keep track of discovery and advertising
+ private static double mAdvertisingRemaining = 0;
+ private static double mDiscoveryRemaining = 0;
+
+ // nearby client to stop discovery and to stop advertising
+ private static INearbyConnectionClient mClient = null;
+
+ public static void CreateObject(INearbyConnectionClient client)
+ {
+ if (instance != null)
+ {
+ return;
+ }
+
+ mClient = client;
+ if (Application.isPlaying)
+ {
+ // add an invisible game object to the scene
+ GameObject obj = new GameObject("PlayGames_NearbyHelper");
+ DontDestroyOnLoad(obj);
+ instance = obj.AddComponent();
+ }
+ else
+ {
+ instance = new NearbyHelperObject();
+ }
+ }
+
+ private static double ToSeconds(TimeSpan? span)
+ {
+ if (!span.HasValue)
+ {
+ return 0;
+ }
+
+ if (span.Value.TotalSeconds < 0)
+ {
+ return 0;
+ }
+
+ return span.Value.TotalSeconds;
+ }
+
+ public static void StartAdvertisingTimer(TimeSpan? span)
+ {
+ mAdvertisingRemaining = ToSeconds(span);
+ }
+
+ public static void StartDiscoveryTimer(TimeSpan? span)
+ {
+ mDiscoveryRemaining = ToSeconds(span);
+ }
+
+ public void Awake()
+ {
+ DontDestroyOnLoad(gameObject);
+ }
+
+ public void OnDisable()
+ {
+ if (instance == this)
+ {
+ instance = null;
+ }
+ }
+
+ public void Update()
+ {
+ // check if currently advertising
+ if (mAdvertisingRemaining > 0)
+ {
+ mAdvertisingRemaining -= Time.deltaTime;
+ if (mAdvertisingRemaining < 0)
+ {
+ mClient.StopAdvertising();
+ }
+ }
+
+ // check if currently discovering
+ if (mDiscoveryRemaining > 0)
+ {
+ mDiscoveryRemaining -= Time.deltaTime;
+ if (mDiscoveryRemaining < 0)
+ {
+ mClient.StopDiscovery(mClient.GetServiceId());
+ }
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs.meta
new file mode 100644
index 0000000..7e4b250
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: b66cca4a5a1f4a5092a280c452185308
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs
new file mode 100644
index 0000000..5fce45b
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs
@@ -0,0 +1,58 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+namespace GooglePlayGames.OurUtils
+{
+ using UnityEngine;
+ using System;
+
+ public static class PlatformUtils
+ {
+ ///
+ /// Check if the Google Play Games platform is supported at runtime.
+ ///
+ /// If the platform is supported.
+ public static bool Supported
+ {
+ get
+ {
+#if UNITY_EDITOR
+ return false;
+#else
+ var up = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
+ var ca = up.GetStatic("currentActivity");
+ var packageManager = ca.Call("getPackageManager");
+
+ AndroidJavaObject launchIntent = null;
+ //if the app is installed, no errors. Else, doesn't get past next line
+ try
+ {
+ launchIntent =
+ packageManager.Call("getLaunchIntentForPackage", "com.google.android.play.games");
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ return launchIntent != null;
+#endif
+ }
+ }
+ }
+}
+#endif //UNITY_ANDROID
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs.meta
new file mode 100644
index 0000000..7b6bedf
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 053811e778f3d4e3e98065f5db5bd005
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs
new file mode 100644
index 0000000..6c8551c
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs
@@ -0,0 +1,222 @@
+//
+// Copyright (C) 2014 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+namespace GooglePlayGames.OurUtils
+{
+ using System;
+ using System.Collections;
+ using UnityEngine;
+ using System.Collections.Generic;
+
+ public class PlayGamesHelperObject : MonoBehaviour
+ {
+ // our (singleton) instance
+ private static PlayGamesHelperObject instance = null;
+
+ // are we a dummy instance (used in the editor?)
+ private static bool sIsDummy = false;
+
+ // queue of actions to run on the game thread
+ private static List sQueue = new List();
+
+ // member variable used to copy actions from the sQueue and
+ // execute them on the game thread. It is a member variable
+ // to help minimize memory allocations.
+ List localQueue = new List();
+
+ // flag that alerts us that we should check the queue
+ // (we do this just so we don't have to lock() the queue every
+ // frame to check if it's empty or not).
+ private volatile static bool sQueueEmpty = true;
+
+ // callback for application pause and focus events
+ private static List> sPauseCallbackList =
+ new List>();
+
+ private static List> sFocusCallbackList =
+ new List>();
+
+ // Call this once from the game thread
+ public static void CreateObject()
+ {
+ if (instance != null)
+ {
+ return;
+ }
+
+ if (Application.isPlaying)
+ {
+ // add an invisible game object to the scene
+ GameObject obj = new GameObject("PlayGames_QueueRunner");
+ DontDestroyOnLoad(obj);
+ instance = obj.AddComponent();
+ }
+ else
+ {
+ instance = new PlayGamesHelperObject();
+ sIsDummy = true;
+ }
+ }
+
+ public void Awake()
+ {
+ DontDestroyOnLoad(gameObject);
+ }
+
+ public void OnDisable()
+ {
+ if (instance == this)
+ {
+ instance = null;
+ }
+ }
+
+ public static void RunCoroutine(IEnumerator action)
+ {
+ if (instance != null)
+ {
+ RunOnGameThread(() => instance.StartCoroutine(action));
+ }
+ }
+
+ public static void RunOnGameThread(System.Action action)
+ {
+ if (action == null)
+ {
+ throw new ArgumentNullException("action");
+ }
+
+ if (sIsDummy)
+ {
+ return;
+ }
+
+ lock (sQueue)
+ {
+ sQueue.Add(action);
+ sQueueEmpty = false;
+ }
+ }
+
+ public void Update()
+ {
+ if (sIsDummy || sQueueEmpty)
+ {
+ return;
+ }
+
+ // first copy the shared queue into a local queue
+ localQueue.Clear();
+ lock (sQueue)
+ {
+ // transfer the whole queue to our local queue
+ localQueue.AddRange(sQueue);
+ sQueue.Clear();
+ sQueueEmpty = true;
+ }
+
+ // execute queued actions (from local queue)
+ // use a loop to avoid extra memory allocations using the
+ // forEach
+ for (int i = 0; i < localQueue.Count; i++)
+ {
+ localQueue[i].Invoke();
+ }
+ }
+
+ public void OnApplicationFocus(bool focused)
+ {
+ foreach (Action cb in sFocusCallbackList)
+ {
+ try
+ {
+ cb(focused);
+ }
+ catch (Exception e)
+ {
+ Logger.e("Exception in OnApplicationFocus:" +
+ e.Message + "\n" + e.StackTrace);
+ }
+ }
+ }
+
+ public void OnApplicationPause(bool paused)
+ {
+ foreach (Action cb in sPauseCallbackList)
+ {
+ try
+ {
+ cb(paused);
+ }
+ catch (Exception e)
+ {
+ Logger.e("Exception in OnApplicationPause:" +
+ e.Message + "\n" + e.StackTrace);
+ }
+ }
+ }
+
+ ///
+ /// Adds a callback that is called when the Unity method OnApplicationFocus
+ /// is called.
+ ///
+ ///
+ /// Callback.
+ public static void AddFocusCallback(Action callback)
+ {
+ if (!sFocusCallbackList.Contains(callback))
+ {
+ sFocusCallbackList.Add(callback);
+ }
+ }
+
+ ///
+ /// Removes the callback from the list to call when handling OnApplicationFocus
+ /// is called.
+ ///
+ /// true, if focus callback was removed, false otherwise.
+ /// Callback.
+ public static bool RemoveFocusCallback(Action callback)
+ {
+ return sFocusCallbackList.Remove(callback);
+ }
+
+ ///
+ /// Adds a callback that is called when the Unity method OnApplicationPause
+ /// is called.
+ ///
+ ///
+ /// Callback.
+ public static void AddPauseCallback(Action callback)
+ {
+ if (!sPauseCallbackList.Contains(callback))
+ {
+ sPauseCallbackList.Add(callback);
+ }
+ }
+
+ ///
+ /// Removes the callback from the list to call when handling OnApplicationPause
+ /// is called.
+ ///
+ /// true, if focus callback was removed, false otherwise.
+ /// Callback.
+ public static bool RemovePauseCallback(Action callback)
+ {
+ return sPauseCallbackList.Remove(callback);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs.meta
new file mode 100644
index 0000000..fa51c96
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs.meta
@@ -0,0 +1,14 @@
+fileFormatVersion: 2
+guid: 7dd6f93ee6cb54945aea72a87542f720
+labels:
+- gvh
+- gvh_version-0.11.01
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms.meta
new file mode 100644
index 0000000..dd9d70b
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms.meta
@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: 58fac82a81a11415b99606841f6040a6
+folderAsset: yes
+DefaultImporter:
+ userData:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android.meta
new file mode 100644
index 0000000..a8981c4
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 5c9032ae026414e1bbe872da53708edd
+folderAsset: yes
+timeCreated: 1441206393
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs
new file mode 100644
index 0000000..ec9c53e
--- /dev/null
+++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs
@@ -0,0 +1,1024 @@
+//
+// Copyright (C) 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#if UNITY_ANDROID
+#pragma warning disable 0642 // Possible mistaken empty statement
+
+namespace GooglePlayGames.Android
+{
+ using GooglePlayGames.BasicApi;
+ using GooglePlayGames.BasicApi.Events;
+ using GooglePlayGames.BasicApi.SavedGame;
+ using GooglePlayGames.OurUtils;
+ using System;
+ using UnityEngine;
+ using UnityEngine.SocialPlatforms;
+
+ public class AndroidClient : IPlayGamesClient
+ {
+ private enum AuthState
+ {
+ Unauthenticated,
+ Authenticated
+ }
+
+ private readonly object GameServicesLock = new object();
+ private readonly object AuthStateLock = new object();
+ private readonly static String PlayGamesSdkClassName =
+ "com.google.android.gms.games.PlayGamesSdk";
+
+ private volatile ISavedGameClient mSavedGameClient;
+ private volatile IEventsClient mEventsClient;
+ private volatile Player mUser = null;
+ private volatile AuthState mAuthState = AuthState.Unauthenticated;
+ private IUserProfile[] mFriends = new IUserProfile[0];
+ private LoadFriendsStatus mLastLoadFriendsStatus = LoadFriendsStatus.Unknown;
+
+ AndroidJavaClass mGamesClass = new AndroidJavaClass("com.google.android.gms.games.PlayGames");
+ private static string TasksClassName = "com.google.android.gms.tasks.Tasks";
+
+ private AndroidJavaObject mFriendsResolutionException = null;
+
+ private readonly int mLeaderboardMaxResults = 25; // can be from 1 to 25
+
+ private readonly int mFriendsMaxResults = 200; // the maximum load friends page size
+
+ internal AndroidClient()
+ {
+ PlayGamesHelperObject.CreateObject();
+ InitializeSdk();
+ }
+
+ private static void InitializeSdk() {
+ using (var playGamesSdkClass = new AndroidJavaClass(PlayGamesSdkClassName)) {
+ playGamesSdkClass.CallStatic("initialize", AndroidHelperFragment.GetActivity());
+ }
+ }
+
+ public void Authenticate(Action callback)
+ {
+ Authenticate( /* isAutoSignIn= */ true, callback);
+ }
+
+ public void ManuallyAuthenticate(Action callback)
+ {
+ Authenticate( /* isAutoSignIn= */ false, callback);
+ }
+
+ private void Authenticate(bool isAutoSignIn, Action callback)
+ {
+ callback = AsOnGameThreadCallback(callback);
+ lock (AuthStateLock)
+ {
+ // If the user is already authenticated, just fire the callback, we don't need
+ // any additional work.
+ if (mAuthState == AuthState.Authenticated)
+ {
+ OurUtils.Logger.d("Already authenticated.");
+ InvokeCallbackOnGameThread(callback, SignInStatus.Success);
+ return;
+ }
+ }
+
+ string methodName = isAutoSignIn ? "isAuthenticated" : "signIn";
+
+ OurUtils.Logger.d("Starting Auth using the method " + methodName);
+ using (var client = getGamesSignInClient())
+ using (
+ var task = client.Call(methodName))
+ {
+ AndroidTaskUtils.AddOnSuccessListener(task, authenticationResult =>
+ {
+ bool isAuthenticated = authenticationResult.Call("isAuthenticated");
+ SignInOnResult(isAuthenticated, callback);
+ });
+
+ AndroidTaskUtils.AddOnFailureListener(task, exception =>
+ {
+ OurUtils.Logger.e("Authentication failed - " + exception.Call("toString"));
+ callback(SignInStatus.InternalError);
+ });
+ }
+ }
+
+ private void SignInOnResult(bool isAuthenticated, Action callback)
+ {
+ if (isAuthenticated)
+ {
+ using (var signInTasks = new AndroidJavaObject("java.util.ArrayList"))
+ {
+ AndroidJavaObject taskGetPlayer =
+ getPlayersClient().Call("getCurrentPlayer");
+ signInTasks.Call("add", taskGetPlayer);
+
+ using (var tasks = new AndroidJavaClass(TasksClassName))
+ using (var allTask = tasks.CallStatic("whenAll", signInTasks))
+ {
+ AndroidTaskUtils.AddOnCompleteListener(
+ allTask,
+ completeTask =>
+ {
+ if (completeTask.Call("isSuccessful"))
+ {
+ using (var resultObject = taskGetPlayer.Call("getResult"))
+ {
+ mUser = AndroidJavaConverter.ToPlayer(resultObject);
+ }
+
+ lock (GameServicesLock)
+ {
+ mSavedGameClient = new AndroidSavedGameClient(this);
+ mEventsClient = new AndroidEventsClient();
+ }
+
+ mAuthState = AuthState.Authenticated;
+ InvokeCallbackOnGameThread(callback, SignInStatus.Success);
+ OurUtils.Logger.d("Authentication succeeded");
+ LoadAchievements(ignore => { });
+ }
+ else
+ {
+ if (completeTask.Call("isCanceled"))
+ {
+ InvokeCallbackOnGameThread(callback, SignInStatus.Canceled);
+ return;
+ }
+
+ using (var exception = completeTask.Call("getException"))
+ {
+ OurUtils.Logger.e(
+ "Authentication failed - " + exception.Call("toString"));
+ InvokeCallbackOnGameThread(callback, SignInStatus.InternalError);
+ }
+ }
+ }
+ );
+ }
+ }
+ }
+ else
+ {
+ lock (AuthStateLock)
+ {
+ OurUtils.Logger.e("Returning an error code.");
+ InvokeCallbackOnGameThread(callback, SignInStatus.Canceled);
+ }
+ }
+ }
+
+ public void RequestServerSideAccess(bool forceRefreshToken, Action callback)
+ {
+ callback = AsOnGameThreadCallback(callback);
+
+ if (!GameInfo.WebClientIdInitialized())
+ {
+ throw new InvalidOperationException("Requesting server side access requires web " +
+ "client id to be configured.");
+ }
+
+ using (var client = getGamesSignInClient())
+ using (var task = client.Call("requestServerSideAccess",
+ GameInfo.WebClientId, forceRefreshToken))
+ {
+ AndroidTaskUtils.AddOnSuccessListener(
+ task,
+ authCode => callback(authCode)
+ );
+
+ AndroidTaskUtils.AddOnFailureListener(task, exception =>
+ {
+ OurUtils.Logger.e("Requesting server side access task failed - " +
+ exception.Call("toString"));
+ callback(null);
+ });
+ }
+ }
+
+ private static Action AsOnGameThreadCallback(Action callback)
+ {
+ if (callback == null)
+ {
+ return delegate { };
+ }
+
+ return result => InvokeCallbackOnGameThread(callback, result);
+ }
+
+ private static void InvokeCallbackOnGameThread(Action callback)
+ {
+ if (callback == null)
+ {
+ return;
+ }
+
+ PlayGamesHelperObject.RunOnGameThread(() => { callback(); });
+ }
+
+ private static void InvokeCallbackOnGameThread(Action callback, T data)
+ {
+ if (callback == null)
+ {
+ return;
+ }
+
+ PlayGamesHelperObject.RunOnGameThread(() => { callback(data); });
+ }
+
+
+ private static Action AsOnGameThreadCallback(
+ Action toInvokeOnGameThread)
+ {
+ return (result1, result2) =>
+ {
+ if (toInvokeOnGameThread == null)
+ {
+ return;
+ }
+
+ PlayGamesHelperObject.RunOnGameThread(() => toInvokeOnGameThread(result1, result2));
+ };
+ }
+
+ private static void InvokeCallbackOnGameThread(Action callback, T1 t1, T2 t2)
+ {
+ if (callback == null)
+ {
+ return;
+ }
+
+ PlayGamesHelperObject.RunOnGameThread(() => { callback(t1, t2); });
+ }
+
+ public bool IsAuthenticated()
+ {
+ lock (AuthStateLock)
+ {
+ return mAuthState == AuthState.Authenticated;
+ }
+ }
+
+ public void LoadFriends(Action callback)
+ {
+ LoadAllFriends(mFriendsMaxResults, /* forceReload= */ false, /* loadMore= */ false, callback);
+ }
+
+ private void LoadAllFriends(int pageSize, bool forceReload, bool loadMore,
+ Action callback)
+ {
+ LoadFriendsPaginated(pageSize, loadMore, forceReload, result =>
+ {
+ mLastLoadFriendsStatus = result;
+ switch (result)
+ {
+ case LoadFriendsStatus.Completed:
+ InvokeCallbackOnGameThread(callback, true);
+ break;
+ case LoadFriendsStatus.LoadMore:
+ // There are more friends to load.
+ LoadAllFriends(pageSize, /* forceReload= */ false, /* loadMore= */ true, callback);
+ break;
+ case LoadFriendsStatus.ResolutionRequired:
+ case LoadFriendsStatus.InternalError:
+ case LoadFriendsStatus.NotAuthorized:
+ InvokeCallbackOnGameThread(callback, false);
+ break;
+ default:
+ GooglePlayGames.OurUtils.Logger.d("There was an error when loading friends." + result);
+ InvokeCallbackOnGameThread(callback, false);
+ break;
+ }
+ });
+ }
+
+ public void LoadFriends(int pageSize, bool forceReload,
+ Action callback)
+ {
+ LoadFriendsPaginated(pageSize, /* isLoadMore= */ false, /* forceReload= */ forceReload,
+ callback);
+ }
+
+ public void LoadMoreFriends(int pageSize, Action callback)
+ {
+ LoadFriendsPaginated(pageSize, /* isLoadMore= */ true, /* forceReload= */ false,
+ callback);
+ }
+
+ private void LoadFriendsPaginated(int pageSize, bool isLoadMore, bool forceReload,
+ Action callback)
+ {
+ mFriendsResolutionException = null;
+ using (var playersClient = getPlayersClient())
+ using (var task = isLoadMore
+ ? playersClient.Call("loadMoreFriends", pageSize)
+ : playersClient.Call("loadFriends", pageSize,
+ forceReload))
+ {
+ AndroidTaskUtils.AddOnSuccessListener(
+ task, annotatedData =>
+ {
+ using (var playersBuffer = annotatedData.Call("get"))
+ {
+ AndroidJavaObject metadata = playersBuffer.Call("getMetadata");
+ var areMoreFriendsToLoad = metadata != null &&
+ metadata.Call("getString",
+ "next_page_token") != null;
+ mFriends = AndroidJavaConverter.playersBufferToArray(playersBuffer);
+ mLastLoadFriendsStatus = areMoreFriendsToLoad
+ ? LoadFriendsStatus.LoadMore
+ : LoadFriendsStatus.Completed;
+ InvokeCallbackOnGameThread(callback, mLastLoadFriendsStatus);
+ }
+ });
+ AndroidTaskUtils.AddOnFailureListener(task, exception =>
+ {
+ AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired =>
+ {
+ if (resolutionRequired)
+ {
+ mFriendsResolutionException =
+ exception.Call("getResolution");
+ mLastLoadFriendsStatus = LoadFriendsStatus.ResolutionRequired;
+ mFriends = new IUserProfile[0];
+ InvokeCallbackOnGameThread(callback, LoadFriendsStatus.ResolutionRequired);
+ }
+ else
+ {
+ mFriendsResolutionException = null;
+
+ if (IsApiException(exception))
+ {
+ var statusCode = exception.Call("getStatusCode");
+ if (statusCode == /* GamesClientStatusCodes.NETWORK_ERROR_NO_DATA */ 26504)
+ {
+ mLastLoadFriendsStatus = LoadFriendsStatus.NetworkError;
+ InvokeCallbackOnGameThread(callback, LoadFriendsStatus.NetworkError);
+ return;
+ }
+ }
+
+ mLastLoadFriendsStatus = LoadFriendsStatus.InternalError;
+ OurUtils.Logger.e("LoadFriends failed: " +
+ exception.Call("toString"));
+ InvokeCallbackOnGameThread(callback, LoadFriendsStatus.InternalError);
+ }
+ });
+ return;
+ });
+ }
+ }
+
+ private static bool IsApiException(AndroidJavaObject exception) {
+ var exceptionClassName = exception.Call("getClass")
+ .Call("getName");
+ return exceptionClassName == "com.google.android.gms.common.api.ApiException";
+ }
+
+ public LoadFriendsStatus GetLastLoadFriendsStatus()
+ {
+ return mLastLoadFriendsStatus;
+ }
+
+ public void AskForLoadFriendsResolution(Action callback)
+ {
+ if (mFriendsResolutionException == null)
+ {
+ GooglePlayGames.OurUtils.Logger.d("The developer asked for access to the friends " +
+ "list but there is no intent to trigger the UI. This may be because the user " +
+ "has granted access already or the game has not called loadFriends() before.");
+ using (var playersClient = getPlayersClient())
+ using (
+ var task = playersClient.Call("loadFriends", /* pageSize= */ 1,
+ /* forceReload= */ false))
+ {
+ AndroidTaskUtils.AddOnSuccessListener(
+ task, annotatedData => { InvokeCallbackOnGameThread(callback, UIStatus.Valid); });
+ AndroidTaskUtils.AddOnFailureListener(task, exception =>
+ {
+ AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired =>
+ {
+ if (resolutionRequired)
+ {
+ mFriendsResolutionException =
+ exception.Call("getResolution");
+ AndroidHelperFragment.AskForLoadFriendsResolution(
+ mFriendsResolutionException, AsOnGameThreadCallback(callback));
+ return;
+ }
+
+ if (IsApiException(exception))
+ {
+ var statusCode = exception.Call("getStatusCode");
+ if (statusCode ==
+ /* GamesClientStatusCodes.NETWORK_ERROR_NO_DATA */ 26504)
+ {
+ InvokeCallbackOnGameThread(callback, UIStatus.NetworkError);
+ return;
+ }
+ }
+
+ OurUtils.Logger.e("LoadFriends failed: " +
+ exception.Call("toString"));
+ InvokeCallbackOnGameThread(callback, UIStatus.InternalError);
+ });
+ });
+ }
+ }
+ else
+ {
+ AndroidHelperFragment.AskForLoadFriendsResolution(mFriendsResolutionException,
+ AsOnGameThreadCallback(callback));
+ }
+ }
+
+ public void ShowCompareProfileWithAlternativeNameHintsUI(string playerId,
+ string otherPlayerInGameName,
+ string currentPlayerInGameName,
+ Action callback)
+ {
+ AndroidHelperFragment.ShowCompareProfileWithAlternativeNameHintsUI(
+ playerId, otherPlayerInGameName, currentPlayerInGameName,
+ AsOnGameThreadCallback(callback));
+ }
+
+ public void GetFriendsListVisibility(bool forceReload,
+ Action callback)
+ {
+ using (var playersClient = getPlayersClient())
+ using (
+ var task = playersClient.Call("getCurrentPlayer", forceReload))
+ {
+ AndroidTaskUtils.AddOnSuccessListener(task, annotatedData =>
+ {
+ AndroidJavaObject currentPlayerInfo =
+ annotatedData.Call("get").Call(
+ "getCurrentPlayerInfo");
+ int playerListVisibility =
+ currentPlayerInfo.Call("getFriendsListVisibilityStatus");
+ InvokeCallbackOnGameThread(callback,
+ AndroidJavaConverter.ToFriendsListVisibilityStatus(playerListVisibility));
+ });
+ AndroidTaskUtils.AddOnFailureListener(task, exception =>
+ {
+ InvokeCallbackOnGameThread(callback, FriendsListVisibilityStatus.NetworkError);
+ return;
+ });
+ }
+ }
+
+ public IUserProfile[] GetFriends()
+ {
+ return mFriends;
+ }
+
+ public string GetUserId()
+ {
+ if (mUser == null)
+ {
+ return null;
+ }
+
+ return mUser.id;
+ }
+
+ public string GetUserDisplayName()
+ {
+ if (mUser == null)
+ {
+ return null;
+ }
+
+ return mUser.userName;
+ }
+
+ public string GetUserImageUrl()
+ {
+ if (mUser == null)
+ {
+ return null;
+ }
+
+ return mUser.AvatarURL;
+ }
+
+ public void GetPlayerStats(Action callback)
+ {
+ using (var playerStatsClient = getPlayerStatsClient())
+ using (var task = playerStatsClient.Call("loadPlayerStats", /* forceReload= */ false))
+ {
+ AndroidTaskUtils.AddOnSuccessListener(
+ task,
+ annotatedData =>
+ {
+ using (var playerStatsJava = annotatedData.Call("get"))
+ {
+ int numberOfPurchases = playerStatsJava.Call("getNumberOfPurchases");
+ float avgSessionLength = playerStatsJava.Call("getAverageSessionLength");
+ int daysSinceLastPlayed = playerStatsJava.Call("getDaysSinceLastPlayed");
+ int numberOfSessions = playerStatsJava.Call("getNumberOfSessions");
+ float sessionPercentile = playerStatsJava.Call("getSessionPercentile");
+ float spendPercentile = playerStatsJava.Call("getSpendPercentile");
+ float spendProbability = playerStatsJava.Call("getSpendProbability");
+ float churnProbability = playerStatsJava.Call("getChurnProbability");
+ float highSpenderProbability = playerStatsJava.Call("getHighSpenderProbability");
+ float totalSpendNext28Days = playerStatsJava.Call("getTotalSpendNext28Days");
+
+ PlayerStats result = new PlayerStats(
+ numberOfPurchases,
+ avgSessionLength,
+ daysSinceLastPlayed,
+ numberOfSessions,
+ sessionPercentile,
+ spendPercentile,
+ spendProbability,
+ churnProbability,
+ highSpenderProbability,
+ totalSpendNext28Days);
+
+ InvokeCallbackOnGameThread(callback, CommonStatusCodes.Success, result);
+ }
+ });
+
+ AndroidTaskUtils.AddOnFailureListener(task, exception =>
+ {
+ OurUtils.Logger.e("GetPlayerStats failed: " + exception.Call("toString"));
+ var statusCode = IsAuthenticated()
+ ? CommonStatusCodes.InternalError
+ : CommonStatusCodes.SignInRequired;
+ InvokeCallbackOnGameThread(callback, statusCode, new PlayerStats());
+ });
+ }
+ }
+
+ public void LoadUsers(string[] userIds, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ InvokeCallbackOnGameThread(callback, new IUserProfile[0]);
+ return;
+ }
+
+ using (var playersClient = getPlayersClient())
+ {
+ object countLock = new object();
+ int count = userIds.Length;
+ int resultCount = 0;
+ IUserProfile[] users = new IUserProfile[count];
+ for (int i = 0; i < count; ++i)
+ {
+ using (var task = playersClient.Call("loadPlayer", userIds[i]))
+ {
+ AndroidTaskUtils.AddOnSuccessListener(
+ task,
+ annotatedData =>
+ {
+ using (var player = annotatedData.Call("get"))
+ {
+ string playerId = player.Call("getPlayerId");
+ for (int j = 0; j < count; ++j)
+ {
+ if (playerId == userIds[j])
+ {
+ users[j] = AndroidJavaConverter.ToPlayer(player);
+ break;
+ }
+ }
+
+ lock (countLock)
+ {
+ ++resultCount;
+ if (resultCount == count)
+ {
+ InvokeCallbackOnGameThread(callback, users);
+ }
+ }
+ }
+ });
+
+ AndroidTaskUtils.AddOnFailureListener(task, exception =>
+ {
+ OurUtils.Logger.e("LoadUsers failed for index " + i +
+ " with: " + exception.Call("toString"));
+ lock (countLock)
+ {
+ ++resultCount;
+ if (resultCount == count)
+ {
+ InvokeCallbackOnGameThread(callback, users);
+ }
+ }
+ });
+ }
+ }
+ }
+ }
+
+ public void LoadAchievements(Action callback)
+ {
+ using (var achievementsClient = getAchievementsClient())
+ using (var task = achievementsClient.Call("load", /* forceReload= */ false))
+ {
+ AndroidTaskUtils.AddOnSuccessListener(
+ task,
+ annotatedData =>
+ {
+ using (var achievementBuffer = annotatedData.Call("get"))
+ {
+ int count = achievementBuffer.Call("getCount");
+ Achievement[] result = new Achievement[count];
+ for (int i = 0; i < count; ++i)
+ {
+ Achievement achievement = new Achievement();
+ using (var javaAchievement = achievementBuffer.Call("get", i))
+ {
+ achievement.Id = javaAchievement.Call("getAchievementId");
+ achievement.Description = javaAchievement.Call("getDescription");
+ achievement.Name = javaAchievement.Call("getName");
+ achievement.Points = javaAchievement.Call("getXpValue");
+
+ long timestamp = javaAchievement.Call("getLastUpdatedTimestamp");
+ achievement.LastModifiedTime = AndroidJavaConverter.ToDateTime(timestamp);
+
+ achievement.RevealedImageUrl = javaAchievement.Call("getRevealedImageUrl");
+ achievement.UnlockedImageUrl = javaAchievement.Call("getUnlockedImageUrl");
+ achievement.IsIncremental =
+ javaAchievement.Call("getType") == 1 /* TYPE_INCREMENTAL */;
+ if (achievement.IsIncremental)
+ {
+ achievement.CurrentSteps = javaAchievement.Call("getCurrentSteps");
+ achievement.TotalSteps = javaAchievement.Call("getTotalSteps");
+ }
+
+ int state = javaAchievement.Call("getState");
+ achievement.IsUnlocked = state == 0 /* STATE_UNLOCKED */;
+ achievement.IsRevealed = state == 1 /* STATE_REVEALED */;
+ }
+
+ result[i] = achievement;
+ }
+
+ achievementBuffer.Call("release");
+ InvokeCallbackOnGameThread(callback, result);
+ }
+ });
+
+ AndroidTaskUtils.AddOnFailureListener(task, exception =>
+ {
+ OurUtils.Logger.e("LoadAchievements failed: " + exception.Call("toString"));
+ InvokeCallbackOnGameThread(callback, new Achievement[0]);
+ });
+ }
+ }
+
+ public void UnlockAchievement(string achId, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ InvokeCallbackOnGameThread(callback, false);
+ return;
+ }
+
+ using (var achievementsClient = getAchievementsClient())
+ {
+ achievementsClient.Call("unlock", achId);
+ InvokeCallbackOnGameThread(callback, true);
+ }
+ }
+
+ public void RevealAchievement(string achId, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ InvokeCallbackOnGameThread(callback, false);
+ return;
+ }
+
+ using (var achievementsClient = getAchievementsClient())
+ {
+ achievementsClient.Call("reveal", achId);
+ InvokeCallbackOnGameThread(callback, true);
+ }
+ }
+
+ public void IncrementAchievement(string achId, int steps, Action callback)
+ {
+ if (!IsAuthenticated())
+ {
+ InvokeCallbackOnGameThread(callback, false);
+ return;
+ }
+
+ using (var achievementsClient = getAchievementsClient())
+ {
+ achievementsClient.Call("increment", achId, steps);
+ InvokeCallbackOnGameThread(callback, true);
+ }
+ }
+
+ public void SetStepsAtLeast(string achId, int steps, Action