Выпуск новостей завершён 15 сентября 2026. Материалы сохранены на дату публикации. Перейти к инструкциям →

Архив · Полный материал · Хабр

Content Directories в Unity 6.6: закат Asset Bundles

Unity опубликовали ролик-анонс новой версии 6.6 и бегло засветили новую любопытную технологию. И нет, речь не про сериализуемые словари. Если бы мы только знали, что это такое — так что придётся...

Игры · ХабрРедакция Хабр4 минуты
Перейти к тексту ↓
Content Directories в Unity 6.6: закат Asset Bundles
Хабр
Коротко о главномРазвернутьСвернуть
  1. Unity опубликовали ролик-анонс новой версии 6.
  2. 6 и бегло засветили новую любопытную технологию.
  3. Если бы мы только знали, что это такое — так что придётся знакомиться.

Unity опубликовали ролик-анонс новой версии 6.6 и бегло засветили новую любопытную технологию. И нет, речь не про сериализуемые словари. Если бы мы только знали, что это такое — так что придётся знакомиться.

Content Directories — новая низкоуровневая система сборки и загрузки контента, которая планирует заменить собой уже изрядно постаревшие AssetBundles.

  1. Разделить билд на core-контент, который нужен сразу, и остальной контент, который нужен не сразу.
  2. Предоставить lazy references на эти ассеты и подгружать их в память во время выполнения по востребованию.

Но делают они это до банального иначе ( многие старожилы узнают в этом свои велосипеды ). И работают только для локального контента, который не загружается по remote-каналам и тянется через StreamingAssets ( что для WebGL и за Remote-канал сойдёт , хе-хе ).

Суть работы

  1. Создаётся ScriptableObject ( один или несколько ). Внутри через Loadable<T> и LoadableSceneId в инспекторе задаются ссылки на ассеты, которые должны попасть в ContentDirectories .
  2. Через Editor-скрипт вызвать BuildPipeline.BuildContentDirectory() для созданных ScriptableObject .
  3. Операция создаст в указанных папках те самые ContentDirectories ( по одной на каждый SO ), внутри которых будут отдельные файлы с хэш-именами и BuildManifest с маппингом { GUID ассета → хеш-имя файла } .
  4. Теперь в Runtime регистрируем полученные ContentDirectories ( одна или несколько ) через ContentLoadManager.RegisterContentDirectory . Это загрузит в память созданную мета-информацию об ассетах, но не сами ассеты — lazy references.
  5. Теперь можно через ContentLoadManager.GetRootAssets<....>() запрашивать ScriptableObject 'ы из п.1. А из них обращаться к Loadable<T> ссылкам на ассеты.
  6. Получить ассет нужно через Load / LoadAsync . И затем, когда больше не понадобится, выгрузить через Release .
// 1. Создаём ScriptableObject:
[CreateAssetMenu]
public class AssetRegistry : ScriptableObject
{
public Loadable<GameObject>[] enemies;
public Loadable<Texture2D>[] textures;
}

// 2-3. Строим Content Directory (Editor):
BuildPipeline.BuildContentDirectory(new BuildContentDirectoryParameters
{
outputPath = "Assets/StreamingAssets/Content",
rootAssetPaths = new[] { "Assets/Content/AssetRegistry.asset" }
});

// 4. Регистрируем Content Directory (Runtime):
var handle = ContentLoadManager.RegisterContentDirectory(
Path.Combine(Application.streamingAssetsPath, "Content"));

// 5. Получаем SO:
var registry = ContentLoadManager.GetRootAssets<AssetRegistry>()[0];

// 6. Загружаем контент:
GameObject prefab = await registry.enemies[2].LoadAsync();

// 7. Выгружаем контент:
registry.enemies[2].Release();

// 8. Выгружаем Content Directory:
ContentLoadManager.UnregisterContentDirectory(handle);

Вытекающие особенности

  1. Технически собирать ContentDirectory можно в любое место. Но лучше использовать StreamingAssets , которые будут автоматически скопированы в игровой билд для всех платформ. И Unity умеет предоставлять путь до этой директории в runtime.
  2. Контент из ContentDirectory попадает в сборку. Оно не попадает в исполняемые пакеты, но всё равно остаётся частью билда.
  3. Каждый ассет хранится отдельным файлом, а не в составе бандла. Поэтому загрузка конкретного ассета повлечёт загрузку только конкретно этого ассета. А не всего бандла с другим контентом.
  4. Каждый ассет сам за себя, поэтому не возникает дублирования ассетов, как это было в бандлах при неосторожном разрешении зависимостей между ассетами. Но дублирование можно создать, если разные ContentDirectory на одни и те же ассеты настроить.
  5. Каждый ассет-файл именуется хэшом, поэтому инкрементальная сборка работает на уровне отдельных ассетов и точечно не пересобирает контент, который не изменился. И позволяет версионировать этот контент. Как и бандлы.
  6. Release прям выгружает ассет. Нет ref counting ( как у Addressables). За использованиями нужно следить. Как с бандлами.

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

Настройка пока чуть замороченнее. И нет поддержки remote-доставки. Но зато взамен мы получаем " implicit de-duplication, reduced load times, and a lower memory overhead " (с).

Совместимость с Addressables

ContentDirectory и AssetBundle — это низкоуровневые системы сборки. Addressables — это высокоуровневый фреймворк для организации и доставки контента.

ContentDirectory заменяют AssetBundles , но не отменяют Addressables . Они могут работать вместе. И это официально поддерживается. Более того, можно использовать одновременно ContentDirectory для локального контента и AssetBundles — для remote. И всё это в рамках Addressables .

Т.е. если ваш проект построен на Addressables , то теоретически переезд на ContentDirectory будет максимально простым, т.к. с оригинальным низкоуровневым API напрямую общаться не приходится. И всё ограничится настройками в редакторе.

Выводы

Это всё пересказ документации и увиденного в видео. Опробовать это вживую мне ещё только предстоит. Наверняка там найдётся не один подводный камень.

Но пока чувствую, что наши юнитёвые WebGL-проекты в ближайшее время точно стоит попробовать перевести на эту систему сборки. Unity CLI не подвёл — глядишь, и это не подведёт.