Создание сборки своей игры на базе CRYENGINE 5.3. Часть вторая. Запаковка ресурсов.

06. декабря 2017 CRYENGINE 5 2

Официальная документация по теме:

http://docs.cryengine.com/display/CEPROG/Compiling+Assets+for+Multiple+Platforms

В первой части сказа о создании сборки своей игры речь шла о подготовке к запаковке ресурсов игры, а в этой непосредственно осуществим её.

Запаковка ресурсов в основном оптимизирует занимаемое игрой дисковое пространство, а так же позволяет при желании зашифровать файлы игры. Не смотря на некоторую трудоёмкость процесса, рекомендую запаковывать ресурсы игры, чтобы было красиво и занимало меньше места у игроков. В CRYENGINE для этого используются zip-архивы с несильным сжатием и расширением pak, условимся называть их pak-архивами. Несильное сжатие предпочтительно для pak-архивов, так как это позитивно влияет на скорость запуска игры в виду экономии времени на распаковку движком.

Упакованный GameSDK от Crytek по умолчанию выглядел так:

 Примечание: В данном случае .cryasset.pak и их содержимое нужны для редактора и в сборке игры их быть не должно.

 

Разделение на паки применяется для снижения нагрузки на систему при распаковке-чтении движком и для оптимизации перекачки при шифровании pak-архивов. Можно не заморачиваться и упаковать почти все ресурсы в один pak-архив, но с очень важным условием — размер pak-архива не должен превышать 2 Гб, иначе движок не сможет с ним работать.

У нас получится примерно так:

Или вот так, когда по ленивому всё в один pak, но при условии, что он будет менее 2 Гб:


Способы запаковки.

Их три:

  1. Запаковка специальным скриптом (RC Jobs) rcjob.xml для rc.exe (компилятор ресурсов движка);

  2. Вывести используемый игрой контент с помощью Save Level Resources, а потом долго и упорно запаковывать вручную, используя свободный архиватор 7-zip.

  3. Комбинированный. Совместить способ запаковки с помощь скрипта rcjob.xml для rc.exe с ручной запаковкой с помощью Save Level Resources. Для этого достаточно будет сохранить используемые ресурсы с применением Save Level Resources, почистить от лишнего и докинуть недостающее, а потом применить rcjob.xml. Метод подойдёт для захламлённого проекта.

 

1. Запаковка с использованием скрипта (RC Jobs) для rc.exe.

Примечание: Это оптимальный метод для проекта, в котором используются только необходимые ресурсы из GameSDK или не используются вовсе. Иными словами, проект не содержит в себе разнообразный мусор, надёрганный и напиханный в процессе работы.

Официальная документация: http://docs.cryengine.com/display/CEPROG/Compiling+Assets+for+Multiple+Platforms

Основная суть этого метода заключается в автоматизации процесса копирования и запаковки ресурсов, что позволит после настройки скрипта запаковывать ресурсы игры в пару кликов. В данном случае запакуем содержимое каталога assets.

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

Для осуществления задуманного нам потребуется:

  • bat-файл, который будет запускать rc.exe с командами из скрипта rcjob.xml, осуществляя сборку под указанную платформу и с указанным числом потоков процессора.

  • rcjob.xmlэто набор команд для rc.exe, перечисленный в текстовом файле, по копированию и запаковке указанных типов ресурсов. То есть сначала все необходимые файлы будут скопированы в промежуточный каталог, а затем будут упакованы в pak-архивы. Так больше контроля и 100% защиты от сбоев с повреждением файлов. Для заполнения файла используется синтаксис xml.

  • Если используются ресурсы из GameSDK, то все необходимые для игры (в данном примере в каталоге assets) должны быть извлечены из pak-архивов, кроме содержимого level.pak для уровней и pak-архивов локализации.

 

Создание bat-файла.

Это обычный текстовый файл с расширением .bat. Создаём его в любом удобном месте, лучше рядом со сборкой, чтобы не потерять. Название любое, написанное на латинице и без спецсимволов. Пример:

D:\MyBestGameBuild\PC.bat

