Hi I'm trying to serialize a class that includes a Unity Vector3, something like: Code (csharp): [System.Serializable] public class GhostNode { public Vector3 position; } The code I use to serialize is pretty standard: Code (csharp): void SaveToDisk(string fileName, GhostNode daNode) { Stream str = File.OpenWrite(fileName); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(str, daNode); str.Close(); } 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
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.
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
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...
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?
I have serialized both Vector3s and Quaternions using the XMLSerializer. I don't know what's up in your case. -Jeremy
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.
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!
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?
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
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.
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
Here's my stupid solution: Code (csharp): [Serializable] public struct Vector3Serializer { public float x; public float y; public float z; public void Fill(Vector3 v3) { x = v3.x; y = v3.y; z = v3.z; } public Vector3 V3 { get { return new Vector3(x, y, z); } } } [Serializable] public struct QuaternionSerializer { public float x; public float y; public float z; public float w; public void Fill(Quaternion q) { x = q.x; y = q.y; z = q.z; w = q.w; } public Quaternion Q { get { return new Quaternion(x, y, z, w); } } }
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
if this code Code (csharp): using System; using System.Reflection; using UnityEngine.Internal; namespace UnityEngine { public struct Vector3 ..... ..... { get edited this way Code (csharp): using System; using System.Reflection; using UnityEngine.Internal; using System.Runtime.Serialization; namespace UnityEngine { [Serializable()] public struct Vector3 { ..... ..... 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): [Serializable()] public struct Vector_3: struct { public float x; public float y; public float z; }
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.
Thats a very old thread... Vector3 are serializable, as stated in the docs. I tried it a few month ago and it worked.
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): FieldInfo[] fields = ret.GetType().GetFields(); foreach(FieldInfo field in fields) { string pref = prefix + "." + field.Name; attributes = field.GetCustomAttributes(false); if ( attributes.Any(x=>x.GetType()==typeof(ScrambleWhenSerializingToPlayerPrefsAttribute)) (field.FieldType.IsSerializable || typeof(ISerializable).IsAssignableFrom(field.FieldType)) ) { result = PlayerPrefs.GetString(pref,""); if ( result != "" ) { field.SetValue(ret,result.CallGenericExtensionMethod(typeof(UtilityExtensions),"DeserializeToObject",new object[]{result},typeof(T))); } } else { if ( field.FieldType == typeof(int) ) { field.SetValue(ret, PlayerPrefs.GetInt(pref,(int)field.GetValue(ret))); } else if ( field.FieldType == typeof(bool) ) { field.SetValue(ret, PlayerPrefs.GetInt(pref,((bool)field.GetValue(ret))?1:0)==1); } else if ( field.FieldType == typeof(float) ) { field.SetValue(ret, PlayerPrefs.GetFloat(pref,(float)field.GetValue(ret))); } else if ( field.FieldType == typeof(string) ) { field.SetValue(ret, PlayerPrefs.GetString(pref,(string)field.GetValue(ret))); } else { if ( attributes.Any(x=>x.GetType()==typeof(SerializeIndividualFieldsToPlayerPrefsAttribute)) ) { field.SetValue(ret, field.GetValue(ret).DeserializeFromPlayerPrefs(pref)); } else if ( field.FieldType.IsSerializable || typeof(ISerializable).IsAssignableFrom(field.FieldType) ) { result = PlayerPrefs.GetString(pref,""); if ( result != "" ) { field.SetValue(ret,result.CallGenericExtensionMethod(typeof(UtilityExtensions),"DeserializeToObject",new object[]{result},field.FieldType)); } } else { Debug.LogWarning(field.Name+ " not serialized"); // couldn't handle this field } } } Debug.Log("load " + pref + " = " + field.GetValue(ret).ToString()); }
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): Hashtable data = new Hashtable(); data.Add("position", transform.position); data.Add("localScale", transform.localScale); // etc. And then I gather these up and try to write 'em out: Code (csharp): IFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 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?
Nice solution! I used this in my code and added a setter to the properties. Code (csharp): [System.Serializable] public class Vector3Serializer { public float x; public float y; public float z; public void Fill(Vector3 v3) { x = v3.x; y = v3.y; z = v3.z; } public Vector3 V3 { get { return new Vector3(x, y, z); } set { Fill(value); } } }
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?
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): Debug.Log(System.Attribute.IsDefined(typeof(Vector3), typeof(System.SerializableAttribute))); //prints true in 4.3.4f1
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.
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
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): /// <summary> /// Since unity doesn't flag the Vector3 as serializable, we /// need to create our own version. This one will automatically convert /// between Vector3 and SerializableVector3 /// </summary> [Serializable] public struct SerializableVector3 { /// <summary> /// x component /// </summary> public float x; /// <summary> /// y component /// </summary> public float y; /// <summary> /// z component /// </summary> public float z; /// <summary> /// Constructor /// </summary> /// <param name="rX"></param> /// <param name="rY"></param> /// <param name="rZ"></param> public SerializableVector3(float rX, float rY, float rZ) { x = rX; y = rY; z = rZ; } /// <summary> /// Returns a string representation of the object /// </summary> /// <returns></returns> public override string ToString() { return String.Format("[{0}, {1}, {2}]", x, y, z); } /// <summary> /// Automatic conversion from SerializableVector3 to Vector3 /// </summary> /// <param name="rValue"></param> /// <returns></returns> public static implicit operator Vector3(SerializableVector3 rValue) { return new Vector3(rValue.x, rValue.y, rValue.z); } /// <summary> /// Automatic conversion from Vector3 to SerializableVector3 /// </summary> /// <param name="rValue"></param> /// <returns></returns> public static implicit operator SerializableVector3(Vector3 rValue) { return new SerializableVector3(rValue.x, rValue.y, rValue.z); } }
Use an ISerializationSurrogate for the Vector3 type. Code (CSharp): using System.Runtime.Serialization; using UnityEngine; sealed class Vector3SerializationSurrogate : ISerializationSurrogate { // Method called to serialize a Vector3 object public void GetObjectData(System.Object obj, SerializationInfo info, StreamingContext context) { Vector3 v3 = (Vector3) obj; info.AddValue("x", v3.x); info.AddValue("y", v3.y); info.AddValue("z", v3.z); Debug.Log(v3); } // Method called to deserialize a Vector3 object public System.Object SetObjectData(System.Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) { Vector3 v3 = (Vector3) obj; v3.x = (float)info.GetValue("x", typeof(float)); v3.y = (float)info.GetValue("y", typeof(float)); v3.z = (float)info.GetValue("z", typeof(float)); obj = v3; return obj; // Formatters ignore this return value //Seems to have been fixed! } } Add it to your BinaryFormatter: Code (CSharp): using System.Runtime.Serialization; BinaryFormatter bf = new BinaryFormatter(); // 2. Construct a SurrogateSelector object SurrogateSelector ss = new SurrogateSelector(); Vector3SerializationSurrogate v3ss = new Vector3SerializationSurrogate(); ss.AddSurrogate(typeof(Vector3), new StreamingContext(StreamingContextStates.All), v3ss); // 5. Have the formatter use our surrogate selector bf.SurrogateSelector = ss;
Serialisation Exceptions are thrown when you try to serialise an object which is not marked Serializable Solution for this is same as said by @Cherno implement ISerializationSurrogate to extend serialization support to classes which are not marked as Serializable. Check this link for more info on how to use surrogate classes https://msdn.microsoft.com/en-us/library/system.runtime.serialization.surrogateselector(v=vs.110).aspx
I had that same issue, so ended up creating mine, can use used to save transform position and vector3 position Code (CSharp): [Serializable] public class Position { public float x = 0; public float y = 0 ; public float z = 0; public void Positon(Transform transform) { x = transform.position.x; y = transform.position.y; z = transform.position.z; } public void Positon(Vector3 vector) { x = vector.x; y = vector.y; z = vector.z; } public void Positon(float posX, float posY, float posZ) { x = posX; y = posY; z = posZ; } } hope it helps
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.
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.
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/
Surprised that this is still a problem. Anyway, this is my serializable Vector3S workaround that includes Vector3 constructors, operator and implicit overloading for easy interaction with Vector3 (ie you can largely treat them as though they are Vector3 in Unity code). Code (CSharp): [Serializable] public class Vector3S { public float x; public float y; public float z; public Vector3S() { x = y = z = 0; } public Vector3S(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public Vector3S(Vector3 orig) { x = orig.x; y = orig.y; z = orig.z; } public Vector3 AsVector3() { return new Vector3() { x = this.x, y = this.y, z = this.z }; } #region OPERATOR_OVERLOADS public static Vector3 operator +(Vector3S a, Vector3 b) { return a.AsVector3() + b; } public static Vector3 operator +(Vector3 a, Vector3S b) { return a + b.AsVector3(); } public static Vector3 operator -(Vector3S a, Vector3 b) { return a.AsVector3() - b; } public static Vector3 operator -(Vector3 a, Vector3S b) { return a - b.AsVector3(); } public static implicit operator Vector3S(Vector3 v) { return new Vector3S(v); } #endregion } Probably bugs and such that I haven't noticed yet, but maybe a good starting point for a pain-free Vector3 serialization experience.