- Home /
How to wait for a database result?
Hello everyone,
I guess I have a rather standard issue, but I do not figure out how to solve it.
The szenario is a racing game where at the moment the finish line is reached the following things shall happen:
Load previous highscores from the database
Do some magical calculation (check if new top highscore, etc.)
Save the new highscore list to the database
The problem I am facing right now is that 2 and 3 is done before I got the result from 1, hence I do not have the stored highscores yet before the rest is done.
So at the end I "simply" looking for a way to wait until loading the database is finished.
I tried different approaches with Coroutines and "yield return new WaitUntil" but non of it worked.
Here are the relevant parts of my code:
Class: HighscoreController
public void AddHighScore(string playerName, float time)
{
currentPlayerHighscore = new PlayerHighscore(playerName, time);
//LoadHighscores();
highscoresDB = FirebaseManagerGame.instance.LoadHighscoresOfLevel(levelInfo.LevelName);
Debug.LogWarning("HERE I HAVE TO WAIT UNTIL DATABASE RESULT IS THERE");
//reset values
newTopHighscore = false; inTop10 = false; notInTop10 = false;
[...] some magical calculation [...]
highscoresDB.Sort(SortByTime);
SaveHighscoresDB();
ShowHighScores();
}
Class: FirebaseManagerGame
public List<PlayerHighscore> LoadHighscoresOfLevel(string levelName)
{
Debug.Log("FireBaseGame - LoadHighscoresOfLevel START");
List<PlayerHighscore> tmpList = new List<PlayerHighscore>();
StartCoroutine(GetHighscoresOfLevel(levelName, returnValue =>
{
tmpList = returnValue;
}));
Debug.Log("LoadHighscoresOfLevel List.count: " + tmpList.Count);
return tmpList;
}
private IEnumerator GetHighscoresOfLevel(string levelName, System.Action<List<PlayerHighscore>> callback)
{
Debug.Log("FireBaseGame - getHighscoresOfLevel START");
List<PlayerHighscore> tmpHighscores = new List<PlayerHighscore>();
Task<DataSnapshot> DBTask = DBreference.Child("levelHighscores").Child(levelName).GetValueAsync();
yield return new WaitUntil(predicate: () => DBTask.IsCompleted);
if (DBTask.Exception != null)
{
Debug.LogWarning(message: $"Failed to register task with {DBTask.Exception}");
}
else if (DBTask.Result.Value == null) //No data exists yet
{
Debug.Log("getHighscoresOfLevel - NO DATA EXISTS");
}
else //Data has been retrieved
{
DataSnapshot snapshot = DBTask.Result;
tmpHighscores = JsonConvert.DeserializeObject<List<PlayerHighscore>>(snapshot.GetRawJsonValue());
Debug.Log("getHighscoresOfLevel - FOUND DATA - count: " + tmpHighscores.Count);
callback(tmpHighscores);
}
}
I hope you can help me to solve this issue.
Thanks in advance!
oetzi
Answer by XoetziX · Jan 20 at 04:07 PM
Here is the solution. The magic trick are 2 words: "yield return" which cause the method to wait until the database results returned. To be able to use these magic words I had to change the AddHighScore method into an IEnumerator.
public IEnumerator AddHighScore(string playerName, float time)
{
currentPlayerHighscore = new PlayerHighscore(playerName, time);
//IEnumerator cannot return any internal values / variables. Hence, the following way can be used:
//pass a place holder (= returnValue) to the IEnumerator. Within the IEnumerator this placeholder can be set to any value. Outside the Enumerator / here it can be further processed.
yield return StartCoroutine(FirebaseManagerGame.instance.GetHighscoresOfLevel(levelInfo.LevelName, returnValue =>
{
highscoresDB = returnValue;
}));
[...]