Где D:\MyBestGameBuild это каталог для формирования сборки игры. Располагаем его ближе к корню, чтобы не столкнуться с ограничением Windows на количество символом в пути. Название любое на латинице, без пробелов и спецсимволов.

Содержимое записывается в одну строку:

"D:\Programs\CRYENGINE Launcher\Crytek\CRYENGINE_5.3\Tools\rc\rc.exe" /job="D:\MyBestGameBuild\rcjob_PC.xml" /p=pc /threads=4 > pclog.log

Описание содержимого:

«D:\Programs\CRYENGINE Launcher\Crytek\CRYENGINE_5.3\Tools\rc\rc.exe» — указываем путь до rc.exe, который поставляется вместе с движком. Кавычки нужны для корректного чтения интерпретатором путей с пробелом.

/job=»D:\MyBestGameBuild\rcjob_PC.xml» — указываем путь до xml-файла с командами, который имеет название rcjob_PC.xml. Само название файла не принципиально лишь бы латиницей, без спецсимволов и пробелов. О его содержимом упоминается дальше по статье.

/p=pc — указываем целевую платформу. В данном случае подразумевается Windows.

/threads=4 — количество потоков процессора, которые будет использовать rc.exe. Чтобы не было тормозов, имеет смысл указать число физических ядер процессора, а не все имеющиеся потоки.

> pclog.log — вывести список операций в процессе работы rc.exe в текстовый файл. Очень полезно при диагностировании проблем с выполнением команд.

Примечание: Перед и после знака > нужен пробел.

Создание rcjob_PC.xml.

Это текстовый файл, содержимое которого описано с применением xml-синтаксиса. Создаём его в любом удобном месте, лучше рядом с PC.bat. Название любое, написанное на латинице и без спецсимволов. Пример:

D:\MyBestGameBuild\rcjob_PC.xml

Для редактирования рекомендую использовать Notepad++ или любой другой текстовый редактор с указанием номеров строк и подсветкой синтаксиса. Можно обойтись стандартным блокнотом, но будет существенно менее удобно.

Расписывать по особенностям xml-синтаксиса в данной статье не буду, оставляю это для самостоятельного ознакомления, но уточню, что быть программистом не обязательно, там всё довольно просто.

Содержимое.

Примечание: Ниже приведённый код является примером, для личного использования необходимо указать актуальные для конкретной ситуации данные.

Примечание: Код может «скакать» по строкам при отображении на странице блога, но на деле строки строго определены. Рекомендую использовать Notepad++ или его аналоги для корректного просмотра кода.

<RCJobs>
<DefaultProperties src="D:\Programs\CRYENGINE Launcher\Crytek\MyBestGameProject" game="assets" trg="D:\MyBestGameBuild\${p}\temp" pak_root="D:\MyBestGameBuild\${p}\MyBestGame" />

<Properties src_game="${src}\${game}" trg_game="${trg}\${game}" pak_game="${pak_root}\${game}" />

<CopyJob>
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cgf" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cga" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.mtl" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.dds" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.1" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.2" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.3" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.4" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.5" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.6" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.7" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.8" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.9" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.1a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.2a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.3a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.4a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.5a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.6a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.7a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.8a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.9a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.adb" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.animevents" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.anm" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.bnk" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.bspace" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.caf" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cax" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cdf" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.chr" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.chrparams" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cfg" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.comb" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.dba" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.ent" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.lua" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.skin" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.swf" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.thread_config" copyonly="1" />
    <Job sourceroot="${src_game}\languages" targetroot="${pak_game}\languages" input="*.pak" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_01" targetroot="${pak_game}\Levels\MyBestLevel_01" input="level.pak" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_02" targetroot="${pak_game}\Levels\MyBestLevel_02" input="level.pak" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_03" targetroot="${pak_game}\Levels\MyBestLevel_02" input="level.pak" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_01" targetroot="${pak_game}\Levels\MyBestLevel_01" input="filelist.xml" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_02" targetroot="${pak_game}\Levels\MyBestLevel_02" input="filelist.xml" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_03" targetroot="${pak_game}\Levels\MyBestLevel_03" input="filelist.xml" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.xml" copyonly="1" />
