Saving and Loading a procedurally generated planet?

I am quite new to procedural generation and Saving and Loading. I have a script that procedurally generates a planet according to some values I put in. Now, I am trying to save that planet and load it when I run the game. But without succes.

This it the code for generating the planet:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class PlanetGenerator : MonoBehaviour
{
    [Header("Base Settings:")]
    public float Radius;
    public int IcosphereSubdivisions;
    public Material PlanetMaterial;
    public bool SmoothNormals;
    public bool Rotate;
    public float TurnSpeed;
    public List<ColorSetting> Colors = new List<ColorSetting>();

    [Header("Oceans:")]
    public bool DrawShore;
    public float MinShoreWidth;
    public float MaxShoreWidth;

    [Header("Continents:")]
    public int MaxAmountOfContinents;
    public float ContinentsMinSize;
    public float ContinentsMaxSize;
    public float MinLandExtrusionHeight;
    public float MaxLandExtrusionHeight;

    [Header("Mountains:")]
    public float MaxAmountOfMountains;
    public float MountainBaseSize;
    public float MinMountainHeight;
    public float MaxMountainHeight;

    [Header("Bumpiness:")]
    public float MinBumpFactor;
    public float MaxBumpFactor;

    private GameObject planetGameObject;
    private MeshRenderer meshRenderer;
    private MeshFilter meshFilter;
    private Mesh planetMesh;

    private List<MeshTriangle> MeshTriangles = new List<MeshTriangle>();
    private List<Vector3> Vertices = new List<Vector3>();

    private TriangleHashSet oceans;
    private TriangleHashSet continents;
    private TriangleHashSet continentsSides;
    private TriangleHashSet mountains;

    private MeshCollider meshCollider;

    public bool generatePlanet = true;

    public void Start()
    {
        if(generatePlanet)
        {
            StartGeneration();
        }
    }

    public Color FindColor(string _name)
    {
        for(int i = 0; i < Colors.Count; i++)
        {
            if(Colors[i].name == _name)
            {
                return Colors[i].color;
            }
        }

        return Color.magenta;
    }

    public void StartGeneration()
    {
        planetGameObject = this.gameObject;
        planetGameObject.transform.parent = transform;

        if(meshRenderer == null)
        {
            meshRenderer = planetGameObject.AddComponent<MeshRenderer>();
            meshRenderer.material = PlanetMaterial;
        }

        if(meshFilter == null)
        {
            meshFilter = planetGameObject.AddComponent<MeshFilter>();
        }

        if (meshCollider == null)
        {
            meshCollider = planetGameObject.GetComponent<MeshCollider>();
            if (meshCollider == null)
            {
                meshCollider = planetGameObject.AddComponent<MeshCollider>();
            }
        }
        
        planetMesh = new Mesh();
        GenerateIcosphere();
        CalculateNeighbors();

        AddContinents();
        AddOceans();
        AddMountains();
        GenerateMesh();
        GenerateCollider();

        // Add a sphere collider to the planetGameObject
        //SphereCollider sphereCollider = planetGameObject.AddComponent<SphereCollider>();
        //sphereCollider.radius = Radius / 8.7f;
    }

    private void AddContinents()
    {
        continents = new TriangleHashSet();

        for(int i = 0; i < MaxAmountOfContinents; i++)
        {
            float continentSize = Random.Range(ContinentsMinSize, ContinentsMaxSize);
            TriangleHashSet addedLandmass = GetTriangles(Random.onUnitSphere, continentSize, MeshTriangles);
            Debug.Log("continetSize:" + continentSize);
            continents.UnionWith(addedLandmass);
        }
        continents.ApplyColor(FindColor("GrassColor"));

        continentsSides = Extrude(continents, Random.Range(MinLandExtrusionHeight,MaxLandExtrusionHeight));
        continentsSides.ApplyColor(FindColor("DirtColor"));

        foreach(MeshTriangle triangle in continents)
        {
            Vector3[] currentVerts = new Vector3[3];
            for(int i = 0; i < triangle.VertexIndices.Count; i++)
            {
                currentVerts[i] = Vertices[triangle.VertexIndices[i]];
            }
            AddBumpyness(currentVerts);
            for(int i = 0; i < triangle.VertexIndices.Count; i++)
            {
                Vertices[triangle.VertexIndices[i]] = currentVerts[i];
            }
        }
    }

    private void AddOceans()
    {
        oceans = new TriangleHashSet();

        foreach (MeshTriangle triangle in MeshTriangles)
        {
            if (!continents.Contains(triangle))
                oceans.Add(triangle);
        }

        TriangleHashSet ocean = new TriangleHashSet(oceans);
        ocean.ApplyColor(FindColor("OceanColor"));
        if(DrawShore)
        {
            TriangleHashSet shore;
            shore = Inset(ocean, Random.Range(MinShoreWidth,MaxShoreWidth));
            shore.ApplyColor(FindColor("ShoreColor"));

            shore = Extrude(ocean, -0.02f);
            shore.ApplyColor(FindColor("OceanColor"));
        
            shore = Inset(ocean, 0.02f);
            shore.ApplyColor(FindColor("OceanColor"));
        }
    }

    private void AddMountains()
    {
        TriangleHashSet sides;

        for(int i = 0; i < MaxAmountOfMountains; i++)
        {
            mountains = GetTriangles(Random.onUnitSphere, MountainBaseSize, continents);
            mountains.ApplyColor(FindColor("DirtColor"));
            continents.UnionWith(mountains);
            sides = Extrude(mountains,Random.Range(MinMountainHeight,MaxMountainHeight));
            sides.ApplyColor(FindColor("DirtColor"));

            mountains.ApplyColor(FindColor("HillColor"));
            mountains = GetTriangles(Random.onUnitSphere, MountainBaseSize * -.33f, continents);  
            continents.UnionWith(mountains);
            sides = Extrude(mountains,Random.Range(MinMountainHeight,MaxMountainHeight));
            mountains.ApplyColor(FindColor("HillColor"));

            mountains = GetTriangles(Random.onUnitSphere, MountainBaseSize * -.66f, continents); 
            continents.UnionWith(mountains); 
            sides = Extrude(mountains,Random.Range(MinMountainHeight,MaxMountainHeight));
            mountains.ApplyColor(FindColor("HillColor"));
        }
    }

    private void Update()
    {
        if(Rotate)
        {
            transform.Rotate(Vector3.up, TurnSpeed * Time.deltaTime);
        }
    }


    public void GenerateIcosphere()
    {
        this.transform.localScale = Vector3.one * Radius;
        MeshTriangles = new List<MeshTriangle>();
        Vertices = new List<Vector3>();

        float t = (1.0f + Mathf.Sqrt(5.0f)) / 2.0f;

        Vertices.Add(new Vector3(-1,  t,  0).normalized);
        Vertices.Add(new Vector3( 1,  t,  0).normalized);
        Vertices.Add(new Vector3(-1, -t,  0).normalized);
        Vertices.Add(new Vector3( 1, -t,  0).normalized);
        Vertices.Add(new Vector3( 0, -1,  t).normalized);
        Vertices.Add(new Vector3( 0,  1,  t).normalized);
        Vertices.Add(new Vector3( 0, -1, -t).normalized);
        Vertices.Add(new Vector3( 0,  1, -t).normalized);
        Vertices.Add(new Vector3( t,  0, -1).normalized);
        Vertices.Add(new Vector3( t,  0,  1).normalized);
        Vertices.Add(new Vector3(-t,  0, -1).normalized);
        Vertices.Add(new Vector3(-t,  0,  1).normalized);

        MeshTriangles.Add(new MeshTriangle( 0, 11,  5));
        MeshTriangles.Add(new MeshTriangle( 0,  5,  1));
        MeshTriangles.Add(new MeshTriangle( 0,  1,  7));
        MeshTriangles.Add(new MeshTriangle( 0,  7, 10));
        MeshTriangles.Add(new MeshTriangle( 0, 10, 11));
        MeshTriangles.Add(new MeshTriangle( 1,  5,  9));
        MeshTriangles.Add(new MeshTriangle( 5, 11,  4));
        MeshTriangles.Add(new MeshTriangle(11, 10,  2));
        MeshTriangles.Add(new MeshTriangle(10,  7,  6));
        MeshTriangles.Add(new MeshTriangle( 7,  1,  8));
        MeshTriangles.Add(new MeshTriangle( 3,  9,  4));
        MeshTriangles.Add(new MeshTriangle( 3,  4,  2));
        MeshTriangles.Add(new MeshTriangle( 3,  2,  6));
        MeshTriangles.Add(new MeshTriangle( 3,  6,  8));
        MeshTriangles.Add(new MeshTriangle( 3,  8,  9));
        MeshTriangles.Add(new MeshTriangle( 4,  9,  5));
        MeshTriangles.Add(new MeshTriangle( 2,  4, 11));
        MeshTriangles.Add(new MeshTriangle( 6,  2, 10));
        MeshTriangles.Add(new MeshTriangle( 8,  6,  7));
        MeshTriangles.Add(new MeshTriangle( 9,  8,  1));

        Subdivide();
    }

    public void Subdivide()
    {
        var midPointCache = new Dictionary<int, int>();

        for (int i = 0; i < IcosphereSubdivisions; i++)
        {
            var newPolys = new List<MeshTriangle>();
            foreach (var poly in MeshTriangles)
            {
                int a = poly.VertexIndices[0];
                int b = poly.VertexIndices[1];
                int c = poly.VertexIndices[2];

                int ab = GetMidPointIndex(midPointCache, a, b);
                int bc = GetMidPointIndex(midPointCache, b, c);
                int ca = GetMidPointIndex(midPointCache, c, a);

                newPolys.Add(new MeshTriangle(a, ab, ca));
                newPolys.Add(new MeshTriangle(b, bc, ab));
                newPolys.Add(new MeshTriangle(c, ca, bc));
                newPolys.Add(new MeshTriangle(ab, bc, ca));
            }
            
            MeshTriangles = newPolys;
        }
    }

    private void GenerateCollider()
    {
        Mesh mesh = new Mesh();
        mesh.vertices = Vertices.ToArray();
        mesh.triangles = GetTriangleIndices().ToArray();
        mesh.RecalculateNormals();

        meshCollider.sharedMesh = mesh;
    }

    public int GetMidPointIndex(Dictionary<int, int> cache, int indexA, int indexB)
    {
        int smallerIndex = Mathf.Min(indexA, indexB);
        int greaterIndex = Mathf.Max(indexA, indexB);
        int key = (smallerIndex << 16) + greaterIndex;

        // If a midpoint is already defined, just return it.

        int ret;
        if (cache.TryGetValue(key, out ret))
            return ret;

        // If we're here, it's because a midpoint for these two
        // vertices hasn't been created yet. Let's do that now!

        Vector3 p1 = Vertices[indexA];
        Vector3 p2 = Vertices[indexB];
        Vector3 middle = Vector3.Lerp(p1, p2, 0.5f).normalized;

        ret = Vertices.Count;
        Vertices.Add(middle);

        // Add our new midpoint to the cache so we don't have
        // to do this again.

        cache.Add(key, ret);
        return ret;
    }

    public void CalculateNeighbors()
    {
        foreach (MeshTriangle poly in MeshTriangles)
        {
            foreach (MeshTriangle other_poly in MeshTriangles)
            {
                if (poly == other_poly)
                    continue;

                if (poly.IsNeighbouring(other_poly))
                    poly.Neighbours.Add(other_poly);
            }
        }
    }

    public List<int> CloneVertices(List<int> old_verts)
    {
        List<int> new_verts = new List<int>();
        foreach (int old_vert in old_verts)
        {
            Vector3 cloned_vert = Vertices[old_vert];
            new_verts.Add(Vertices.Count);
            Vertices.Add(cloned_vert);
        }
        return new_verts;
    }

    public TriangleHashSet StitchPolys(TriangleHashSet polys, out BoarderHashSet stitchedEdge)
    {
        TriangleHashSet stichedPolys = new TriangleHashSet();

        stichedPolys.IterationIndex = Vertices.Count;

        stitchedEdge      = polys.CreateBoarderHashSet();
        var originalVerts = stitchedEdge.RemoveDublicates();
        var newVerts      = CloneVertices(originalVerts);

        stitchedEdge.Seperate(originalVerts, newVerts);

        foreach (TriangleBoarder edge in stitchedEdge)
        {
            // Create new polys along the stitched edge. These
            // will connect the original poly to its former
            // neighbor.

            var stitch_poly1 = new MeshTriangle(edge.OuterVertices[0],
                                           edge.OuterVertices[1],
                                           edge.InnerVertices[0]);
            var stitch_poly2 = new MeshTriangle(edge.OuterVertices[1],
                                           edge.InnerVertices[1],
                                           edge.InnerVertices[0]);
            // Add the new stitched faces as neighbors to
            // the original Polys.
            edge.InnerTriangle.UpdateNeighbour(edge.OuterTriangle, stitch_poly2);
            edge.OuterTriangle.UpdateNeighbour(edge.InnerTriangle, stitch_poly1);

            MeshTriangles.Add(stitch_poly1);
            MeshTriangles.Add(stitch_poly2);

            stichedPolys.Add(stitch_poly1);
            stichedPolys.Add(stitch_poly2);
        }

        //Swap to the new vertices on the inner polys.
        foreach (MeshTriangle poly in polys)
        {
            for (int i = 0; i < 3; i++)
            {
                int vert_id = poly.VertexIndices[i];
                if (!originalVerts.Contains(vert_id))
                    continue;
                int vert_index = originalVerts.IndexOf(vert_id);
                poly.VertexIndices[i] = newVerts[vert_index];
            }
        }

        return stichedPolys;
    }

    public TriangleHashSet Extrude(TriangleHashSet polys, float height)
    {
        BoarderHashSet stitchedEdge;
        TriangleHashSet stitchedPolys = StitchPolys(polys, out stitchedEdge);
        List<int> verts = polys.RemoveDublicates();

        // Take each vertex in this list of polys, and push it
        // away from the center of the Planet by the height
        // parameter.

        foreach (int vert in verts)
        {
            Vector3 v = Vertices[vert];
            v = v.normalized * (v.magnitude + height);
            Vertices[vert] = v;
        }

        return stitchedPolys;
    }

    public TriangleHashSet Inset(TriangleHashSet polys, float insetDistance)
    {
        BoarderHashSet stitchedEdge;
        TriangleHashSet stitchedPolys = StitchPolys(polys, out stitchedEdge);

        Dictionary<int, Vector3> inwardDirections = stitchedEdge.GetInwardDirections(Vertices);

        // Push each vertex inwards, then correct
        // it's height so that it's as far from the center of
        // the planet as it was before.

        foreach (KeyValuePair<int, Vector3> kvp in inwardDirections)
        {
            int     vertIndex       = kvp.Key;
            Vector3 inwardDirection = kvp.Value;

            Vector3 vertex = Vertices[vertIndex];
            float originalHeight = vertex.magnitude;

            vertex += inwardDirection * insetDistance;
            vertex  = vertex.normalized * originalHeight;
            Vertices[vertIndex] = vertex;
        }

        return stitchedPolys;
    }

    public TriangleHashSet GetTriangles(Vector3 center, float radius, IEnumerable<MeshTriangle> source)
    {
        TriangleHashSet newSet = new TriangleHashSet();

        foreach(MeshTriangle p in source)
        {
            foreach(int vertexIndex in p.VertexIndices)
            {
                float distanceToSphere = Vector3.Distance(center, Vertices[vertexIndex]);

                if (distanceToSphere <= radius)
                {
                    newSet.Add(p);
                    break;
                }
            }
        }

        return newSet;
    }

    public void GenerateMesh()
    {
        int vertexCount = MeshTriangles.Count * 3;

        int[] indices = new int[vertexCount];

        Vector3[] vertices = new Vector3[vertexCount];
        Vector3[] normals  = new Vector3[vertexCount];
        Color32[] colors   = new Color32[vertexCount];
        Vector2[] uvs      = new Vector2[vertexCount];

        for (int i = 0; i < MeshTriangles.Count; i++)
        {
            var poly = MeshTriangles[i];

            indices[i * 3 + 0] = i * 3 + 0;
            indices[i * 3 + 1] = i * 3 + 1;
            indices[i * 3 + 2] = i * 3 + 2;

            vertices[i * 3 + 0] = Vertices[poly.VertexIndices[0]];
            vertices[i * 3 + 1] = Vertices[poly.VertexIndices[1]];
            vertices[i * 3 + 2] = Vertices[poly.VertexIndices[2]];

            uvs[i * 3 + 0] = poly.UVs[0];
            uvs[i * 3 + 1] = poly.UVs[1];
            uvs[i * 3 + 2] = poly.UVs[2];

            colors[i * 3 + 0] = poly.Color;
            colors[i * 3 + 1] = poly.Color;
            colors[i * 3 + 2] = poly.Color;

            if(SmoothNormals)
            {
                normals[i * 3 + 0] = Vertices[poly.VertexIndices[0]].normalized;
                normals[i * 3 + 1] = Vertices[poly.VertexIndices[1]].normalized;
                normals[i * 3 + 2] = Vertices[poly.VertexIndices[2]].normalized;
            }
            else
            {
                Vector3 ab = Vertices[poly.VertexIndices[1]] - Vertices[poly.VertexIndices[0]];
                Vector3 ac = Vertices[poly.VertexIndices[2]] - Vertices[poly.VertexIndices[0]];

                Vector3 normal = Vector3.Cross(ab, ac).normalized;

                normals[i * 3 + 0] = normal;
                normals[i * 3 + 1] = normal;
                normals[i * 3 + 2] = normal;
            }
        }

        planetMesh.vertices = vertices;
        planetMesh.normals  = normals;
        planetMesh.colors32 = colors;
        planetMesh.uv       = uvs;

        planetMesh.SetTriangles(indices, 0);

        meshFilter.mesh = planetMesh;

    }

    private List<int> GetTriangleIndices()
    {
        List<int> triangleIndices = new List<int>();
        foreach (MeshTriangle triangle in MeshTriangles)
        {
            triangleIndices.Add(triangle.VertexIndices[0]);
            triangleIndices.Add(triangle.VertexIndices[1]);
            triangleIndices.Add(triangle.VertexIndices[2]);
        }
        return triangleIndices;
    }

    Vector3[] AddBumpyness(Vector3[] verts) {
       Dictionary<Vector3, List<int>> dictionary = new Dictionary<Vector3, List<int>>();
       for (int x = 0; x < verts.Length; x++) {
          if (!dictionary.ContainsKey(verts[x])) {
               dictionary.Add(verts[x], new List<int>());
           }
           dictionary[verts[x]].Add(x);
       }
       foreach (KeyValuePair<Vector3, List<int>> pair in dictionary) {
         Vector3 newPos = pair.Key * Random.Range(MinBumpFactor, MaxBumpFactor);
           foreach (int i in pair.Value) {
               verts[i] = newPos;
          }
       }
        return verts;
    }
}

I would greatly appreciate some help. Thank you!

Saving a proceduraly generated object is really a complex thing.
It depends on how you generate your object.
For example, you can use the concept of seeds, it is a string or a set of numbers that will tell to your script what to do to load your object.

Let’s say that for your planet, you have different parameters. They are randomizing, but at the end, you get a value. This value, which is a value between min and max (for example, MinShoreWidgth and MaxShoreWidth) can be then, set between 0 and 255, which is the min value and max value of 2 hexadecimal digits. If you want to have a higher range, to make the saving more precise, you can increase the number of hexadecimal digits.
Knowing that, you can save every random numbers you got as a set of digits, creating you a seed.

Example:
All my values are being set between 0 and 100. And I have 5 random values defining my procedural object. If my 5 random values are: 54, 77, 61, 13, 89, Then, they would transform in 2 hexadecimal digits, so 36, 4D, 3D, 0D, 59. Letting me have a seed, 364D3D0D59.

Now, to load it back, you just need to take the values and separate them 2 by 2. Then transforming it back to decimal numbers, and then creating the object again with defined values.

Note that it is only way to do it, and there are multiple ones left. I’m sure some are more easier, and others less.

Hope it helps giving you an idea on how to do it ^^