Импорт своего формата: материал из RGB
Рабочий C#-импортёр, настройка шероховатости и повторный импорт.
Импортёр превращает собственный исходный формат в обычный ресурс Reckfell. Здесь файл paint.rfcolor содержит три целых канала RGB от 0 до 255, а результат — StandardMaterial3D с настраиваемой шероховатостью. После импорта загружайте исходный путь asset://paint.rfcolor: система ресурсов сама найдёт подготовленный материал.
Нужен редактор Reckfell 1.0.0 с C# и уже собирающийся проект. Это плагин редактора, не скрипт игровой Entity. Сначала прочитайте создание плагина, если ещё не включали плагины проекта.
1. Создайте три файла
Положите их в asset://addons/docs_rgb/. Имена файлов C# должны совпадать с именами классов.
plugin.cfg:
[plugin]
name="RGB Material Importer"
description="Imports RGB bytes as a material."
author="Reckfell"
version="1.0.0"
script="RgbImportPlugin.cs"RgbImportPlugin.cs регистрирует импортёр при включении и снимает регистрацию при выключении. EditorImportPlugin — ресурс со счётчиком ссылок: после удаления из реестра освобождаем собственную C#-обёртку через Dispose(), а не QueueFree().
using Reckfell;
[Tool]
public partial class RgbImportPlugin : EditorPlugin
{
private RgbMaterialImporter? _importer;
public override void _EnterTree()
{
_importer = new RgbMaterialImporter();
AddImportPlugin(_importer);
}
public override void _ExitTree()
{
if (_importer is null) return;
RemoveImportPlugin(_importer);
_importer.Dispose();
_importer = null;
}
}RgbMaterialImporter.cs задаёт формат и выполняет преобразование:
using System.Globalization;
using Reckfell;
using Reckfell.Collections;
[Tool]
public partial class RgbMaterialImporter : EditorImportPlugin
{
public override string _GetImporterName() => "reckfell.docs.rgb_material";
public override string _GetVisibleName() => "RGB Material";
public override string[] _GetRecognizedExtensions() => ["rfcolor"];
public override string _GetSaveExtension() => "material";
public override string _GetResourceType() => "StandardMaterial3D";
public override int _GetPresetCount() => 1;
public override string _GetPresetName(int presetIndex) => "Default";
public override int _GetFormatVersion() => 1;
public override bool _CanImportThreaded() => false;
public override Array<Dictionary> _GetImportOptions(string path, int presetIndex) =>
[
new Dictionary
{
{ "name", "roughness" },
{ "default_value", 0.7 },
{ "property_hint", (int)PropertyHint.Range },
{ "hint_string", "0,1,0.01" }
}
];
public override Error _Import(string sourceFile, string savePath,
Dictionary options, Array<string> platformVariants, Array<string> genFiles)
{
using var file = FileAccess.Open(sourceFile, FileAccess.ModeFlags.Read);
if (file is null) return FileAccess.GetOpenError();
if (file.GetLength() > 128) return Error.ParseError;
string[] parts = file.GetAsText().Trim().Split(',');
if (parts.Length != 3) return Error.ParseError;
byte[] rgb = new byte[3];
for (int i = 0; i < rgb.Length; i++)
if (!byte.TryParse(parts[i], NumberStyles.Integer,
CultureInfo.InvariantCulture, out rgb[i])) return Error.ParseError;
double roughness = 0.7;
if (options.ContainsKey("roughness"))
{
Variant value = options["roughness"];
if (value.VariantType != Variant.Type.Float &&
value.VariantType != Variant.Type.Int) return Error.InvalidParameter;
roughness = value.AsDouble();
}
if (!double.IsFinite(roughness) || roughness < 0 || roughness > 1)
return Error.InvalidParameter;
using var material = new StandardMaterial3D
{
AlbedoColor = Color.Color8(rgb[0], rgb[1], rgb[2]),
Roughness = (float)roughness
};
return ResourceSaver.Save(material, savePath + "." + _GetSaveExtension());
}
}Здесь нет доступа к дереву редактора из _Import(). Параллельный импорт намеренно выключен: включать _CanImportThreaded() можно только после проверки потокобезопасности всего обработчика и используемых зависимостей.
2. Включите импортёр и проверьте результат
- Соберите C#-проект кнопкой сборки редактора. При ошибке сначала исправьте её: несобранный плагин не загрузится.
- В Project → Project Settings → Plugins включите RGB Material Importer. Регистрация запускает сканирование ресурсов; дождитесь его завершения.
- Создайте
asset://paint.rfcolorс содержимым0,128,255и сохраните файл. Не называйте его.txt: импортёр распознаёт расширениеrfcolor. - Выберите файл в FileSystem. В Import должен быть импортёр RGB Material и параметр Roughness со значением
0.7. - У
MeshInstance3Dс назначенным мешем установите этот файл в Material Override. Получится материал с RGB(0,128,255). Итоговая яркость на экране зависит от освещения, экспозиции и тонального отображения; численные каналы материала не равны гарантированному цвету экранного пикселя. - В Import измените Roughness на
0.25и нажмите Reimport. Изменится шероховатость материала, а не исходный RGB. Затем измените содержимое исходника на255,32,0и повторите импорт: цвет обновится, сохранённая настройка0.25останется.
Загружайте файл через ResourceLoader.Load<StandardMaterial3D>("asset://paint.rfcolor"). Не используйте путь из .reckfell/imported: он принадлежит кэшу и может измениться. Если проверяете повторный импорт программно, учитывайте кэш уже загруженных ресурсов; в тесте чтения с диска можно явно указать cacheMode: ResourceLoader.CacheMode.Ignore.
Что хранится и что нужно коммитить
| Файл | Назначение |
|---|---|
paint.rfcolor | Исходные данные. Храните в системе контроля версий. |
paint.rfcolor.import | Метаданные импортёра, настройки и ссылка на результат. Храните рядом с исходником. |
.reckfell/imported/…material | Сгенерированный кэш при стандартной конфигурации проекта. Не редактируйте вручную. |
addons/docs_rgb/… | Код и конфигурация импортёра. Нужны редактору, чтобы восстановить кэш. |
savePath приходит от редактора без расширения. Импортёр сохраняет savePath + ".material" и возвращает результат ResourceSaver.Save(). Нельзя вернуть Error.Ok, если сохранение не удалось. Пустые platformVariants и genFiles здесь верны: создаётся только один основной материал, без дополнительных вариантов и зависимых файлов.
Контракт импортёра
| Метод | Что важно |
|---|---|
_GetImporterName() | Уникальный постоянный идентификатор, записываемый в .import. Не переименовывайте его ради изменения надписи. |
_GetVisibleName() | Читаемое имя в панели импорта; может отличаться от идентификатора. |
_GetRecognizedExtensions() | Расширения без точки. Используйте своё rfcolor, чтобы не перехватить все .txt или .json проекта. |
_GetResourceType() / _GetSaveExtension() | Настоящий класс ресурса и формат результата: StandardMaterial3D / material. |
_GetImportOptions() | Массив словарей. У каждой настройки обязательны name и default_value; тип значения задаёт тип поля. Подсказка диапазона улучшает UI, но проверку данных всё равно выполняет _Import(). |
_GetPresetCount() / _GetPresetName() | Один пресет Default в этом примере. Даже без пресетов _GetImportOptions() должен вернуть корректный массив. |
_GetFormatVersion() | Версия формата импортёра, а не версия движка. Увеличивайте при несовместимом изменении генерируемых данных. |
Если несколько импортёров понимают одно расширение, учитывайте _GetPriority() и явный выбор импортёра в настройках файла. Флаг firstPriority у AddImportPlugin() меняет место регистрации; он не отменяет сравнение численного приоритета. Для собственного уникального расширения дополнительные приоритеты не нужны.
Ошибки и исправления
| Симптом | Проверка |
|---|---|
| В списке нет плагина | Проверьте путь addons/docs_rgb/plugin.cfg, поле script, успешную C#-сборку и [Tool]. |
| Файл не импортируется | Включён ли плагин? Верно ли расширение? Дождались ли сканирования? Не вызывайте повторный импорт рекурсивно из _Import(). |
ParseError | Нужны ровно три десятичных целых числа 0…255 через запятую. 256, -1, NaN, дробные каналы и файл длиннее 128 байт отвергаются. |
InvalidParameter | roughness должен быть конечным числом от 0 до 1. Строка "0.7" не является числовым значением настройки. |
| Ошибка открытия | Проверьте существование и доступность исходного файла; возвращается ошибка FileAccess.GetOpenError(). |
| После редактирования код работает по-старому | Пересоберите C#, выключите и включите плагин, затем выполните Reimport файла. Смена кода не гарантирует автоматический повторный импорт всех прежних результатов. |
| После отключения плагина ресурс перестал импортироваться | Для пересоздания кэша нужен тот же импортёр. Включите плагин; не удаляйте исходник и .import для маскировки проблемы. |
Границы проверки
В установленном редакторе 1.0.0 проверены реальный импорт через FileSystem, метаданные .import, загрузка результата по исходному пути, смена параметра и исходника при повторном импорте, расширение в верхнем регистре, ошибки входных данных и повторное включение плагина. Проверки выполнены без графического окна: внешний вид материала, клики в панели Import, экспорт игры, параллельная обработка, варианты по feature tags и дополнительные генерируемые зависимости этим тестом не подтверждены.