</CopyJob>

<PakJob>
    <Job sourceroot="${trg_game}" input="Animations\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="Audio\*.*" zip="${pak_game}\MyBestGame_Audio.pak" />
    <Job sourceroot="${trg_game}" input="config\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="difficulty\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="entities\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="libs\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="materials\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="prefabs\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="_newpreview_.mtl" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="autoexec.cfg" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="entities.xml" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="hud_settings.xml" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="Savegames.xml" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="Objects\*.*" zip="${pak_game}\MyBestGame_Objects.pak" />
    <Job sourceroot="${trg_game}" input="Scripts\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="Textures\*.*" zip="${pak_game}\MyBestGame_Textures.pak" />
</PakJob>

<Run Job="CopyJob"/>
<Run Job="PakJob"/>

</RCJobs>

 

Описание содержимого.

Примечание: В данном примере рассматриваются параметры с названиями из официальной документации, но можно задавать свои названия для параметров.

Примечание: Для удобства ориентирования в коде рекомендую скопировать его в Notepad++ или любой другой аналог, где будет включено отображение номеров строк.

Строка 2:

<DefaultProperties src=»D:\Programs\CRYENGINE Launcher\Crytek\MyBestGameProject» game=»assets» trg=»D:\MyBestGameBuild\${p}\temp» pak_root=»D:\MyBestGameBuild\${p}\MyBestGame» /> — определяем значения для параметров scr, game, trg и pak_root.

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

game это название каталога, где находятся ресурсы игры. По умолчанию это каталог assets.

trg — это путь до промежуточного каталога, в который будут скопированы ресурсы для упаковки в pak-архивы.

pak_root — это путь для сохранения готовых pak-архивов. В примере пути можно заметить ${p} — это имя для каталога по названию платформы, которую указали в PC.bat. В данном случае название каталога будет pc. В итоге путь будет такой: D:\MyBestGameBuild\pc\MyBestGame. В данном случае MyBestGame это название каталога по имени игры. Можно обойтись без использования ${p} и написать прямо — pc.

Строка 4:

<Properties src_game=»${src}\${game}» trg_game=»${trg}\${game}» pak_game=»${pak_root}\${game}» /> — определяем значения для дополнительных параметров.

src_game=»${src}\${game}» — путь до рабочего проекта с переходом в каталог, который мы задали для параметра game во второй строке. В данном примере это каталог assets. Пример: D:\Programs\CRYENGINE Launcher\Crytek\MyBestGameProject\assets

trg_game=»${trg}\${game}» — путь до промежуточного каталога с переходом в каталог, который мы задали для параметра game во второй строке. В данном примере будет создан каталог assets, так как он не был создан вручную. Пример: D:\MyBestGameBuild\pc\temp\assets

pak_game=»${pak_root}\${game}» — это путь для сохранения готовых pak-архивов с переходом в каталог assets, в который будут непосредственно сохранены pak-архивы. Пример: D:\MyBestGameBuild\pc\MyBestGame\assets

 

Описание содержимого элемента <CopyJob>…</CopyJob>.

CopyJob — это описание задачи копирования для rc.exe, где указывается источник ресурсов, из которого нужно скопировать обозначенный тип файлов в целевой каталог. rc.exe осуществляет рекурсивный поиск по всем каталогам источника и копирует все найденные файлы указанного типа. При этом копирование производится не просто всех файлов в кучу, а с созданием иерархии каталогов, в которых они были в каталогах источника.

Основной задачей по этому элементу будет описать все типы файлов, откуда их копировать и куда.

Строка 7:

<Job sourceroot=»${src_game}» targetroot=»${trg_game}» input=»*.cgf» copyonly=»1″ />

sourceroot=»${src_game}» — источник файлов для копирования. В данном примере это каталог assets в директории рабочего проекта. Пример: D:\Programs\CRYENGINE Launcher\Crytek\MyBestGameProject\assets

