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
1
Question by dood_legacy · Nov 10, 2011 at 11:22 AM · inspectorserialization

Unity types unable to be serialized

Hello,

I've written a custom inspector for GameObjects that can serialize/restore data changed at runtime (I can save the values I've changed at runtime, so they don't revert after playmode is stopped). However, most Unity types can't be serialized using the code from System.Runtime.Serialization. For example, I'd like to serialize Vector3 etc. (seems simple enough.)

Does anyone know of a work-around? Right now I can only operate on basic types; bool,string,float,int etc.

Comment
Add comment · Show 1
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 syclamoth · Nov 10, 2011 at 11:31 AM 1
Share

Well, there's a surprising amount of abstracted information that you can store just with primitives! If your classes derive from Unity's 'Object' class, they will hook in nicely to Unity's inbuilt serialization, but that isn't really good enough if you want to use it for player-made levels and other such custom content. I have a generic Object Loader script which I've been using to pass level setup files between my level designers- but I'm not actually sure if it'd be good for anything more than primitives and classes which only contain primitives.

2 Replies

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

Answer by Zeanog · Dec 14, 2011 at 07:53 PM

We use ISerializationSurrogate to serialize Unity objects and scripts.

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializationsurrogate.aspx

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 chuckrussell · Apr 12, 2012 at 05:22 PM 1
Share

Could you be a little more specific?

avatar image numberkruncher · Aug 19, 2012 at 01:17 AM 0
Share

yes, I would like to know more about this too!

avatar image Zeanog · Aug 21, 2012 at 02:18 AM 0
Share

This is an example of usage. http://msdn.microsoft.com/en-us/library/system.runtime.serialization.surrogateselector.aspx

You just have to write a surrogate for every Unity type that you want to serialize. GameObject, Transform, etc. Our implementation for a GameObject surrogate sucked. Need to rethink that one. :)

Hope this helps

avatar image numberkruncher Zeanog · Aug 21, 2012 at 12:21 PM 0
Share

How are you registering this with the Unity serializer? The serialization mechanism (including a surrogate selector) are implemented privately within the Unity library.

avatar image
5

Answer by vexe · Jan 04, 2015 at 11:53 AM

Surrogates are the right idea, yes. Elaborating more on Zeanog answer: There are two things here. Do you want to actually convert the Unity objects to serializable data that you could move around (say network/file stream)? - or do you only care about data persistence between assembly reloads? - If it's the latter, see this hack here. But I assume you're asking about the first case, again, you need some sort of converters/surrogates. Here's what I did in the saving system of VFW:

  • I attach a SaveMarker to whatever gameObjects I want to save, and then choose what components I want saved

  • When saving, I iterate over all the gameObjects in the scene and get those marked with SaveMarker

  • Foreach object, I save it and whatever components marked for saving.

  • When saving an object, I lookup a converter for it. The convert specifies how the object is to be saved.

An example converter, is the GameObjectConverter:

 public class GameObjectConverter : SaveConverter<GameObject>
 {
     public override void SerializeInstanceIntoData(GameObject instance, Dictionary<string, fsData> data)
     {
         data["name"]     = Serialize<string> (instance.name);
         data["tag"]      = Serialize<string> (instance.tag);
         data["layer"]    = Serialize<int>    (instance.layer);
         data["isStatic"] = Serialize<bool>   (instance.isStatic);
         data["id"]       = Serialize<string> (instance.GetId());
         data["parentId"] = Serialize<string> (instance.GetParentId());
     }
 
     public override void DeserializeDataIntoInstance(GameObject instance, Dictionary<string, fsData> data)
     {
         instance.name     = Deserialize<string> (data["name"]);
         instance.tag      = Deserialize<string> (data["tag"]);
         instance.layer    = Deserialize<int>    (data["layer"]);
         instance.isStatic = Deserialize<bool>   (data["isStatic"]);
     }
 }

For Transform for ex, you save it's localPosition, localEulerAngles and localScale. For MonoBehaviours it's a bit more tricky. You need to reflect the behaviour and get whatever serializable fields it had, and serialize them individually:

 public class MonoBehaviourConverter : SaveConverter<MonoBehaviour>
 {
     public override void SerializeInstanceIntoData(MonoBehaviour instance, Dictionary<string, fsData> data)
     {
         var members = SerializationLogic.Default.GetMemoizedSerializableMembers(instance.GetType());
         for(int i = 0; i < members.Count; i++)
         {
             var member = members[i];
             member.Target = instance;
             data[member.Name] = Serialize(member.Value);
         }
     }
 
     public override void DeserializeDataIntoInstance(MonoBehaviour instance, Dictionary<string, fsData> data)
     {
         var members = SerializationLogic.Default.GetMemoizedSerializableMembers(instance.GetType());
         for(int i = 0; i < members.Count; i++)
         {
             var member = members[i];
             member.Target = instance;
             member.Value = Deserialize<object>(data[member.Name]);
         }
     }
 }

