Розширення для Unity editor: базовий сетап проєкту. Автоматизація

Привіт! Я Красніков Данііл, Unity Developer у VOLMI — A Virtuos Studio.

Останнім часом мені подобається займатися прототипуванням. Мати можливість швидко перевірити ідеї «Чи працюватиме ця механіка в реальному проєкті» та «Чи буде цікаво мені це робити» завжди допомагає розвиватися (ну або як мінімум весело провести час). Проте створення нового проєкту, інсталяція всіх пакетів, налаштування кожного з них... Monkey job і цього ніяк не уникнути. Хоча є дещо...

Сьогодні ми з вами розберемося, як створити кастомний пакет, який буде автоматично виконувати всі звичні дії для сетапу проєкту.

Традиційний дисклеймер: рішення та код можуть бути не найкращими, тож для когось це буде гайд, а для когось план «як робити не треба». Також головна ціль тексту — показати, що і як просто можна створити засобами Unity та C#. Тож не судіть строго)

Мета

Спочатку треба визначитись, що ми хочемо отримати в кінці. Для себе я виділив такі пункти:

— Швидка інсталяція
Я не хочу вишукувати кожен пакет, який мені потрібен. А в процесі розробки виявилося, що їх так-то багато.

— Можливість швидко поміняти список «а що мені треба» та оновити його в усіх місцях
Кожен місяць в асет сторі та на гітхабі з’являється куча корисних асетів. Після використання деяких з них у мене в голові з’являється думка «так, без цього я більше не можу жити».

— Виставлення неймспейсу
Не знаю як вас, але для мене це нереально багато кроків: Edit->Project Settings->Editor->Root namespace = Project Name.

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

Але пакет провайдер також треба вишукувати та завантажувати, що може з часом дратувати. Тим паче якщо це архів чи файл .unitypackage.

Створення пакету

Видихаємо, але не стогоном мученика: в документації Unity є розділ Creating custom packages. Він то нас і врятує. Все просто:

  1. Створюєш репозиторій
  2. Додаєш ліцензію, ченджлог та рідмі
  3. Створюєш маніфест — основний файл, за яким Unity розуміє, що це пакет і отримує інформацію про нього.

Потім виділяєш дві основні папки: Runtime (логіка, яка піде в білд) та Editor (чисто функціонал едітора). Повний рекомендований layout з документації виглядає так:

Повторімо його в юніті:

А тепер детальніше по кожному файлу. Обов’язковим тут є тільки package, тож почнемо з нього.

По суті своїй це звичайний json. Опис кожного поля можна знайти в документації, але для валідної структури достатньо лише імені у форматі com.[назва організації].[назва пакету] та версії:

{
  "name": "com.daniilcoolukraine.projectsetuptools",
  "version": "1.0.0",
}

Мікро-уточнення: в імені не використовуються великі літери та спеціальні символи.

Поверх цієї структури я накинув ще ім’я, опис, автора та посилання на доку+ченджлог.

{
  "name": "com.daniilcoolukraine.projectsetuptools",
  "version": "1.0.5",
  "displayName": "Project Setup Tools",
  "description": "Package contains references to all default things, that can be useful for developing a Unity project from scratch",
  "author": {
"name": "DaniilCoolUkraine"
  },
  "changelogUrl": "https://github.com/DaniilCoolUkraine/ProjectSetupTools/blob/main/CHANGELOG.md",
  "documentationUrl": "https://github.com/DaniilCoolUkraine/ProjectSetupTools/blob/main/README.md"
}

Наступним йде readme. Він відображається в гітхабі, тож порад як і чим його заповнити існує безліч. Особисто я використав його як документацію та опис «що саме робить цей пакет».

Changelog цілком проста річ: версія та опис змін. Як і в рідмі, тут використовується markdown, тож можна досягти максимально красивого форматування. Наприклад отак:

## [1.0.0] - 2025-03-06
### First release
- base project setup and initial test

Ліцензія — це найпростіший крок. В гуглі знаходите ліцензію, яка підходить вам, та вставляєте в файл. Я за все опенсорсне, тож використав MIT ліцензію, але їх набагато більше. Взяти текст та ознайомитися з умовами можна тут Licenses | Choose a License.