targetroot=»${trg_game}» — каталог, в который будет осуществлено копирование ресурсов из источника. Пример: D:\MyBestGameBuild\pc\temp\assets

input=»*.cgf» — указываем тип файлов, которые будут найдены в источнике и скопированы. Как раз * указывает rc.exe, то нужно найти все файлы с расширением cgf. В данном случае это файлы статичной геометрии.

copyonly=»1″ — подтверждаем копирование.

В том же духе описывается копирование для прочих типов файлов:

Стоит учесть, что копирование по типу файлов (*.расширение_файла) копирует все файлы указанного типа, которые будут найдены в каталоге-источнике. Если такое не нужно, то можно указать явно из каких каталогов копировать указанный тип файлов.

Примеры:

  1. В каталоге-источнике могут быть сторонние pak-архивы и xml-файлы, которые нам не нужны в сборке. К примеру, компоненты уровня geometry.pak, terraintexture.pak, TimeOfDay.xml, Objectives.xml и прочие, которые используются в редакторе и не нужны в сборке, поэтому укажем явно какие pak-архивы и xml-файлы нужно скопировать из каталогов уровней.

  2. Тоже самое применимо и для файлов анимации .caf (и для всех остальных):

     

 

Описание содержимого элемента <PakJob>…</PakJob>.

Если указывать запаковку разных каталогов в один и тот же pak-архив, то они будут в него добавлены.

При желании упаковать всё в один pak-архив нужно учитывать, что предельный размер для упакованного pak-архива равен 2 Гб, при превышении этого лимита rc.exe не сможет его запаковать корректно.

Чтобы rc.exe не пытался упаковывать pakархивы уровней и локализации, придётся явно указать какие каталоги упаковывать. Так же явное указание каталогов для запаковки нужно для создания дополнительных pak-архивов, чтобы не превысить лимит в 2 Гб на pak.

sourceroot=»${trg_game}» указываем, что источником является каталог, в который в элементе <CopyJob>…</CopyJob> производилось копирование содержимого каталогов рабочего проекта. В примере каталог копирования это D:\MyBestGameBuild\pc\temp, а рабочий проект D:\Programs\CRYENGINE Launcher\Crytek\MyBestGameProject.

input это каталог с файлами, который был скопирован из рабочего проекта. В примере мы явно указываем какой каталог в какой pak запаковывать.

zip указываем, что нужно запаковать и сохранить запакованный pak-архив по указанному пути с указанным именем. В примере это D:\MyBestGameBuild\pc\MyBestGame\assets.

Исходя из условий примера, будут созданы следующие pak-архивы и каталоги:

  • Каталог languages, в который были скопированы english_xml.pak и russian_xml.pak.

  • Каталог Levels, в который были скопированы каталоги уровней и их содержимое в виде filelist.xml и level.pak.

  • Pak-архив MyBestGame.pak, в который вошли Animations, config, difficulty, entities, libs, materials, prefabs, _newpreview_.mtl, autoexec.cfg, entities.xml, hud_settings.xml, Savegames.xml, Scripts.

  • Pak-архив MyBestGame_Audio.pak, в котором находится каталог Audio.

  • Pak-архив MyBestGame_Objects.pak, в котором находится каталог Objects.

  • Pak-архив MyBestGame_Textures.pak, в котором находится каталог Textures

 

Команды запуска выполнения действий rc.exe.

 
CopyJob — выполнить копирование, описанное в элементе <CopyJob>…</CopyJob>.

PakJob — выполнить запаковку скопированных ресурсов, запаковать их в pak-архивы и сохранить по указанному пути. Это было описано в элементе <PakJob>…</PakJob>.

Код rcjob_PC.xml целиком, финальный вариант.

<RCJobs>
<DefaultProperties src="D:\Programs\CRYENGINE Launcher\Crytek\MyBestGameProject" game="assets" trg="D:\MyBestGameBuild\${p}\temp" pak_root="D:\MyBestGameBuild\${p}\MyBestGame" />

<Properties src_game="${src}\${game}" trg_game="${trg}\${game}" pak_game="${pak_root}\${game}" />

