Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Імпорт плагінів
Примітка
Цей підручник передбачає, що ви вже знаєте, як створювати загальні плагіни. Якщо ви сумніваєтеся, зверніться до сторінки Створення додатків. Це також передбачає, що ви знайомі з системою імпорту Godot.
Вступ
Плагін імпорту — це особливий тип редактора, який дозволяє Godot імпортувати власні ресурси та розглядати їх як першокласні ресурси. Сам редактор постачається в комплекті з багатьма плагінами для імпорту для роботи зі звичайними ресурсами, такими як зображення PNG, моделі Collada та glTF, звуки Ogg Vorbis та багато іншого.
У цьому підручнику показано, як створити плагін імпорту для завантаження спеціального текстового файлу як матеріального ресурсу. Цей текстовий файл міститиме три числові значення, розділені комами, які представляють три канали кольору, а отриманий колір використовуватиметься як альбедо (основний колір) імпортованого матеріалу. У цьому прикладі він містить чистий синій колір (нуль червоного, нуль зеленого та повністю синій):
0,0,255
Налаштування
Спочатку нам потрібен загальний плагін, який оброблятиме ініціалізацію та знищення нашого плагіна імпорту. Давайте спочатку додамо файл plugin.cfg:
[plugin]
name="Silly Material Importer"
description="Imports a 3D Material from an external text file."
author="Yours Truly"
version="1.0"
script="material_import.gd"
Потім нам знадобиться файл material_import.gd, щоб додавати та видаляти плагін імпорту за потреби:
# material_import.gd
@tool
extends EditorPlugin
var import_plugin
func _enter_tree():
import_plugin = preload("import_plugin.gd").new()
add_import_plugin(import_plugin)
func _exit_tree():
remove_import_plugin(import_plugin)
import_plugin = null
Коли цей плагін активовано, він створить новий екземпляр плагіна імпорту (який ми незабаром створимо) і додасть його до редактора за допомогою методу add_import_plugin(). Ми зберігаємо посилання на нього в члені класу import_plugin, щоб ми могли посилатися на нього пізніше під час його видалення. Метод remove_import_plugin() викликається, коли плагін дезактивовано, щоб очистити пам’ять і повідомити редактору, що плагін імпорту більше не доступний.
Зауважте, що плагін імпорту є довідковим типом, тому його не потрібно явно вивільняти з пам’яті за допомогою функції free(). Він буде автоматично звільнений двигуном, коли він вийде за межі області видимості.
Клас EditorImportPlugin
Головним героєм шоу є EditorImportPlugin клас. Він відповідає за впровадження методів, які викликає Godot, коли йому потрібно знати, як працювати з файлами.
Давайте почнемо кодувати наш плагін, по одному методу:
# import_plugin.gd
@tool
extends EditorImportPlugin
func _get_importer_name():
return "demos.sillymaterial"
Першим методом є _get_importer_name(). Це унікальне ім’я вашого плагіна, яке Godot використовує, щоб знати, який імпорт використовувався в певному файлі. Коли файли потрібно буде повторно імпортувати, редактор знатиме, який плагін викликати.
func _get_visible_name():
return "Silly Material"
Метод _get_visible_name() відповідає за повернення назви типу, який він імпортує, і вона буде показана користувачеві в доку Import.
Вам слід вибрати це ім’я як продовження «Імпортувати як», наприклад. "Імпортувати як безглуздий матеріал". Ви можете назвати його як завгодно, але ми рекомендуємо описову назву для вашого плагіна.
func _get_recognized_extensions():
return ["mtxt"]
Система імпорту Godot визначає типи файлів за їх розширенням. У методі _get_recognized_extensions() ви повертаєте масив рядків для представлення кожного розширення, яке може зрозуміти цей плагін. Якщо розширення розпізнається кількома плагінами, користувач може вибрати, яке з них використовувати під час імпорту файлів.
Порада
Загальні розширення, такі як .json і .txt, можуть використовуватися багатьма плагінами. Крім того, у проекті можуть бути файли, які є лише даними для гри, і їх не слід імпортувати. Ви повинні бути обережними під час імпорту, щоб перевірити дані. Ніколи не очікуйте, що файл буде правильно сформованим.
func _get_save_extension():
return "material"
Імпортовані файли зберігаються в папці .import у корені проекту. Їхнє розширення має відповідати типу ресурсу, який ви імпортуєте, але оскільки Godot не може сказати, що ви використовуватимете (оскільки для одного ресурсу може бути кілька дійсних розширень), вам потрібно оголосити, що використовуватиметься під час імпорту.
Оскільки ми імпортуємо матеріал, ми будемо використовувати спеціальне розширення для таких типів ресурсів. Якщо ви імпортуєте сцену, ви можете використовувати scn. Загальні ресурси можуть використовувати розширення res. Однак це жодним чином не забезпечується двигуном.
func _get_resource_type():
return "StandardMaterial3D"
Імпортований ресурс має певний тип, тому редактор може знати, до якого слота властивостей він належить. Це дозволяє перетягувати з док-станції FileSystem до властивості в інспекторі.
У нашому випадку це class_StandardMaterial3D, який можна застосовувати до 3D-об’єктів.
Примітка
Якщо вам потрібно імпортувати різні типи з одного розширення, вам потрібно створити кілька плагінів імпорту. Ви можете абстрагувати код імпорту в інший файл, щоб уникнути дублювання в цьому відношенні.
Опції та пресети
Ваш плагін може надавати різні параметри, щоб дозволити користувачеві контролювати, як ресурс буде імпортовано. Якщо набір вибраних параметрів є загальним, ви також можете створити різні стилі, щоб полегшити роботу користувача. На наступному зображенні показано, як параметри відображатимуться в редакторі:
Оскільки може бути багато попередніх налаштувань і вони ідентифікуються числом, добре використовувати перелік, щоб ви могли посилатися на них за допомогою імен.
@tool
extends EditorImportPlugin
enum Presets { DEFAULT }
...
Тепер, коли enum визначено, давайте продовжимо дивитися на методи плагіна імпорту:
func _get_preset_count():
return Presets.size()
Метод _get_preset_count() повертає кількість попередніх налаштувань, які визначає цей плагін. Зараз у нас є лише один стиль, але ми можемо зробити цей метод перспективним, повернувши розмір нашого переліку Presets.
func _get_preset_name(preset_index):
match preset_index:
Presets.DEFAULT:
return "Default"
_:
return "Unknown"
Тут у нас є метод _get_preset_name(), який дає назви стилям, як вони будуть представлені користувачеві, тому використовуйте короткі та зрозумілі назви.
Тут ми можемо використати оператор match, щоб зробити код більш структурованим. Таким чином можна легко додавати нові стилі в майбутньому. Ми також використовуємо шаблон catch all, щоб щось повернути. Незважаючи на те, що Godot не запитуватиме попередні налаштування, окрім заданої вами кількості, завжди краще перестрахуватися.
Якщо у вас є лише один стиль, ви можете просто повернути його ім’я безпосередньо, але якщо ви це зробите, вам потрібно бути обережним, додаючи більше стилів.
func _get_import_options(path, preset_index):
match preset_index:
Presets.DEFAULT:
return [{
"name": "use_red_anyway",
"default_value": false
}]
_:
return []
Це метод, який визначає доступні опції. _get_import_options() повертає масив словників, і кожен словник містить кілька ключів, які перевіряються для налаштування опції, яка відображається користувачеві. У наступній таблиці наведено можливі ключі:
Ключ |
Тип |
Опис |
|---|---|---|
|
Строка (рядок, текст) |
Назва опції. Коли відображаються, підкреслення стають пробілами, а перші літери великими. |
|
Будь-який |
Стандартне значення параметра для цього стилю. |
|
Значення Enum |
Одне зі значень PropertyHint для використання як підказки. |
|
Строка (рядок, текст) |
Текст підказки властивості. Те саме, що ви додаєте в оператор |
|
Значення Enum |
Одне зі значень PropertyUsageFlags для визначення використання. |
Ключі name і default_value є обов’язковими, решта необов’язкові.
Зауважте, що метод _get_import_options отримує номер попереднього налаштування, тому ви можете налаштувати параметри для кожного окремого стилю (особливо значення за замовчуванням). У цьому прикладі ми використовуємо інструкцію match, але якщо у вас є багато параметрів і стилі змінюють лише значення, ви можете спочатку створити масив параметрів, а потім змінити його на основі стилю.
Попередження
Метод _get_import_options викликається, навіть якщо ви не визначаєте попередні налаштування (через те, що _get_preset_count повертає нуль). Ви повинні повернути масив, навіть якщо він порожній, інакше ви можете отримати помилки.
func _get_option_visibility(path, option_name, options):
return true
Для методу _get_option_visibility() ми просто повертаємо true, оскільки всі наші параметри (тобто єдиний, який ми визначили) видимі весь час.
Якщо вам потрібно зробити певну опцію видимою, лише якщо іншу встановлено з певним значенням, ви можете додати логіку в цей метод.
Метод імпорт
Важка частина процесу, відповідальна за перетворення файлів на ресурси, покривається методом _import(). Наш зразок коду трохи довгий, тому давайте розділимо його на кілька частин:
func _import(source_file, save_path, options, r_platform_variants, r_gen_files):
var file = FileAccess.open(source_file, FileAccess.READ)
if file == null:
return FileAccess.get_open_error()
var line = file.get_line()
Перша частина нашого методу імпорту відкриває та читає вихідний файл. Для цього ми використовуємо клас FileAccess, передаючи параметр source_file, який надає редактор.
Якщо під час відкриття файлу виникає помилка, ми повертаємо його, щоб повідомити редактору, що імпортування не відбулося.
var channels = line.split(",")
if channels.size() != 3:
return ERR_PARSE_ERROR
var color
if options.use_red_anyway:
color = Color.from_rgba8(255, 0, 0)
else:
color = Color.from_rgba8(int(channels[0]), int(channels[1]), int(channels[2]))
Цей код бере рядок файлу, який він прочитав раніше, і розбиває його на частини, розділені комою. Якщо значень більше або менше, він вважатиме файл недійсним і повідомляє про помилку.
Потім він створює нову змінну Color і встановлює її значення відповідно до вхідного файлу. Якщо опцію use_red_anyway увімкнено, замість цього колір встановлюється як чистий червоний.
var material = StandardMaterial3D.new()
material.albedo_color = color
Ця частина створює новий StandardMaterial3D, який є імпортованим ресурсом. Ми створюємо його новий екземпляр, а потім встановлюємо його колір альбедо як значення, яке ми отримали раніше.
return ResourceSaver.save(material, "%s.%s" % [save_path, _get_save_extension()])
Це остання частина і досить важлива, тому що тут ми зберігаємо зроблений ресурс на диск. Шлях до збереженого файлу створюється та повідомляється редактором через параметр save_path. Зауважте, що це без розширення, тому ми додаємо його за допомогою строкового форматування. Для цього ми викликаємо метод _get_save_extension, який ми визначили раніше, тому ми можемо бути впевнені, що вони не вийде з синхронізації.
Ми також повертаємо результат із методу ResourceSaver.save(), тож якщо на цьому кроці буде помилка, редактор дізнається про це.
Варіанти платформи та згенеровані файли
Можливо, ви помітили, що наш плагін ігнорує два аргументи методу import. Це повернуті аргументи (звідси r на початку їх назви), що означає, що редактор читатиме їх після виклику вашого методу імпорту. Обидва вони є масивами, які ви можете заповнити інформацією.
Аргумент r_platform_variants використовується, якщо вам потрібно імпортувати ресурс по-різному залежно від цільової платформи. Хоча це називається варіантами платформи, воно базується на наявності тегів функцій, тому навіть одна платформа може мати кілька варіантів залежно від налаштувань.
Щоб імпортувати варіант платформи, вам потрібно зберегти його з тегом функції перед розширенням, а потім додати тег до масиву r_platform_variants, щоб редактор міг знати, що ви це зробили.
Наприклад, скажімо, ми зберігаємо інший матеріал для мобільної платформи. Нам потрібно було б зробити щось на зразок наступного:
r_platform_variants.push_back("mobile")
return ResourceSaver.save(mobile_material, "%s.%s.%s" % [save_path, "mobile", _get_save_extension()])
Аргумент r_gen_files призначений для додаткових файлів, які генеруються під час процесу імпорту та потребують збереження. Редактор перегляне його, щоб зрозуміти залежності та переконатися, що зайвий файл не буде випадково видалено.
Це також масив, який має бути заповнений повними шляхами файлів, які ви зберігаєте. Для прикладу давайте створимо інший матеріал для наступного проходу та збережемо його в іншому файлі:
var next_pass = StandardMaterial3D.new()
next_pass.albedo_color = color.inverted()
var next_pass_path = "%s.next_pass.%s" % [save_path, _get_save_extension()]
err = ResourceSaver.save(next_pass, next_pass_path)
if err != OK:
return err
r_gen_files.push_back(next_pass_path)
Випробування плагіна
Це було теоретично, але тепер, коли плагін імпорту завершено, давайте перевіримо його. Переконайтеся, що ви створили файл зразка (з вмістом, описаним у вступному розділі) і збережіть його як test.mtxt. Потім активуйте плагін у налаштуваннях проекту.
Якщо все йде добре, плагін імпорту додається до редактора, а файлова система сканується, завдяки чому настроюваний ресурс з’являється в док-станції FileSystem. Якщо ви виберете його та сфокусуєтеся на панелі «Імпорт», ви побачите єдиний варіант для вибору там.
Створіть у сцені вузол MeshInstance3D і для його властивості Mesh налаштуйте новий SphereMesh. Розгорніть розділ Material в Inspector, а потім перетягніть файл із док-станції FileSystem до властивості material. Об’єкт оновиться у вікні перегляду синім кольором імпортованого матеріалу.
Перейдіть до док-станції «Імпорт», увімкніть параметр «Усе одно використовувати червоний» і натисніть «Повторний імпорт». Це оновить імпортований матеріал і має автоматично оновити подання, яке замість нього буде червоним.
І все! Ваш перший плагін імпорту готовий! Тепер будьте креативними та створюйте плагіни для своїх улюблених форматів. Це може бути дуже корисно, щоб записати ваші дані у спеціальному форматі, а потім використовувати їх у Godot, як якщо б вони були рідними ресурсами. Це показує, наскільки потужна та розширювана система імпорту.