Unity 6.6 отправляет AssetBundles на покой: инкрементальная сборка Slime Rancher 2 ускорилась с 32 минут до трёх
Unity выпустила в версии 6.6 content directories — новый способ упаковки и загрузки контента, который разработчики движка прямо называют заменой AssetBundles. Главное отличие в том, что рантайм теперь адресует, загружает и выгружает отдельные артефакты — например, конкретный меш или текстуру, — а не бандл целиком. Компоновка бандлов, ради которой команды годами придумывали стратегии группировки, перестаёт быть проектным решением.
Цифры Unity приводит на реальном проекте: Slime Rancher 2, перенесённый с Addressables на content directories. Инкрементальная сборка сократилась с 32 минут 16 секунд до 3 минут 4 секунд, чистая — с 58 минут 6 секунд до 37 минут 13 секунд. Сборка игры похудела с 4 ГБ до 2,88 ГБ, а загрузка ускорилась с 45 до 30 секунд — примерно на треть. Замеры сделаны в Unity 6.6 Beta (6000.6.0b10) на MacBook Pro с M5 Max.
Почему бандл как единица загрузки перестал устраивать
AssetBundle — неделимая единица распространения, хранения и загрузки. Зависимости отслеживаются на уровне бандла, а загружать и выгружать его приходится целиком. Отсюда и вся сопутствующая работа: ручная раскладка ассетов по группам, отслеживание цепочек зависимостей, борьба с дублированием общих ресурсов между бандлами.
Content directories устроены иначе. Unity использует схему адресуемого по содержимому хранилища — ту же идею, что лежит в основе git: каждый файл контента именуется и адресуется хэшем собственного содержимого. Дедупликация из задачи разработчика превращается в свойство формата. При этом друг на друга артефакты ссылаются не по хэшу, а по стабильным идентификаторам — иначе правка одного файла каскадом меняла бы хэши всей цепочки; соответствие идентификаторов и хэшей хранится в манифесте сборки.
Что включать в сборку, теперь задаётся не пометкой каждого ассета, а корневыми ассетами — обычными ScriptableObject. Зависимости подтягиваются автоматически и отслеживаются по отдельным ассетам, а не по бандлам. В коде появился тип Loadable<T> — загружаемая ссылка на уровне движка: объявляется поле вида Loadable<Mesh> bodyMesh, дальше вызывается bodyMesh.Load(); загружать и выгружать отдельные ассеты можно синхронно или асинхронно, через async/await. Объекты, на которые ссылается Loadable, попадают в сборку, но не грузятся в память, пока их не запросят. Сама загрузка полностью асинхронна и на чтении, и на десериализации, с использованием платформенных async-API; в основе лежит формат контент-файлов, появившийся в DOTS в 2022 году.
Что делать тем, кто уже сидит на Addressables
Unity не стала ломать существующие проекты. Content directories совместимы с пакетом Addressables, который остаётся интерфейсом для организации контента, а существующие проекты можно конвертировать на новый бэкенд: Slime Rancher 2 перевели без единой правки кода. Порядок конвертации и сравнение вариантов описаны в документации Addressables.
Меняется сам подход к тому, что вообще нужно помечать. Unity автоматически включает в сборку ассеты, на которые ссылается Loadable, и сама убирает дубли, так что отдельные бандлы ради общих зависимостей больше не нужны. В документации рекомендуют создавать один корневой ассет на весь проект, а если код грузит много ассетов по строковым ключам — использовать ScriptableObject в роли списка ассетов вместо множества корневых.
Ограничения, о которых стоит знать заранее
В 6.6 content directories работают только с локальным контентом — тем, что едет вместе с плеером. Для удалённой доставки и докачки после установки по-прежнему нужны AssetBundles или собственный механизм. Полноценную гранулярную доставку «по воздуху» Unity обещает в поколении Unity 7, подробности — в 2027 году.
- API
BuildUsageс content directories несовместим: использующие его ассеты придётся править, для поиска проблем предлагается Project Auditor; - ассеты с циклическими зависимостями склеиваются в один загружаемый блок — Unity выводит предупреждение, а если суммарный размер цикла превышает 64 МБ, сборка падает;
- чистая сборка может оказаться медленнее, чем сборка AssetBundles;
- смешивание AssetBundles и content directories в одном проекте приводит к тому, что общие зависимости собираются дважды;
- каждая сборка самодостаточна: если два content directory ссылаются на один ассет, копия попадёт в каждый.
Content directory регистрируется в рантайме, после чего её ассеты становятся доступны; сцены тоже подключаются через загружаемые ссылки. Подробности описаны в официальной документации Unity по content directories.
Зачем Unity понадобилось менять фундамент именно сейчас
Content directories выглядят как смена опоры всего контентного стека, а не как отдельная функция 6.6. Ограничения AssetBundle просматриваются и в дизайне Addressables: заметная часть работы с этим пакетом сводилась к тому, чтобы компенсировать неделимость бандла. Если базовая единица становится атомарной, часть привычных задач техартистов и билд-инженеров — раскладка по группам, охота за дублями, ручное управление цепочками зависимостей — теряет смысл сама по себе.
Направление совпадает с общим движением индустрии к контентно-адресуемым хранилищам и инкрементальным сборкам: тот же принцип давно работает в системах контроля версий и кэшах сборки, и в больших проектах он даёт выигрыш в первую очередь на времени итерации. Десятикратное сокращение инкрементальной сборки в примере Slime Rancher 2 бьёт не столько по финальному билду, сколько по ежедневному циклу правки и проверки — а это то, на что команды тратят рабочие часы.
Addressables при этом никуда не уходит: судя по тому, как устроена миграция, пакет остаётся пользовательским интерфейсом, а content directories занимают место под ним. Учитывая, что удалённую доставку Unity привязывает к новому фундаменту в поколении Unity 7, переход на этот бэкенд, вероятно, со временем станет условием для гранулярной докачки контента, и проектам, которые сегодня живут на ручной раскладке бандлов, имеет смысл присмотреться к конвертации заранее.
Почему AssetBundles отправили на покой только сейчас: давление Godot и Unreal, накопленная боль Addressables, смена курса после ухода Джона Ричителло?