<CopyJob>
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cgf" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cga" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.mtl" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.dds" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.1" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.2" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.3" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.4" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.5" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.6" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.7" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.8" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.9" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.1a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.2a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.3a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.4a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.5a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.6a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.7a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.8a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.9a" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.adb" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.animevents" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.anm" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.bnk" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.bspace" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.caf" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cax" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cdf" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.chr" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.chrparams" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.cfg" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.comb" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.dba" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.ent" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.lua" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.skin" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.swf" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.thread_config" copyonly="1" />
    <Job sourceroot="${src_game}\languages" targetroot="${pak_game}\languages" input="*.pak" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_01" targetroot="${pak_game}\Levels\MyBestLevel_01" input="level.pak" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_02" targetroot="${pak_game}\Levels\MyBestLevel_02" input="level.pak" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_03" targetroot="${pak_game}\Levels\MyBestLevel_02" input="level.pak" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_01" targetroot="${pak_game}\Levels\MyBestLevel_01" input="filelist.xml" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_02" targetroot="${pak_game}\Levels\MyBestLevel_02" input="filelist.xml" copyonly="1" />
    <Job sourceroot="${src_game}\Levels\MyBestLevel_03" targetroot="${pak_game}\Levels\MyBestLevel_03" input="filelist.xml" copyonly="1" />
    <Job sourceroot="${src_game}" targetroot="${trg_game}" input="*.xml" copyonly="1" />
</CopyJob>

<PakJob>
    <Job sourceroot="${trg_game}" input="Animations\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="Audio\*.*" zip="${pak_game}\MyBestGame_Audio.pak" />
    <Job sourceroot="${trg_game}" input="config\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="difficulty\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="entities\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="libs\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="materials\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="prefabs\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="_newpreview_.mtl" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="autoexec.cfg" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="entities.xml" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="hud_settings.xml" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="Savegames.xml" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="Objects\*.*" zip="${pak_game}\MyBestGame_Objects.pak" />
    <Job sourceroot="${trg_game}" input="Scripts\*.*" zip="${pak_game}\MyBestGame.pak" />
    <Job sourceroot="${trg_game}" input="Textures\*.*" zip="${pak_game}\MyBestGame_Textures.pak" />
</PakJob>

<Run Job="CopyJob"/>
<Run Job="PakJob"/>

</RCJobs>

 

Запуск скрипта = запуск запаковки.

Всё готово к запаковке:

  • rcjob_PC.xml все действия и пути прописаны.
  • PC.bat — скрипт готов к запуску.

 

После запуска PC.bat и успешной отработки rc.exe по описанным командам в файле rcjob_PC.xml:

Это содержимое каталога D:\MyBestGameBuild\pc\MyBestGame

Если что-то не так (не то скопировано и упаковано, упаковка прервалась и подобное), то необходимо ознакомиться с выводом работы rc.exe в виде текстового файла pclog.log. Ответ обычно в самом конце на моменте прерывания операции.

Таким образом можно упаковать почти всю игру целиком, включая содержимое каталога Bin, кроме шейдерного кэша, который располагается в корневой директории игры в каталоге engine: <Root MyBestGame>\engine\

ShaderCache.pak, ShaderCacheStartup.pak, shaders.pak, ShadersBin.pakэто pak-архивы с шейдерным кэшем и шейдерами, которые запаковываются особым образом и про это будет в пункте про компиляцию шейдерного кэша. Для нетерпеливых:

http://docs.cryengine.com/display/CEPROG/Shader+Cache

http://noostyche.ru/blog/2017/10/21/optimization-shadercache-generation-cryengine-5/

По первому методу упаковки с помощью набора команд для rc.exe на этом всё. Напомню, что это основной и самый правильный метод для CRYENGINE 5.3 и младше. Далее будет рассмотрен альтернативный метод, который имеет право на существование, как метод решения задачи в лоб.


 

2. Запаковка вручную с использованием Save Level Resources.

Подготовка ресурсов.

Примечание: Это альтернативный и не оптимальный крайний метод, подходящий для захламлённого рабочего проекта. Вместо него лучше использовать запаковку с помощью rc.exe.

