How to load a scene when it completes getting data from firebase? - c#

there are two scenes in my game.
first one is "main Scene" and second one is "user Data Scene".
in "user data scene" I am retrieving current user data from firebase.
The problem is when I switch to "user data scene" from "main scene" there are no data for few seconds until its retrieved from firebase. it looks very bad to me.
All I want is when user is on "main scene" and try to open "user data scene" it should be not active until retrieving data from firebase is done.
I attached the script that gets data from firebase to the main scene's empty object which does not destroy on load. and calling it in start function of the "user data scene".
I am calling below function in start function of "user data scene".
I want to wait until data is loaded from firebase and value is attached to text objects before activating the "user data scene" ?
public IEnumerator getUserDataFromDb(Text userNameTxt, Text totalDiamondTxt, Text totalGoldText) //get data from database of diamond and how much diamond has been sold
{
userNameTxt.text = FirebaseAuth.DefaultInstance.CurrentUser.DisplayName;
var getDbTask = FirebaseDatabase.DefaultInstance.GetReference("Users").Child(FirebaseAuth.DefaultInstance.CurrentUser.UserId).GetValueAsync();
yield return new WaitUntil(predicate: () => getDbTask.IsCompleted);
if (getDbTask.Exception != null)
{
Debug.LogWarning(getDbTask.Exception.InnerExceptions[0].InnerException.Message);
}
else
{
DataSnapshot snapshot = getDbTask.Result;
totalDiamondTxt.text = snapshot.Child("Sell").Child("Total").Child("TotalDiamond").Value.ToString();
int dbDiamondValue = int.Parse(snapshot.Child("Sell").Child("Total").Child("TotalDiamond").Value.ToString());
totalGoldText.text = snapshot.Child("Sell").Child("Total").Child("TotalGold").Value.ToString();
int dbGoldValue = int.Parse(snapshot.Child("Sell").Child("Total").Child("TotalGold").Value.ToString());
}
}

Maybe something like this:
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => {
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available) {
db = Firebase.Firestore.FirebaseFirestore.DefaultInstance;
//use your data and load your secene after
DocumentReference docRef =
db.Collection("yourCollection").Document("yourDocumentCode");
docRef.GetSnapshotAsync().ContinueWithOnMainThread(task => {
DocumentSnapshot snapshot = task.Result;
if (snapshot.Exists) {
//do you stuff here after retrieving the info
} else {
Debug.Log(String.Format("Document {0} does not exist!", snapshot.Id));
}
});
} else {
UnityEngine.Debug.LogError(System.String.Format("Could not resolve all Firebase dependencies: {0}", dependencyStatus));
// Firebase Unity SDK is not safe to use here.
}
});
Need that for the specific use of firestore, but you got a similar snippet in the documentation so that right after you do whatever you need with the firebase services you move on executing your app.

Related

System.Collections.Generic.Dictionary '2 { Firebase Realtime Database } - Error