(Not going into detail, there's more things to cover like what you do when loading if a component went missing? or a gameObject was destroyed etc)

Now, how do you persist references to Unity objects like Texture, AudioClip, etc? - Well, the trick here is that we care about saving/loading our data, regardless how. One approach is to get the byte information of textures/audio and serialize that, but that's not necessary to persist the information. The thing is, those textures/audios are already there in your project so you just need to reference them, no need to recreate them. So what I do is I have a Store object, that has a serializable dictionary to save assets. When the serializer come across a Texture, AudioClip etc, it just stores it in the Store:

 public class Store : BetterScriptableObject
 {
     public Dictionary<string, UnityObject> Items
     {
         get { return _items ?? (_items = new Dictionary<string, UnityObject>()); }
     }
 
     [Serialize, Readonly, FormatMember("$name"), FormatPair("$valueType: $key")]
     private Dictionary<string, UnityObject> _items;
 
     /// <summary>
     /// A dictionary of keys representing all the item types we could store
     /// and values being whether or not the type needs inheritance support from the serializer
     /// </summary>
     public static readonly Dictionary<Type, bool> ItemTypes = new Dictionary<Type, bool>()
     {
         { typeof(Mesh),                         false },
         { typeof(AudioClip),                   false },
         { typeof(Material),                    false },
         { typeof(PhysicMaterial),              false },
         { typeof(Flare),                      false },
         { typeof(GUIStyle),                  false },
         { typeof(Texture),                   true  },
         { typeof(RuntimeAnimatorController), true  },
         { typeof(AnimationClip),             true  },
     };
 
     public static Store Current
     {
         get { return StoreManager.Current.Store; }
     }
 
     public string StoreAsset(UnityObject asset)
     {
         var name = asset.name;
         Items[name] = asset;
         return name;
     }
 
     public string StoreComponent(Component comp)
     {
         var key = comp.gameObject.name + comp.GetType().Name;
         Items[key] = comp;
         return key;
     }
 
     public UnityObject RetrieveItem(string key)
     {
         UnityObject result;
         if (!Items.TryGetValue(key, out result))
         {
             Debug.LogError("Trying to retrieve an item that doesn't exist: " + key);
         }
         return result;
     }
 }

 /// <summary>
 /// The FullSerializer converter to use to serialize/deserialize asset references (Textures, Meshes, Materials, AudioClips, AnimationClips, etc)
 /// Instead of serializing the actual bytes of meshes, audio etc we just save thsoe references into a store object live in the scene.
 /// When loading, we just ask the store to give us the item.
 /// Note the use of the name of the assets meaning assets you want to save *must* have unique names
 /// </summary>
 public class fsAssetReferenceConverter : fsConverter
 {
     public override bool RequestCycleSupport(Type storageType)
     {
         return false;
     }
 
     public override bool RequestInheritanceSupport(Type storageType)
     {
         return Store.ItemTypes[storageType];
     }
 
     public override bool CanProcess(Type type)
     {
         return canProcess(type);
     }
 
     private static Func<Type, bool> _canProcess;
     private static Func<Type, bool> canProcess
     {
         get
         {
             return _canProcess ?? (_canProcess = new Func<Type, bool>(x =>
             {
                 if (Store.ItemTypes.ContainsKey(x))
                     return true;
                 return Store.ItemTypes.Keys.Any(x.IsA);
             }).Memoize());
         }
     }
 
     public override fsStatus TrySerialize(object instance, out fsData serialized, Type storageType)
     {
         // StoreItem gives us back the name of the asset
         serialized = Store.Current.StoreAsset(instance as UnityObject);
         return fsStatus.Success;
     }
 
     public override fsStatus TryDeserialize(fsData data, ref object instance, Type storageType)
     {
         // the data holds the name of the asset since that's what we serialized...
         instance = Store.Current.RetrieveItem(data.AsString);
         return fsStatus.Success;
     }
 }

The output of the serialization is pure text (JSON) (see the end of the video linked at the beginning) And that's pretty much it. For more detailed information, check out VFW linked above as well.

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

7 People are following this question.

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

Related Questions

[Solved]Why doesn't my ScriptableObject based asset save using a custom inspector ? 1 Answer

Serializable class using generics 3 Answers

Public fields not showing in inspector 2 Answers

Array not updating in inspector 0 Answers

Custom Inspector: Using 'serializedObject' to access inherited members 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