I am having some trouble with the initialization of scripts when it comes to the OnValidate function calls. In particular I don’t understand when and why it is called in prefabs, and I would appreciate if someone can explain to me what happens.
More specifically, it seems that every time I edit anything in the inspector (in the prefab mode) the OnValidate is called several times, and the variables of the prefab itself keep changing.
I have the following example where a prefab has 1 public variable (so I could activate the OnValidate), and 3 private variables - 1 primitive (integer), 1 standard class, and 1 MonoBehaviour (Line renderer).
Also, since I want the intialization to happened just once, I added a boolean variable which checks if the script was initialized already or not (The Init method is what I usually call in the Awake()).
class SecondClass
{
public int number = 0;
}
public class InitTry : MonoBehaviour
{
private bool initialized = false;
public int index = 0;
private int temp = 0;
private SecondClass secondClass;
private LineRenderer lineRenderer;
public void Init()
{
if (initialized)
return;
TrueInitialize();
initialized = true;
}
public void TrueInitialize()
{
temp = 1; // private primitive
secondClass = new SecondClass(); // private class
secondClass.number = 2;
lineRenderer = gameObject.GetComponent<LineRenderer>();
}
private void OnValidate()
{
Debug.Log($"BEFORE: initialized = {initialized}, temp = {temp}, index = {index}, " +
$"second class = {(secondClass == null ? -1 : secondClass.number)} " +
$"renderer = {(lineRenderer == null ? -1 : 100)}");
Init();
Debug.Log($"AFTER: initialized = {initialized}, temp = {temp}, index = {index}, " +
$"second class = {(secondClass == null ? -1 : secondClass.number)} " +
$"renderer = {(lineRenderer == null ? -1 : 100)}");
}
}
When I change the public variable, the OnValidate is usually called 4 times:
- When I change the variable, but before pressing enter, or loosing the focus in the field input, there is a single OnValidate call where (1) the call stack starts at the GUI process, (2) the ‘initialized’ flag is true before and after the Init call, and (3) all of the other variables are already initialized properly:
AFTER: initialized = True, temp = 1, index = 0, second class = 2 renderer = 100```
2. Once I press enter, or move out of the input field, there is a second call. This time (1) the call stack moves through a "SavePrefabAsAsset" stage, (2) the 'initialized' flag is false BEFORE the init call and (3) after the init call it becomes true and all the other variables are initialized properly :
```BEFORE: initialized = False, temp = 0, index = 0, second class = -1 renderer = -1
AFTER: initialized = True, temp = 1, index = 0, second class = 2 renderer = 100```
3. Afterwards there are two more calls, where (1) they are still part of the same "SavePrefabAsAsset" call (2) the 'initialized' flag is true before and after the Init call and (3) the only variable with the right value is the primitive float 'temp' variable:
BEFORE: initialized = True, temp = 1, index = 0, second class = -1 renderer = -1
AFTER: initialized = True, temp = 1, index = 0, second class = -1 renderer = -1
BEFORE: initialized = True, temp = 1, index = 0, second class = -1 renderer = -1
AFTER: initialized = True, temp = 1, index = 0, second class = -1 renderer = -1
The first call seems to be what needs to happen with the prefab that I am editing. The second is like Unity generates another copy to save from scratch. My problem is the two other calls. Not only that I don't know why they are happening, because the 'initialized' is always true at the beginning, the other non primitive values don't get the right values. This is a problem for me because usually after the initialization I want to use these values, and I keep getting null pointer errors.
Sometimes there are extra calls, either of the second or third kind.
Anyway, I would appreciate any help with understanding what happens here.