Создание сборки своей игры на базе CRYENGINE 5.3. Часть вторая. Запаковка ресурсов.
Официальная документация по теме:
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 Гб:
Способы запаковки.
Их три:
-
Запаковка специальным скриптом (RC Jobs) rcjob.xml для rc.exe (компилятор ресурсов движка);
-
Вывести используемый игрой контент с помощью Save Level Resources, а потом долго и упорно запаковывать вручную, используя свободный архиватор 7-zip.
-
Комбинированный. Совместить способ запаковки с помощь скрипта 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″ — подтверждаем копирование.
В том же духе описывается копирование для прочих типов файлов:
Стоит учесть, что копирование по типу файлов (*.расширение_файла) копирует все файлы указанного типа, которые будут найдены в каталоге-источнике. Если такое не нужно, то можно указать явно из каких каталогов копировать указанный тип файлов.
Примеры:
-
В каталоге-источнике могут быть сторонние pak-архивы и xml-файлы, которые нам не нужны в сборке. К примеру, компоненты уровня geometry.pak, terraintexture.pak, TimeOfDay.xml, Objectives.xml и прочие, которые используются в редакторе и не нужны в сборке, поэтому укажем явно какие pak-архивы и xml-файлы нужно скопировать из каталогов уровней.
-
Тоже самое применимо и для файлов анимации .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); генерация шейдерного кэша; шифрование запакованных ресурсов; предзагрузка ресурсов.