reckfellENGINE

Импорт своего формата: материал из 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().

C#
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 задаёт формат и выполняет преобразование:

C#
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. Включите импортёр и проверьте результат

  1. Соберите C#-проект кнопкой сборки редактора. При ошибке сначала исправьте её: несобранный плагин не загрузится.
  2. В Project → Project Settings → Plugins включите RGB Material Importer. Регистрация запускает сканирование ресурсов; дождитесь его завершения.
  3. Создайте asset://paint.rfcolor с содержимым 0,128,255 и сохраните файл. Не называйте его .txt: импортёр распознаёт расширение rfcolor.
  4. Выберите файл в FileSystem. В Import должен быть импортёр RGB Material и параметр Roughness со значением 0.7.
  5. У MeshInstance3D с назначенным мешем установите этот файл в Material Override. Получится материал с RGB (0,128,255). Итоговая яркость на экране зависит от освещения, экспозиции и тонального отображения; численные каналы материала не равны гарантированному цвету экранного пикселя.
  6. В 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 байт отвергаются.
InvalidParameterroughness должен быть конечным числом от 0 до 1. Строка "0.7" не является числовым значением настройки.
Ошибка открытияПроверьте существование и доступность исходного файла; возвращается ошибка FileAccess.GetOpenError().
После редактирования код работает по-старомуПересоберите C#, выключите и включите плагин, затем выполните Reimport файла. Смена кода не гарантирует автоматический повторный импорт всех прежних результатов.
После отключения плагина ресурс перестал импортироватьсяДля пересоздания кэша нужен тот же импортёр. Включите плагин; не удаляйте исходник и .import для маскировки проблемы.

Границы проверки

В установленном редакторе 1.0.0 проверены реальный импорт через FileSystem, метаданные .import, загрузка результата по исходному пути, смена параметра и исходника при повторном импорте, расширение в верхнем регистре, ошибки входных данных и повторное включение плагина. Проверки выполнены без графического окна: внешний вид материала, клики в панели Import, экспорт игры, параллельная обработка, варианты по feature tags и дополнительные генерируемые зависимости этим тестом не подтверждены.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.