Save Level Resourcesэто инструмент редактора, который позволяет сохранить в выбранный каталог все используемые на уровне ресурсы, в том числе те, что были в pak-архивах.

Чтобы сохранить все ресурсы, которые применяются на уровнях игры, необходимо загрузить каждый уровень и на каждом выбрать Level / Save Level Resources и сохранить в один и тот же каталог. Каталог выбираем любой, но не каталог рабочего проекта, имя должно быть без спецсимволов и кириллицы, а так же желательно расположение ближе к корню диска, что избавит от проблем из-за ограничения количества символов для путей в Windows. Например:
D:\MyBestGameBuild\SavedLevelResources\

Save Level Resources может сохранить файлы с расширением .cryasset, которые нужны для редактора, а в сборке игры их быть не должно.

Save Level Resources может сохранить часть ресурсов неправильно, закинув их в сторонние подкаталоги, к примеру, сохранить отдельно каталоги с файлами уровней. Так же может быть сохранено лишнее, поэтому необходимо обязательно проверить то, что там насохранялось.

Если используется контент из GameSDK, то лучше сразу распаковать всё, что необходимо для использования в проекте, при том, чтобы было как можно меньше лишнего. Это в первую очередь очень важно для графического контента, который формирует основной «вес» конечной сборки. В то же время gamedata.pak и scripts.pak лучше не распаковывать до последнего, так как это может создать сложности при переходе на новую версию движка. В конечном итоге вытаскивание из GameSDK только нужного, а не всего подряд, очень сильно облегчит процесс сборки и уменьшит занимаемый объём в файловой системе.

Ресурсы из катологов Scripts и Libs в основном нужно докидывать вручную. Если используются ресурсы GameSDK, то необходимо скопировать всё необходимое из них по конфигам и скриптам.

Примечание: В GameSDK каталог Libs находится в gamedata.pak.

Если нет понимания о том, что может понадобиться из тех каталогов, то их можно скопировать в сборку целиком, места они всё равно занимают мало. Исключением может быть каталог Libs/UI, если используется собственное меню и прочие интерфейсы, то из SDK подобное не потребуется.

Пример того, как должно выглядеть в нормальном почищенном виде, останется докинуть каталоги levels и languages (с pak-архивами локализации):

Примечание: Исключением может быть каталог engineassets, так как по-хорошему этот каталог должен располагаться только в engine.pak и дублировать его нет особого смысла.

Важным нюансом использования ресурсов GameSDK заключается в том, что текстуры расщеплены на отдельные mipуровни, представленные отдельными файлами с расширением .dds.1, .dds.2 и так далее. В итоге для одной текстуры получается набор из нескольких файлов, например: trunk_diff.dds, trunk_diff.dds.1, trunk_diff.dds.2 и так далее.

Само расщепление это особая оптимизация, которая применяется в движке для textures streaming.

Проблема расщепления заключается в том, что Save Level Resources не сохраняет файлы с этим расширением, сохраняя только одинокий файл с расширением .dds без его mip-уровней. Это приводит к тому, что текстуры отображаются некорректно в сборке игры. В случае запаковки вручную проблема решается докидыванием недостающих файлов, кто бы мог подумать, вручную.

Докинули недостающее, почистили от файлов .cryasset и привели к подобному виду:

По подготовке ресурсов всё.

 

Непосредственная запаковка.

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

Для запаковки рекомендую использовать свободный архиватор 7-zip.

Каталог levels и его подкаталоги с файлами уровней (filelist.xml и level.pak) запаковывать в какой-то ещё pak-архив НЕ НУЖНО, так как вложенные pak-архивы не будут работать.

Каталог languages, содержащий pak-архивы локализации, тоже запаковывать в pak-архив НЕ НУЖНО по той же причине.

Если размер ресурсов превышает 2 Гб, то их нельзя упаковывать в один pak-архив, так как движок не сможет с ним работать. В этом случае придётся сделать несколько pak-архивов.

Сам процесс довольно простой:

