Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 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 D3Duck · Mar 28, 2017 at 01:53 AM · editorscriptableobjectsaving

Handling change in Class variables with saving ScriptableObject

I've been playing with saving Scriptable Objects using binary serialization. This is the loading from file code:

 public static T ReadFromBinaryFile<T>(string filePath)
 {
     using (Stream stream = File.Open(filePath, FileMode.Open))
     {
         var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
         return (T)binaryFormatter.Deserialize(stream);
     }
 }

Then using this class (short version):

 using UnityEngine;
 public class Item : ScriptableObject 
 {
     [SerializeField]
     int value;
 }

My apprehension in using this for things like my Item database, is that I don't see how I could implement an additional variable to my classes and then still be able to load the old data and save with the new variables. When I change this class to add, for example, a float durability;, this doesn't match the saved file anymore and this has so far just wiped my database. Is there a standard way to solve this?

So far I've been trying out adding a version number to a save and comparing the different classes, but then I get into having to write extensive 'conversion scripts' which put the data from the old class versions into new ones and all this also means I need to keep copies of my old classes around etc. Which I'd really prefer not to.

Comment
Add comment · Show 5
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 Adam-Mechtley · Mar 28, 2017 at 07:40 AM 0
Share

Could you provide a little more concrete detail on what you're trying to and and what the problem is? Whenever you add a new serialized field to a ScriptableObject, it will just get the default value from its field initializer if there is not data for it on disk. So assume I have this class:

 using UnityEngine;
 [CreateAsset$$anonymous$$enu]
 public class Item : ScriptableObject {
     [SerializeField]
     private int m_Value;
 }

Then I create a bunch of assets and realize I want to add a field for weight:

 using UnityEngine;
 [CreateAsset$$anonymous$$enu]
 public class Item : ScriptableObject {
     [SerializeField]
     private int m_Value;
     [SerializeField]
     private float m_Weight = 2f;
 }

Now, all items will automatically have a default weight of 2 if there is no value manually serialized for it (i.e. you did not manually select the item asset, change the weight, and save the project).

avatar image D3Duck Adam-Mechtley · Mar 29, 2017 at 02:09 AM 0
Share

Thanks, I updated the question with more data. So you're saying I should just save it in binary with one class type and then just load it back into another class?

avatar image Adam-Mechtley D3Duck · Mar 29, 2017 at 07:11 AM 0
Share

So what you are doing is basically what Unity does in native code when we change the serialization layout of something (i.e. bump version number and add some logic to handle changes), but I guess I would ask why you need to maintain your item database as external, binary-serialized data in the first place?

Show more comments
avatar image dvandamme · Mar 28, 2017 at 09:55 AM 0
Share

i removed a comment about scriptableobject which isn't valid enough

use the JsonUtility class in unity, and then you can serialise your item database into a nicely formated json string, write that to a file, and then back again into your program... you can add any number of extra properties from that point on, and keep bring data set's forward through build iterations. trim$$anonymous$$g excess properites can be a little annoying, growing is always easy with that helper class

https://docs.unity3d.com/ScriptReference/JsonUtility.html

2 Replies

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

Answer by Adam-Mechtley · Mar 30, 2017 at 07:03 AM

If you are using ScriptableObjects to define your items, then you should just save them as assets in your project, and your database should just be another ScriptableObject asset in your project that serializes references to them. (You can also use AssetDatabase.AddObjectToAsset() to make the items children of the database asset, if it makes them easier to manage.)

It would look something like this (note you can of course just make your serialized fields public if you want to go that route and trust all consumers of your class):

 // in Item.cs
 using UnityEngine;

 [CreateAssetMenu]
 public class Item : ScriptableObject {
     public int Value { get { return m_Value; } set { m_Value = value; } }
     [SerializeField]
     private int m_Value;
 
     public float Weight { get { return m_Weight; } set { m_Weight = value; } }
     [SerializeField]
     private float m_Weight;
 
     // and so on...
 }

 // in ItemDatabase.cs
 using System.Collections.Generic;
 using UnityEngine;

 [CreateAssetMenu]
 public class ItemDatabase : ScriptableObject {
     [SerializeField]
     private List<Item> m_Items = new List<Item>();
 
     public int Count { get { return m_Items.Count; } }
     public Item this[int index] { get { return m_Items[index]; } }

     // and so on...
 }

