Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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
1
Question by xarismax · Sep 13, 2017 at 06:00 PM · serializationruntimejsonruntime-generationmodding

Dual Serialisation: Saving Monobehaviour and ScriptableObject At Runtime

All games, want to have a game engine that supports modding capacity, however... unity doesnt provide the tools (Runtime Inspector, Runtime Serialization).

99.999% of the unity answers say it is impossible and discourage you from going that direction. Go alone or go home. And judging from the outcome, whoever tried to "fix" unity serialization died in the end (example Vexe). Conclusion = go home (abandon) :(

Yet the solution was given years ago : https://www.youtube.com/watch?v=6vmRwLYWNRo&feature=youtu.be&t=25m45s

     public class TestDualSerialization : MonoBehaviour
     {
         public string Json;
         public Object Object;
 
         [ContextMenu("ObjectToJson")] public void ObjectToJson()
         {
             Json = JsonUtility.ToJson(Object);
             Debug.Log(Json);
         }
 
         //must use FromJsonOverwrite for Monobehaviour or ScriptableObject
         [ContextMenu("ObjectFromJson")] public void ObjectFromJson()
         {
             JsonUtility.FromJsonOverwrite(Json, Object);
             Debug.Log(Object);
         }
     }

I tried to code in the video, and it WORKS!!! So the question is, what are the limitations of this method, that everyone here undermines it ?

1) Is the only problem the no "Reference-Sharing" capacity ? if so, I dont care, i could have a giant array with every object with 'int' array index as reference.

2) Actually i might care. It creates references like "instanceID": 12822 . Are these unique for each type?

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 Bunny83 · Sep 14, 2017 at 12:05 PM

Well, the JsonUtility is rather new when looking at the Unity history. (the talk you've linked was from Dec 2016 so not even a year ago).

The JsonUtility basically has the same rules as the normal Unity serialization system though with some restrictions.

As you said it does not support references to other UnityEngine.Object derived types as there is no general way how to get such references back during deserialization. You have to deserialize every UnityEngine.Object derived object on it's own.

Instance IDs are only unique for one "session". So deserializing a ScriptableObject at runtime will give that instance a new instance ID. The Instance ID actually is not serialized. It's mainly used by the editor

I haven't really used / tested the JsonUtility well to the bone. Though i hope that it also makes use of the ISerializationCallbackReceiver interface. It would allow to circumvent most limitations the serialization system has.

I may setup a test case and report back to give a certain answer on that matter. edit

So yes, the ISerializationCallbackReceiver interface does work when serializing / deserializing with the JsonUtility. So you can easily ship your own reference system if really necessary. Though the objects that you want to reference need to be managed in a static way. You can use a simple object tracker like this one. The only requirement is that each object you want to track has a unique ID string. You could simply use a GUID.

A tracked object would register "itself" to the tracker in "OnAfterDeserialize". At this point the object has it's ID loaded from the file (given your class has a string field for the ID). Likewise any class that holds references to other tracked objects will "request" an object reference based on a given ID. The Tracker allows "late binding". So if you deserialize an object that has a reference to an object that hasn't been loaded yet, it will initialize it once the object is registrated.

For a class to register itself to the tracker you would use:

 ObjectTracker.Instance.AddObject(objID, this);

where "objID" would be the unique ID of this object.

To "deserialize" a reference you would use this pattern:

 ObjectTracker.Instance.GetObject(refID, o=>yourMemberVariable = o);

Note that yourMemberVariable = o is the code that might be executed immediately or delayed. So make sure the code in that delegate is able to set the reference to the correct variable.

A very quick example:

 public interface ITrackableObject
 {
     string GetID();
 }
 
 public class TestObject : ScriptableObject, ITrackableObject, ISerializationCallbackReceiver
 {
     public string myID;
     [System.NonSerialized]
     public List<ITrackableObject> someObjects;
     [SerializeField]
     private List<string> m_TrackedIDs = new List<string>();
     public string GetID()
     {
         return myID;
     }
 
     public void OnAfterDeserialize()
     {
         ObjectTracker.Instance.AddObject(myID, this);
         someObjects = new List<ITrackableObject>();
         for(int i = 0; i < m_TrackedIDs.Count; i++)
         {
             int index = someObjects.Count;
             someObjects.Add(null); // add a null item to the list to prepare the "variable".
             ObjectTracker.Instance.GetObject(m_TrackedIDs[i], o=> someObjects[index] = (ITrackableObject)o);
         }
     }
 
     public void OnBeforeSerialize()
     {
         m_TrackedIDs.Clear();
         foreach(var o in someObjects)
         {
             m_TrackedIDs.Add(o.GetID());
         }
     }
 }

The "ITrackableObject" interface is not necessary but it provides a generic way for other classes to obtain the IDs of other objects they might reference.

Note: instead of adding a "null" item to the list and then using the index of that item in the delegate you could simply use:

 ObjectTracker.Instance.GetObject(m_TrackedIDs[i], o=> someObjects.Add( (ITrackableObject)o));

However this will not preserve the order of the objects in the list as the delegates might be called in a different order.

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

74 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

Related Questions

Stop specific fields from being serialized by JSON utility 3 Answers

How to protect JSON file game data? 3 Answers

Json Serialization documentation official Unity website - marking it [Serializable] caused error 1 Answer

Creating bitmap texture2d during runtime 0 Answers

Json . NET, iOS and AOT 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