Папки едітора та рантайму також потребують додаткового сетапу: треба створити їм власну assembly definition. По налаштуванням та неймінгам проходитись не буду, літератури в інтернеті на це предостатньо.

Пункт один виконаний: ми маємо порожній, але цілком валідний пакет, який можна закинути на гіт та інсталювати в будь-яке місце. Як саме? Просто скопіювати посилання, яке використовується для клонування репозиторію та вставити його в пекедж менеджер.

Asset importer

Тепер зробимо імпортер.

Насправді, частина «мені точно треба ось це в проєкті» буде різною для кожного дева: хто що купив та який підхід любить більше. Але для мене це точно: Odin, Unitask, Zenject, Tween-бібліотеки, власна реалізація EventBus, іконки компонентів в ієрархії та віконце обраних файлів.

І... всі ці речі імпортуються по різному. Тому об’єднаємо їх у дві групи за правильною термінологією.

Все, що прилітає з асет стору, зберігається як .unitypackage на диску у конкретного користувача. Це приблизно тут C:\Users\[User]\AppData\Roaming\Unity\Asset Store-5.x\. І звуться вони assets. Все, що прилітає з гіта, за принципом, який я описував вище, — це packages.

Подушніли, йдемо далі.

Щоб імпортнути асети, юніті має для нас чудове апі — AssetDatabase.ImportPackage. Параметрами ми передаємо шлях до асета (конкретно .unitypackage файл) та булку, якою можна заглушити віконце вибору. Загалом сніпет простий, тож залишу його без пояснень:

public static void ImportAssets(string asset, string folder)
{
var basePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var assetsFolder = Path.Combine(basePath, "Unity/Asset Store-5.x");
AssetDatabase.ImportPackage(Path.Combine(assetsFolder, folder, asset), false);
}

Імпорт пакетів вже трошки tricky тема. Спочатку варто зробити чергу всіх пакетів, потім витягати їх один за одним через едітор веб реквест. Якщо не закомплітилось — чекаємо ще. Коли отримали пейлоад, стартуємо наступний процес:

private static async void StartNextPackageInstall()
{
request = Client.Add(packagesToInstall.Dequeue());
while (!request.IsCompleted) await Task.Delay(10);
if (request.Status == StatusCode.Success)
    Debug.Log($"Installed {request.Result.packageId}");
else
    Debug.LogError($"{request.Error.message}");
if (packagesToInstall.Count > 0)
{
    await Task.Delay(1000);
    StartNextPackageInstall();
}
}

Ііііі... це працює через раз. Імпорт пекеджа стартує компіляцію, яка діспозить реквести. В результаті воно встигає поставити 1-2 пакети за один клік. Конкретно цю проблему я поки не зміг подолати. Якщо у вас є ідеї як це обійти без збільшення затримки, буду радий почути в коментарях)

І останнє — виставлення неймспейсу. Тут все вирішується однією строчкою: EditorSettings.projectGenerationRootNamespace = PlayerSettings.productName.Replace(" «, »").

Висновки

В результаті ми повинні отримати щось таке: DaniilCoolUkraine/ProjectSetupTools. На цьому репозиторії я триматиму актуальну (та, сподіваюся, робочу) версію розширення. За бажанням до всього описаного можна докинути автоматичне створення папок з мого іншого допису (отут: Розширення для Unity editor: базовий сетап проєкту).

На цьому загалом і все. Діліться думками, власними мастхев-пакетами та робіть форки для власних автоматичних сетаперів. До зустрічі)

Підписуйтеся на Telegram-канал @gamedev_dou, щоб не пропустити найважливіші статті і новини

👍ПодобаєтьсяСподобалось11
До обраногоВ обраному4
LinkedIn


Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

можна ще як варіант створити 1 раз проєкт, там зробити ієрархію папок + за необхідністю базову mvc архітектуру з необхадними пекеджами, потім в 1 клік зібрати unitypackage і використовувати його при створенні нових проєктів.

Я пішов простішим шляхом, просто маю template repository на gitgub. І сетапиш як звичайний проект

Що також цілком валідний шлях) Дякую за ідею

Підписатись на коментарі