The whole point of ScriptableObjects is basically to allow you to serialize and save persistent, arbitrary data in your project, so the extra step of dumping the data into another format—whether binary or JSON—is unnecessary. Another benefit of this approach is that you can select multiple ScriptableObjects at once in the Editor and edit them at the same time. As I noted in my comment above, adding a new field then simply becomes a matter of applying a default value in the field initializer, and you can then quickly edit several items together when you need to apply different values to them.

Comment
Add comment · Show 4 · 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 dvandamme · Mar 30, 2017 at 07:11 AM 0
Share

there's a big difference in our requirements which is now much clearer..

I have to be able to save data into a transportable format, and i can't store the data inside unity, and I have to avoid as much as possible complex unity objects, and it all must work at runtime, not in the editor.... :D

so this has been useful to see. thanks for sharing

avatar image Adam-Mechtley dvandamme · Mar 30, 2017 at 07:21 AM 0
Share

Yes then in that case you are best off using a custom serializable type in conjunction with the JsonUtility class. Something like this:

 using System;
 using UnityEngine;
 
 [Serializable]
 public class Item {
     public int Value { get { return m_Value; } set { m_Value = value; } }
     [SerializeField]
     private int m_Value;

     // and so on...
 }
avatar image dvandamme Adam-Mechtley · Mar 30, 2017 at 09:17 AM 0
Share

:D exactly.... would you be inclined to convert my comment which states that into an answer? I could just delete my comment and post it again as an answer, obviously, but this has been a useful discussion

Show more comments
avatar image
0

Answer by dvandamme · Mar 30, 2017 at 05:22 AM

jsonutility is just a serialiser that works nicely for converting a dataset into a big string, and then you use a filewriter to send that string to a file... your data structure (the item database) should be entirely separate to this process. FileIO and object manipulation shouldn't live in the same class all but the most tiny projects...

If you use the jsonutility, then growing the structure over time is not even a thing to worry about. The api will do all the heavy lifting for you and you can just worry about your datastructure doing what you want it to do. .

this is the entire datastructure i use for a full application that is saved to file by the user, and allows drawing lines with various colours and thickness, making user notes on their drawing, placing any number of 3d objects in 3d space, and a few other things. that gets churned into json for saving, but its i can be a 10,000 item datastructure without any effor or slowdown in processing

  [Serializable]
     public class DataStructures
     {
         [Serializable]
         public class DataSet
         {
             public List<Item> items = new List<Item>();
            // public List<Item> lines = new List<Item>();
             //public List<Item> nodeConnections = new List<Item>();
 
             public DataSet()
             {
             }
         }
 
         [Serializable]
         public class BasicStruct
         {
             public string id;
         }
 
         [Serializable]
         public class Item : BasicStruct
         {
             public string prefabReference;
             public string value;
             public Vector3 position;
             public Quaternion rotation;
             public Vector3 point1;
             public Vector3 point2;
             public Color color;
             public float width;
             public List<string> links = new List<string>();
 
             public Item()
             {
                 links = new List<string>();
                 position = Vector3.zero;
                 rotation = Quaternion.Euler(Vector3.up);
             }
         }
     }

and then i use this to write to a file

   string jsonfile = JsonUtility.ToJson(datset); //

   using (StreamWriter writer = new StreamWriter(filepath, false))
   {
                 writer.Write(jsonfile );
   }
Comment
Add comment · 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

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

80 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

Related Questions

Drag from custom editor ObjectField 0 Answers

Is there any way to associate a "custom asset" with a particular file type? 1 Answer

How do I associate my custom object for the serializedProperty objectReferenceValue 1 Answer

Scriptable Objects, how to force Include in Compile / Build without referencing it in the scene? 1 Answer

Custom Editor Script Sets Scene as Dirty Regardless of Changes 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