Search Unity

  1. Check out the Unite LA keynote for updates on the Visual Effect Editor, the FPS Sample, ECS, Unity for Film and more! Watch it now!
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  4. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  5. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Vector3 not serializable?

Discussion in 'Scripting' started by JohnGalt, Dec 13, 2007.

  1. JohnGalt

    JohnGalt

    Joined:
    Nov 27, 2007
    Posts:
    85
    Hi

    I'm trying to serialize a class that includes a Unity Vector3, something like:

    Code (csharp):
    1.  
    2. [System.Serializable]
    3. public class GhostNode
    4. {
    5.     public Vector3 position;
    6. }
    7.  
    The code I use to serialize is pretty standard:

    Code (csharp):
    1.  
    2. void SaveToDisk(string fileName, GhostNode daNode)
    3. {
    4.        Stream str = File.OpenWrite(fileName);
    5.        BinaryFormatter formatter = new BinaryFormatter();
    6.      formatter.Serialize(str, daNode);
    7.         str.Close();   
    8. }
    And I get the next exception:


    SerializationException: Type UnityEngine.Vector3 is not marked as Serializable.
    System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteValue (System.IO.BinaryWriter writer, System.Type valueType, System.Object val)


    Is this normal?? Is there any solution?

    Thanks,
    Víctor
     
    AdmiralThrawn and yashpal like this.
  2. Foxxis

    Foxxis

    Joined:
    Jun 27, 2006
    Posts:
    1,107
    While I haven't done too much serialization yet, I believe that Unity-specific stuff isn't serializable. The workaround is to store the values in another type that's suitable.

    I might be wrong, in which case I believe someone will be along shortly to correct me.
     
  3. JohnGalt

    JohnGalt

    Joined:
    Nov 27, 2007
    Posts:
    85
    aaah, I see...

    It would be nice to provide the serialization mechanism a function external to the type so that it can serialize it.

    I'll look for this and post if I see something.

    Thanks
     
  4. JohnGalt

    JohnGalt

    Joined:
    Nov 27, 2007
    Posts:
    85
    I was thinking about that it's very strange that types like Quaternion and Vector3 are not serializables... a reason for this is that they display in the editor directly...
     
  5. Foxxis

    Foxxis

    Joined:
    Jun 27, 2006
    Posts:
    1,107
    Gave this some more thought, and unless there's a built-in solution (which I haven't heard of), the easiest workaround is to create a translation class. Use its functions to translate between Vector3 and a custom helper storage class.

    Or maybe UT has some trick up their collective sleeves? Please? ;)
     
  6. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    I have serialized both Vector3s and Quaternions using the XMLSerializer. I don't know what's up in your case.

    -Jeremy
     
  7. Foxxis

    Foxxis

    Joined:
    Jun 27, 2006
    Posts:
    1,107
    Where/how do you declare the variables you serialize?
     
  8. Foxxis

    Foxxis

    Joined:
    Jun 27, 2006
    Posts:
    1,107
    Probably doesn't matter. What does matter is that the XmlSerializer doesn't throw an error for a Vector3 variable, while the "normal" serializer does. Why I'm not sure.

    I will probably use the XmlSerializer anyway, as I hope that will circumvent the assembly namespace problem when reading saves from earlier versions.

    Still, clarification from UT would be good.
     
  9. Madbit

    Madbit

    Joined:
    Apr 2, 2009
    Posts:
    31
    Sorry to bump this ancient thread, but I'm having the exact same problem, and using XmlSerializer is not an option for me because of file size and performance reasons.

    Is there a -short- workaround for this now? I am currently implementing ISerializable and writing my own serialization code, but it's not very mantainable and the code gets unnecessarily long.

    I too find it curious that those classes are not marked as Serializable. Anyone have any idea why is this?

    Thanks!
     
  10. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    I hate to bump this but I just ran into this problem.

    Is this somehow able to be corrected in Unity3? Does anyone know if a fix for this is in the pipeline or some suitable workaround so we can use Binary Serialization?
     
  11. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,600
    you can use it but you must serialize manually through the corresponding functions that are being called by the formaters / serializers through the ISerializable interface
     
  12. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Ah ok I'll look into this. Thanks a bunch. Though it would be nice if the Unity types were able to feed into the automatic approach.

    Nice to know there is a workaround though.
     
  13. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,600
    would be nice but its known and well documented around the board that all that extends UnityEngine.Object won't serialize and that you better write your datastorage classes as extends from System.Object :)
     
  14. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Well... now I know! And here goes nothing... :twisted:
     
  15. Zyxil

    Zyxil

    Joined:
    Nov 23, 2009
    Posts:
    111
    Here's my stupid solution:

    Code (csharp):
    1.     [Serializable]
    2.     public struct Vector3Serializer
    3.     {
    4.         public float x;
    5.         public float y;
    6.         public float z;
    7.  
    8.         public void Fill(Vector3 v3)
    9.         {
    10.             x = v3.x;
    11.             y = v3.y;
    12.             z = v3.z;
    13.         }
    14.  
    15.         public Vector3 V3
    16.         { get { return new Vector3(x, y, z); } }
    17.     }
    18.  
    19.     [Serializable]
    20.     public struct QuaternionSerializer
    21.     {
    22.         public float x;
    23.         public float y;
    24.         public float z;
    25.         public float w;
    26.  
    27.         public void Fill(Quaternion q)
    28.         {
    29.             x = q.x;
    30.             y = q.y;
    31.             z = q.z;
    32.             w = q.w;
    33.         }
    34.  
    35.         public Quaternion Q
    36.         { get { return new Quaternion(x, y, z, w); } }
    37.     }
     
    monotoan, forestrf and killer_mech like this.
  16. imtrobin

    imtrobin

    Joined:
    Nov 30, 2009
    Posts:
    1,543
    Hmm, in 3.5 I can serialize it to text file fine (the data is there), but when I deserialize, it gives me an error

    InvalidCastException: Value is not a convertible object: System.String to UnityEngine.Vector3
    System.Convert.ToType (System.Object value, System.Type conversionType, IFormatProvider provider, Boolean try_target_to_type)
    System.String.System.IConvertible.ToType (System.Type targetType, IFormatProvider provider)


    - Ok, I found I can use it as XMLText, but not as XMLAttribute
     
    Last edited: May 2, 2012
  17. Ali-Nagori

    Ali-Nagori

    Joined:
    Apr 9, 2010
    Posts:
    135
    if this code

    Code (csharp):
    1. using System;
    2. using System.Reflection;
    3. using UnityEngine.Internal;
    4.  
    5. namespace UnityEngine
    6. {
    7.     public struct Vector3
    8. .....
    9. .....
    10.     {
    get edited this way

    Code (csharp):
    1. using System;
    2. using System.Reflection;
    3. using UnityEngine.Internal;
    4. using System.Runtime.Serialization;
    5.  
    6. namespace UnityEngine
    7. {
    8.     [Serializable()]
    9.     public struct Vector3
    10.     {
    11. .....
    12. .....
    we can then Serialize :0

    but tell then you still can create your own private struct or class with serialize flag before it

    Code (csharp):
    1.         [Serializable()]
    2.         public struct Vector_3: struct
    3.         {
    4.             public float x;
    5.             public float y;
    6.             public float z;
    7.         }
     
  18. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,356
    Yeah... A mystery why Unity didn't flag their structs as Serializable... I can understand for their other object in which the internal value lives in the C++ side, but for struct, they have fields, not wrapping properties.
     
  19. Carpe-Denius

    Carpe-Denius

    Joined:
    May 17, 2013
    Posts:
    784
    Thats a very old thread... Vector3 are serializable, as stated in the docs. I tried it a few month ago and it worked.
     
  20. Loius

    Loius

    Joined:
    Aug 16, 2012
    Posts:
    545
    No they're not. Never have been. He says, wondering if he's telling the truth or not. #_#

    I know i certainly fight "not serializable!" errors often enough though.

    This definitely prints "fieldname not serialized" when it gets to a V3 though:

    Code (csharp):
    1.  
    2.         FieldInfo[] fields = ret.GetType().GetFields();
    3.         foreach(FieldInfo field in fields) {
    4.             string pref = prefix + "." + field.Name;
    5.             attributes = field.GetCustomAttributes(false);
    6.             if ( attributes.Any(x=>x.GetType()==typeof(ScrambleWhenSerializingToPlayerPrefsAttribute))
    7.                  (field.FieldType.IsSerializable || typeof(ISerializable).IsAssignableFrom(field.FieldType)) ) {
    8.                 result = PlayerPrefs.GetString(pref,"");
    9.                 if ( result != "" ) {
    10.                     field.SetValue(ret,result.CallGenericExtensionMethod(typeof(UtilityExtensions),"DeserializeToObject",new object[]{result},typeof(T)));
    11.                 }
    12.             } else {
    13.                 if ( field.FieldType == typeof(int) ) {
    14.                     field.SetValue(ret, PlayerPrefs.GetInt(pref,(int)field.GetValue(ret)));
    15.                 } else if ( field.FieldType == typeof(bool) ) {
    16.                     field.SetValue(ret, PlayerPrefs.GetInt(pref,((bool)field.GetValue(ret))?1:0)==1);
    17.                 } else if ( field.FieldType == typeof(float) ) {
    18.                     field.SetValue(ret, PlayerPrefs.GetFloat(pref,(float)field.GetValue(ret)));
    19.                 } else if ( field.FieldType == typeof(string) ) {
    20.                     field.SetValue(ret, PlayerPrefs.GetString(pref,(string)field.GetValue(ret)));
    21.                 } else {
    22.                     if ( attributes.Any(x=>x.GetType()==typeof(SerializeIndividualFieldsToPlayerPrefsAttribute)) ) {
    23.                         field.SetValue(ret, field.GetValue(ret).DeserializeFromPlayerPrefs(pref));
    24.                     } else if ( field.FieldType.IsSerializable || typeof(ISerializable).IsAssignableFrom(field.FieldType) ) {
    25.                         result = PlayerPrefs.GetString(pref,"");
    26.                         if ( result != "" ) {
    27.                             field.SetValue(ret,result.CallGenericExtensionMethod(typeof(UtilityExtensions),"DeserializeToObject",new object[]{result},field.FieldType));
    28.                         }
    29.                     } else {
    30.                         Debug.LogWarning(field.Name+ " not serialized");
    31.                         // couldn't handle this field
    32.                     }
    33.                 }
    34.             }
    35.             Debug.Log("load " + pref + " = " + field.GetValue(ret).ToString());
    36.         }
    37.  
     
    Last edited: May 14, 2014
    AdmiralThrawn likes this.
  21. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    7,364
    I've just run into the same thing. I know I can't expect a MonoBehaviour to be Serializable — of course! So I've got translation code that copies all my data into a set of nested Hashtables, like this:

    Code (csharp):
    1.     Hashtable data = new Hashtable();
    2.     data.Add("position", transform.position);
    3.     data.Add("localScale", transform.localScale);
    4.     // etc.
    And then I gather these up and try to write 'em out:

    Code (csharp):
    1.     IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    2.     formatter.Serialize(stream, data);
    This appears to work right up to the point where it hits a Vector3, whereupon it pukes with:

    SerializationException: Type UnityEngine.Vector3 is not marked as Serializable.
    System.Runtime.Serialization.Formatters.Binary.BinaryCommon.CheckSerializable (System.Type type, ISurrogateSelector selector, StreamingContext context) (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/BinaryCommon.cs:119)
    System.Runtime.Serialization.Formatters.Binary.ObjectWriter.GetObjectData ...

    So, seriously, what's the deal? Why wouldn't simple, common structs like Vector3 be marked as Serializable?
     
  22. caLLow

    caLLow

    Joined:
    Apr 21, 2014
    Posts:
    35
    Nice solution! I used this in my code and added a setter to the properties.

    Code (csharp):
    1. [System.Serializable]
    2. public class Vector3Serializer
    3. {
    4.     public float x;
    5.     public float y;
    6.     public float z;
    7.  
    8.     public void Fill(Vector3 v3)
    9.     {
    10.         x = v3.x;
    11.         y = v3.y;
    12.         z = v3.z;
    13.     }
    14.  
    15.     public Vector3 V3 { get { return new Vector3(x, y, z); } set { Fill(value); } }
    16.  
    17. }
     
  23. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    7,364
    Yes, I ended up doing something like that too. Actually I made my own FileVector3 class, which looks exactly like a Vector3 except that I didn't neglect the [Serializable] attribute. And then I have methods to get/set the value of these as a Vector3.

    Still a pain in the neck though... Unity really should fix this. Turns out there's already a feature request for this; please vote for it to help it get more attention.

    What mystifies me is why so many people claim that these are already serializable. Clearly they're not, in the current version of Unity at least; you get a "SerializationException: Type UnityEngine.Vector3 is not marked as Serializable" error when you try to use them. So why do some people think they are? Has this actually worked in some versions of Unity, and maybe it just got (re)broken recently?
     
    AdmiralThrawn likes this.
  24. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    5,921
    The new version of Unity 4.5 has it.

    http://unity3d.com/unity/whats-new/unity-4.5

    And if you test if Vector3 has the SerializableAttribute, it does:

    Code (csharp):
    1.  
    2. Debug.Log(System.Attribute.IsDefined(typeof(Vector3), typeof(System.SerializableAttribute))); //prints true in 4.3.4f1
    3.  
     
    Last edited: May 29, 2014
  25. arturmandas

    arturmandas

    Joined:
    Sep 29, 2012
    Posts:
    169
    Provided it works now, how do you deserialize string into Vector3 using XMLSerializer? I mean, what string should I put in my Vector3 type field in a plain XML file for Unity to read it properly? Real life example: I use XML file to construct levels on-the-fly, and this XML structure reflects my class structure (there is one root class which gathers it all). I want one of my "zones" position to be fed from XML, but when I enter something like "(0f,4f,0f)" it always reads to (0,0,0). Earlier on I did this with XML doc and my custom parse methods, but this is very unelastic and inextensible. How do I do this in 4.5? I don't want to construct custom struct overrides or break Vector3 down to floats.
     
  26. zsofttech

    zsofttech

    Joined:
    Nov 12, 2013
    Posts:
    10
    Actually, this does not seem to work. Lordofduct's code above does return true for me with Unity 4.5.3f3, but when I try to serialize an object containing Vector3's I get
    "Type UnityEngine.Vector3 is not marked as Serializable" ... "at System.Runtime.Serialization.Formatters.Binary.BinaryCommon.CheckSerializable" in the console, when I try to serialize using the .net BinaryFormatter in order to serialize an object to a MemoryStream.


    Same for Vector2 or Color
     
  27. arturmandas

    arturmandas

    Joined:
    Sep 29, 2012
    Posts:
    169
    True, I had to use floats instead
     
  28. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,036
    I do it this way so the conversion happen automatically both ways...

    Vector3 lTest1 = new SerializableVector3(0, 0, 0);
    SerializableVector3 lTest2 = Vector3.zero;

    Code (CSharp):
    1.     /// <summary>
    2.     /// Since unity doesn't flag the Vector3 as serializable, we
    3.     /// need to create our own version. This one will automatically convert
    4.     /// between Vector3 and SerializableVector3
    5.     /// </summary>
    6.     [Serializable]
    7.     public struct SerializableVector3
    8.     {
    9.         /// <summary>
    10.         /// x component
    11.         /// </summary>
    12.         public float x;
    13.  
    14.         /// <summary>
    15.         /// y component
    16.         /// </summary>
    17.         public float y;
    18.  
    19.         /// <summary>
    20.         /// z component
    21.         /// </summary>
    22.         public float z;
    23.  
    24.         /// <summary>
    25.         /// Constructor
    26.         /// </summary>
    27.         /// <param name="rX"></param>
    28.         /// <param name="rY"></param>
    29.         /// <param name="rZ"></param>
    30.         public SerializableVector3(float rX, float rY, float rZ)
    31.         {
    32.             x = rX;
    33.             y = rY;
    34.             z = rZ;
    35.         }
    36.  
    37.         /// <summary>
    38.         /// Returns a string representation of the object
    39.         /// </summary>
    40.         /// <returns></returns>
    41.         public override string ToString()
    42.         {
    43.             return String.Format("[{0}, {1}, {2}]", x, y, z);
    44.         }
    45.  
    46.         /// <summary>
    47.         /// Automatic conversion from SerializableVector3 to Vector3
    48.         /// </summary>
    49.         /// <param name="rValue"></param>
    50.         /// <returns></returns>
    51.         public static implicit operator Vector3(SerializableVector3 rValue)
    52.         {
    53.             return new Vector3(rValue.x, rValue.y, rValue.z);
    54.         }
    55.  
    56.         /// <summary>
    57.         /// Automatic conversion from Vector3 to SerializableVector3
    58.         /// </summary>
    59.         /// <param name="rValue"></param>
    60.         /// <returns></returns>
    61.         public static implicit operator SerializableVector3(Vector3 rValue)
    62.         {
    63.             return new SerializableVector3(rValue.x, rValue.y, rValue.z);
    64.         }
    65.     }
     
    Philip-Rowlands and JoeStrout like this.
  29. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,059
    AAAah, why?? :mad:
     
  30. indianalf

    indianalf

    Joined:
    Aug 6, 2014
    Posts:
    7
    add this on top your class declaration :

    [XmlInclude(typeof(Vector3))]

    should fix ..
     
  31. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    513
    Use an ISerializationSurrogate for the Vector3 type.

    Code (CSharp):
    1. using System.Runtime.Serialization;
    2. using UnityEngine;
    3.  
    4. sealed class Vector3SerializationSurrogate : ISerializationSurrogate {
    5.  
    6.     // Method called to serialize a Vector3 object
    7.     public void GetObjectData(System.Object obj,
    8.                               SerializationInfo info, StreamingContext context) {
    9.      
    10.         Vector3 v3 = (Vector3) obj;
    11.         info.AddValue("x", v3.x);
    12.         info.AddValue("y", v3.y);
    13.         info.AddValue("z", v3.z);
    14.         Debug.Log(v3);
    15.     }
    16.  
    17.     // Method called to deserialize a Vector3 object
    18.     public System.Object SetObjectData(System.Object obj,
    19.                                        SerializationInfo info, StreamingContext context,
    20.                                        ISurrogateSelector selector) {
    21.      
    22.         Vector3 v3 = (Vector3) obj;
    23.         v3.x = (float)info.GetValue("x", typeof(float));
    24.         v3.y = (float)info.GetValue("y", typeof(float));
    25.         v3.z = (float)info.GetValue("z", typeof(float));
    26.         obj = v3;
    27.         return obj;   // Formatters ignore this return value //Seems to have been fixed!
    28.     }
    29. }
    Add it to your BinaryFormatter:

    Code (CSharp):
    1.  
    2.          using System.Runtime.Serialization;
    3.  
    4.  
    5.        
    6.          BinaryFormatter bf = new BinaryFormatter();
    7.  
    8.         // 2. Construct a SurrogateSelector object
    9.         SurrogateSelector ss = new SurrogateSelector();
    10.      
    11.         Vector3SerializationSurrogate v3ss = new Vector3SerializationSurrogate();
    12.         ss.AddSurrogate(typeof(Vector3),
    13.                         new StreamingContext(StreamingContextStates.All),
    14.                         v3ss);
    15.      
    16.         // 5. Have the formatter use our surrogate selector
    17.         bf.SurrogateSelector = ss;
     
  32. Voxel-Busters

    Voxel-Busters

    Joined:
    Feb 25, 2015
    Posts:
    538
  33. stannesi

    stannesi

    Joined:
    Apr 18, 2015
    Posts:
    1
    I had that same issue, so ended up creating mine, can use used to save transform position and vector3 position

    Code (CSharp):
    1. [Serializable]
    2. public class Position
    3. {
    4.     public float x = 0;
    5.     public float y = 0 ;
    6.     public float z = 0;
    7.  
    8.     public void Positon(Transform transform)
    9.     {
    10.         x = transform.position.x;
    11.         y = transform.position.y;
    12.         z = transform.position.z;
    13.     }
    14.  
    15.     public void Positon(Vector3 vector)
    16.     {
    17.         x = vector.x;
    18.         y = vector.y;
    19.         z = vector.z;
    20.     }
    21.  
    22.     public void Positon(float posX, float posY, float posZ)
    23.     {
    24.         x = posX;
    25.         y = posY;
    26.         z = posZ;
    27.     }
    28. }
    hope it helps
     
  34. MidnightStudiosInc

    MidnightStudiosInc

    Joined:
    Jun 8, 2015
    Posts:
    3
    I've just released GameObject Serializer Pro which can serialize many builtin Unity types like Vector3/Quaternion *much* faster than XmlSerializer and in a *much* more efficient data format.

    The best part? It even serializes many subclasses of UnityEngine.Object like GameObject and Components.

    Type support is limited at the moment but will grow over time. Check the documentation to see what types are supported in the most recent release.
     
  35. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    86
    I know this is old, but just a note for anyone using Cherno's ISerializationSurrogate stuff: you can clean up the code (and probably performance) a lot by using GetSingle instead of the doing all the GetValue(typeof(float)) stuff.
     
  36. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    513
    You are right, thanks.
     
  37. liuzongshun

    liuzongshun

    Joined:
    Feb 19, 2016
    Posts:
    1

    Very good!thanks!
     
  38. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    513
    For people looking to dig further into Unity serialization and saving / loading scene and GameObject/component data, take a look at my free asset SerializeHelper. It aims to teach users the basics of such features and also works as a standalone plugin framework to use as-is or to expand and implement your own save / load functionality. Of course, it also uses the ISerializationSurrogate technique outline above.

    http://forum.unity3d.com/threads/se...e-serialize-all-objects-in-your-scene.338148/