Предотвратите потерю данных для EditorWindow в dll, когда Editor перекомпилирует - PullRequest
0 голосов
/ 11 июня 2018

Я делаю собственное окно EditorWindow.Очень очень упрощенная версия выглядит следующим образом:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;

namespace testDllForUnity {
    [Serializable]
    public class WindowTestDllForUnity : EditorWindow {
        string myString = "Hello World";
        private static float x = 0;
        private static float y = 0;        
        private static int yOffset = 10;
        private static float width = 100f;
        private static float height = 40f;

        private static List<Rect> buttonsRectList = new List<Rect>();

        [MenuItem("Window/WindowTestDllForUnity")]
        static void Init() {            
            WindowTestDllForUnity window = (WindowTestDllForUnity)EditorWindow.GetWindow(typeof(WindowTestDllForUnity));
            buttonsRectList.Add(new Rect(x, y, width, height));

            window.Show();
        }


        void OnGUI() {
            GUILayout.Label(myString, EditorStyles.boldLabel);
            if (GUILayout.Button("AddButton")) {
                y += height + yOffset;                
                buttonsRectList.Add(new Rect(x, y, width, height));
            }

            for (int i = 0; i < buttonsRectList.Count; i++) {
                if (GUI.Button(new Rect(buttonsRectList[i]), "button_" + i))
                    Debug.Log("button_" + i + " clicked!");                
            }
        }
    }
}

На самом деле мое окно более сложное, чем это.

Этот код, который я собрал как dll с VisualStudio и поместил в Unity 's Папка «Assets / Editor /».

Работает нормально, но ... если я добавлю какой-либо скрипт C # в Unity, напишу что-нибудь и сохраню его - Unity запустит его автокомпиляцию и мойПользовательское окно становится пустым, только что очищенное окно.

Что я должен сделать, чтобы предотвратить очистку моего окна?Можно ли попросить Unity не перестраивать окно при компиляции других скриптов?Или я должен каждый раз сохранять данные и восстанавливать их после перекомпиляции?Разве это не плохой подход?

1 Ответ

0 голосов
/ 13 июня 2018

Когда вы добавляете, изменяете или удаляете скрипт (или DLL) в Unity, все затронутые сборки перекомпилируются и перезагружаются.Когда вы входите и выходите из режима воспроизведения, сборки также перезагружаются.Это приводит к тому, что все статические переменные очищаются, поскольку они принадлежат загруженной сборке и больше нигде не сохраняются.

Чтобы сохранить изменения после перезагрузки сборки, Unity должна быть в состоянии сохранить данные (переменные-члены) вдиск, а затем снова заполнить их после восстановления всего.К счастью, во многих случаях это делается автоматически.Базовый класс EditorWindow уже помечен как [Serializable], поэтому нет необходимости также отмечать наш дочерний класс.Далее, все переменные, которые необходимо сохранить, также должны быть сериализуемыми.Простые типы данных, такие как string и int, являются сериализуемыми, но некоторые типы, такие как Rect, не являются таковыми, поэтому ваш список не будет сохранен, даже если он является частью экземпляра (не является статичным).См. Руководство по Unity - Сериализация скриптов .Обратите внимание, что правила для классов EditorWindow немного отличаются от правил для сериализации классов MonoBehaviour.Например, частные переменные сериализуются без атрибута [SerializeField], по крайней мере, в моей версии Unity 2018.1.0f2.

Попробуйте следующий код, чтобы лучше понять:

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;

namespace PersistChangesThroughAssemblyLoad
{
    public class MyEditorWindow : EditorWindow
    {
        Vector2 buttonStartPosition = new Vector2(0, 0);
        Vector2 buttonStartSize = new Vector2(100f, 40f);
        int yOffset = 10;

        // All data types which should be peristent, need to be
        // serializable, Vector2 is, but Rect is not.
        List<Vector2> buttonPositions = new List<Vector2>();
        List<Vector2> buttonSizes = new List<Vector2>();

        [MenuItem("Window/MyEditorWindow")]
        static void Init()
        {
            MyEditorWindow window = GetWindow<MyEditorWindow>("MyWindow");
            LogMessage(window, "Window will be opened via the menu item.");
            window.Show();
        }

        void OnEnable()
        {
            LogMessage("Window is enabled (either after opening or after assembly reload/recompile).");
        }

        void OnDisable()
        {
            LogMessage("Window is disabled (either when being closed or because the assembly is about to reload/recompile).");
        }

        void OnGUI()
        {
            if (GUILayout.Button("Add Button"))
            {
                buttonStartPosition.y += buttonStartSize.y + yOffset;
                AddNewButton(buttonStartPosition, buttonStartSize);
            }

            for (int i = 0; i < buttonPositions.Count; i++)
            {
                string buttonName = "Button " + i;
                if (GUI.Button(new Rect(buttonPositions[i], buttonSizes[i]), buttonName))
                {
                    LogMessage(buttonName + " was clicked!");
                }
            }
        }

        void AddNewButton(Vector2 position, Vector2 size)
        {
            buttonPositions.Add(position);
            buttonSizes.Add(size);
            LogMessage("Added new button. Total count: " + buttonPositions.Count);
        }

        void LogMessage(string message)
        {
            LogMessage(this, message);
        }

        static void LogMessage(Object context, string message)
        {
            Debug.Log("Window [" + context.GetInstanceID() + "]: " + message);
        }
    }
}

Обратите внимание на идентификаторы экземпляра, зарегистрированные в консоли.При создании нового окна из меню идентификатор изменяется, но если окно является сериализуемым, оно сохраняется в режиме воспроизведения.Такой подход поможет вам пройти долгий путь, поскольку большинство данных можно разбить на простые типы данных.Также удобно создавать собственные структуры и помечать их атрибутом [Serializable] следующим образом:

[System.Serializable]
public struct MyRect
{
    public float x, y, width, height;
}

Кроме этого, можно записать данные в EditorPrefs в OnDisable и загрузитьэто в OnEnable.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...