banner



How To Create Json File In Firebase

Search Unity

Unity ID

A Unity ID allows you to buy and/or subscribe to Unity products and services, shop in the Asset Store and participate in the Unity community.

  1. I have a class that saves two variables into an array. i have managed to send that json file to firebase and i can debug it to see its correct when i load the games database but i cannot set those variables to the game. the class is like this :
    1. public int lastUnlockedLevel = 0 ;
    2. public LevelItem[ ] levelItemArray;
    to save it to firebase i do this
    1. string levels = JsonUtility. ToJson (LevelSystemManager. Instance . LevelData ) ;
    2. reference. Child (data) . Child ( "Sets" ) . Child ( "Art" ) . SetValueAsync (levels) ;
    and i am trying to retrieve it and set those values (lastUnlocked , star achieved , unlocked and the levelItemArray) back to the game. my other variables like difficulty work fine with this :
    1. LevelSystemManager. Instance . Bundles . difficulty = int . Parse (snapshot. Child ( "Settings" ) . Child ( "Difficulty" ) . GetRawJsonValue ( ) ) ;
    but i cannot load the whole levelData class back to the game! any tips or help?
    when i was saving the json localy i was doing it like this to load the values
    1. string levelDataString = System.IO . File . ReadAllText (Application. persistentDataPath + "/LevelData.json" ) ;
    2. LevelData levelData = JsonUtility. FromJson <LevelData> (levelDataString) ;
    3.          LevelSystemManager. Instance . LevelData . levelItemArray = levelData. levelItemArray ;
    4.          LevelSystemManager. Instance . LevelData . lastUnlockedLevel = levelData. lastUnlockedLevel ;
    but this approach wont work with firebase

    EDIT :
    i did come close i think by doing this

    1. var json = snapshot. Child ( "Sets" ) . Child ( "Art" ) . GetRawJsonValue ( ) ;
    2. LevelData levelData = JsonUtility. FromJson <LevelData> (json) ;
    3. LevelSystemManager. Instance . LevelData . levelItemArray = levelData. levelItemArray ;
    4.                 LevelSystemManager. Instance . LevelData . lastUnlockedLevel = levelData. lastUnlockedLevel ;
    but this gives an error ArgumentException: JSON must represent an object type.

    The JSON that gets saved localy is this one

    1. { "lastUnlockedLevel" : 1,"levelItemArray" : [ { "unlocked" : true,"starAchieved" : 1 },{ "unlocked" : true,"starAchieved" : 0 },{ "unlocked" : false,"starAchieved" : 0 },{ "unlocked" : false,"starAchieved" : 0 },{ "unlocked" : false,"starAchieved" : 0 },{ "unlocked" : false,"starAchieved" : 0 },{ "unlocked" : false,"starAchieved" : 0 },{ "unlocked" : false,"starAchieved" : 0 },{ "unlocked" : false,"starAchieved" : 0 },{ "unlocked" : false,"starAchieved" : 0 } ] }
    and this is the one that gets saved on firebase
    1. "Art" : "{\"lastUnlockedLevel\":1,\"levelItemArray\":[{\"unlocked\":true,\"starAchieved\":3},{\"unlocked\":true,\"starAchieved\":0}]}"
    i did manage to break out of the error by this code, but this code even though it debugs the json it doesnt pass over to the levelData var
    1. string json = snapshot. Child ( "Sets" ) . Child ( "Art" ) . GetRawJsonValue ( ) ; // levelDataString
    2. LevelData levelData = JsonUtility. FromJson <LevelData> ( "{\"type\":" + json + "}" ) ; //(json); ////
    3. Debug. Log (levelData. lastUnlockedLevel ) ;
    As you can see i do have more classes saved there which like my difficulty example work just fine . my whole issue is that i cannot load back the entire LevelData Class and set it to the games variables.Thank you!
    Last edited: Apr 24, 2021
  2. bumping it just in case!!
  3. You need to add more information.

    The very first question to answer is whether your data shows up in the database at all.
    Reason I'm asking is because you're using Unity's JsonUtility, which by default does not serialize plain C# types if they are not marked with the attribute System.Serializable. You've done that with your LevelData class, but you did not add the attribute to the LevelItem type. Hence the JSON it generates would not contain the array at all.
    The consequence would be that you push LevelData without the level item information to the database, so it wouldn't even exist when you try to query it.

    You can quickly see the effect by exposing your LevelData in the editor. It won't show the array of the level items, except when the attribute is added to LevelItem as well. That's the quick way to see what Unity's JsonUtility will be able to serialize and thus what you'll push to the db.

    There are better json serializers, for instance this asset. It behaves differently than the Unity's utility, but it'll probably be the better choice as it also handles common data structures reliably.

    Last edited: Apr 24, 2021
  4. thank you for the reply , yes it seems it got lost on copying the code, both classes are serializable , the json send to firebase is correct and i can debug it just fine (Debug.Log(json) but as it is if i do Debug.Log(levelData.lastUnlockedLevel) it returns 0 and if i do the array it returns null

    edit :

    1. string json = snapshot. Child ( "Sets" ) . Child ( "Art" ) . GetRawJsonValue ( ) ; // levelDataString
    2.     LevelData levelData = JsonUtility. FromJson <LevelData> ( "{\"type\":" + json + "}" ) ; //(json); ////
    3. //LevelSystemManager.instance.LevelData.levelItemArray = levelData.levelItemArray;
    4.      Debug. Log (levelData. lastUnlockedLevel ) ;
    this part here as ive come so far debugs the json just fine in the console but i dont see the value of lastUnlockedLevel and as i said the array returns null
  5. What's this:
    1. LevelData levelData = JsonUtility. FromJson <LevelData> ( "{\"type\":" + json + "}" ) ; //(json); ////
    supposed to do? The json that you pass in won't fit your data structure. It should simply take the json string, just like it's written in the part that you commented out (at the end of that line):
    1. LevelData levelData = JsonUtility. FromJson <LevelData> (json) ;
  6. i did it like this which i found in a stack overflow thread because if i just use
    1. LevelData levelData = JsonUtility. FromJson <LevelData> (json) ;
    like i was doing i get this error here
    1. ArgumentException: JSON must represent an object type.
    2. UnityEngine . JsonUtility . FromJson ( System . String json, System . Type type) (at <1386288601af43018501cce2912f52f4>: 0 )
    3. UnityEngine. JsonUtility . FromJson [T] ( System . String json) (at <1386288601af43018501cce2912f52f4>: 0 )
    4. LevelUnlockSystem. SaveLoadData +<LoadFB>d__23. MoveNext ( ) (at Assets/Scripts/SaveLoad/SaveLoadData. cs : 151 )
    5. UnityEngine. SetupCoroutine . InvokeMoveNext ( System.Collections . IEnumerator enumerator, System . IntPtr returnValueAddress) (at <e5b75411c8cd4bfaa9e760be20206f29>: 0 )
    whereas with the one i used now i get this in the console
    1. "{\"lastUnlockedLevel\":2,\"levelItemArray\":[{\"unlocked\":true,\"starAchieved\":1},{\"unlocked\":false,\"starAchieved\":1}]}"
    2. UnityEngine. Debug :Log( Object )
    3. LevelUnlockSystem.<LoadFB>d__23:MoveNext( ) (at Assets/Scripts/SaveLoad/SaveLoadData. cs : 152 )
    4. UnityEngine. SetupCoroutine :InvokeMoveNext(IEnumerator, IntPtr)
    edit again , also i did update my opening post with more info, thanks!
  7. Please post what's logged to the console when you log the json. The one that you get when you read from the snapshot.
    It could be a malformed json (not sure if the realtime database would even care about it or just use it as a string instead) or an issue with Unity's Jsonutility... you know, it's sort of special and not as flexible / solid like one would expect.

    Again, you've checked that it shows up correctly in the firebase dev console? It should be a nested structure, not a plain string or anything like that.

  8. i did maybe you missed it. if i log the snapshot json i get the json as it should be
    1. "{\"lastUnlockedLevel\":2,\"levelItemArray\":[{\"unlocked\":true,\"starAchieved\":1},{\"unlocked\":false,\"starAchieved\":1}]}"
    if i debug the snapshot in case that is what you mean then its this
    1. DataSnapshot { key = User, value = System.Collections . Generic . Dictionary`2 [ System . String,System . Object ] }
    and this is directly from firebase
    1. "Art" : "{\"lastUnlockedLevel\":2,\"levelItemArray\":[{\"unlocked\":true,\"starAchieved\":1},{\"unlocked\":false,\"starAchieved\":1}]}"
  9. and to show you both my save and load functions here they are :
    Save
    1. public string saveDataToFirebase( string data)
    2. string levels = JsonUtility. ToJson (LevelSystemManager. Instance . LevelData ) ;
    3.             reference. Child (data) . Child ( "Sets" ) . Child ( "Art" ) . SetValueAsync (levels) ;
    4.             reference. Child (data) . Child ( "Purchases" ) . Child ( "animalSet" ) . SetValueAsync (LevelSystemManager. Instance . Bundles . animalSet ) ;
    5.             reference. Child (data) . Child ( "Purchases" ) . Child ( "architecture" ) . SetValueAsync (LevelSystemManager. Instance . Bundles . architectureSet ) ;
    6.             reference. Child (data) . Child ( "Purchases" ) . Child ( "technology" ) . SetValueAsync (LevelSystemManager. Instance . Bundles . technologySet ) ;
    7.             reference. Child (data) . Child ( "Purchases" ) . Child ( "vehicles" ) . SetValueAsync (LevelSystemManager. Instance . Bundles . vehiclesSet ) ;
    8.             reference. Child (data) . Child ( "Purchases" ) . Child ( "nature" ) . SetValueAsync (LevelSystemManager. Instance . Bundles . natureSet ) ;
    9.             reference. Child (data) . Child ( "Purchases" ) . Child ( "allsets" ) . SetValueAsync (LevelSystemManager. Instance . Bundles . allSets ) ;
    10.             reference. Child (data) . Child ( "Purchases" ) . Child ( "noAds" ) . SetValueAsync (LevelSystemManager. Instance . Bundles . noAds ) ;
    11.             reference. Child (data) . Child ( "Settings" ) . Child ( "Difficulty" ) . SetValueAsync (LevelSystemManager. Instance . Bundles . difficulty ) ;
    12.             Debug. Log ( "Save to firebase" ) ;
    13. return "Save data to firebase Done." ;
    and Load
    1. public IEnumerator LoadFB( string userId)
    2. var task = reference. Child (userId) . GetValueAsync ( ) ;
    3. yield return new WaitUntil(predicate: ( ) => task. IsCompleted ) ;
    4.                 Debug. LogError (task. Exception ) ;
    5.                 Debug. Log ( "firebase faulted" ) ;
    6. else if (task. Result . Value == null )
    7.                 DataSnapshot snapshot = task. Result ;
    8. string json = snapshot. Child ( "Sets" ) . Child ( "Art" ) . GetRawJsonValue ( ) ; // levelDataString
    9.                 LevelData levelData = JsonUtility. FromJson <LevelData> ( "{\"LevelData\":" + json + "}" ) ; //(json); ////
    10.                     levelData. levelItemArray = LevelSystemManager. Instance . LevelData . levelItemArray ;
    11.                     levelData. lastUnlockedLevel = LevelSystemManager. Instance . LevelData . lastUnlockedLevel ;
    12.                 LevelSystemManager. Instance . Bundles . difficulty = int . Parse (snapshot. Child ( "Settings" ) . Child ( "Difficulty" ) . GetRawJsonValue ( ) ) ;
    13.                 LevelSystemManager. Instance . Bundles . noAds = int . Parse (snapshot. Child ( "Purchases" ) . Child ( "noAds" ) . GetRawJsonValue ( ) ) ;
    14.                 LevelSystemManager. Instance . Bundles . allSets = int . Parse (snapshot. Child ( "Purchases" ) . Child ( "allsets" ) . GetRawJsonValue ( ) ) ;
    15.                 LevelSystemManager. Instance . Bundles . animalSet = int . Parse (snapshot. Child ( "Purchases" ) . Child ( "animalSet" ) . GetRawJsonValue ( ) ) ;
    16.                 LevelSystemManager. Instance . Bundles . architectureSet = int . Parse (snapshot. Child ( "Purchases" ) . Child ( "architecture" ) . GetRawJsonValue ( ) ) ;
    17.                 LevelSystemManager. Instance . Bundles . technologySet = int . Parse (snapshot. Child ( "Purchases" ) . Child ( "technology" ) . GetRawJsonValue ( ) ) ;
    18.                 LevelSystemManager. Instance . Bundles . vehiclesSet = int . Parse (snapshot. Child ( "Purchases" ) . Child ( "vehicles" ) . GetRawJsonValue ( ) ) ;
    19.                 LevelSystemManager. Instance . Bundles . natureSet = int . Parse (snapshot. Child ( "Purchases" ) . Child ( "nature" ) . GetRawJsonValue ( ) ) ;
  10. Yes sorry, missed that edit.

    Looks correct though.

    Let's start all over...

    Have you already tried to deserialize the response value directly?

    1. LevelData data = JsonUtility. FromJson <LevelData> ( "{\"lastUnlockedLevel\":2,\"levelItemArray\":[{\"unlocked\":true,\"starAchieved\":1},{\"unlocked\":false,\"starAchieved\":1}]}" ) ;
    That should work. If it works, it should definitely work when you get that exact value from the snapshot. If it doesn't, well... then there's something fishy going on.

    The "fix" that you got from StackOverflow is for an issue with Unity's utility implementation. It does not (or did not) like arrays as root objects. However, you don't use an array as root object here, so that shouldn't be the problem and that change won't do anything but make your program "fail" to deserialize your value (it doesn't actually fail but just won't find the key/value pairs and that's why you get default values).

  11. well i didnt think of that but now that i did try it nothing happens, and i mean that since i can check those variables in the inspector i can see my other stats go back to the way they were saved but my array wont change nor does my level Unlocked . In the console now i do get the array back like this LevelUnlockSystem.LevelItemArray[] instead of null and i can still read the json as it is. And yes it is strange since that was the way i was loading when i had the json locally and it worked fine!

    also since the levels wont always be the same since i can set the array through the inspector it would really help if it worked properly!! each level holds a bool and and an int, for unlocked and the stars achieved so i need those values too!

  12. Perhaps that's not what you wanted:
    1.         levelData. levelItemArray = LevelSystemManager. Instance . LevelData . levelItemArray ;
    2.         levelData. lastUnlockedLevel = LevelSystemManager. Instance . LevelData . lastUnlockedLevel ;
    I could imagine you want the assignment to happen the other way 'round?

    That's part of your load method, you basically take whatever is currently set in your app and assign it to the local instance of the LevelData instance, which you just queried from the database... Talking about loading, you probably wanna take whatever you received from the database and assign it to LevelSystemManager.Instance.LevelData ... otherwise that part wouldn't make a alot of sense.

  13. ohhhh
    1. string json = snapshot. Child ( "Sets" ) . Child ( "Art" ) . GetRawJsonValue ( ) ; // levelDataString
    2. LevelData levelData = JsonUtility. FromJson <LevelData> ( "{\"lastUnlockedLevel\":1,\"levelItemArray\":[{\"unlocked\":true,\"starAchieved\":1},{\"unlocked\":false,\"starAchieved\":1}]}" ) ; //(json); ////
    3.  Debug. Log (levelData. levelItemArray ) ;
    4.  LevelSystemManager. Instance . LevelData . levelItemArray = levelData. levelItemArray ;
    5. LevelSystemManager. Instance . LevelData . lastUnlockedLevel = levelData. lastUnlockedLevel ;
    this works!
    yeah i just saw it to be honest! i had the the other way around. and ok great so far but why isnt it working like it should?!!
  14. and sure enough if i set json back as the string i get the error about the JSON must represent an object type.
    another thing if i may and yeah thank you for the help!! , if i change the child to just one of them
    1. string json = snapshot. Child ( "Sets" ) . GetRawJsonValue ( ) ; // levelDataString
    2. LevelData levelData = JsonUtility. FromJson <LevelData> (json) ;
    3. Debug. Log (levelData. levelItemArray ) ;
    4. LevelSystemManager. Instance . LevelData . levelItemArray = levelData. levelItemArray ;
    5.  LevelSystemManager. Instance . LevelData . lastUnlockedLevel = levelData. lastUnlockedLevel ;
    it doesn't throw an error but it also doesn't update my variables

    also this is what the console shows when using just the first child

    1. { "Art" : "{\"lastUnlockedLevel\":1,\"levelItemArray\":[{\"unlocked\":true,\"starAchieved\":1},{\"unlocked\":false,\"starAchieved\":1}]}" }
    its like it either expecting another child after the "Art" or because of the way it reads it , it cant get those values out? i have no idea but since the stars and levels will be updated while playing i have to figure out a way to make that json dynamic each time..pfff
    Last edited: Apr 24, 2021
  15. Great!

    Side note... s

    The issue in this case is that the json does no longer match your data structure, because your LevelData representation is now the value for the key "Art". The serializer looks at your LevelData type and everything that it consists of. However, it does not just attempt to find the data somewhere in the nested structure, but rather tries to map it directly starting at the root.

    1. { "unlocked" : true, "starAchieved" : 1 },
    2. { "unlocked" : false, "starAchieved" : 1 }

    As you can see, the root object only has the field "Art", there's neither 'lastUnlockedLevel' nor 'levelItemArray' at the same level. Instead, these fields are part of the object that serves as the value for "Art".

    You could add a type (class or struct, wouldn't matter for serialization purposes in this particular case) that matches that exact nested layout:

    1. public class <choose a name> // based on your database, this could be "Sets"
    Probably not worth it though.
    Last edited: Apr 25, 2021

  16. so what should i do?? any ideas?! i mean you can understand i wont be able to save and load the data like this and the game wont be playable.

    IS there any way i can structure my class without affecting the rest of the level mechanics?

    i mean if i use this tool to convert it , it seems to be ok like my class is right?

    1. // Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
    2. public class LevelItemArray
    3. public bool unlocked { get ; set ; }
    4. public int starAchieved { get ; set ; }
    5. public int lastUnlockedLevel { get ; set ; }
    6. public List<LevelItemArray> levelItemArray { get ; set ; }
    now i did try it like this before but i had an issue in another class because i made the levelItemArray into a list
    1.  LevelItemArray[ ] levelItemsArray = LevelSystemManager. Instance . LevelData . levelItemArray ; // in this part here i get  error CS0029: Cannot implicitly convert type 'System.Collections.Generic.List<LevelUnlockSystem.LevelItemArray>' to 'LevelUnlockSystem.LevelItemArray[]'
    2. for ( int i = 0 ; i < levelItemsArray. Length ; i++ )
    3. if (i % buttonsPerPage == 0 )
    4.   currentPage = page. AddPageUsingTemplate ( ) . transform ;
    5. currentPage. tag = ( "pages" ) ;
    6.  LevelButtonScript levelButton = Instantiate(levelBtnPrefab, currentPage) ;
    7.  levelButton. SetLevelButton (levelItemsArray[i], i, i == LevelSystemManager. Instance . LevelData . lastUnlockedLevel ) ;
    Last edited: Apr 25, 2021
  17. I'm confused and not sure if you've understood what I was trying to explain.

    You do neither need to rename your class LevelData to Root nor do you need to rename LevelItem to LevelItemArray.

    It was all fine except that you now wanted to read the data from the parent node.
    You cannot just expect the serializer to find your data somewhere in a json. If you read the raw json of node "Sets", you'll need a data type like the one I posted earlier, which has a field "Art" of type "LevelData" or anything that"s structured like it.

    I said "probably not worth it" because you could just read the data like you did before... Child("Sets").Child("Art").Read....
    If you want to read Child("Sets") instead, use an extra type like the one I posted.

  18. I did not read every post here but I'd like to point out that the json you provided does contain escaped json in another json structure. So your inner json is just an escaped string value. I'm just wondering, do you use two different json serializers at once? This is the main issue here:I haven't really used firebase, so I'm not sure what that "reference" actually represents. However since it clearly represents your "outer" json data, it's either another seperate json serializer or just a built in json serializer of firebase.

    (edit: It's integrated in the firebase framework ^^)

    When you copy your complete json to jsonLint and click validate it will tell you that it's valid json, however the content of the "Art" key is just an ordinary string. So you have a quite convoluted construct here. The main issue is that as your inner json is serialized twice, it need to be deserialized twice. You kinda do that but you also throw in another serialize ^^.

    Let me explain that last sentence. The Firebase framework can already seriaiize and deserialize json. When you read the result of "GetRawJsonValue" it will actually serialize that json node back to a json string. However since your "set" this node as a string (you used SetValueAsync) it will return the json representation of that string. That means it includes the quotes around your json string. Of course "SetValueAsync" and "GetRawJsonValue" do not work together. They do different things. You essentially have two options here:

    First you can keep your double encoding if you really want to and replace your

                            xxx.GetRawJsonValue                      
    for
                            (string)xxx.GetValue                      
    to get your excaped json back out.

    However the second solution, which is probably the more clean solution, is to use

                            SetRawJsonValueAsync                      
    instead of
                            SetValueAsync                      
    and keep your "GetRawJsonValue". This also isn't super nice since we still use two serializers, the one that comes with firebase and Unity's JsonUtility. However the resulting json that is saved in your database would be a proper json object tree whilch would look something like that instead:(This has been formatted by jsonLint)
    As you can see the "Art" key now actually contains a json object and not a string that contains an escaped json object. Of course that means the deserialization when using "GetRawJsonValue" would look like this:
    1. get the raw json from the server.
    2. firebase is deserializing the whole json string into it's own object structure.
    3. We use GetRawJsonValue which will again serialize that subtree to a json string
    4. We now deserialize that json string again using JsonUtility
    I would suggest you do not mix json serializers. If the firebase object representation is to cumbersome to work with, you should represent all your json with objects and use the JsonUtility (or a different json serializer) for everything and just pass the result to the firebase API. Though I just glanced over the documentation that I quickly googled and as I said I did never really use firebase myself.
  19. Nice catch @Bunny83.

    I should stop assisting at night. :D

  20. wow i cant thank you enough for this!!!

    load funtion

    1. string json = snapshot. Child ( "Sets" ) . Child ( "Art" ) . GetRawJsonValue ( ) ; // levelDataString
    2. LevelData levelData = JsonUtility. FromJson <LevelData> (json) ;
    3. LevelSystemManager. Instance . LevelData . lastUnlockedLevel = levelData. lastUnlockedLevel ;
    4. LevelSystemManager. Instance . LevelData . levelItemArray = levelData. levelItemArray ;
    and my save function
    1. string levels = JsonUtility. ToJson (LevelSystemManager. Instance . LevelData ) ;
    2. reference. Child (data) . Child ( "Sets" ) . Child ( "Art" ) . SetRawJsonValueAsync (levels) ;
    this works great so far!! saving and loading! i just left the other values as they were since they worked anyway!

    and this is the generated json from firebase!

    thank you both!! thank you very much!!

How To Create Json File In Firebase

Source: https://forum.unity.com/threads/loading-a-json-from-firebase.1098511/

Posted by: burtonegary1949.blogspot.com

0 Response to "How To Create Json File In Firebase"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel