Войти
UnityФорумПрограммирование

Вопрос про сериализацию линков на gameobject

Страницы: 1 2 Следующая »
#0
(Правка: 21:11) 13:09, 28 окт 2021

Всем привет!

Допиливая свой нодовый редактор миссий столкнулся с необходимостью сериализации всяких переменных, ссылок на текстуры, скрипты и gameobject'ы. Создал класс для хранения всех этих параметров ноды. Переменные и текстуры отлично изменяются, сохраняются в файл и считываются. Но ссылки на скрипты и gameobject'ы живут только в окне редактора. Сериализоваться они не хотят.

В документации сказано, что gameobject'ы не сериализуются. Оно и понятно - в них куча различных компонентов. Однако требуется хранить лишь ссылки на объекты и различные скрипты. Почему не работает нативно - непонятно. Со скриптами аналогичная ситуация. Они нужны для управления дверьми,  источниками света и т.д. Опять же сохранять нужно лишь ссылку на скрипт, причём без gameobject'а на котором он висит (т.е. всё это стандартно, идентично Inspector'у).

Вопрос к опытным программистам: как обойти имеющиеся ограничения? На данный момент планирую просто извлекать атрибуты InstanceID, GUID и Type, и писать их в ссылку. Т.е. по аналогии с хранением ссылок на класс Texture2D, который сохраняется без всяких танцев с бубном.

Заранее спасибо!

P. S. Или в данном случае сохраняются вообще ui.elements, в которых ссылки и отображаются?

========

P.P.S.
Ноды в редакторе обладают своими специфическими UIElements, в которых хранятся значения переменных, ссылки на текстуры Texture2D (как верно было сказано выше, технически это ссылки на ассеты), gameobjects и скрипты (в данном случае это DoorRotate, управляющий дверьми):

+ Показать

Эти данные я сериализую и записываю в файл .asset при помощи стандартного контейнера:

var dialogueContainerObject = ScriptableObject.CreateInstance<DialogueContainer>();

  • здесь DialogueContainer - это контейнер для всех данных в миссии. Пусть название не смущает - оно подлежит изменению.
  • В этот контейнер сохраняются данные о линиях, соединяющих ноды, и данные собственно норд. Для их сохранения я сделал два класса:

    + Показать

    Сохраняется всё, кроме gameobjects и DoorRotate. Похоже я создаю пустые инстансы и пытаюсь их сериализовать, естественно ничего не получается:

    + Показать
    #1
    13:28, 28 окт 2021

    MSA2
    ссылки на GameObject-ы, скрипты и всякие там Texture2D по-умолчанию сериализуются именно в виде ссылок.

    > Почему не работает нативно - непонятно.
    пример кода? :)

    #2
    13:30, 28 окт 2021

    kkolyan
    пример кода

    вечером могу привести пример. Однако там куча скриптов и кода.
    Знать бы как работает в принципе

    #3
    14:47, 28 окт 2021

    MSA2
    не совсем понятно, что ты вкладываешь в понятие "ссылку на скрипт, причём без gameobject'а на котором он висит", в отличии от скрипта Texture2D - ассет, ну, если не был создан в рантайме как new Texture, а скрипт на объекте - это инстанс скрипта, а не ассет. Ты что именно хочешь сохранить и как с этим работать?

    #4
    17:16, 28 окт 2021

    MSA2
    > Знать бы как работает в принципе
    в юнити есть 3 способа хранить свои объекты в файлах
    1. в `*.asset` файлах в виде наследников ScriptableObject (при желании, один файл может содержать много инстансов, в т.ч. разного типа).
    2. в `*.prefab` файлах в виде наследников MonoBehavior, навешанных на объект.
    3. в `*.scene` файлах в виде наследников MonoBehavior, навешанных на объекты в сцене.

    полезны класс AssetDatabase, PrefabUtility и SceneManagement

    при сериализации все ссылки на любые наследники `UnityEngine.Object` сериализуются именно в виде ссылок (с помощью GUID). все остальное - как копия (хотя есть SerializedReference, позволяющий и простые классы хранить ссылкой в рамках того же файла, но это "такое")
    думаю очевидно, что ссылки могут биться, если не учитывать их жизненный цикл. например, если сериализовать ссылку на временный объект (не прикрепленный к файлу) в файл, то ссылка при следующей загрузке будет невалидна. в то время как для хот-релоада отлично сериализуются и ссылки на временные объекты.

    то что вы описываете просто должно работать из коробки и все. видимо где-то в мелочах делаете что-то не так. что именно - без подробностей непонятно.

    #5
    19:04, 28 окт 2021

    kkolyan и bool, замечания справедливые, добавил P.P.S. в стартовый топег.

    #6
    (Правка: 19:54) 19:40, 28 окт 2021

    >MSA2
    Прикольный визуальный редактор запилен!
    Вряд ли предложение поможет, так как уже судя по всему вся логика реализована, но может все же как-то избавиться от ссылок на объекты вообще и хранить только индексы и булы?

    У  Меня ноды вопросов и ответов сделаны так, и не нужны никакие объекты, и сохранять легко будет (пока не занимался, но не думаю, что вопросы возникнут глобальные).

    + Показать

    Все объекты, можно хранить так же в массивах и сохранять их не нужно, так как достаточно будет сохранить индексы на эти объекты их положение и вращение, возможно еще какие-то данные, пока не дошел еще до этого, но все объекты известны, известны ссылки на их префабы, какой смысл сам объект-то сохранять? А если потом понадобится поменять этот объект на другой? или Спрайт/текст надо будет поменять или еще что?

    #7
    (Правка: 20:25) 20:22, 28 окт 2021

    MSA2
    структуры выглядят хорошо. но чтобы оно правильно работало, нужно чтобы поля obj, door и texture имели такой же lifetime как и DialogueContainer, т.е. они, как и контейнер, должны иметь свои файлы: для obj и door это значит что они должны быть частью какого-то префаба (или префаб-варианта, но не инстанса).

    MSA2
    > На сколько я понимаю, я создаю пустые инстансы и пытаюсь их сериализовать,
    видимо здесь как раз и имеешь ввиду что присваиваешь временные объекты, не имеющие своих файлов (кроме texture - который работает).

    #8
    (Правка: 23:25) 23:02, 28 окт 2021

    kkolyan
    структуры выглядят хорошо. но чтобы оно правильно работало, нужно чтобы поля obj, door и texture имели такой же lifetime как и DialogueContainer, т.е. они, как и контейнер, должны иметь свои файлы: для obj и door это значит что они должны быть частью какого-то префаба (или префаб-варианта, но не инстанса).

    Это довольно абсурдно)) В иерархии объектов сцены все эти кубы, модели и прочее однозначно имеют GUID и прочие параметры, позволяющие идентифицировать в том числе инстансы, а сохранить эти данные нельзя... Там в проекте целый кэш есть с кучей папок от "00" до "FF", с кучей файлов, из которых все эти инстансы сериализует тот же  редактор, когда закрываешь проект.. :) Абсурд, что требуются костыли...

    Я пробовал из файла .asset параметры файла текстуры копировать в поле "obj", при загрузке миссии соответствующая нода без проблем отображает ссылку на текстуру:

    obj: {fileID: 0}
    door: {fileID: 0}
    texture: {fileID: 2800000, guid: 085c75ec74a82cf44868d70cf7af2d21, type: 3}

    :) может мне просто сохранять эти три параметра? правда пока не понимаю как вытащить GUID

    kkolyan
    видимо здесь как раз и имеешь ввиду что присваиваешь временные объекты, не имеющие своих файлов (кроме texture - который работает)

    да, получается именно так

    #9
    (Правка: 23:52) 23:16, 28 окт 2021

    FourGen
    может все же как-то избавиться от ссылок на объекты вообще и хранить только индексы и булы?

    Этот вариант на крайний случай. я обдумывал такой подход, но пришёл к выводу, что в моём случае кидать объекты из иерархии сцены и работать с ними проще, ведь не требуется дублировать в массиве названия, и контролировать что там чему соответствует. В случае объектов, названий дверей, названий источников света и т.д. название куда наглядней, чем ID. Если не прикасаюсь к проекту месяц, забываю детали напрочь)) Каждый раз всё приходится вспоминать. А названия говорящие. ИМХО К тому же есть готовый массив - сама иерархия сцены.

    На массивах пришлось делать контроллёр реплик персонажей, которые у меня просто в файле .txt построчно (для простоты подключения переводов на разные языки). Контроллёр читает реплики и загружает в класс с атрибутами. Всё это пришлось колхозить ради кастомного редактора реплик, иначе реплики я не допишу никогда, потому что разобью нафиг комп))

    А так работать уже можно:

    + Показать
    #10
    (Правка: 0:26) 0:08, 29 окт 2021

    Если не прикасаюсь к проекту месяц, я забываю вообще всё

    Да это минус глобальный, что не названия, действительно фиг вспомнишь что где, но + в том, что все в одном месте, все закешировано и прямой доступ к элементам минуя все геткомпонет, и прочее. Префаб создаем на старте, получаем все данные распихиваем по массивам 1 раз и далее прямой доступ в одно действие к любому элементу. (какие вынесены).

    А так работать уже можно:

    * Согласен, так однозначно лучше.
    Я поковырял создание этих визуальных нод в редакторе, работы много, лень.

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

    иначе реплики я не допишу никогда, потому что разобью нафиг комп

    А собственно, что я написал-то, просто я вашу тему давно видел, тогда нечего было предложить, сейчас вроде не вижу у вас, вы спрашивали, что можно еще сделать что бы упростить, скорее всего вы уже все допилили, но обратите внимания на названия полей у меня. Если вы не реализовали еще что-то можно так же сделать используя систему токенов. Получается вообще универсальная штука. на дверь кликнули, проверяем есть ли токен или набор токенов, нет... не открываем... смотрим есть ли такие-то токены... не открываем... поговорили с персом... дали токен или несколько токенов, если надо забрали... удобно просто получается, и вложенность без ограничений.
    Токен - что угодно... массив интов булов стрингов или структур с количеством этих токенов в
    элементе.
    Реализуется крайне легко, всего несколько процедур. Зато гибкость появляется без ограничений на любые действия.

    #11
    (Правка: 1:23) 0:34, 29 окт 2021

    MSA2
    > В иерархии объектов сцены все эти кубы, модели и прочее однозначно имеют GUID и прочие параметры, позволяющие идентифицировать в том числе инстансы
    вообще-то нет :) глобальные идентификаторы в пространстве проекта есть только у префабов и ассетов. у объектов сцены айдишки есть только в рантайме.

    Мне видится такое решение
    1. заводим СОшку DoorOpenEvent. сначала можно вообще без полей
    2. для каждой открываемой через внешнее событие двери создаем в ассетах инстанс этой сошки с понятным именем
    3. инжектим эту сошку через инспектор в DoorRotate (там заводим поле для этого)
    4. инжектим ссылку на Door в "NodeData.door" в редакторе диалогов
    5. в рантайме составляем обратный мэппинг в один проход как больше нравится

    если честно, мне прямая ссылка на объект сцены кажется более кастыльной, чем озвученное выше решение, т.к. сам факт ссылки на объект извне очень неочевиден, а описанное решение делает связь более явной. плюс, с таким подходом легко работать с разными копиями одной и той же сцены (бывает удобно), а с глобальной ссылкой в духе экселя "Сцена1/Узел123" такое не прокатит, да и в целом довольно хрупко получается.

    #12
    11:01, 29 окт 2021

    kkolyan
    вообще-то нет :) глобальные идентификаторы в пространстве проекта есть только у префабов и ассетов. у объектов сцены айдишки есть только в рантайме.

    Вы разрушили мою веру в человечество..))

    Ваш метод понятен, но он потребует много файлов и телодвижений при создании миссий. Наверно будет проще действительно сделать массив с обьектами, как советовали выше, и сделать его доступным в редакторе и рантаме.

    Не ожидал подобных замарочек, как мне кажется, на пустом месте.. Не совсем понимаю такой подход инженеров юнити.

    #13
    11:39, 29 окт 2021

    Посмотри как у Bolt'а референсы на объекты живут
    Суть примерно в следующем: граф хранится в своем формате (по сути json с описанием графа), все референсы на все что UnityObject имеют внутренний индекс, а компонент в котором живет граф служит мостом между окружением где референсы валидны и сериализуются (компонент в сцене) и внутренней логикой графа. В дебаг режиме инспектора если посмотреть - там есть массив ObjectReferences

    #14
    16:41, 30 окт 2021

    to Никус
    Нормальной документации по встроенным в Unity нодам нет, поэтому как это примерно работает почерпнул у пары нодовых редакторов, которые лежать в сети, а нормально настроить всё это под мои конкретные задачи получилось только после изучения скриптов Bolt и ShaderGraph.

    Страницы: 1 2 Следующая »
    UnityФорумПрограммирование