Перейти к содержимому
SheetForge

Основные концепции

Таблица — единственный источник истины

Существует ровно одна каноническая форма ваших данных: таблица. Всё остальное — производное от неё:

  • IR (неизменяемые определения, Definitions) — это проверенная, собранная форма таблицы.
  • Сгенерированные классы C# — это схема IR, ставшая строго типизированной.
  • Запечённые объекты ScriptableObject — это значения IR, ставшие загружаемыми, — кеш для поиска, но никогда не независимый источник истины.

Любое изменение проходит через таблицу и должно пройти проверку при повторном импорте, чтобы стать реальным. Прямое редактирование запечённого SO создало бы второй источник истины и обошло бы проверку — продукт намеренно не поддерживает это как рабочий процесс.

(Переключатель «тестовая правка» в инспекторе существует для временных экспериментов во время выполнения. Он никогда не записывается обратно, и повторный импорт стирает его.)

Почему это важно: проекты, которые считают SO источником истины, в итоге получают непроверенные данные, расходящиеся с таблицей, без какого-либо способа их согласовать. Здесь согласование заложено в саму структуру — всегда перегенерируйте из таблицы.

IR — неизменяемая, проверенная сборка

IR — это то, что производит проверка. Для каждой вкладки он содержит SheetTable (схема + записи), чьи ячейки уже являются типизированными значениями: int, float, значения enum, ссылки на записи, ссылки на ассеты, списки, пользовательские типы плагинов.

Ключевые свойства:

  • Никакой частичной сборки. Если где-либо существует хотя бы одна ошибка, IR не строится (ImportResult.Success == false ⇔ Registry == null — жёсткий инвариант).
  • Никаких null. Пустая необязательная ячейка немедленно материализует значение по умолчанию для своего типа с флагом IsDefaulted — потребителям никогда не нужно проверять на null.
  • Неизменяемость. После сборки IR доступен только для чтения; точки выхода (генерация кода, запекание, экспорт) читают его, но никогда не изменяют.

Конвейер

fetch → parse markers/schema → parse cells → validate (keys, references,
@overlap, asset keys, domain rules) → assemble IR → codegen (.cs) → bake (SO)
       └──────────────── collect ALL diagnostics ────────────────┘
  • Проверка собирает всё. Вы получаете полный список проблем за один прогон — где / что / почему / как, для каждой ошибки — вместо исправления одной ошибки за один повторный импорт.
  • Генерация кода — последний этап, после проверки и сборки значений, потому что запись файлов .cs вызывает перезагрузку домена. Конвейер устроен так, что перезагрузка безопасна, а цепочка автоматически продолжается после неё.
  • Ошибки — это структурированные объекты, отображаемые в виде предложений. Каждая ошибка содержит вкладку, номер строки (с отсчётом от 1) и букву столбца и имя поля. Она также содержит некорректное значение, нарушенное правило и практическую рекомендацию по исправлению (с предложениями ближайшего совпадения для опечаток). Те же объекты также отображаются в виде машинных координат для логов/CI.

Автоматическая цепочка импорта

Когда схема новая или изменилась, один запуск импорта внутренне выполняет:

  1. Запись сгенерированного кода → компиляция Unity → перезагрузка домена.
  2. После перезагрузки цепочка возобновляется сама по себе и завершает запекание.

Вам никогда не нужно ничего запускать вручную повторно. Если компиляция завершается неудачно (например, код вашей игры ссылается на поле, которое только что изменило имя из-за переименования), цепочка безопасно прерывается с предложением конкретных действий в консоли, вместо того чтобы зацикливаться (лимит попыток — 3, лог возобновления).

Строгая типизация, без разбора во время выполнения

Генерация кода читает @name / @type / @desc и создаёт для каждой вкладки Foo:

  • FooDefinition — строго типизированный класс-запись, по одному полю на столбец; @desc становится XML doc-комментарием и подсказкой в инспекторе.
  • FooDatabase : DefinitionDatabase — SO-контейнер для вкладки с Records, отложенным поиском по id и SchemaFingerprint.

Запекание записывает настоящие типизированные поля — никакого разбора текста во время выполнения, никакой reflection во время выполнения, что делает его безопасным для IL2CPP (никаких рисков, связанных с усечением кода).

Загрузка по адресу — как кеш остаётся общим для команды

Запечённые SO — это кеши, локальные для каждой машины, с локальными для каждой машины GUID. Прямые ссылки на них из сцены ломались бы при переходе между машинами. Вместо этого:

  • Импорт автоматически регистрирует каждый Database SO в группе Addressables SheetForge по стабильному адресу "SheetForge/{tab}" (повторное запекание перепривязывает новый GUID к тому же адресу; удалённые вкладки автоматически удаляются).
  • Код игры загружает данные по адресу: SheetForgeDatabases.LoadAsync<FooDatabase>("Foo").
  • Ассет группы Addressables исключён из Git и самовосстанавливается (пересоздаётся импортом, если отсутствует).

Baseline — как round-trip сохраняет вашу таблицу

При импорте нормализованный снимок структуры каждой вкладки (строки маркеров, порядок столбцов, комментарии, написанный человеком текст) сохраняется как baseline. Затем экспорт подставляет текущие значения SO в структуру baseline.

Поэтому round-trip таблица → импорт → экспорт → таблица сохраняет вашу таблицу на 100% структурно и сохраняет значения семантически:

  • 1.01 допустимо, потому что значение идентично.
  • Для float используется кратчайший round-trip-формат.
  • Десятичный разделитель всегда ., независимо от локали.

Что коммитится, а что перегенерируется

АртефактПолитика
Таблицы (локальные файлы) / Google ТаблицаИстина. Коммитится / расшаривается.
Запечённые Database SO (Assets/SheetForgeBaked)Исключённый из Git, локальный для каждой машины кеш — перегенерируется при запуске импорта.
Сгенерированный код (Assets/SheetForgeGenerated)Рекомендуется его коммитить. Это собственный исходный код вашего проекта, он находится вне Assets/SheetForge, поэтому переустановка продукта не может его удалить, а коммит означает, что свежий клон компилируется ещё до того, как кто-либо выполнит импорт. Результат детерминирован, поэтому импорт у коллег даёт идентичные байты. Исключить его через gitignore — тоже допустимый вариант; тогда следующий импорт перегенерирует его. Проект, существовавший до этого значения по умолчанию, продолжает генерировать код в Assets/SheetForge/Runtime/Generated, пока эта папка не опустеет; см. Начало работы.
Ассет группы Addressables SheetForgeИсключён из Git, самовосстанавливается. Не коммитьте однострочный diff настроек, который создаётся при его первом создании.
Собственная папка Generated доменного пакетаРешение самого пакета. Встроенный пример SheetForge.PluginDemo коммитит свой сгенерированный код, чтобы демо компилировалось сразу же после импорта.
Ассет настроек импортаУправляется вами; держите пути к ключу сервисного аккаунта вне репозитория (используйте переменную окружения SHEETFORGE_SHEETS_KEY).

Расширение без изменений

Контракты регистрации позволяют плагинам подключаться к конвейеру без единой правки Core:

  • парсеры типов ячеек (включая wrapper-типы), доменные валидаторы, поставщики рёбер;
  • пользовательские структурные маркеры, шаблоны «Create sheet», провайдеры источников импорта;
  • переопределения холста, реестры кода, виджеты, действия, виджеты ячеек, цветовые пресеты и строки интерфейса Data Studio.

Core никогда не ссылается на доменный пакет; однонаправленная зависимость обеспечивается компилятором. Авторитетный список — вместе с их количеством — приведён в разделе Создание плагинов.

Похожие страницы