Serialized Fields Lost On Play

This is kind of a complicated question so please bear with me. :slight_smile:

Setup -
I have two prefabs: a node and an edge. The node is a go with the following MonoBehaviour:

[ExecuteInEditMode]
public class NodeController : MonoBehaviour {
	
	[SerializeField]
	private List<EdgeController> edges;
	[SerializeField]
	private EdgeController activeEdge;
	
	public void AddEdge(EdgeController edge) {
		
		if(!edges.Contains(edge))
			edges.Add(edge);
	}
	
	public void RemoveEdge(EdgeController edge) {
		
		if(edges.Contains(edge))
			edges.Remove(edge);
	}
	
	public void SetActiveEdge(EdgeController edge) {
		activeEdge = edge;
	}
	
	void Awake() {
		
		if(edges == null)
			edges = new List<EdgeController>();
	}
}

The edge is a go with the following MonoBehaviour:

[ExecuteInEditMode]
public class EdgeController : MonoBehaviour {
	
	[SerializeField]
	private NodeController node1;
	[SerializeField]
	private NodeController node2;
	
	public void SetNodes(NodeController node1, NodeController node2) {
		
		this.node1 = node1;
		this.node2 = node2;
		
		if(node1 != null)
			node1.AddEdge(this);
		if(node2 != null) 
			node2.AddEdge(this);
		
		node1.SetActiveEdge(this);
	}
}

I also have an Editor Class that creates a menu item. The Editor class looks like this:

public class GraphEditor : Editor {
	
	[MenuItem ("Custom/Create Edge")]
    static void CreateEdge () {
        
		List<NodeController> nodes = new List<NodeController>();
		foreach(GameObject go in Selection.gameObjects) {
			
			NodeController nc = (NodeController)go.GetComponent<NodeController>();
			if(nc != null)
				nodes.Add(nc);
		}
		
		if(nodes.Count == 2) {
			
			GameObject edge = (GameObject)Instantiate(Resources.Load("Models/Edge"));
			EdgeController edgeController = edge.GetComponent<EdgeController>();
			edgeController.SetNodes(nodes[0], nodes[1]);
		}
    }
}

How I Use it -
I drag two nodes into the Hierarchy. I then select both nodes and use my custom menu item to create an edge. Once I have done this the edge is storing a reference to both nodes and both nodes have the edges in their respective List. One node has activeEdge set to the edge I just created. This is all good and expected.

The Problem -
I press play and the nodes lose all references to the edge, but the edge retains its references to the nodes. Why are the nodes losing their references to the edges?

Thanks to Sarper Soher and this post I have found the answer. The solution is to change GraphEditor.CreateEdge() to the following:

public class GraphEditor : Editor {
	
	[MenuItem ("Custom/Create Edge")]
    static void CreateEdge () {
        
		List<NodeController> nodes = new List<NodeController>();
		foreach(GameObject go in Selection.gameObjects) {
			
			NodeController nc = (NodeController)go.GetComponent<NodeController>();
			if(nc != null)
				nodes.Add(nc);
		}
		
		if(nodes.Count == 2) {
			
			GameObject edge = (GameObject)Instantiate(Resources.Load("Models/Edge"));
			EdgeController edgeController = edge.GetComponent<EdgeController>();
			edgeController.SetNodes(nodes[0], nodes[1]);
			EditorUtility.SetDirty(nodes[0]);
			EditorUtility.SetDirty(nodes[1]);
		}
    }
}

The key is the call to EditorUtility.SetDirty(node). Doing this allows me to change the prefab without needing to break the connection.

Whenever I edit the private fields marked with SerializedField attribute on a prefab, If I don’t apply that state of the prefab, I lose the changes on play. I don’t know why. What you can do is, select all your prefab instances in the scene and select “Break Prefab Instance” from the Gameobject menu so they are no longer linked to the saved prefab, this way they preserve the changes on play mode.