NullReferenceException от UnityEditor.InspectorWindow.GetEditorsWithPreviews

У меня есть довольно сложный Unity Editor Script для модификации моделей. Он используется путем создания нового объекта в папке ресурсов, а затем в его инспекторе, дающего ему модель, применяются некоторые модификаторы и нажатия. Это изменяет модель и заменяет созданный объект на новый сборный объект.

При нажатии применить метод Apply() вызывается и после этого консоль выводит следующее:

NullReferenceException: ссылка на объект не установлена ​​для экземпляра объекта UnityEditor.InspectorWindow.GetEditorsWithPreviews (редакторы UnityEditor.Editor[]) (в C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindowityEditor 51.): InspectorWindow.DrawPreviewAndLabels () (в C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:612) UnityEditor.InspectorWindow.OnGUI () (в C: / buildslave / unity / build / Editor / Mono Inspector/InspectorWindow.cs:398) System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, привязка System.Reflection.Binder, параметры System.Object[], культура System.Globalization.CultureInfo) (в /Users/buildduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222) Rethrow as TargetInvocationException: Исключение было сгенерировано целью вызова. System.Reflection.MonoMethod.Invoke (объект System.Object, объект BindingFlags invokeAttr, привязка System.Reflection.Binder, параметры System.Object[], культура System.Globalization.CultureInfo) (в каталоге /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:232) System.Reflection.MethodBase.Invoke (параметры System.Object obj, System.Object[]) (в /Users/buildduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115) UnityEditor.HostView.Invoke (System.String methodName, System.Object obj) (в C:/buildslave/unity/build/Editor/Mono/HostView.cs:272) UnityEditor.HostView.Invoke (System.String methodName) (в C:/buildslave/unity/build/Editor/Mono/HostView.cs:265) UnityEditor.HostView.InvokeOnGUI (Rect onGUIPosition) (в C: / buildslave / единство / сборки / редактор /Mono/HostView.cs:232)

Я нашел вопрос 2014 года с похожей ошибкой, но с другими обстоятельствами и без ответа.

Я проверил декомпилированное репозиторий MattRix Unity на предмет того, что может вызвать исключение, и хотя репо имеет версию 2017.1.0f3, и я нахожусь на 2017.1.1f1, я думаю, что нашел места, где возникает проблема. в DrawPreviewsAndLabels():

IPreviewable[] editorsWithPreviews = this.GetEditorsWithPreviews(this.tracker.activeEditors);

А потом

GetEditorsWithPreviews(Editor[] editors){
...
for (int i = 0; i < editors.Length; i++)
            {
                Editor editor = editors[i];
...

Кажется, исключение вызывается на линии Editor editor = editors[i];, Это заставляет меня думать, что this.tracker.activeEditors это список, который имеет элементы, которые null, Вот где я застрял.

Что может вызвать это, и что я могу сделать или проверить, чтобы исправить эту ошибку?

РЕДАКТИРОВАТЬ: Было выявлено, что это, вероятно, означает, что this.tracker.activeEditors само по себе является нулевым. Если бы это было так, я думаю, что исключение произошло бы в editors.Length и, по крайней мере, это не должно входить в цикл for. Так как номера строк могли измениться с изменением версии Unity, строка в этом коде на самом деле не может быть причиной исключения, но у меня нет возможности узнать это.

Проблема, почему я не могу легко исправить этот нулевой указатель, состоит в том, что это происходит в коде редактора без каких-либо вызовов из моего кода, и я не знаю, что делать, чтобы this.tracker.activeEditors или что-то, что вызывает это, будет назначено правильно, где это должно быть.

Нужно ли делать что-то активное, чего не может быть, чтобы были активные редакторы, что бы это ни значило?

Это мое Apply() метод:

private void Apply(List<Mesh> meshes, List<Material[]> materials, Chamferer chamferer)
{
    GameObject newObject = Instantiate(chamferer.gameObject);
    Object targetPrefab = PrefabUtility.GetPrefabObject(chamferer);

    string name = chamferer.source.name;
    //Delete previous meshes
    MeshFilter[] filters = newObject.transform.GetComponentsInChildren<MeshFilter>();
    for (int i = 0; i < filters.Length; i++)
    {
        filters[i].transform.SetParent(null);
        GameObject.DestroyImmediate(filters[i].gameObject);
    }

    string prefabPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(targetPrefab));

    Mesh prev = null;
    //Add new meshes
    for (int i = 0; i < meshes.Count; i++)
    {
        Mesh mesh = meshes[i];
        Mesh newMesh = EdgeChamfer.AddChamfer(mesh, chamferer.scale);
        GameObject obj = new GameObject(mesh.name);
        obj.transform.SetParent(newObject.transform);
        MeshFilter mf = obj.AddComponent<MeshFilter>();
        MeshRenderer mr = obj.AddComponent<MeshRenderer>();
        mf.sharedMesh = newMesh;
        mr.sharedMaterials = materials[i];

        //Adds mesh under prefab
        if (i == 0)
        {
            AssetDatabase.CreateAsset(newMesh, prefabPath + "/" + name + ".asset");
            prev = newMesh;
        }
        else
        {
            AssetDatabase.AddObjectToAsset(newMesh, prev);
            prev = newMesh;
        }
    }
    AssetDatabase.SaveAssets();

    GameObject newPrefab = PrefabUtility.ReplacePrefab(newObject, targetPrefab);

    //Renames the object accordingly
    string renamingerr = AssetDatabase.RenameAsset(prefabPath + "/" + newPrefab.name + ".prefab", "Chamfered" + name);
    if (renamingerr != "")
    {
        Debug.Log(renamingerr);
    }
    Selection.activeObject = newPrefab;
    EditorGUIUtility.PingObject(newPrefab);
    GameObject.DestroyImmediate(newObject);
}

И полный GetEditorsWithPreviews() из репозитория MattRix:

public IPreviewable[] GetEditorsWithPreviews(Editor[] editors)
        {
            IList<IPreviewable> list = new List<IPreviewable>();
            int num = -1;
            for (int i = 0; i < editors.Length; i++)
            {
                Editor editor = editors[i];
                num++;
                if (!(editor.target == null))
                {
                    if (!EditorUtility.IsPersistent(editor.target) || !(AssetDatabase.GetAssetPath(editor.target) != AssetDatabase.GetAssetPath(editors[0].target)))
                    {
                        if (EditorUtility.IsPersistent(editors[0].target) || !EditorUtility.IsPersistent(editor.target))
                        {
                            if (!this.ShouldCullEditor(editors, num))
                            {
                                if (!(editors[0] is AssetImporterEditor) || editor is AssetImporterEditor)
                                {
                                    if (editor.HasPreviewGUI())
                                    {
                                        list.Add(editor);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            foreach (IPreviewable current in this.m_Previews)
            {
                if (current.HasPreviewGUI())
                {
                    list.Add(current);
                }
            }
            return list.ToArray<IPreviewable>();
        }

1 ответ

Решение

Похоже, что ошибка может появляться, когда OnInspectorGUI() пытается что-то сделать после замены объекта.

Ошибка не появляется, если вместо замены префаба создается новый префаб. Так что в коде проблема решается заменой

GameObject newPrefab = PrefabUtility.ReplacePrefab(newObject, targetPrefab);

в "Применить ()" с

    GameObject newPrefab = PrefabUtility.CreatePrefab(prefabPath + "/" + name + ".prefab", newObject);
Другие вопросы по тегам