моддинг игр с чего начать
Как разрабатываются моды для Unity-игр: пишем свой мод
В этой части на примере мода для Beat Saber мы рассмотрим общие принципы разработки модов для Unity-игр, узнаем, какие есть трудности, а также познакомимся с Harmony — библиотекой для модификации кода игр, которая используется в RimWorld, Battletech, Cities: Skylines и многих других играх.
Хоть эта статья и похожа на туториал, как написать свой мод для Beat Saber, ее цель — показать, какие принципы используются при создании любых пользовательских модов и какие проблемы приходится решать при разработке. Все, что здесь описано, с некоторыми оговорками применимо для всех Unity-игр как минимум в Windows.
В предыдущей серии
Информация из первой части не нужна для понимания того, что будет происходить здесь, но все равно советую с ней ознакомиться.
Вот ее краткое (очень) содержание:
Программные моды (также известные как плагины) — это dll-библиотеки, которые загружаются вместе с игрой и выполняют какой-то код, добавляя в игру новую функциональность или модифицируя существующую. Если у игры нет встроенной поддержки модов, то никакие dll-файлы она запускать не будет. Поэтому для внедрения сторонних модов используются специальные библиотеки, например BepInEx или IPA. В Beat Saber используется BSIPA — улучшенная версия IPA. Сначала ее просто адаптировали специально для Beat Saber, а сейчас она в техническом плане значительно превосходит оригинальную IPA и может использоваться для любых Unity-игр.
Про Beat Saber и мод, который мы будем делать
Beat Saber является одной из самых популярных игр для VR-шлемов. Если у вас есть такой шлем, то, скорее всего, вы уже знаете, что такое Beat Saber. Если нет, то, возможно, вы видели хотя бы одно видео из игры в рекомендациях Youtube:
Давайте напишем мод, который показывает время в игре. Он будет показывать текущее время (обычные часы), количество минут, проведенных в игре с ее запуска, и количество минут, активно проведенных в игре, т.е. только время, проведенное в основном геймплее с размахиванием мечей и без учета времени в меню и на паузе.
В этой статье будет описана полная разработка мода, начиная с создания пустого проекта. Я разбил все на 5 шагов, в конце каждого шага будет краткий вывод об особенностях разработки модов. Если не хотите углубляться в код и детали, то можно просто пробежаться по выводам. Для полного понимания желательно знать основы Unity: работа со сценами, иерархия объектов, компоненты и их жизненный цикл.
Подготовка
Для начала нам нужно сделать так, чтобы игра была пригодна для модов. Для этого в случае с Beat Saber нужно скачать ModAssistant, настроить его (ничего сложного), установить обязательные моды вроде BSIPA, SongCore и BS_Utils и установить другие моды по вкусу. Теперь игра поддерживает моды, а в папках с игрой есть все нужные для нас библиотеки, и можно приступать к разработке.
В случае с другими играми нужно либо искать, что используется у них, либо читать мою прошлую статью про моды и добавлять поддержку модов самостоятельно.
Замечание про версии
Все, что написано в данной статье, работает как минимум для Beat Saber версии 1.9.1 и BSIPA версии 4.0.5. Все развивается и меняется, поэтому если вы читаете этот текст спустя какое-то время после его публикации, то имейте в виду, что часть информации может устареть.
Шаг 0: минимальный рабочий мод
Начнем с создания проекта и минимального набора сущностей, которые нужны, чтобы можно было добавить наш мод в игру и проверить, что он работает.
Начальные шаги неплохо написаны на сайте Beat Saber Modding Group (далее просто BSMG). К сожалению, только начальные шаги там и описаны. Там предлагается несколько шаблонов Visual Studio для создания проекта на выбор — просто берете, какой нравится и создаете проект из шаблона.
manifest.json
Json-файл, содержащий мета-данные для BSIPA. Помечаем его в проекте как EmbeddedResource, чтобы при сборке он добавлялся внутрь нашего dll-файла.
$schema указывает на файл с описанием схемы для валидации формата. Файл лежит на GitHub в репозитории BSIPA. Нас это сильно волновать не должно, просто добавляем и забываем. В dependsOn указываем, какие сторонние моды мы используем в нашем собственном моде. BSIPA использует эту информацию, чтобы определить порядок загрузки dll-файлов. gameVersion и version используют семантическое версионирование.
Plugin.cs
Теперь создаем класс, который будет точкой входа для нашего плагина. В BSIPA 3 нужно было написать класс, реализующий интерфейс IBeatSaberPlugin. BSIPA 3 считывала все классы из dll-файла мода, находила там класс, реализующий интерфейс IBeatSaberPlugin, и создавала объект этого класса — так запускался мод. В BSIPA 4 убрали интерфейс IBeatSaberPlugin. Теперь BSIPA ищет класс, помеченный атрибутом [Plugin], и методы с атрибутами [Init], [OnStart] и [OnExit].
Название класса может быть любое, но обычно его просто называют Plugin. Главное, чтобы пространство имен (namespace) соответствовало названию, которое мы указали в манифесте — в данном случае это BeatSaberTimeTracker. На этом этапе мы просто будем писать в лог, если был вызван какой-то метод.
Чтобы это собралось, нужно указать компилятору, где определены атрибуты [Plugin], [Init], [OnStart] и [OnExit]. Для этого в свойствах проекта добавляем в зависимости файл IPA.Loader.dll. Будем считать, что моды у нас уже внедрены в игру, а значит, все нужные библиотеки уже лежат в папке с Beat Saber где-то в папках Steam. Библиотеки игры, Unity, системные библиотеки и файлы IPA лежат в папке Beat Saber/Beat Saber_Data/Managed. Все просто добавляют файлы прямиком из папки Steam в проект и так и выкладывают на GitHub, тут нечего стесняться. BSMG сами советуют так делать.
Собираем наш мод, копируем получившийся dll-файл в папку Beat Saber/Plugins и запускаем игру. Для простой отладки не обязательно подключать VR-шлем, можно запустить игру из терминала с флагом fpfc. Игра запустится в режиме отладки с управлением мышью. Этого достаточно, чтобы потыкать кнопки в главном меню. После этого выходим из игры, идем в папку Beat Saber/Logs и ищем там логи для нашего мода.
Поздравляю, наш мод работает.
Вывод для шага 0
У любого мода должна быть точка входа. Это что-то типа аналога main в обычных программах. Детали реализации зависят от того, как именно работают моды: где-то нужно реализовать интерфейс, где-то использовать атрибуты или аннотации, а где-то просто добавить метод с определенным именем.
Шаг 1: выводим время на экран
На этом шаге сделаем так, чтобы мод делал что-то осмысленное, но еще не трогал код самой игры — добавим часы где-нибудь в углу и покажем время, проведенное в игре с ее запуска. Последуем принципу единственной ответственности и создадим новый класс TimeTracker. Класс Plugin нужен только для запуска и инициализации мода, никакой другой логики там быть не должно.
На этом этапе класс TimeTracker будет создавать canvas в мировом пространстве, добавлять на него два текстовых поля и раз в секунду обновлять на них значения.
Создаем объекты в Awake:
Создаем объект, добавляем на него Canvas, настраиваем его, создаем два текстовых поля. Текстовые поля создаются в CreateText:
Этот метод выглядит громоздко, но, по сути, мы здесь просто создаем объект TextMeshProUGUI и выставляем параметры RectTransform, которые мы в обычном случае установили бы в редакторе Unity.
Тут мы подходим к одному серьезному ограничению при разработке модов для Unity-игр — у нас нет редактора Unity. У нас нет удобного графического интерфейса, и у нас нет сцены, на которой можно накидать все руками и сохранить в префаб — все нужно делать руками из кода. Из-за этого координаты объектов приходится подбирать экспериментально: пробуем какое-нибудь число, запускаем игру, смотрим в каком месте оказался текст. Меняем координаты, перезапускаем игру, смотрим. Повторять, пока текст не окажется там, где нужно.
Чтобы хотя бы примерно понимать, какие координаты должны быть у элементов интерфейса, я сначала вывел на экран 400 текстовых полей: сетку 20 на 20. В каждом поле я выводил его координаты. Это помогло мне начать хоть как-то ориентироваться в координатах и масштабе сцены.
В Update обновляем значения на текстовых полях:
Теперь обновляем наш класс Plugin, чтобы он создавал объект TimeTracker:
Чтобы наш объект жил долго и счастливо и не был убит сборщиком мусора, нужно либо прикрепить его к какой-нибудь существующей сцене в игре, либо вызвать DontDestroyOnLoad(…). Второй способ проще.
Чтобы все это работало, нам нужно добавить библиотеки Unity в список зависимостей проекта: UnityEngine.CoreModule.dll для GameObject и MonoBehaviour, UnityEngine.UI.dll и Unity.TextMeshPro.dll для TextMeshPro и UnityEngine.UIModule.dll для Canvas. Взять их можно все там же, в папке с игрой.
Собираем dll-файл, копируем его в папку с плагинами, запускаем игру и любуемся результатом.
Все отлично, наш мод работает и уже даже приносит пользу. Пока что он живет своей жизнью — он не влияет на игру, а игра не влияет на него. Но из-за этого у нашего мода есть серьезная проблема: он показывает время всегда, даже если оно нам мешает. Например, в самом геймплее. С этим мы разберемся далее.
Вывод из шага 1
У нас нет исходных файлов игры, а значит, ее нельзя открыть в редакторе Unity и пользоваться теми же инструментами, что и при нормальной разработке. Приходится изучать, как все устроено, выводя информацию либо в логи, либо через UI в самой игре.
Шаг 2: взаимодействуем с логикой самой игры
На этом шаге начинаем контактировать с игрой. Будем считать активное время, проведенное в геймплее, и прятать UI мода, когда он не нужен. Для этого нужно научиться определять переходы из меню в основной геймплей и определять, поставили ли игру на паузу.
Обновляем метод Update. Теперь будем использовать логическую переменную _trackActiveTime, чтобы включать и выключать отслеживание активного времени. Ну и выводим его в новое текстовое поле _activeTimeText. Создаем его так же, как и остальные, просто сдвигаем координаты чуть пониже.
Теперь добавляем метод для включения и выключения отслеживания активного времени:
Здесь мы устанавливаем _trackActiveTime и скрываем текстовые поля. Это заодно решает проблему из прошлого этапа, когда время показывалось в основном геймплее.
Теперь нам нужно каким-то образом сделать так, чтобы основная игра вызывала SetTrackingMode(true), когда мы запускаем какой-то уровень, и SetTrackingMode(false), когда мы возвращаемся в меню или ставим игру на паузу. Проще всего это сделать через события. Для начала пойдем простым путем и добавим мод, который упрощает взаимодействие с игрой, а потом уже посмотрим, как это делается руками.
Нам нужен мод BS_Utils. Добавляем в список зависимостей проекта библиотеку BS_Utils.dll из папки Beat Saber/Plugins (мы ее установили когда ставили моды через ModAssistant). Теперь добавляем BS_Utils в манифест. Это нужно для того, чтобы наш мод загружался после него.
Находим в событиях BS_Utils те, которые нам нужны, подписываемся на них и переключаем отслеживание активного времени.
Методы EnableTrackingMode и DisableTrackingMode я добавил просто для удобства, чтобы можно было их использовать как делегаты в событиях без аргументов.
Собираем проект, копируем dll в Plugins, запускаем игру, проверяем.
Если бы мы просто разрабатывали мод для Beat Saber, то на этом этапе можно было бы и остановиться. Мод готов, он делает то, что мы хотели, и так, как мы хотели. Он использует сторонний мод BS_Utils, но почти все моды используют его. BS_Utils поддерживается одним из главных разработчиков в сообществе BSMG, так что не нужно переживать, что в какой-то момент он перестанет работать. Но это познавательная статья, поэтому мы пойдем дальше. И мы еще не все разобрали, что нужно для разработки модов.
Вывод из шага 2
Если у игры большое сообщество моддеров, то, скорее всего, они уже сделали многое, чтобы облегчить работу друг другу. Например, в Beat Saber мод BS_Utils значительно упрощает работу с кодом игры, а BSML — это мод, позволяющий создавать графический интерфейс с помощью xml-конфигураций.
Шаг 3: удаляем BS_Utils, лезем в код игры
Удаляем BS_Utils из зависимостей проекта и из манифеста. Компилятор сообщает нам, что BSEvents и его события теперь не определены. Их мы и будем заменять на этом шаге.
menuSceneActive и gameSceneActive
Эти события срабатывают, когда активируется сцена с меню и сцена с основным геймплеем соответственно. Для работы со сценами у Unity есть статический класс SceneManager, у которого есть события sceneLoaded, sceneUnloaded и activeSceneChanged. Добавляем обработчики событий для них и просто выводим названия сцен в логи. Так как мы уже добавили библиотеку UnityEngine.CoreModule.dll в зависимости, проблем с определением SceneManager быть не должно.
Собираем мод, запускаем игру, заходим в основной геймплей, выходим из него, выходим из игры, смотрим логи.
Здесь так много разных сцен, потому что Beat Saber использует разные сцены для разных компонентов и загружает их в режиме Additive. Интерфейс на одной сцене, платформа с игроком — на другой. Анализируем логи и делаем вывод: отслеживать переход в основной геймплей можно, например, при активации сцены GameCore. По аналогии, переход в меню — по активации сцены MenuCore. Но с MenuCore есть проблема — судя по логам, она не активируется при запуске игры, когда мы только попадаем в меню. Поэтому для меню лучше использовать сцену MenuViewControllers. Еще одно полезное наблюдение: сцены для меню загружаются один раз при запуске игры и просто деактивируются при запуске геймплея, а вот сцены геймплея загружаются заново при запуске уровня. Это нам еще пригодится.
Обновляем OnActiveSceneChanged: проверяем имя сцены и переключаем отслеживание активного времени:
songPaused и songUnpaused
Для следующих событий придется покопаться в коде игры, поэтому переходим к настоящему реверс-инжинирингу. Теперь нам нужна библиотека, в которой содержится код Beat Saber. В папке «Beat Saber/Beat Saber_Data/Managed» лежат 2 библиотеки: Main.dll и MainAssembly.dll. Я сначала копался в MainAssembly.dll, из-за чего потратил 2 дня на отладку одного очень странного поведения. Оказалось, что по какой-то причине и Main.dll, и MainAssembly.dll содержат определения одних и тех же классов. Я использовал MainAssembly.dll, а в игре использовались классы из Main.dll. Возможно, какая-то ошибка при сборке билда у разработчиков игры.
Судя по тому, что я узнал и посмотрел в других модах, все, что нам нужно, лежит в библиотеке Main.dll. Нам нужно посмотреть ее содержимое, а для этого нужен декомпилятор. На сайте BSMG советуют использовать dnSpy. Я использую Rider в качестве среды разработки, и у него есть встроенный декомпилятор, поэтому про dnSpy ничего конкретного сказать не могу, не пользовался. Но, судя по описанию, вещь полезная — это не только декомпилятор, но еще и дебаггер, который может подключаться к Unity-процессам.
Дальше идет рутина: берем содержимое Main.dll и ищем класс, который делает то, что нам нужно. Это сложно, но по-другому никак. Разве что можно пойти в Discord-канал BSMG и спросить. Вам, скорее всего, ответят, потому что там много людей, которые уже когда-то декомпилировали Main.dll и что-то там искали (и нашли).
Рано или поздно мы найдем класс GamePause, который отвечает в игре за включение и выключение паузы. У него есть два метода: Pause и Resume. А еще у GamePause есть два события: didPauseEvent и didResumeEvent. Отлично, нам даже не пришлось делать что-то сложное, у GamePause уже есть события, на которые мы можем подписаться.
Значит, нам каким-то образом нужно получить ссылку на компонент GamePause. В Unity это можно сделать так:
Этому методу все равно, на какой сцене компонент, что за объект и активен ли он. Если компонент создан, он будет найден. Но нужно как-то найти момент времени, когда этот компонент создан. Можно предположить, что он висит на каком-то объекте на одной из сцен в геймплее. Мы уже выяснили, что геймплейные сцены каждый раз создаются заново. У нас есть обработчики событий OnSceneLoaded и OnActiveSceneChanged, поэтому мы можем отловить там сцену GameCore и в этот момент попробовать получить ссылку на GamePause. Проблема в том, что он может создаваться динамически чуть позже, чем загружаются сцены, поэтому тут есть два варианта: поискать в игре событие, которое срабатывает после того, как GamePause создан (вряд ли такое есть), либо вызывать Resources.FindObjectsOfTypeAll каждый кадр, пока не найдем компонент. Например, через корутину:
Запускаем ее в OnActiveSceneChanged для сцены GameCore:
Собираем мод, запускаем игру и убеждаемся, что все работает. Также можно заглянуть в логи. Там видно, что GamePause существует сразу же после активации GameCore, а значит, корутина не нужна и можно ее убрать. Я решил оставить для надежности.
Вывод из шага 3
Чтобы сделать мод для игры, нужно знать ее архитектуру и исходный код. Для этого приходится много времени тратить с декомпилятором, копаясь в исходном коде и пытаясь понять, как там все устроено. А копаться в чужом коде не всегда легко и приятно.
Шаг 4: вмешиваемся в логику игры с помощью Harmony
Модификации Harmony в терминах самой библиотеки называются патчами (patches). Есть несколько видов патчей:
Самые популярные патчи — это Prefix и Postfix. Transpiler слишком сложный, так как это уже не C#, а IL-код, да и зачастую проще скопировать исходный метод через декомпилятор, изменить там что-то и заменить весь метод через Prefix/Postfix. Finalizer звучит полезно, но он появился только недавно, в Harmony 2.0, поэтому примеров его использования я еще не видел.
Когда я только придумывал идею для мода, я думал, что Harmony мне понадобится сразу же, как только я решу убрать BS_Utils. Оказалось, что GamePause сам по себе содержит все нужные события, и теперь придется искусственно усложнить задачу, чтобы показать, как работает Harmony. Давайте представим, что в GamePause нет событий didPauseEvent и didResumeEvent, и нам нужно что-то с этим сделать.
Так как мы все еще придерживаемся принципа единственной ответственности, создаем класс HarmonyPatcher. У него будет всего один метод: public static void ApplyPatches() <>, в котором будет примерно такой код:
Этих двух строк достаточно, чтобы установить все патчи, который у нас есть (но их пока нет). «com.fck_r_sns.BeatSaberTimeTracker» — это имя пакета. Оно должно быть уникальным, чтобы не было коллизий с патчами из других модов. Теперь идем в класс Plugin, который у нас отвечает за старт и инициализацию мода, и добавляем туда вызов HarmonyPatcher.ApplyPatches() перед созданием TimeTracker.
Переходим к написанию самих патчей. Для каждого метода, который мы хотим модифицировать, нужно написать отдельный класс. Каждый патч — это статический метод в этом классе. Чтобы указать, что это за патч, мы можем либо использовать соответствующее имя метода (например, метод с именем Prefix — это Prefix-патч), либо использовать любые имена и помечать методы атрибутами (например, [HarmonyPrefix]). Я всегда предпочитаю, чтобы код был явным и легко читаемым, поэтому я сторонник подхода с атрибутами. Начнем с патчей для метода GamePause.Pause(). Добавим в него Postfix-патч, который просто пишет в лог, что был вызван метод Pause() и сработал Postfix-патч.
Атрибут [HarmonyPatch] указывает, какие класс и метод нам нужно модифицировать. Статический метод TestPostfixPatch помечен атрибутом [HarmonyPostfix], поэтому это Postfix-патч. Создаем аналогичный класс для GamePause.Resume() (можно в том же файле), собираем, запускаем игру, запускаем уровень, жмем паузу, снимаем паузу, выходим из игры, проверяем логи.
Проверяем, что патчи применились:
Проверяем, что Postfix-патчи сработали:
Отлично, Harmony работает, можно переходить к логике. В нашем искусственном примере мы представили, что событий didPauseEvent и didResumeEvent не существует, а значит, нам нужно в Postfix-патчах что-то сделать, чтобы TimeTracker включал и выключал отслеживание активного времени. Тут мы натыкаемся на главную проблему Harmony — все патчи являются статическими методами. А TimeTracker — это компонент, который висит где-то в иерархии объектов и статическим явно не является. Тут я вижу два нормальных решения этой задачи.
Первый — это сделать TimeTracker доступным из статического контекста. Например, сделать его синглтоном или каждый раз получать на него ссылку через Resources.FindObjectsOfTypeAll(). В BS_Utils, например, используется синглтон.
Второй — это добавить класс со статическими событиями вроде BS_Utils.Utilities.BSEvents, который мы использовали на ранних этапах. Этот вариант мне нравится больше, давайте реализовывать его.
Создаем класс EventsHelper:
Теперь обновляем наши патчи, чтобы они вызывали эти события:
GamePauseResumePatch делается аналогично. Пришлось добавить публичные методы FireOnGamePausedEvent и FireOnGameResumedEvent, так как нельзя вызывать события из-за пределов их класса. Теперь TimeTracker может в любой момент подписаться на события в EventsHelper. Получаем код со слабым зацеплением — именно из-за этого подход с событиями мне нравится больше, чем вариант с синглтоном или Resources.FindObjectsOfTypeAll().
Если мы соберем мод и запустим игру, то все будет работать. Однако, мы пока не учли одну деталь. В оригинальном коде GamePause.Pause() есть проверка от многократного перехода в режим паузы.
Postfix-патч же будет вызван в любом случае: и если мы установили паузу, и если это было повторное нажатие. А значит, и событие EventsHelper будет срабатывать всегда, даже если фактического перехода в паузу уже не было. Давайте добавим Prefix-патч, в котором будем проверять текущее состояние паузы. Harmony позволяет читать и изменять приватные переменные класса, а также передавать состояние между патчами одного метода. В Harmony вообще много чего можно получить в патче:
Начнем со структуры, которая будет хранить состояние:
Теперь добавляем Prefix-патч:
Здесь мы добавляем состояние с модификатором out, чтобы его можно было изменять, и приватную переменную ____pause ( _pause и еще три подчеркивания перед ней). Просто сохраняем ____pause в __state — тут ничего хитрого.
Теперь обновляем Postfx-патч:
Запускаем игру и проверяем, что все работает.
Вывод из шага 4
Harmony — это очень полезная и важная для сообщества моддеров библиотека, которая используется в RimWorld, Battletech, Cities: Skylines, Kerbal Space Program, Oxygen Not Included, Stardew Valley, Subnautica и многих других играх.
Заключение
Создание модов — это довольно утомительный процесс. При разработке модов нужно постоянно копаться в декомпилированном коде, искать классы, которые делают то, что вам нужно, модифицировать их, постоянно пересобирать моды, чтобы проверить изменения в игре, страдать из-за отсутствия нормального режима отладки и полноценного Unity-редактора.
А потом разработчики выпускают новую версию игры, в которой они поменяли логику, которая использовалась в моде, и нужно делать все сначала.
Игровые модификации: виды и базовый инструментарий для создания модов
А также пять сайтов, где можно отыскать лучшие моды для популярных игр.
Абрикос Абрикосовый для Skillbox Media
Это вторая часть нашего цикла об игровых модификациях. Первую часть, посвящённую их истории и влиянию на индустрию, уже можно прочитать в Skillbox Media. В этом материале мы расскажем о разновидностях пользовательского контента в играх, а также о том, что необходимо знать начинающему моддеру и куда загружать свои творения.
Классификация сквозь призму научного подхода
У всех модификаций есть своя специфика, поэтому их принято делить на несколько категорий. Мы проиллюстрируем одну из таких классификаций, взяв за основу исследование, представленное в работе «Моддеры Skyrim: мотивации и модификации» (Modders of Skyrim: Motivations and Modifications). Его авторы — шведские специалисты из Университета Сёдертёрна, Элеонора Хакман и Ульфрик Бьорквист.
Хакман и Бьорквист выделяют восемь основных направлений, связанных с игровыми модами:
Нельзя забывать, что моды нередко бывают гибридными. Чем больше в них сочетаний, тем больше шансов, что мод станет масштабным аддоном или самостоятельной игрой.
Существуют и другие классификации. Например, Уолт Скаччи — кандидат наук в области информатики и технологий в Калифорнийском университете — в своём исследовании «Моддинг как open-source-подход к расширению систем в компьютерных играх» (Modding as an Open Source Approach to Extending Computer Game Systems) разделил моды на четыре вида: настройки UI и замена объектов, переделка содержимого игры, машинимы и взлом игр с закрытым исходным кодом.
Правда, для нашего ознакомительного материала такая классификация слишком обширна, и в ней много взаимосвязанных опций (например, взломав игру, можно заменить некоторые детали). Подход Хакман и Бьорквиста проще для понимания, поэтому мы разберём именно его, при необходимости разбив направления на подкатегории с конкретными примерами. Кроме того, последний пункт этой классификации, связанный с помощью в создании модов (custom help), мы заменим на модификации для улучшения интерфейса — изменение UI в контексте нашего материала гораздо важнее.
Считает игры произведением искусства и старается донести эту идею до широких масс. В свободное время стримит, рисует и часами зависает в фоторежимах.
Персонажи
Самый распространённый вид модов. Включает манипуляции с игровыми персонажами, противниками, NPC и анимированными объектами, которые входят в окружение (животные, насекомые и так далее). Такой вариант модификаций используется в первую очередь для визуальных улучшений или для изменения общей эстетики. Ниже — конкретные примеры.
Улучшение оригинальных моделей
Если в оригинальной игре персонажи не отличаются детализацией и разнообразием, модификации могут исправить этот недостаток. В сборке Total Character Makeover для The Elder Scrolls 5: Skyrim представлены обновлённые ассеты, делающие персонажей более реалистичными. Модели персонажей разных рас наделили дополнительными полигонами и высокодетализированными текстурами. Но всё же оставили прежние черты, чтобы сохранить стиль оригинальной игры.
Согласно данным сайта Nexus Mods, модификацию Total Character Makeover скачали более 1,3 млн раз. А число просмотров страницы с модом достигло почти 6,5 млн.
Замена моделей
Игроки любят уникальные аватары. Именно поэтому существует немало модификаций и дополнений, заменяющих оригинальные модели на известных героев из других видеоигр или придающих игровым персонажам внешность реальных людей. Так, на сайтах, посвящённых модификациям для The Sims 4, встречается немало контента со знаменитостями, известными личностями и даже политиками. Ничто не мешает игрокам прожить жизнь в роли Мистера Бина или Мэрилин Монро. Аналогичные замены моделей регулярно встречаются в играх других жанров.
(NSFW) Nude mod
К этому подвиду модов можно относиться по-разному, но нельзя отрицать тот факт, что практически на каждую игру найдётся умелец, который разденет героиню (или героя) до нижнего белья, а то и вовсе догола. В основе этих модификаций лежат оригинальные текстуры как минимум лица персонажа. Остальные манипуляции, в том числе доработка модели без одежды, зависят от фантазии и навыков самого моддера. Несмотря на сомнительную ценность таких модов с точки зрения морали и игровых канонов, они остаются актуальными и пользуются спросом среди определённого круга геймеров. Например, мод, «раздевающий» женских персонажей в The Witcher 3: Wild Hunt, скачали более 90 тысяч раз.
Одним из первых Nude-модов в трёхмерных играх был патч Nude Raider, оголяющий модель Лары Крофт. Разработчики Core Design были крайне возмущены распространением такого контента, так как, по их мнению, он дискредитировал персонажа как личность. К тому же этот патч могли установить несовершеннолетние игроки. В 1999 году разработчики потребовали авторов прекратить распространение патча и даже угрожали судебными исками. Вскоре сайт с Nude Raider был закрыт, но от стремлений умельцев раздеть главную героиню это не спасло. В Сети до сих пор можно найти достаточно Nude-модов для любой игры из серии Tomb Raider.
Замена на сторонние модели
Сюда входит умышленная замена оригинальных персонажей моделями — для создания комической ситуации в игре. Чем сюрреалистичнее изменённая модель, тем больший эффект модификация произведёт. В своё время стал популярным мод для Resident Evil 2 Remake, где вместо Мистера X героев преследует Паровозик Томас — и всё это действо сопровождается музыкой из одноимённого шоу.
«Свайп» оригинальных персонажей
Вариант похож на стандартную замену модели и популярен в сообществах игр, сфокусированных на сюжете. Игроки нередко хотят отыграть роль от лица понравившегося второстепенного героя или злодея: подмены персонажей мотивируют игроков вернуться в пройденную игру, чтобы посмотреть на скриптовые сцены под другим углом. Как, например, в моде Model Swapper от camtino, созданном для Cyberpunk 2077. Иногда такой вариант модификаций используется для достижения вышеупомянутого эффекта — превращения игры в театр абсурда. Подобное регулярно практикуется в сообществе Resident Evil в целом и недавней Resident Evil: Village в частности.
Снаряжение
Согласно данным портала Nexus Mods, модификацию Immersive Armors для TES 5: Skyrim, созданную hothtrooper44, скачали почти 3,5 млн раз. Также мод «засветился» в изданиях TIME, Kotaku, PC Gamer и Gamespot.
Изменение параметров
Этот тип модов требует более углублённого знакомства с «внутренностями» игры. Сюда входит изменение баланса и свойств предметов, характеристик, рейтинга дропа, а также ограничений, связанных с уровнем, профессией или крафтом. Такие модификации можно расценить как читерство, однако при должной балансировке модификацию вполне можно сделать полезной, заметно улучшающей геймплей.
Например, модификация Better Generators для Fallout 4, созданная expired6978, изменяет свойства оригинальных генераторов внутри игры, позволяя им вырабатывать больше электричества (10 000 единиц мощности вместо 500 единиц). С обновлённой мощностью игрок сократит количество генераторов и сосредоточится на освещении и защите своего поселения, сэкономив при этом на пространстве для будущего строительства.
Перестановка предметов
В таких модификациях авторы изменяют расположение новых (или существующих) объектов на уровне, чтобы создать более реалистичную картинку. Сюда также относится улучшенная интерактивность окружения. Например, мод Placeable Statics — Move Anything для TES 5: Skyrim — Special Edition даёт игроку больше возможностей во взаимодействии с предметами — чтобы кастомизировать интерьер дома на свой вкус или, наоборот, устроить кавардак.
Графика
Комплексная работа по улучшению внешнего вида игры. Достигается за счёт преобразования уже имеющихся в игре 3D-моделей и текстур — или же путём создания новых ассетов. До того как волна официальных ремастеров и ремейков захлестнула рынок видеоигр, были популярны модификации, в которых оригинальный игровой контент переделывали сами игроки. В последние годы для этих целей моддеры всё чаще прибегают к использованию нейросетей и машинному обучению: новые технологии успешно справляются с апскейлом текстур и задников, поэтому время на разработку сокращается.
Так, группа энтузиастов из четырёх человек сделала коллекцию любительских ремастеров трёх первых частей Resident Evil. Благодаря Resident Evil Seamless HD Project игры запускаются на PC с помощью эмулятора Dolphin: классические хорроры могут похвастаться новыми фонами с высокой детализацией, улучшенными текстурами моделей персонажей и даже обновлёнными FMV-роликами.
Для апскейла текстур из старых игр также используются нейросети Gigapixel AI (Red Faction, Sonic Adventure 2, Half-Life, Final Fantasy VII), ESRGAN (TES 3:Morrowind, Max Payne, Turok 2), NVIDIA NGX Technology (DOOM) и другие.
Локации
Пользовательские карты с грамотной расстановкой объектов и продуманными миссиями всегда ценились сообществом. Такой контент удерживает интерес игроков и даёт самим моддерам возможность получить новый опыт в разработке, а некоторые модификации могут даже похвастаться уникальной атмосферой и погрузить игрока в новый мир.
Иммерсивность
Комплексные модификации, нацеленные на повышение иммерсивности. Помимо всех вариаций, описанных выше, в эту категорию попадают изменения или дополнения, связанные с нарративом: сюжетные линии, уникальные персонажи, новое развитие лора и квесты. Такие моды нередко эволюционируют в самостоятельные игры, которые при должной поддержке даже превосходят оригинал.
В сообществе поклонников S.T.A.L.K.E.R. модификация S.T.A.L.K.E.R. Anomaly считается одним из лучших любительских дополнений. Помимо исправления багов и улучшения визуала, мод добавляет несколько режимов: сюжетный (с дополнительными кампаниями), «песочницу» и «войну фракций». Он также вводит в игру множество NPC, улучшает интерфейс и искусственный интеллект противников, изменяет внешний вид представителей некоторых фракций и выдаёт главному герою трёхмерный КПК. После версии 1.5.1 мод больше не зависит от оригинальных файлов игры и запускается самостоятельно.
Кастомизация интерфейса
Пользовательские модификации интерфейса значительно улучшают игровой опыт. Одни могут быть «косметическими», добавляющими в игру стильные фреймы, иконки или панели. Другие способны сделать весь UI гораздо удобнее, изменив HUD и сделав его более функциональным.
Ещё один вариант UI-модов технически может быть связан с браузером и непосредственно с клиентом игры, если речь идёт об MMO-проектах. Данные, полученные с сервера, улучшают геймплей, но при этом не дают какого-либо преимущества по отношению к другим игрокам. Самый яркий пример таких пользовательских модификаций — аддоны для World of Warcraft. Для этой MMORPG существует почти девять тысяч аддонов с разными задачами — от реализации встроенной навигации по квестам и добавления улучшенной карты до отображения подсказок по тактикам в данжах.
Однако у таких модификаций есть и обратная сторона. Хотя они никоим образом не влияют на игровой процесс в целом, в некоторых играх обладатель таких аддонов получает значительное преимущество в PvP.
Несколько лет назад с такой проблемой столкнулось сообщество World of Tanks. Игра не запрещала устанавливать различные аддоны, и вскоре появились модификации, легальность которых с этической точки зрения была под большим вопросом: анализ брони в бою, отображение цели противника для удачного уклонения, прозрачность объектов на карте и тому подобное. Из-за многочисленных жалоб в 2017 году Wargaming официально запретила подобные аддоны. При этом разработчики World of Tanks не против модов в целом: на сайте игры есть раздел одобренных компанией модификаций.
Лучшие друзья моддера, или с чего начать
В предыдущем материале цикла мы уже упоминали, что технические сложности в процессе создания модов часто отпугивают тех, кто хочет сделать что-то своё. Но если желание улучшить игру достаточно сильно, стоит ознакомиться с базовыми навыками, которые нужны начинающему моддеру.
Профессиональные навыки
Понимание принципов Software Development Kit (SDK)
Требования к техническим навыкам зависят в первую очередь от того, какой вид модификации задумал пользователь. В любом случае потребуется знание SDK того движка, на котором написана игра. Речь идёт обо всём необходимом инструментарии для манипуляций с исходным кодом: это и скрипты, и утилиты импорта-экспорта моделей и текстур, и редактор уровней. Но такую творческую свободу игрокам готов предоставить не каждый разработчик. Если Source SDK от Valve с подробнейшей документацией доступен для скачивания всем желающим, то к играм, сделанным, например, на Decima Engine, уже не подступиться без помощи хакеров и написания собственных программ.
Желание знакомиться с дополнительными программами для базового моддинга
К такому виду софта относятся звуковые и графические редакторы, с помощью которых пользователь создаёт контент для «косметических» изменений.
Не исключено, что для создания мода понадобится и звуковой редактор. Их существует довольно много (Sound Forge, Adobe Audition, Audacity). Здесь всё зависит от личных навыков, бюджета и наличия плагинов для экспорта.
Знание кода
Если пользователь захочет копнуть глубже и сделать масштабный мод, то без навыков программирования ему не обойтись, так как предстоит работа с внутриигровыми скриптами. Некоторые игры используют несколько языков программирования, но большинство работает на С++.
При этом для моддинга необходимо в первую очередь знание общих концепций кода, а не знание синтаксиса конкретного языка. Код связывает воедино все аспекты игры: уровни и модели, анимацию, искусственный интеллект и так далее. Чтобы не нарушить эту связь при создании масштабного дополнения, моддеру следует понимать все аспекты создания игры.
Личные навыки
Знания базовых программ и технических навыков недостаточно для создания качественного пользовательского контента. Софт-скиллы играют не последнюю роль. И начинающий моддер не должен о них забывать.
Усидчивость. Перед тем как начать что-то создавать, необходимо изучить информацию о функциональности необходимого SDK или сторонних программ, которые используются для создания контента в той или иной игре. Чем хуже игра поддерживает модификации, тем больше придётся гуглить информацию и находить нужных людей для консультаций. Всё это может занять немало времени.
Коммуникация. В создании масштабных модификаций нередко задействованы большие команды, и за каждым разработчиком в ней закреплена отдельная задача, как и в игровых студиях. В сообществе всегда можно найти единомышленников-энтузиастов, которые согласятся сотрудничать. Это ускорит срок создания модификации и поможет восполнить пробелы в тех областях, которые сложно освоить пользователю.
Этика. У многих студий есть документы, в которых чётко прописаны правила создания модификаций. Помимо того, что создавать контент с расистским, ксенофобским, сексистским, клеветническим и оскорбительным содержанием просто запрещено, могут также возникнуть проблемы с нарушением авторских прав. Например, сотрудники CD Projekt Red убедительно просят не создавать контент с нарушением прав третьих сторон (авторов книг, комиксов и так далее), реальных людей и брендов. Для разработки такого контента нужно просить разрешение у всех затронутых лиц, в том числе и самих разработчиков.
И, наконец, любовь к игре. Пожалуй, главный фактор, который движет сообществом при создании модов.
Полезные ресурсы
Где же можно опубликовать свою модификацию? Как поделиться модом с другими игроками? Ниже — подборка самых популярных ресурсов, где фанаты обычно ищут пользовательские моды для любимых игр.
Steam Workshop
Мастерская пользовательского контента, встроенная в клиент Steam. Загрузка модов доступна игроку сразу, без дополнительных манипуляций с установками. Для моддеров существует две опции загрузки контента: открытая и модерируемая. Если в открытой мастерской можно загрузить любой вид модификации, то в модерируемой создаются платные моды, при этом качество контента тщательно отслеживается, а цену устанавливает сам разработчик. При всём удобстве в Steam Workshop есть один минус — модификации есть только для тех игр, разработчики которых сами завели страницу в «Мастерской».
Nexus Mods
Один из ведущих сайтов с модами. Варианты премиум-подписок (месяц/полгода/год/пожизненно) не только отключают рекламные блоки, но и ускоряют загрузку и улучшают поиск. Ресурс уникален тем, что можно найти модификации даже к играм, которые по умолчанию их не поддерживают.
По данным сайта, на портале зарегистрировано более 27 млн пользователей и представлено более 310 тысяч файлов для 1323 игр. Общее количество скачиваний за всё время существования достигло более 4,7 млрд.
CurseForge
Крупнейший ресурс модификаций для World of Warcraft, в прошлом известный в игровом сообществе как Curse. В 2016 году сервис выкупила Twitch, а с середины 2020 года права на портал принадлежат компании Overwolf — разработчику сервиса дополнительных приложений для мультиплеерных игр (League of Legends, Hearthstone, CS:GO, Fortnite, PUBG) Все аддоны, загружаемые на CurseForge, проходят строгую модерацию, при этом авторы модификаций зарабатывают на своих творениях путём набора очков, которые можно обменивать на реальные деньги. На сегодняшний день CurseForge поддерживает 13 игр, среди них Minecraft, WoW, TES: Online и Rift.
Mod DB
Один из самых старых порталов, посвящённых модам, основанный ещё в 2002 году. Примечателен тем, что помимо загруженного пользователями контента на сайте собрано немало материалов, посвящённых моддингу и нюансам разработки модификаций. Главная цель портала — объединить разработчиков, игроков, а также их идеи, предоставив им возможность вместе улучшать игры с помощью модов.
Согласно текущей статистике, на Mod DB загружено более 24 тысяч модификаций, которые просмотрели почти 1,5 млрд пользователей.
Mod.io
Австралийский портал для моддинга, созданный в 2018 году основателями Mod DB. Сервис привлекает как авторов пользовательского контента, так и самих разработчиков. Моддерам доступны API и SDK игр, которые есть на сайте, в том числе специальные плагины для игр на Unity, Unreal Engine, GameMaker Studio, Lumberyard и прочих движков. Главное отличие от Steam Workshop в том, что Mod.io — кроссплатформенный сервис, поэтому разработчики могут с его помощью анализировать метрики и статистику по запросам пользовательского контента.
В следующей части мы подробно рассмотрим ещё одну разновидность модификаций, которая не вписывается ни в одну из категорий модов и требует максимальных творческих навыков. Имя ей — машинима.