0. Выделяем каталоги, которые нужно запаковать, и выбираем в 7z «Добавить к архиву». В данном примере выбраны config, difficulty, Entities, Libs и Materials.

1. Указываем желаемое название для архива и расширение pak. В данном случае pak-архив назван на манер того, как это было в SDK. Кириллицу, пробелы и спецсимволы использовать НЕ НУЖНО.

2. Формат архива: zip.

3. Уровень сжатия по вкусу. Если игра долго запускается, то выбрать меньшее сжатие и наоборот.

4. Метод сжатия: Deflate (другие движок не понимает).

5. Размер словаря стандартный.

6. Размер слова стандартный.

7. Число потоков под количество потоков у процессора.

8. Подтверждаем запаковку.

Результат:

В данном примере объём занимаемого контентом места на жёстком диске снизился почти в два раза.

Руководствуясь тем же принципом, запаковываем остальное, кроме каталогов levels и languages (по ранее описанным причинам), и получаем схожий результат:

В данном примере можно заметить несколько pak-архивов, связанных с Objects. Каталог Objects это основной (корневой) каталог, в котором движок ищет 3D модели. Чтобы движок мог корректно считывать содержимое pak-архива, иерархия каталогов в pak-архиве должна быть такой же, как в распакованном виде:

В примере видно, что внутри ObjectsPropsA.pak содержится каталог Objects, в котором находятся каталоги props и thecursedforest, в которых находятся прочие подкаталоги. Таким образом мы отделили в отдельный pak-архив часть каталогов из Objects, тем самым снизив объём до менее, чем 2 Гб. Таким же образом нужно отделять все каталоги, которые создают превышение лимита в 2 Гб на pak-архив.

Если все ресурсы занимают менее 2 Гб, то их можно запаковать в один pak-архив:

На этом запаковка ресурсов вторым методом заканчивается, но есть ещё пара нюансов по каталогу engine:

engine.pak содержит различные конфиги, специальные текстуры и так далее. Можно почистить от лишнего и перепаковать.

Про настройке конфигов в engine.pak можно почитать здесь: http://noostyche.ru/blog/2017/12/04/configure-configuration-file-graphics-levels-cryengine-5/

ShaderCache.pak, ShaderCacheStartup.pak, shaders.pak, ShadersBin.pakэто pak-архивы с шейдерным кэшем и шейдерами, которые запаковываются особым образом и про это будет в пункте про компиляцию шейдерного кэша. Для нетерпеливых:

http://docs.cryengine.com/display/CEPROG/Shader+Cache

http://noostyche.ru/blog/2017/10/21/optimization-shadercache-generation-cryengine-5/


3. Комбинированный метод запаковки.

Совместить способ запаковки с помощь скрипта rcjob.xml для rc.exe с ручной запаковкой с помощью Save Level Resources. Для этого достаточно будет сохранить используемые ресурсы с применением Save Level Resources, почистить от лишнего и докинуть недостающее, а потом применить rcjob.xml. Метод подойдёт для захламлённого проекта.

На этом завершаем разбор методов запаковки ресурсов игры. В третьей (заключительной) статье будет описано следующее: сборка библиотек и GameLauncher; зачистка библиотек и прочих ресурсов редактора (Sandbox.exe); генерация шейдерного кэша; шифрование запакованных ресурсов; предзагрузка ресурсов.


2 отзыва к статье “Создание сборки своей игры на базе CRYENGINE 5.3. Часть вторая. Запаковка ресурсов.”

  • 1
    Алексей Напечкин в 22.01.2024 Ответить

    5.7.1 сильно отличается?)

    Сайт который указал, прикалывал когда-т

    • 2
      Igor в 25.01.2024 Ответить

      Довольно значительно, но движок скорее мёртв, чем жив, тем более лицензия стала ещё хуже. Можно сказать, абсолютно негодная относительно других движков, не считая Unity (самые худшие лицензионные условия среди всех игровых движков). Если интересен Cryengine, рекомендую ознакомиться с O3DE: https://o3de.org/ Это бывший Lumberyard, который сделали открытым и перелицензировали под свободной лицензией.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *