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);