Основные концепции
Таблица — единственный источник истины
Существует ровно одна каноническая форма ваших данных: таблица. Всё остальное — производное от неё:
- 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.
Автоматическая цепочка импорта
Когда схема новая или изменилась, один запуск импорта внутренне выполняет:
- Запись сгенерированного кода → компиляция Unity → перезагрузка домена.
- После перезагрузки цепочка возобновляется сама по себе и завершает запекание.
Вам никогда не нужно ничего запускать вручную повторно. Если компиляция завершается неудачно (например, код вашей игры ссылается на поле, которое только что изменило имя из-за переименования), цепочка безопасно прерывается с предложением конкретных действий в консоли, вместо того чтобы зацикливаться (лимит попыток — 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.0↔1допустимо, потому что значение идентично.- Для 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 никогда не ссылается на доменный пакет; однонаправленная зависимость обеспечивается компилятором. Авторитетный список — вместе с их количеством — приведён в разделе Создание плагинов.
Похожие страницы
- Синтаксис таблиц — грамматика маркеров и типов, которую читает парсер
- Data Studio — авторинг поверх этой модели
- Источники, экспорт и отправка — механика round-trip
- Ядро авторинга — движок, лежащий в основе окна авторинга