• 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 MehruneD · Jul 05 at 04:15 PM · serializationscriptable object

How to serialize a scriptable object?

Hello, I'm trying to make a save system in my deck building game, and I'm having trouble saving the player's deck because it is a list of "Cards" which are scriptable objects. Here's the save script:

 using UnityEngine;
 using System.IO;
 using System.Runtime.Serialization.Formatters.Binary;
 
 public static class SaveSystem 
 {
 
     public static void SaveDeck(Deck deck) 
     {
         BinaryFormatter binaryFormatter = new BinaryFormatter();
         string path = Application.persistentDataPath + "/deck.data";
         FileStream stream = new FileStream(path, FileMode.Create);
 
         PlayerData data = new PlayerData(deck);
 
         binaryFormatter.Serialize(stream, data);
         stream.Close();
     }
 }

I receive the error SerializationException: Type 'UnityEngine.ScriptableObject' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. on the binaryFormatter.Serialize(stream, data); line. After some research, I tried making a separate SaveDeck class in order to try to implement a copy constructor, but I don't understand copy constructors very well, so I couldn't get it to work. Does anyone have a suggestion for how to fix the error, or can someone give details on how to implement a copy constructor? In case it's helpful, here's the PlayerData that this script is pulling from:

 [System.Serializable]
 public class PlayerData
 {
     public Card[] playerDeck; //the Card is the scriptable object, here I made it an array because a list was giving problems
     
     public int deckIndex;
 
     public PlayerData (Deck deck)
     {
         playerDeck = new Card[deck.GetDeckCards().Count];
 
         for (int i = 0; i < deck.GetDeckCards().Count; i++)
         {
             playerDeck[i] = deck.GetDeckCards()[i];
         }
 
         deckIndex = deck.GetCurrentDeckIndex();
     }
 }

Thank you for taking a look.

Comment
Add comment
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

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Captain_Pineapple · Jul 05 at 04:30 PM

Hey there,

i suggest you check out this thread on stackoverflow. Apparently Unitys internal JSON-Utility is able to parse Scriptable objects into jsonstrings which in return can be fed to a binary formatter.



Other (not so nice solutions) that you could try if number one above fails:


Regarding the copy constructor this is just a fancy name for: "Your class "X" has a seperate constructor which does not take a set of some values but instead an object of type "X" and uses that objects values to initialize the new object" -> hence it copys the given object. But since the type of the class is the same this concept will not really help you here.


What instead could be done here (but is not really recommendable as this overcomplicates things) is that you create a second class "Serializable_Card" which is basically identical regarding the member variables of "Card". Only difference: "Serializable_Card" would not inherit from ScriptableObject but would just be marked as "Serializable". At this point you could then create a Constructor for "Serializable_Card" which takes a "Card" and then copys all values.


Also thinkable (but not really nice, please try the JSON solution) would be something like this:

 public class Card : ScriptableObject
 {
        public SerializableCard values;
 }
 
 [System.Serializable]
 public class SerializableCard {
       int id;
       string name;
       //yaddayadda more values go here
 }

Not really sure if this structure would work but in the end you could then make your Scriptable Object contain a SerializableStructure of the actual values which make up a card. (Not tested but should work)



Hope this helps, let me know if something is unclear or if you need more help.

Comment
Add comment · Show 8 · 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 MehruneD · Jul 05 at 04:44 PM 0
Share

Thank you for the suggestions, I'll start by looking into the JSON options!

avatar image MehruneD · Jul 05 at 08:07 PM 0
Share

