Save List(Vector3)

Hello everybody,
For my VR project, I have to save a list of Vector3 in a file but I have tried several methods but I did not succeed.
Do you have any tips to help me please?
Thank you in advance.

‘I did not succeed’ doesn’t exactly tells us what issues you were running into. At which point were you running into issues?

I do know that if you try to serialise a Vector3 to a file using something like Newtonsoft.JSON it will have issues, so you’ll need to implement a serialisable surrogate.

3 Likes

This is the error : SerializationException: Type ‘UnityEngine.Vector3’ in Assembly ‘UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’ is not marked as serializable.

using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.Serialization.Formatters.Binary;

public class Trajectory : MonoBehaviour
{
    [SerializeField] private GameObject Circle;
    [SerializeField] private GameObject ObjectToFollow;
    private float timestamp = 0.0f;
    [SerializeField] private float delay = 0.05f;
    private int i = 0;
    [SerializeField] private List<Vector3> tab;


    private void Start()
    {
        tab = new List<Vector3>();
    }
    void Update()
    {
        if (timestamp <= Time.time && Time.time > 12.0f)
        {
            timestamp = Time.time + delay;
            Instantiate(Circle, ObjectToFollow.transform.position, Quaternion.identity);
            i += 1;
            tab.Add(ObjectToFollow.transform.position);
        }

        if (i == 10) Save(tab); //only for a test
           
    }

    public static void Save(List<Vector3> tab)
    {
        FileStream fs = File.Create("test.txt");
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(fs, tab);
        fs.Close();
    }
}

Now go read the second line of Spiney’s post.

ALSO, beware of this:

Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

https://docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide

2 Likes

How can I implement a serialisable surrogate ? I have never done it

It’s just a fancy way of saying “Make your own class just like a Vector3 and copy data in and out of the three fields.”

Then make your list out of your surrogate class and have code to marshal the data in and out.

1 Like

Okay I understand now, I will try to do this. Thank you

Here’s one I threw together ages ago when I ran into this problem, using Newtonsoft.JSON:

namespace LBG
{
    using UnityEngine;
    using Newtonsoft.Json;

    /// <summary>
    /// Json Serializable Vector3 serialisable surrogate.
    /// </summary>
    [System.Serializable]
    [JsonObject(MemberSerialization = MemberSerialization.OptIn)]
    public struct Vector3S
    {
        #region Constructor

        public Vector3S(Vector3 vector3)
        {
            _x = vector3.x;
            _y = vector3.y;
            _z = vector3.z;
        }
       
        public Vector3S(float x, float y, float z)
        {
            _x = x;
            _y = y;
            _z = z;
        }

        #endregion

        #region Inspector Fields
        [SerializeField, JsonProperty]
        private float _x;

        [SerializeField, JsonProperty]
        private float _y;

        [SerializeField, JsonProperty]
        private float _z;

        #endregion

        #region Properties
        public float X { get => _x; set => _x = value; }
        public float Y { get => _y; set => _y = value; }
        public float Z { get => _z; set => _z = value; }

        /// <summary>
        /// Returns the Vector3S as a Unity Vector3.
        /// </summary>
        public Vector3 AsVector3
        {
            get
            {
                return new Vector3(_x, _y, _z);
            }
        }

        #endregion
    }
}

Could easily be more functional, but if your only purpose is to serialise Vector3’s then this is all you need really.

2 Likes

Simple alternatives when you want to serialize a list of vectors to json is:

  • Use Unity’s JsonUtility. It supports Vector3 out of the box, just be aware of it’s limitations. You can not serialize a List on its own. You have to use a class that contains the list
  • Use my SimpleJSON library with the Unity extension.file.

If you need / want a compact format, you can always just use the BinaryReader / Writer to write out your list “manually”.

You can use an extension class like this:

BinaryReader / Writer extension for Vector3 and List

    using System.IO;
    using System.Collections.Generic;
    public static class BinaryWriterReaderExt
    {
        public static void Write(this BinaryWriter aWriter, Vector3 aVec)
        {
            aWriter.Write(aVec.x);
            aWriter.Write(aVec.y);
            aWriter.Write(aVec.z);
        }
        public static Vector3 ReadVector3(this BinaryReader aReader)
        {
            return new Vector3(aReader.ReadSingle(), aReader.ReadSingle(), aReader.ReadSingle());
        }

        public static void Write(this BinaryWriter aWriter, List<Vector3> aVectorList)
        {
            aWriter.Write(aVectorList.Count);
            for (int i = 0; i < aVectorList.Count; i++)
                aWriter.Write(aVectorList[i]);
        }
        public static int ReadVector3List(this BinaryReader aReader, ref List<Vector3> aVectorList)
        {
            if (aVectorList == null)
                aVectorList = new List<Vector3>();
            int count = aReader.ReadInt32();
            if (aVectorList.Capacity < aVectorList.Count + count)
                aVectorList.Capacity = aVectorList.Count + count;
            for (int i = 0; i < count; i++)
                aVectorList.Add(aReader.ReadVector3());
            return count;
        }
        public static List<Vector3> ReadVector3List(this BinaryReader aReader)
        {
            var list = new List<Vector3>();
            aReader.ReadVector3List(ref list);
            return list;
        }
    }

With that you can do:

        public static void Save(List<Vector3> tab)
        {
            using (FileStream fs = File.Create("test.txt"))
            using (var w = new BinaryWriter(fs))
                w.Write(tab);
        }
        public static List<Vector3> Load()
        {
            using (FileStream fs = File.OpenRead("test.txt"))
            using (var r = new BinaryReader(fs))
                return r.ReadVector3List();
        }

This is the most compact uncompressed form you can store a Vector3 list. It’s exactly 12 bytes per vector3 + 4 bytes for the length.

2 Likes