Hey I am trying to use Unity Cloud Save feature.
I’ve added SDK for Cloud Save and Authentication and Linked Unity Project. I am also using Firebase so there is also configuration for it.
All fun starts here in the Start()
method of some initial script let’s say GameManager
private void Start()
{
Debug.Log("CloudSave: StartSceneLoader Start");
FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => {
var dependencyStatus = task.Result;
if (dependencyStatus == DependencyStatus.Available)
{
InitializeFirebase();
AuthManager.Instance.SignIn(() => {
StartCoroutine(WaitAndLoadGame());
});
}
else
{
Debug.LogError($"Could not resolve all Firebase dependencies: {dependencyStatus}");
}
});
}
I did basic Firebase initialization (there is no InitializeFirebase()
method here but it is irrelevant). Then after this initialization I’ve run my SignIn()
method on AuthManager
singleton and there is a callback which launch problematic WaitAndLoadGame()
. I’ve added listings with SignIn method but I don’t think it is necessary beacause the fact that this is the part which seems to work well. I can see the login Google Play Games animation and I can see all those logs which ensures me that I am logged.
public async void SignIn(Action callback)
{
await UnityServices.InitializeAsync();
PlayGamesPlatform.Activate();
SignInWithGooglePlayGames(callback);
}
private void SignInWithGooglePlayGames(Action callback)
{
PlayGamesPlatform.Instance.Authenticate(success =>
{
if (success == SignInStatus.Success)
{
Debug.Log("CloudSave: Login with Google Play games successful.");
PlayGamesPlatform.Instance.RequestServerSideAccess(true, code =>
{
Debug.Log($"CloudSave: Authorization code: {code}");
SignInWithGooglePlayGamesAsync(code, callback);
});
}
else
{
Debug.Log("CloudSave: Login Unsuccessful: Failed to retrieve Google play games authorization code");
}
});
}
private async void SignInWithGooglePlayGamesAsync(string authCode, Action callback)
{
try
{
await AuthenticationService.Instance.SignInWithGooglePlayGamesAsync(authCode);
await CheckPlayerInfoAndLinkAsyncAndroid(authCode);
FirebaseAnalytics.SetUserId(AuthenticationService.Instance.PlayerId);
Analytics.SendPlayerLoginEvent();
callback?.Invoke();
Debug.Log($"CloudSave: SignIn is successful. PlayerID: {AuthenticationService.Instance.PlayerId}");
}
catch (AuthenticationException ex)
{
HandleAuthException(ex);
}
catch (RequestFailedException ex)
{
HandleRequestFailedException(ex);
}
}
Let’s back to the problematic part
AuthManager.Instance.SignIn(() => {
StartCoroutine(WaitAndLoadGame());
});
In WaitAndLoadGame()
method I am trying to load the data from the cloud so await GameSaver.Load().Result;
private IEnumerator WaitAndLoadGame()
{
Debug.Log("CloudSave: Loading game data...");
var gameData = await GameSaver.Load().Result;
Debug.Log("CloudSave: Data loaded...");
...
}
And then in GameSaver.Load()
I’ve just await LoadFileStream()
and deseralize it to GameData
public static async Task<GameData> Load(){
await using var fileStream = await LoadFileStream(SAVE_GAME_FILE_NAME);
var savedData = formatter.Deserialize(fileStream) as GameData;
return savedData;
}
And this is the LoadFileStream(string key)
listing:
protected static async Task<Stream> LoadFileStream(string key)
{
try
{
Debug.Log($"CloudSave: Attempting to load data from cloud: [{key}]");
await using var cloudStream = await CloudSaveService.Instance.Files.Player.LoadStreamAsync(key);
return cloudStream;
}
catch (CloudSaveValidationException e)
{
foreach (var detail in e.Details)
{
Debug.LogError(detail.Field);
foreach (var msg in detail.Messages)
{
Debug.LogError(msg);
}
Debug.LogError(detail.Key);
}
return null;
}
catch (CloudSaveRateLimitedException e)
{
Debug.LogError(e);
Debug.LogError(e.RetryAfter);
return null;
}
catch (CloudSaveException e)
{
Debug.LogError(e);
Debug.LogError(e.Reason);
return null;
}
Debug.LogError("CloudSave: LoadFileStream, uncatched!");
return null;
}
Basically if we skip the catch
sections there is this line:
await using var cloudStream = await CloudSaveService.Instance.Files.Player.LoadStreamAsync(key);
This is problematic. When I run the game on Android device I can see that it is signing in then it goes to this line and then is basically dead.
The log which is just one line above, that one:
Debug.Log($"CloudSave: Attempting to load data from cloud: [{key}]");
Is last log from the application. But application don’t crash, its activity is still on top and I can see it. But there are no more logs the code execution appears to be somehow stopped.
This is part of my logcat from this situation:
CloudSave: Attempting to load data from cloud... [w151664_w2h3y1_6.dat]
UnityEngine.Debug:ExtractStackTraceNoAlloc (byte*,int,string)
UnityEngine.StackTraceUtility:ExtractStackTrace () (at /home/bokken/build/output/unity/unity/Runtime/Export/Scripting/StackTrace.cs:37)
UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,UnityEngine.LogOption,string,UnityEngine.Object)
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
UnityEngine.Logger:Log (UnityEngine.LogType,object)
UnityEngine.Debug:Log (object)
Persistence.Savers.BaseSaver/<LoadFileStream>d__2:MoveNext () (at /Users/lukaszciesla/work/defender2/Assets/Scripts/Persistence/Savers/BaseSaver.cs:92)
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<System.IO.Stream>:Start<Persistence.Savers.BaseSaver/<LoadFileStream>d__2> (Persistence.Savers.BaseSaver/<LoadFileStream>d__2&)
Persistence.Savers.BaseSaver:LoadFileStream (string)
Persistence.Savers.GameSaver/<Load>d__2:MoveNext () (at /Users/lukaszciesla/work/defender2/Assets
2024-07-17 00:52:48.590 15516-10835 NetworkScheduler com.google.android.gms.persistent W Error inserting flex_time=14000 job_id=-1 period=30000 source=16 requires_charging=0 preferred_network_type=1 target_class=com.google.android.gms.measurement.PackageMeasurementTaskService user_id=0 target_package=com.google.android.gms tag=Measurement.PackageMeasurementTaskService.UPLOAD_TASK_TAG task_type=0 required_idleness_state=0 service_kind=0 source_version=242632000 persistence_level=1 preferred_charging_state=1 required_network_type=0 runtime=1721170368586 retry_strategy={"maximum_backoff_seconds":{"3600":0},"initial_backoff_seconds":{"30":0},"retry_policy":{"0":0}} last_runtime=0 [CONTEXT service_id=218 ]
android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: pending_ops.tag, pending_ops.target_class, pending_ops.target_package, pending_ops.user_id (code 2067 SQLITE_CONSTRAINT_UNIQUE[2067])
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:1293)
at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:790)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:89)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:2434)
at android.database.sqlite.SQLiteDatabase.insertOrThrow(SQLiteDatabase.java:2329)
at dcxv.d(:com.google.android.gms@[email protected] (190400-650348549):735)
at dcvi.n(:com.google.android.gms@[email protected] (190400-650348549):29)
at dcvi.u(:com.google.android.gms@[email protected] (190400-650348549):360)
at dcvi.h(:com.google.android.gms@[email protected] (190400-650348549):51)
at dcqd.run(:com.google.android.gms@[email protected] (190400-650348549):72)
at anzz.c(:com.google.android.gms@[email protected] (190400-650348549):50)
at anzz.run(:com.google.android.gms@[email protected] (190400-650348549):76)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at aofk.run(:com.google.android.gms@[email protected] (190400-650348549):8)
at java.lang.Thread.run(Thread.java:1012)
2024-07-17 00:52:48.699 1052-1052 PocketProximityManager system_server D setStateOut()
2024-07-17 00:52:48.700 1052-1052 PocketModeEvent system_server D OutPocket prox 2
2024-07-17 00:52:48.858 1052-1052 PocketProximityManager system_server D setStateOut()
2024-07-17 00:52:48.860 1052-1052 PocketModeEvent system_server D OutPocket prox 2
2024-07-17 00:52:49.018 1052-1052 PocketProximityManager system_server D setStateOut()
2024-07-17 00:52:49.019 1052-1052 PocketModeEvent system_server D OutPocket prox 2
2024-07-17 00:52:49.141 771-864 VSyncReactor surfaceflinger I Current= 120, Period= 60, hwcPeriod= 120
2024-07-17 00:52:49.142 771-771 HWComposer surfaceflinger I [4633128672291735932] ActiveConfigToHWC, ID : 3
2024-07-17 00:52:49.143 771-771 LayerHistory surfaceflinger I SurfaceView[app.boardland/com.unity3d.player.UnityPlayerActivity]@0(BLAST)#24841 Max (can't resolve refresh rate)
2024-07-17 00:52:49.143 771-771 SurfaceFlinger surfaceflinger I Idle - choose 60.00 Hz
2024-07-17 00:52:49.149 771-864 VSyncReactor surfaceflinger I Current= 120, Period= 60, hwcPeriod= 120
2024-07-17 00:52:49.149 714-817 display [email protected] I Current VRR MODE is 3
2024-07-17 00:52:49.149 714-817 display [email protected] I setActiveConfigWithConstraints:: HFR match - config: 4, base: 3, try: 0
2024-07-17 00:52:49.149 714-817 display [email protected] I setActiveConfigWithConstraints::update 1080x2340@60phs I Current= 120, Period= 60, hwcPeriod= 60
There is more gibberish but there is generally nothing to investigate, just system related things. There is this android.database.sqlite.SQLiteConstraintException
exception right below the last log but don’t think it is related I can see many of those errors when looking at logcat.
During development I first have bad file name (key) and I had forbidden character there. In that case there was an CloudSaveValidationException
and I could read about a naming problem from the logs.
Also if I disable login to Google Play Games there is an CloudSaveException
that I am not logged.
But when the file name is right and I am logged in it just hangs.
Uff I hope you are still here, that’s it. No idea how to pass this issue.