So I've made some progress with JSON and have saving/loading working as long as I don't stop the game, but when I stop and then restart the game and try to LoadData(), then all the Card objects that I try to reference suddenly become null (NullReferenceException). Here's the script I have for JSON stuff:

 using System.IO;
 
 public class JS$$anonymous$$aves : MonoBehaviour
 {
     private DeckData deckData;
     private Deck playerDeck;
 
     private string persistentPath = "";
 
     private void Start()
     {
         playerDeck = FindObjectOfType<Deck>();
 
         SetPaths();
     }
 
     private void Update()
     {
         if (Input.GetKeyDown(KeyCode.S))
         {
             SaveData();
         }
     }
 
     private void CreateDeckData()
     {
         deckData = new DeckData(playerDeck);
     }
 
     private void SetPaths()
     {
         //path = Application.dataPath + Path.AltDirectorySeparatorChar + "DeckData.json";
 
         persistentPath = Application.persistentDataPath + Path.AltDirectorySeparatorChar + "DeckData.json";
     }
 
     public void SaveData()
     {
         string savePath = persistentPath;
         CreateDeckData();
         string json = JsonUtility.ToJson(deckData);
 
         using StreamWriter writer = new StreamWriter(savePath);
         writer.Write(json);
     }
 
     public DeckData LoadData()
     {
         using StreamReader reader = new StreamReader(persistentPath);
         string json = reader.ReadToEnd();
 
         DeckData data = JsonUtility.FromJson<DeckData>(json);
         Debug.Log(data.ToString());
 
         return data;       
     }
 }

I checked the json file that gets created and the data is definitely there, it's just not being loaded in correctly. I'm new to json so I think I may have made a simple mistake. The LoadData() is called in my deck script (not sure if that's a good way to do it) where it iterates through the data and adds each card back in. The DeckData is identical to the PlayerData above

avatar image Captain_Pineapple MehruneD · Jul 06 at 06:57 AM 1
Share

Hmm, on first glance i cannot really see an issue here, but it is early so i might be a bit blind ;)


What comes to my mind in general is that we are probably trying to tackle this incorrectly. I proposed a solution to the wrong problem i think.

If i understand this correctly you want to create scriptable objects in Unity, where each object is a "Card".

Then the thing that you want to save is a "Deck" that the player assembled right? So basically just a set of cards, but the cards never change. Is that correct?

If it is then we approached this a bit incorrectly.


In this case i'd suggest that each card should have a unique identifier (could be a name(String), id(int) or just some enumeration or something) Then the only thing that needs to make up your "DeckData" would be a set (array) of IDs/Names instead of complete cards. Then you should have some "Card-Repository" which returns a new instance of a card given by the ID/Name given.


Why is this solution better?

For once you have to save a lot less data in your safe-file. Also lets assume that you have some card with ID 42. This card is OP. You decide to nerf this card and patch the game. In this case you only have to patch the game. The game will then load a new instance of the card from your card-repository given by the ID with the updated values. If you always saved all values in your savedata then you'd also always have to patch all savedata files when updating cards.


hope this helps, will take another look when i had some tea.

avatar image Captain_Pineapple MehruneD · Jul 06 at 08:58 AM 1
Share

Just took another look, code does not contain any obvious flaws to me. Can you share more specifics about how you work with the loaded json information?

avatar image MehruneD Captain_Pineapple · Jul 06 at 12:52 PM 0
Share

Thanks for all the help, you're right that cards are being added to a deck, and after reading your comment I realize that I've sort of set myself up to fail. Because the values of the cards aren't static (some events change permanent values) I've been creating instances of the scriptable objects which are the new cards with changed values from the default card (otherwise what you're saying about unique card ID makes a lot of sense). Now I realize I'm trying to load in the instances which have been deleted once the game is stopped. I've put myself in this mess so I'll continue to try to find a way out of it, thanks again for helping out! I'll probably try out the Serializable_Card that you suggested (update) it's ugly but it's working :p

Show more comments

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

145 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 avatar image avatar image

Related Questions

Serializing ScriptableObject into scene without writing to asset 1 Answer

Best way to create runtime variables for Scriptable Objects?,What's the best way to create 'runtime values' for Scriptable Objects? 1 Answer

Can Scriptable Object be use for this? 2 Answers

Cannot see serialized object's fields in Inspector 1 Answer

Serialize a list of scriptable objects to Json 0 Answers


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