Vector3 not serializable?

Hi

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

[System.Serializable] 
public class GhostNode
{
	public Vector3 position;
}

The code I use to serialize is pretty standard:

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

2 Likes

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? :wink:

I have serialized both Vector3s and Quaternions using the XMLSerializer. I don’t know what’s up in your case.

-Jeremy

Where/how do you declare the variables you serialize?

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 :slight_smile:

Well… now I know! And here goes nothing… :twisted:

Here’s my stupid solution:

    [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); } }
    }
3 Likes

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

using System;
using System.Reflection;
using UnityEngine.Internal;

namespace UnityEngine
{
    public struct Vector3
.....
.....
    {

get edited this way

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

        [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:

		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());
		}
1 Like