[SRP, b10] Material Inspector does not respond to clicks after saving project

Happens only when:

  • URP or HDRP is used as active pipeline. No issue with BIRP.
  • Material is selected from assets in isolation, not on game-object.
    Doesn’t happen in Properties window. Custom ShaderGUI doesn’t affect this.

How to reproduce:

  1. Select any Material in Assets
  2. Change any property
  3. Save project
  4. Inspector stops responding to clicks
  5. ??? Now you have to re-select material

As I constantly press Ctrl + S, you may imagine how unbearable it becomes.

Some other very strange behavior:

  1. If you undo changes and save again, it starts working again (and ofc breaks on next save).
  2. If you do all these steps when changing material on game-object, and then select this material in assets - the issue will be gone only for that particular material. (:eyes::eyes::eyes:???) Issue will be back after Editor restart.

I have the same problem on Unity 2022.3.19f1 URP.
Have you solved this?

Try this:

#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using System.Reflection;

public class MaterialInspectorSaveFix : AssetModificationProcessor // is there a better callback method for OnSave?
{
    struct InspectorWindowData
    {
        public EditorWindow window;
        public Dictionary<int, float> editorsHeight;

        static MethodInfo OnSelectionChangedMethod;
     
        public VisualElement QueryEditorsList()
        {
            return window.rootVisualElement.Query(className: "unity-inspector-editors-list").First();
        }

        public void InvokeOnSelectionChanged()
        {
            if (OnSelectionChangedMethod == null)
                OnSelectionChangedMethod = window.GetType().GetMethod("OnSelectionChanged", BindingFlags.NonPublic | BindingFlags.Instance);
            OnSelectionChangedMethod.Invoke(window, null);
        }
    }

    static MethodInfo LayoutSetMethod;

    static void SetLayoutProperty(VisualElement element, Rect rect)
    {
        if (LayoutSetMethod == null)
            LayoutSetMethod = typeof(VisualElement).GetProperty("layout", BindingFlags.Public | BindingFlags.Instance).GetSetMethod(true);

        LayoutSetMethod.Invoke(element, new object[] { rect });
    }
   
    static string[] OnWillSaveAssets (string[] paths)
    {
        var selection = Selection.objects;

        bool hasAnyMaterialSelected = false;
        foreach (var obj in selection)
        {
            if (obj is Material)
            {
                hasAnyMaterialSelected = true;
                break;
            }
        }
        if (!hasAnyMaterialSelected)
            return paths;
       
        var allWindows = Resources.FindObjectsOfTypeAll(typeof(EditorWindow));
        var inspectorWindows = new List<InspectorWindowData>(1);
        foreach (EditorWindow window in allWindows)
        {
            var type = window.GetType();
            if (type.FullName == "UnityEditor.InspectorWindow")
            {
                var data = new InspectorWindowData() { window = window, editorsHeight = new Dictionary<int, float>() };

                foreach (var editor in data.QueryEditorsList().Children())
                {
                    data.editorsHeight.Add(editor.GetHashCode(), editor.layout.height);
                }

                inspectorWindows.Add(data);
            }
        }
       
        // We DO NOT want to mess with Selection, as it'll register garbage Undo.
        //Selection.objects = null;

        //foreach (var inspector in inspectorWindows)
        //    inspector.InvokeOnSelectionChanged();

        //Selection.objects = selection;

        foreach (var inspector in inspectorWindows)
        {
            inspector.InvokeOnSelectionChanged();

            foreach (var editor in inspector.QueryEditorsList().Children())
            {
                var layout = editor.layout;
                if (inspector.editorsHeight.TryGetValue(editor.GetHashCode(), out var height))
                {
                    // dunno where EditorElement sets the layout, so we'll do it manually
                    layout.height = height;
                    SetLayoutProperty(editor, layout);
                }
            }
        }
       
        return paths;
    }
}
#endif

Let me know if it works on your version or if there any issues with it!

While writing this fix, I’ve found the cause of this issue.
If you look in UITK Debugger, the Material EditorElement is not re-initialized properly - height is 65, thus you can only click on it’s header. It’s not the case with Properties window, only the Inspector.
Before save:
9730780--1391428--upload_2024-3-27_17-7-31.png
After save:
9730780--1391431--upload_2024-3-27_17-7-36.png

There’s also another small issue - preview pane (at the bottom) doesn’t remember on save that it was completely hidden, only when height is above zero, so it keeps resetting itself when trying to hide it. :face_with_spiral_eyes:

9730780–1391455–MaterialInspectorSaveFix.cs (3.37 KB)

Wow, thanks, I will try it! I found some bug reports related to this issue, but it looks like Unity doesn’t even touched it.

Did you submit a bug report ?, I couldn’t find any

My report was closed as duplicate and linked to this issue: https://issuetracker.unity3d.com/issues/inspector-with-the-scrollbar-is-unusable-when-material-properties-are-edited-and-the-scene-is-saved

1 Like