Unity-Technologies / com.unity.cinemachine

Smart camera tools for passionate creators
510 stars 117 forks source link

FindAllBehavioursInScene throws an exception if it finds a behavior without an associated gameobject #64

Closed NarryG closed 8 months ago

NarryG commented 4 years ago

When I exit play mode with "Save Play Mode Changes" box checked, I get an exception.

NullReferenceException: Object reference not set to an instance of an object
SaveDuringPlay.ObjectTreeUtil.FindAllBehavioursInScene[T] () (at Library/PackageCache/com.unity.cinemachine@2.6.0-preview.5/Editor/Utility/SaveDuringPlay.cs:78)
SaveDuringPlay.SaveDuringPlay.FindInterestingObjects () (at Library/PackageCache/com.unity.cinemachine@2.6.0-preview.5/Editor/Utility/SaveDuringPlay.cs:476)
SaveDuringPlay.SaveDuringPlay.SaveAllInterestingStates () (at Library/PackageCache/com.unity.cinemachine@2.6.0-preview.5/Editor/Utility/SaveDuringPlay.cs:502)
SaveDuringPlay.SaveDuringPlay.OnPlayStateChanged (UnityEditor.PlayModeStateChange pmsc) (at Library/PackageCache/com.unity.cinemachine@2.6.0-preview.5/Editor/Utility/SaveDuringPlay.cs:431)
UnityEditor.EditorApplication.Internal_PlayModeStateChanged (UnityEditor.PlayModeStateChange state) (at <90d4bcb003fb405fb09241aed2f178aa>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)

This happens on both 2.5.0 stable and 2.6.0 preview.

I've tracked the MonoBehaviour it's finding down to a helper script I have that animates textures on an imported model via animation events. This script actually isn't even being used any more (no animation event refers to it), but I never removed the script from the gameobject.

The gameobject it's attached to is an imported FBX (so it acts kinda like a prefab but it's not a real prefab). I'm guessing that probably has something to do with it.

The script in question is this:

using UnityEngine;

[ExecuteInEditMode]
public class SetTextureHelper : MonoBehaviour
{
    public Material Material;
    public Texture2D[] Textures;

    // This will be called when the animator first transitions to this state.
    public void SetMainTex(int textureIndex)
    {
        if (Textures.Length == 0 || textureIndex > Textures.Length - 1)
        {
            Debug.LogWarning($"Can't set MainTex to index {textureIndex}. Textures is only {Textures?.Length ?? -1} long");
            return;
        }
        Material.SetTexture("_MainTex", Textures[textureIndex]);
    }
}  

Attach it to an imported model, then enter an exit play mode with the "save on exit play mode" option checked. It should throw this exception.

glabute commented 4 years ago

Thanks for reporting this, but I can't repro the exception with your script and instructions.

Looking at the code, the only way I can see that this exception can come up is if Resources.FindObjectsOfTypeAll() somehow returns a deleted gameobject. I can preemptively add a null check here.

Neonalig commented 9 months ago

I was able to accidentally recreate this call stack exception recently on 2.9.7 stable (Unity 2022.3.19f1), though I'm unsure if this was related to the same situation that caused the exception to be thrown in the original issue (unlikely).

Essentially, I had just removed Naughty Attributes from my project and imported Odin Inspector (3.2.1.0), and after that whenever I entered play mode for a scene with a Cinemachine camera and exited, the same exception as above would be raised.

I similarly thought this was caused by not checking for null in the gameObject, and so added a null check. Once back in the project, Unity realised the package cache was invalidated because of my change and reimported Cinemachine again, which also incidentally made it that playing and exiting the scene would no longer raise the exception (perhaps it also caused something else like an AssetDatabase refresh which was the real fix).