Serializing auto-generated values into Unity scene

I’ve been plagued by the same issue for a couple of days now and can’t seem to be able to come up with or find a satisfactory solution to it.

I have created a simple system which lets me define functionality for a component which is executed exclusively in editor mode (and which is not executed when the player is running in the editor either). This makes it much easier and less time consuming for me to manage my scenes, as much of the work becomes automated once I’ve defined the necessary functions. The problem I’ve run into, however, seems to be related.

In Unity, public member variables for a component are serialized into the scene automatically. Pretty nifty feature. Unfortunately, it appears that Unity does not serialize values which are set through my automated editor-mode-only system. As far as I can see, Unity only serializes a variable value if it is input directly by the user into the inspector.

Here’s the particular class which is giving me grief at the moment:

/// <summary>
/// Component to be attached to game objects which have a local Mesh Filter component which is reset due to the Unity
/// bug whereby game objects created from prefabs do not persist procedurally generated meshes.
/// </summary>
public class THMeshPersistor : MonoBehaviour
{
	public Vector3[] vertices = null; /// Recorded mesh vertices.
	public Vector2[] uvs = null; /// Recorded mesh UV co-ordinates.
	public int[] triangles = null;  /// Recorded mesh index buffer.

	// Local components
	private MeshFilter meshFilter = null;  /// Local Mesh Filter component.

	private Mesh latestRecordedMesh = null; /// Latest recorded mesh.

	/// <summary>
	/// Called upon first activity.
	/// </summary>
	public void Start()
	{
		// Do nothing.
	}

	/// <summary>
	/// Performs necessary initialisation.
	/// </summary>
	public void Init()
	{
		// Obtain references to local components.
		if(meshFilter == null)
			meshFilter = GetComponent<MeshFilter>();
	}

	/// <summary>
	/// Records the mesh from the Mesh Filter.
	/// </summary>
	private void RecordMesh()
	{
		// Update last recorded mesh.
		latestRecordedMesh = meshFilter.sharedMesh;

		// Record vertices.
		vertices = new Vector3[latestRecordedMesh.vertexCount];
		System.Array.Copy(latestRecordedMesh.vertices, vertices, latestRecordedMesh.vertexCount);
		// Record UVs.
		uvs = new Vector2[latestRecordedMesh.vertexCount];
		System.Array.Copy(latestRecordedMesh.uv, uvs, latestRecordedMesh.vertexCount);
		// Record indices.
		triangles = new int[latestRecordedMesh.triangles.Length];
		System.Array.Copy(latestRecordedMesh.triangles, triangles, latestRecordedMesh.triangles.Length);
	}

	/// <summary>
	/// Restores the Mesh Filter's mesh from the latest record.
	/// </summary>
	private void ReassembleMesh()
	{
		if(vertices == null || uvs == null || triangles == null)
			return;

		Mesh mesh = new Mesh();
		// Reassemble vertices.
		mesh.vertices = new Vector3[vertices.Length];
		System.Array.Copy(vertices, mesh.vertices, vertices.Length);
		// Reassemble UVs.
		mesh.uv = new Vector2[uvs.Length];
		System.Array.Copy(uvs, mesh.uv, uvs.Length);
		// Reassemble indices.
		mesh.triangles = new int[triangles.Length];
		System.Array.Copy(triangles, mesh.triangles, triangles.Length);

		meshFilter.sharedMesh = mesh;


	}

	/// <summary>
	/// Update function reserved for use in editor mode.
	/// </summary>
	public void EditorUpdate()
	{
		Init();

		// Record mesh if it has changed.
		if(meshFilter.sharedMesh != null && meshFilter.sharedMesh != latestRecordedMesh)
			RecordMesh();
		else if(meshFilter.sharedMesh == null) // Reassemble mesh if it is absent.
			ReassembleMesh();
	}
}

As you’ve probably figured out, the code in the EditorUpdate() function is what gets executed to do the automated work for me.

Is there a way of forcing Unity to serialize my member variables programatically? I can forfeit Unity serialization and serialize it myself to some other file on disk, but I would prefer to avoid this situation.

I think it would be best to move all your editor related code to a proper editor script instead of making it reside at runtime (note that despite the code there won’t be executed in the player, it will be there anyway). If that’s a limitation for you, every time you change a serializable field in your script, call EditorUtility.SetDirty (this).

When you work directly with editor scripts you get access to SerializedObject and SerializedProperty among other great APIs to do exactly what you want. Using serialized properties help you track the state of your assets (e.g. bold on prefabs, dirty state, undo support). And also, you make sure all this code is compiled on an editor pass and it’s not going to be compiled on the runtime assembly (i.e. smaller assembly size). Here’s an example.