I’ve been helping out my friends over at Three Phase Interactive on their game Defect: Spaceship Destruction Kit a little bit. The game is being developed in Unity, and they’re using Perforce for source control. We’re using different combinations of the built-in Unity Perforce support and the P4Connect plugin. We’ve had a strange issue in Unity for a while now where it would try to check out two specific prefabs seemingly randomly. There seemed to be no reason why, as the prefabs weren’t directly being changed!
After much searching around and digging, I was able to discover the reason for this. If you have a prefab in your project with a
MonoBehaviour which implements the
OnValidate function, Unity will at times execute the
OnValidate on prefabs that aren’t in the current scene and are not even selected in the project tab.
OnValidate, if you assign any values to certain members, Unity then flags the prefab as dirty, and thus when you save the project it decides that it needs to be checked out of source control. In our case the values weren’t actually changing; they were being set to the same as their initial values, so the prefabs would be checked out but then there wouldn’t be any changes in the file.
The most common times when Unity runs
OnValidate appear to be when entering play mode, and when Unity rebuilds after code has changed.
I was able to reproduce this behaviour in a small test project, but only when modifying properties of the
GameObject‘s transform (e.g. setting
transform.rotation to identity). Setting serialised class members didn’t seem to trigger this issue, so it seems that it only happens if you set built-in Unity properties (maybe it hooks into the property setter).
In SDK the way I solved this was to add this code to the top of the
#if UNITY_EDITOR if (gameObject.hideFlags == HideFlags.HideInHierarchy) return; #endif
However in my test project, that didn’t work, and I had to instead do this:
if (transform.rotation != Quaternion.identity) transform.rotation = Quaternion.identity;
I suspect that only changing the values if they are different is the more reliable method; in SDK prefabs seemed to be set to
HideInHierarchy but that wasn’t the case in my test project. I’m not sure why as I couldn’t see anywhere where it was changing the hide flags, so I may have to go back and change it in SDK.