Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by CyrinGames · Aug 17, 2020 at 08:54 PM · listsaveloadjson

Why is JSON not saving my Class?

I need to save a List of a class i made. The class is called HeroCard, so naturally i'll just go with heroCards for my List. I'll be saving...err, attempting to save this (preferably only this) to a JSON file. At present I have [Serializable] at the top of both my HeroCollection script (where i save it) and HeroCard...well, just above the class declaration.

This is from HeroCollection:

 private void LoadHeroesFromJsonFile() {
 
          // if file exist, read and load to heroCards
          if (File.Exists(path))
          {
              var inputString = File.ReadAllText(path);
              JsonUtility.FromJsonOverwrite(inputString, heroCards);
              
              if(heroCards.Count < 5)
              {
                  Debug.Log("Hero Cards weren't saved!");
                  CreateNewSave();
              }
          }
          else 
          {
              FileInfo file = new FileInfo(path);
              file.Directory.Create();
              CreateNewSave();
              
          }
          Debug.Log("Number of Hero Cards: " + heroCards.Count);
  
      }
  
      private void CreateNewSave()
      {
          for (int i = 0; i < 5; i++)
          {
              HeroCard hc = new HeroCard(1, 0, 1, firstHeroAssets[i]);
              hc.PopulateInfo();
              heroCards.Add(hc);
          }
      
          SaveHeroesToJsonFile();
      }



...What am I missing here? What is loaded is an empty HeroCard List and it Logs "Hero Cards weren't saved!"

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image highpockets · Aug 17, 2020 at 09:16 PM 0
Share

Are you trying to overwrite an existing file? Or are you trying To save a new one? From your question, you don’t mention overwriting, but your use of JsonUtility is for overwriting an existing instance of HeroCards with new values and not for creating a new instance. Creating a new instance would look like this:

 JsonUtility.FromJson<HeroCard>(jsonString);
avatar image Elango · Aug 17, 2020 at 09:30 PM 0
Share

"heroCards" is a list? Unfortunately Unity JSON does not support unstructured serialization. If you really need to serialize the list then try newtonsoft json or odin. Otherwise, follow the documentation https://docs.unity3d.com/$$anonymous$$anual/JSONSerialization.html

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Bunny83 · Aug 18, 2020 at 01:08 AM

As others have already mentioned in the comments above, Unity's JsonUtility does not support an array as the root element. The root element has to be an object. So just use a serializable wrapper class that holds your List of HeroCards

 [System.Serializable]
 public class Data
 {
     public List<HeroCard> cards;
 }

So you should serialize / deserialize this class instead. So your json text would look something like this:

 {
     "data": [
         {
             Your hero card fields
         },
         {
             Your hero card fields
         }
     ]
 }

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image CyrinGames · Aug 18, 2020 at 06:26 AM 0
Share

i see. i guess i misread something that said Lists were an exception to this rule/lacking capability...


That makes sense. I'll give it a go and be back to confirm I got it working

avatar image CyrinGames · Aug 18, 2020 at 07:49 AM 0
Share

ok, so this shows the right number of Hero Cards in the List in the GameData class i now save, but not the Hero Asset (ScripableObject) i have on a card. is it just because it's a scriptableobject? should i save the name instead and load from resources?

avatar image Bunny83 CyrinGames · Aug 18, 2020 at 04:52 PM 0
Share

ScriptableObjects are standalone assets. So they are not serialized in place. Unity's serialization system would usually serialize a reference to that referenced asset. However JSON does not support any kind of referencing.


It depends on what you actually want / need. If the scriptable objects are actual assets inside your project and you want to recover the references to them, you need to find a workaround. If you want to recreate them from the serialized data, you need a different approach.


In the first case, yes you need some way to actually reference your existing scriptable objects. This could be a unique name and using Resources.Load, or you could have a manager in your project that has a simple array with all items so you just have to find and store the index of the item in that array.


In the second case it gets a bit tricky. Since scriptable objects are seperate standalone assets they need to be serialized as such. Of course you could serialize each instance to json, put that string into another class or your list and serialize this collection. Of course the json strings would serialized as text in the outer json text. However this process can be reversed without issues. So when you deserialize the collection, you get a list of strings. You can then deserialize each of those strings to recreate all those scriptable objects and reassemble the original structure.

avatar image CyrinGames · Aug 18, 2020 at 04:18 PM 0
Share

actually, all it still saves are empty Lists inside the GameData object...

avatar image CyrinGames · Aug 18, 2020 at 04:31 PM 0
Share

I'm using a custom constructor when i create my HeroCard. even tho it's "saved", would i need to reconstruct my cards? if that's the case, i suppose i could save a List of strings for their names and Lists of ints for their levels, etc....just seems silly to have to go through all that

avatar image
0

Answer by CyrinGames · Aug 31, 2020 at 10:37 PM

I'm dumb. After fiddling with having several Lists containing each bit of info, i ran into a wall concerning my method of Loadiing. It relied on everything being in order and if something was removed from one, I'd have to remove the same index from each of the rest. The wall came from the way I load the saved Team by their IDs. Long story short, I went back to my research and found a detail I thought i'd missed, but i hadn't. However, it did lead me to the culprit.