I learning how to use Firebase Realtime Database with unity games...
in Sending data from the game to the database and get the data to the game from the database...
send data work good.
but I have a problem getting data from the database...
the output of the sss (the text that the result will show in) should be 4... the same value in the database... but it shows:(System.Collections.Generic.Dictionary`2[System.String,System.Object])
is there any solution for this?
here is a code on C# to get the data:
private IEnumerator LoadUserData()
{
var DBTask = dbRefence.Child("GameReview").GetValueAsync();
yield return new WaitUntil(predicate: () => DBTask.IsCompleted);
DataSnapshot snapshot = DBTask.Result;
sss.text = snapshot.Value.ToString();
}

Unity Firebase SignInAnonymously sometimes works and sometimes not

I have an issue with signing in anonymously into my Firebase database for my Unity game. I have a method for signing anonymously into the database and another one that reads the database and prints a json string.
public IEnumerator anonymousSignIn()
{
var register = auth.SignInAnonymouslyAsync();
yield return new WaitUntil(predicate: ()=> register.IsCompleted);
}
public IEnumerator readDatabase()
{
var DBTask = DBreference.Child("users").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)
{
Debug.LogWarning("No data found in the database");
}
else
{
DataSnapshot snapshot = DBTask.Result;
string json = snapshot.GetRawJsonValue();
Debug.Log(json);
}
}
I then call these functions via a button in my Unity games using the method:
public void readButton()
{
StartCoroutine(anonymousSign());
StartCoroutine(readDatabase());
}
However, this sometimes works and other times It says permission denied and I don't understand why.
My database rules for reading are: ".read": "auth != null",
I got the same error.
After that, I changed the code
From:
Auth.SignInAnonymouslyAsync().ContinueWith(task => { SignInAnonymously(task, "Guest"); });
To:
Auth.SignInAnonymouslyAsync().ContinueWithOnMainThread(task => { SignInAnonymously(task, "Guest"); });
Don't use Async for Anonymous Sign In, but run on Main Thread.
It worked for me!

Why does my app crash when a button is clicked?

I am trying to make a friends function into my Unity game. Each friend will have their own line with their name and a few buttons (challenge, about, etc.).
I have a friend row prefab and I instantiate it into the parent list for each friend.
It works just fine, until I click the challenge button, which whould call a method that takes in two parameters: the UId of the friend, and their username (two strings).
I am using Firebase Realtime Database for database.
void RetrieveFriendList(object sender, ValueChangedEventArgs args) {
foreach(Transform childTransform in listParent.GetComponentInChildren<Transform>()) {
GameObject.Destroy(childTransform.gameObject);
}
friends.Clear();
foreach (DataSnapshot s in args.Snapshot.Children) {
friends.Add(s.Key);
GameObject newRow = Instantiate(friendRowPrefab);
newRow.transform.Find("Deny").gameObject.GetComponent<Button>().onClick.RemoveAllListeners();
newRow.transform.Find("Challenge").gameObject.GetComponent<Button>().onClick.RemoveAllListeners();
newRow.transform.SetParent(listParent.transform);
newRow.transform.localScale = new Vector3(1f, 1f, 1f);
newRow.transform.Find("Text_Name").gameObject.GetComponent<TMPro.TMP_Text>().text = s.Child("username").Value.ToString();
string retrievedStatus = s.Child("type").Value.ToString();
if (retrievedStatus == "sent") {
newRow.transform.Find("Status").gameObject.GetComponent<TMPro.TMP_Text>().text = "Friend request sent";
} else if (retrievedStatus == "request") {
newRow.transform.Find("Status").gameObject.GetComponent<TMPro.TMP_Text>().text = "Incoming friend request";
newRow.transform.Find("Accept").gameObject.SetActive(true);
newRow.transform.Find("Deny").gameObject.SetActive(true);
newRow.transform.Find("Accept").gameObject.GetComponent<Button>().onClick.AddListener(delegate { AcceptFriendRequest(s.Key); });
newRow.transform.Find("Deny").gameObject.GetComponent<Button>().onClick.AddListener(delegate { DenyFriendRequest(s.Key); });
} else if (retrievedStatus == "friends") {
newRow.transform.Find("Challenge").gameObject.SetActive(true);
Debug.Log(s.Key + " - " + s.Child("username").Value.ToString());
newRow.transform.Find("Challenge").gameObject.GetComponent<Button>().onClick.AddListener(delegate { ChallengeFriend(s.Key, s.Child("username").Value.ToString()); }); //this is the line that causes the crash
newRow.transform.Find("About").gameObject.SetActive(true);
newRow.transform.Find("Status").gameObject.SetActive(false);
}
}
FirebaseDatabase.DefaultInstance.GetReference("users").Child(auth.CurrentUser.UserId).Child("friends").ValueChanged -= RetrieveFriendList;
}
What's likely happening is that the underlying C++ representation of your database snapshot is being cleaned up before your button accesses it. See this bug.
The easiest thing to do would be to find this line:
newRow.transform.Find("Challenge").gameObject.GetComponent<Button>().onClick.AddListener(delegate { ChallengeFriend(s.Key, s.Child("username").Value.ToString()); }); //this is the line that causes the crash
and turn it into something like:
var challengeKey = s.Key;
var challengeUsername = s.Child("username").Value.ToString();
newRow.transform.Find("Challenge").gameObject.GetComponent<Button>().onClick.AddListener(delegate { ChallengeFriend(challengeKey, challengeUsername); });
This way you retrieve the values you need (key and username) at the time of the callback rather than in the context of the button click (at some arbitrary point in the future after this function has returned). If you still get a crash, you may have to .Clone or .CopyTo the data -- but I believe that once an object is retrieved from the underlying snapshot it should be a full on C# object obeying the expected C# GC rules.
You also may experience null reference exceptions if the snapshot hits a local cache first -- so make sure you have null checks around everything (generally a good practice whenever you're hitting the web).

Unity Firebase Authentication CreateUserWithEmailAndPasswordAsync returns empty UserID

When I run CreateUserWithEmailAndPasswordAsync() the task returns as IsCompleted and the FirebaseUser is also not null, but the UserID and email are null/empty. I can see the new user (with UserID) in the firebase console.
The same thing happens when trying to SignInWithEmailAndPasswordAsync() with the newly created User. But when I SignInWithEmailAndPasswordAsync() with an older user account everything works fine.
It's strange because it is the same code I used a year ago. In the mean time I did update the Firebase SDK to 7.0.2. Could that be the cause of the issue?
Here is my code for creating a new user:
public static async Task<CallbackMessage> RegisterNewUser(string email, string password)
{
CallbackMessage callback = new CallbackMessage();
callback.isSuccess = false;
if (!await DatabaseManager.CheckConnection())
{
callback.notConnected = true;
return callback;
}
return await auth.CreateUserWithEmailAndPasswordAsync(email, password).ContinueWith(task =>
{
if (task.IsCanceled)
{
callback.errorMessage = "Create User was canceled";
}
else if (task.IsFaulted)
{
callback.errorMessage = GetErrorMessage(task.Exception);
}
else if (task.IsCompleted)
{
FirebaseUser newUser = task.Result;
Debug.Log("User created succesfully! userID: " + newUser.UserId);
callback.userID = newUser.UserId;
callback.email = newUser.Email;
callback.isSuccess = true;
}
CleanTask(task);
return callback;
});
}
Could really use a nudge in the right direction on this one :)
I was able to solve it. Apologies for doubting the Firebase Auth service.
In my AuthStateChanged code I added a Signout() whenever a user signed in, but wasn't emailVerified yet. That's where the problem was.
My guess what happened: When user creation is called it signs the user in immediately, then goes to Firebase to set things up there. In the mean time I sign out the user because it's not email verified. When the callback comes back it looks for the FirebaseUser that it signed in before going to Firebase, but finds nothing.
Something like pulling the chair from underneath someone as he's about to sit :P

How to download data from Firebase?

I'm attempting to retrieve some data from a Firebase database. I've been able to do it fine in the past, but there's something wrong with my GetValueAsync() code below. When debugging it gets stuck at the "await reference.Database" line, but I'm not sure what I'm doing wrong. When running without debugging, none of the information is ever retrieved.
I'm uncertain if the problem is with the path, or the await/async function. Debugging shows that loggedUserId is storing the value before referencing it in the next line, but the rest of the function never completes or faults. The application compiles but I'm never able to capture any info from the snapshot.
The format of my database is "users" -> 78cVqzA8qNTNigsao3VvdnM0Qol2 (Which is correct) -> (several data pairs such as level : 1, lives : 3, etc)
public static async void GetUserData()
{
FirebaseApp app = FirebaseApp.DefaultInstance;
app.SetEditorDatabaseUrl("https://narwhaltrivia.firebaseio.com/");
if (app.Options.DatabaseUrl != null) app.SetEditorDatabaseUrl(app.Options.DatabaseUrl);
DatabaseReference reference = Firebase.Database.FirebaseDatabase.DefaultInstance.RootReference;
loggedUserId = FirebaseAuth.DefaultInstance.CurrentUser.UserId;
await reference.Database.GetReference("users").Child(loggedUserId).GetValueAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
Debug.LogError("Error retrieving user data");
return;
}
if (task.IsCompleted)
{
DataSnapshot userSnapshot = task.Result;
loggedEmail = userSnapshot.Child("email").GetRawJsonValue();
loggedCurrentScore = userSnapshot.Child("currentScore").GetRawJsonValue();
loggedLevel = userSnapshot.Child("level").GetRawJsonValue();
loggedLives = userSnapshot.Child("lives").GetRawJsonValue();
loggedRound = userSnapshot.Child("round").GetRawJsonValue();
loggedTotalScore = userSnapshot.Child("totalScore").GetRawJsonValue();
return;
}
});
}

Categories