PCK/ZIP: дополнения, патчи и порядок загрузки
Подключение пакетов, совпадение путей, кэш ресурсов и диагностика дополнений.
Что подключает пакет
PCK или ZIP добавляет файлы в виртуальную файловую систему asset://. Это подходит для дополнительных уровней, ассетов и обновлений содержимого. Подключение пакета не запускает уровень, не добавляет экземпляры Entity и не обновляет автоматически объекты, уже находящиеся в памяти.
Пакет с ресурсами — не установщик новой версии исполняемого файла. Для изменения C# кода, нативных расширений или самого движка нужен отдельный согласованный процесс сборки и доставки. Наличие DLL внутри PCK само по себе не загружает её в .NET.
Для обычного изображения или звука вне пакета используйте загрузку внешних файлов.
Подготовьте пакет
- Добавьте содержимое в проект и дождитесь импорта. Используйте ту же версию Reckfell и подходящий целевой платформе профиль экспорта.
- Для дополнения выделите собственные пути, например
asset://Mods/Island/. Включите уровень и все его зависимости. Путь внутри пакета должен совпадать с путём, который будет запрашивать игра. - В окне экспорта выберите профиль и действие Export PCK/ZIP…. Расширение выходного файла выбирает формат. Сохраните результат вне папки проекта.
- Проверьте пакет в целевой сборке игры: успешное подключение ещё не доказывает наличие всех текстур, импортированных данных или совместимость кода.
Экспорт проектов объясняет подготовку профиля. Для автоматизации редактор поддерживает --export-pack <preset> <path>; синтаксис запуска приведён в командной строке. Простое архивирование исходных моделей не заменяет экспорт их импортированных ресурсов.
Подключите до загрузки уровня
В примере пакет содержит уровень asset://Mods/Island/Main.rscene без дополнительных C# сборок. Сохраните класс в PackLevelExample.cs:
using Reckfell;
public static class PackLevelExample
{
public static bool TryLoadLevel(string packFile, string levelPath,
out PackedEntity? level, bool replaceFiles = false)
{
level = null;
if (!FileAccess.FileExists(packFile))
return false;
if (!ProjectSettings.LoadResourcePack(packFile, replaceFiles))
return false;
level = ResourceLoader.Load<PackedEntity>(levelPath);
return level is not null;
}
}Передайте физический путь к PCK/ZIP и логический путь уровня. При true в результате level содержит PackedEntity: загрузка закончена, но экземпляра в дереве ещё нет. Создайте экземпляр через Instantiate() и добавьте его подходящему родителю через AddChild(), либо передайте ресурс в EntityTree.ChangeSceneToPacked() для смены уровня.
Возвращаемое false означает отсутствие файла, отказ подключения или отсутствие результата загрузки уровня. Ошибки формата и зависимостей также смотрите в журнале. Если подключение удалось, а загрузка уровня завершилась неудачей, подключённые пути остаются: функция не выполняет откат.
Запускайте подключение в явном загрузочном этапе раньше первого обращения к ресурсам дополнения. Перенос вызова в _Ready() произвольного объекта не гарантирует этого порядка: другие объекты могли уже загрузить ресурс. Имена _init() и _ready() не являются переопределениями методов C#.
Совпадение путей и кэш
| Условие | Результат |
|---|---|
| Путь ещё не зарегистрирован | Подключённый пакет добавляет его |
Путь уже есть, replaceFiles: false | Существующий файл сохраняет приоритет; новые пути всё равно добавляются |
Путь уже есть, replaceFiles: true | Последний пакет с заменой определяет содержимое файла по этому пути |
| Resource уже загружен с обычным режимом кэша | Следующий обычный ResourceLoader.Load может вернуть прежний объект |
Поэтому replaceFiles: false — управление совпадениями обычных файлов, не изоляция мода. Запись удаления из PCK применяется даже при false: флаг не защищает зарегистрированные пути от удаления патчем. Для независимого дополнения используйте отдельный префикс путей. Для патча подключайте базу, затем обновления в установленном порядке с заменой.
Для диагностики сравните FileAccess.GetFileAsString() текстового файла и новый вызов ResourceLoader.Load<Resource>(path, "", ResourceLoader.CacheMode.Ignore). Первый читает текущие байты, второй обходит кэш самого запрошенного ресурса. Ignore не означает глубокий обход кэша зависимостей и не обновляет старые ссылки, материалы или экземпляры Entity. Для выпуска проще применять патчи до загрузки игровых ресурсов; горячее обновление требует отдельного управления их жизненным циклом.
Обычный патч и дельта
В профиле экспорта раздел Patching задаёт базовые пакеты. Действие экспорта патча сравнивает текущее содержимое с ними и записывает изменения. Для автоматизации есть --export-patch <preset> <path> и --patches <paths> со списком баз через запятую.
Сохраняйте фактически выпущенные базу и патчи. Для дельта-кодирования нужны исходные байты файлов и правильная цепочка: на машине игрока подключайте те же базовые пакеты в том же порядке, на которых строился патч. Дельта хранит различия внутри файлов; обычный патч может хранить изменённые файлы целиком. Размер и время загрузки проверяйте на своём содержимом — меньший патч не гарантирует более быструю загрузку.
Если дополнение не работает
| Симптом | Проверка |
|---|---|
Подключение вернуло false | Физический путь, доступность файла, формат и совместимость пакета; журнал движка |
| Пакет подключён, уровня нет | Точный asset:// путь, регистр имени, включение уровня и его зависимостей в экспорт |
| Видны старые данные | replaceFiles, порядок подключения и ресурс, загруженный до патча |
| Уровень есть, текстур нет | Экспорт импортированных данных и зависимостей для выбранной платформы |
| DLL лежит в пакете, новый C# тип недоступен | Отдельная поставка и загрузка сборок, разрешение зависимостей и совместимость с API игры |
Моды с исполняемым кодом не работают в песочнице только из-за упаковки в PCK/ZIP. Принимайте их из доверенного источника. Для собственных обновлений проверяйте подлинность пакета до подключения; наличие пакета и успешный LoadResourcePack не подтверждают автора. Формат пакета также сам по себе не ограничивает копирование платного содержимого.