I was creating a new List of HeroCards instead of saving the one i already had. It opened up the possibilities and I came up with some simple sh-tuff. I found the wonders of Dictionaries even more delightful than I had already. Though you can't save Dictionaries themselves, you can...can't remember the word they used...squash (i guess) them down to a List or Array. I'm partial to Lists, myself, and i'll explain how here in a minute. For the Dictionary I use an integer as the Key, the HeroCard's ID, and store the HeroCard itself to it.

Anyway, I "convert" this to a List of HeroCards when i save, and save the List in my GameInfo class. Here's some code. And i won't accept my own answer unless it gets a few points. Didnt realize accepting closed it to more answers.

 void SaveCardData()
     {
         HeroCollection.Instance.heroCards.Clear();
         
         for (int i = 0; i < collectionCap; i++)
         {
             if (HeroCollection.Instance.CollectionHeroCards.ContainsKey(i))
             {
                 HeroCollection.Instance.heroCards.Add(HeroCollection.Instance.CollectionHeroCards[i]);
                 Debug.Log("Added Card with ID " + i + " to saved Hero Cards");
                 if (HeroCollection.Instance.heroCards.Count == HeroCollection.Instance.CollectionHeroCards.Count)
                 {
                     Debug.Log("All Hero Cards have been added from the Dictionary. Breaking after " + (i + 1) + " iterations");
                     break;
                 }
             }
             else Debug.Log("No Hero Card with ID " + i + "was found");
 
         }
 
         HeroCards = HeroCollection.Instance.heroCards;
 
     }


Can't do that by the Count of the Dictionary, since there could be cards with IDs higher, so i went with the Collection Cap. Though cards may have higher IDs than the count, a new card will get the lowest missing ID.

Here's how I save, load, create, and delete the save files:
public void SaveDataToJsonFile() { SaveCardData();

         string jsonData = JsonUtility.ToJson(this, true);
         byte[] jsonByte = Encoding.ASCII.GetBytes(jsonData);
 
         try
         {
             File.WriteAllBytes(path, jsonByte);
             Debug.Log("Saved Data to: " + path.Replace("/", "\\"));
         }
         catch (Exception e)
         {
             Debug.LogWarning("Failed To Add PlayerInfo Data to: " + path.Replace("/", "\\"));
             Debug.LogWarning("Error: " + e.Message);
         }
     }
 
 private void LoadDataFromJsonFile()
     {
         // if file exist, read and load to heroCards
         if (!Directory.Exists(Path.GetDirectoryName(path)))
         {
             Directory.CreateDirectory(Path.GetDirectoryName(path));
             
         }
 
         if (!File.Exists(path))
         {
             Debug.Log("File does not exist");
             CreateNewSave();
         }
         else
         {
             byte[] jsonByte;
             try
             {
                 jsonByte = File.ReadAllBytes(path);
                 Debug.Log("Loaded Data from: " + path.Replace("/", "\\"));
             }
             catch (Exception e)
             {
                 Debug.LogWarning("Failed To Load Data from: " + path.Replace("/", "\\"));
                 Debug.LogWarning("Error: " + e.Message);
                 DeleteData();
                 return;
             }
 
             //Convert to json string
             string jsonData = Encoding.ASCII.GetString(jsonByte);
 
             JsonUtility.FromJsonOverwrite(jsonData, this);
 
             LoadCardData();
             LoadTeamData();
            
         }
 
     }
 
 void LoadCardData()
     {
         ///*
         for (int i = 0; i < HeroCards.Count; i++)
         {
             
             HeroCard newHeroCard = HeroCards[i];
             if(newHeroCard.cardID < 6)
             {
                 newHeroCard.cardLocked = true;
             }
             HeroCollection.Instance.heroCards.Add(newHeroCard);
             HeroCollection.Instance.CollectionHeroCards.Add(newHeroCard.cardID, newHeroCard);
         }
         //*/
         if (HeroCollection.Instance.heroCards.Count < 5)
         {
             Debug.Log("Hero Cards weren't saved!");
             CreateNewSave();
         }
                 
     }
 
 public void CreateNewSave()
     {
         for (int i = 0; i < 5; i++)
         {
             HeroCollection.Instance.SummonNewCard(HeroCollection.Instance.firstHeroAssets[i].name);
         }
 
         SaveDataToJsonFile();
     }
 
 public void DeleteData()
     {
         //Exit if Directory or File does not exist
         if (!Directory.Exists(Path.GetDirectoryName(path)))
         {
             Debug.LogWarning("Directory does not exist");
             return;
         }
 
         if (!File.Exists(path))
         {
             Debug.Log("File does not exist");
             return;
         }
 
         try
         {
             File.Delete(path);
             Debug.Log("Data deleted from: " + path.Replace("/", "\\"));
         }
         catch (Exception e)
         {
             Debug.LogWarning("Failed To Delete Data: " + e.Message);
         }
 
         UnityEngine.SceneManagement.SceneManager.LoadScene(0);
     }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image CyrinGames · Aug 31, 2020 at 03:48 AM 0
Share

Oh, and here's my path:
string path = Path.Combine(Application.persistentDataPath, "saved files", "game_data.txt");


I believe it is important to make this a .txt file and not a .json, at least for Android dev

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

143 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Saving/Loading class list with SimpleJSON,Saving class list with SimpleJSON 1 Answer

How i can PlayerPrefs List<>? 0 Answers

How to save and load `List myList`? 1 Answer

Save and Load Function 2 Answers

A node in a childnode? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges