Unity — платформа, которая существует довольно давно и постоянно развивается. Однако, работая в ней с несколькими проектами одновременно, все еще можно столкнуться со сложностями в использовании общих исходников (.cs), библиотек (.dll) и остальных ассетов (изображения, звуки, модели, префабы). В этой статье мы расскажем о нашем опыте работы с нативным решением такой проблемы для Unity.
Методы распространения общих ресурсов
Существует больше одного способа использовать общие ресурсы для разных проектов, но у каждого подхода есть свои плюсы и минусы.
1. Дублирование — «руками» дублируем ресурсы между проектами.
Плюсы:
- Подходит для всех видов ресурсов.
- Нет проблем с зависимостями.
- Нет проблем с GUID’ами ассетов.
Минусы:
- Гигантские репозитории.
- Нет возможности версионирования.
- Сложность отслеживания изменений в общих ресурсах.
- Сложность обновления общих ресурсов.
2. Git submodules — распространение общих ресурсов через внешние подмодули.
Плюсы:
- Можно работать с исходниками.
- Можно распространять ассеты.
- Нет проблем с зависимостями.
Минусы:
- Необходим навык работы с Git.
- Git не очень дружит с бинарными файлами — придется подключать LFS.
- Разграничение доступа для репозиториев.
- Сложности при повышении и понижении версии.
- Возможны коллизии GUID’ов и нет однозначного поведения со стороны Unity для их разрешения.
3. NuGet — распространение общих библиотек через NuGet-пакеты.
Плюсы:
- Удобная работа с проектами, не зависящими от Unity.
- Удобное версионирование и разрешение зависимостей.
Минусы:
- Unity не умеет работать с NuGet-пакетами «из коробки» (на GitHub можно найти NuGet Package Manager for Unity, который исправляет это, но есть нюансы).
- Сложности при распространении остальных видов ассетов.
4. Unity Package Manager — распространение общих ресурсов через нативное решение для Unity.
Плюсы:
- Нативный интерфейс для работы с пакетами.
- Защита от перезаписи .meta файлов в пакетах при конфликтах GUID’ов.
- Возможность версионирования.
- Возможность распространения всех видов ресурсов для Unity.
Минусы:
- Все еще могут случаться конфликты GUID’ов.
- Нет документации для реализации.
Последний способ имеет больше преимуществ, чем недостатков. Однако он сейчас не очень популярен из-за отсутствия документации, и поэтому мы остановимся на нем подробно.
Unity Package Manager
Unity Package Manager (далее UPM) — инструмент для управления пакетами. Его добавили в Unity 2018.1, и он использовался только для пакетов, которые разрабатывались Unity Technologies. Однако начиная с версии 2018.3 появилась возможность добавления кастомных пакетов.
Интерфейс Unity Package Manager
Пакеты не попадают в исходники проекта (директорию Assets). Они находятся в отдельной директории %projectFolder%/Library/PackageCache
и никак на проект не влияют, их единственное упоминание в исходниках — в файле packages/manifest.json
.
Пакеты в файловой системе проекта
Источники пакетов
UPM может использовать несколько источников пакетов:
1. Файловая система.
Плюсы:
- Скорость реализации.
- Не требует сторонних инструментов.
Минусы:
- Сложность версионирования.
- Необходим общий доступ к файловой системе для всех, кто работает с проектом.
2. Git-репозиторий.
Плюсы:
- Нужен только Git-репозиторий.
Минусы:
- Нельзя переключаться между версиями через окно UPM.
- Работает не со всеми Git-репозиториями.
3. npm-репозиторий.
Плюсы:
- Полностью поддерживает функционал UPM и используется для распространения официальных пакетов Unity.
Минусы:
- В настоящее время игнорирует все строковые версии пакетов, кроме «-preview».
Ниже мы рассмотрим реализацию UPM + npm. Эта связка удобна, поскольку позволяет работать с любыми видами ресурсов и управлять версиями пакетов, а также полностью поддерживает нативный интерфейс UPM.
В качестве npm-репозитория можно использовать Verdaccio. К нему есть подробная документация, и для его запуска потребуется буквально пара команд.
Настройка окружения
Для начала нужно установить node.js.
Создание пакета
Чтобы создать пакет, необходимо поместить файл package.json
, который будет его описывать, в директорию с содержимым этого пакета. Нужно сделать следующее:
Перейти в директорию проекта, которую хотим сделать пакетом.
Выполнить команду npm init и во время диалога ввести необходимые значения. Для name указываем имя в формате реверс домена, например com.plarium.somepackage.
Для удобного отображения имени пакета — добавить свойство displayName в package.json и заполнить его.
Так как npm js-ориентирован, в файле есть не нужные нам свойства main и scripts, которые Unity не использует. Лучше их удалить, чтобы не засорять описание пакета. Файл должен выглядеть примерно так:
- Перейти в директорию проекта, которую хотим сделать пакетом.
- Выполнить команду npm init и во время диалога ввести необходимые значения. Для name указываем имя в формате реверс домена, например com.plarium.somepackage.
- Для удобного отображения имени пакета — добавить свойство displayName в package.json и заполнить его.
- Так как npm js-ориентирован, в файле есть не нужные нам свойства main и scripts, которые Unity не использует. Лучше их удалить, чтобы не засорять описание пакета. Файл должен выглядеть примерно так:
{ "name": "com.plarium.somepackage", "displayName": "Some Package", "version": "1.0.0", "description": "Some Package Description", "keywords": [ "Unity", "UPM" ], "author": "AUTHOR", "license": "UNLICENSED" }
- Открыть Unity и сгенерировать .meta файл для package.json (Unity не видит ассеты без .meta файлов, пакеты для Unity открываются только для чтения).
Отправка пакета
Для отправки пакета необходимо выполнить команду: npm publish --registry *адрес до хранилища пакетов*
.
Установка и обновление пакетов через Unity Package Manager
Чтобы добавить пакет в Unity-проект, нужно:
- Внести в файл
manifest.json
информацию об источнике пакетов. Для этого необходимо добавить свойствоscopedRegistries
и указать скоупы и адрес источника, по которому будут искаться конкретные скоупы."scopedRegistries": [ { "name": "Main", "url": "адрес до хранилища пакетов", "scopes": [ "com.plarium" ] } ]
- Перейти в Unity и открыть окно Package Manager’а (работа с кастомными пакетами не отличается от работы со встроенными).
- Выбрать All Packages.
- Найти нужный пакет и добавить его.
Работа с исходниками и отладка
Чтобы исходники подключились к проекту, необходимо создать Assembly Definition для пакета.
Использование пакетов не ограничивает возможности для отладки. Однако при работе с пакетами в Unity нельзя перейти в IDE по клику на ошибку в консоли, если ошибка произошла в пакете. Это связано с тем, что Unity не видит скрипты как отдельные файлы, поскольку при использовании Assembly Definition они собираются в библиотеку и подключаются к проекту. При работе с исходниками из проекта переход в IDE по клику доступен.
Скрипт в проекте с подключенным пакетом:
Скрипт из пакета с работающим брейкпоинтом:
Срочное внесение исправлений в пакеты
Добавленные в проект пакеты Unity открыты только для чтения, но их можно редактировать в кэше пакетов. Для этого необходимо:
- Перейти в пакет в кэше пакетов.
- Внести необходимые изменения.
- Обновить версию в файле
package.json
. - Отправить пакет
npm publish --registry *адрес до хранилища пакетов*
. - Обновить версию пакета до исправленной через интерфейс UPM.
Конфликты импорта пакетов
При импорте пакетов могут произойти следующие конфликты GUID’ов:
- Пакет — пакет. Если при импорте пакета обнаружится, что в уже добавленных пакетах есть ассеты с таким же GUID’ом, ассеты с совпавшими GUID’ами из импортируемого пакета не добавятся в проект.
- Пакет — проект. Если при импорте пакета обнаружится, что в проекте есть ассеты с совпадающими GUID’ами, то ассеты из пакета не добавятся в проект. Однако ассеты, зависящие от них, начнут использовать ассеты из проекта.
Перенос ассетов из проекта в пакет
Если перенести ассет из проекта в пакет при открытой Unity, то его функциональность сохранится, а ссылки в зависимых ассетах начнут использовать ассет из пакета.
Важно: при копировании ассета из проекта в пакет произойдет конфликт «Пакет — проект», описанный в разделе выше.
Возможные решения конфликтов
- Переназначение GUID’ов по собственным алгоритмам при импорте всех ассетов, чтобы исключить коллизии.
- Добавление всех ассетов в один проект с их последующим разделением на пакеты.
- Создание базы данных, содержащей GUID’ы всех ассетов, и проведение валидации при отправке пакетов.
Заключение
UPM — новое решение для распространения общих ресурсов на Unity, которое может стать достойной альтернативой существующим методам. Рекомендации, описанные в статье, возникли на основе реальных кейсов. Надеемся, они вам пригодятся.
Автор: Plarium