Source Modding — Часть 1 — Основы основ
В мире существует множество игровых движков, но нет ни одного движка, похожего на Source своей историей и особенностями.
В этом (пилотном) уроке мы разберем простейшие действия с исходными кодами SDK, а также внесем наше первое изменение в код Half-Life 2.
Вступление
Немножко терминов
Сам по себе Source SDK — набор утилит и программ, помогающих в разработке собственных уровней и модификаций для игры, а также исходные коды Half-Life 2 и эпизодов.
Игра/Мод (Для сурса нет никакой разницы, игра это или мод : p) — скомпилированные исходные коды SDK.
Так почему же именно Source?!
- Модульность. Это может показаться минусом для некоторых, но почти все подсистемы движка вынесены в отдельные модули, каждый из которых может быть заменен без пересборки всего движка.
- Чрезвычайная гибкость. При достаточном количестве усилий вы можете сделать на Source игру абсолютно любого жанра.
- Движок и SDK разрабатывались огромным количеством людей, поэтому код SDK (а также утекший в сеть три раза код движка разных версий, но об этом позже (͡° ͜ʖ ͡°)) состоит из множества разных стилей программирования! Я почти уверен, что именно работа с Source SDK подарила мне умение (но не желание…) читать чужой код.
- Порог вхождения. Он не слишком низок и не слишком высок. Достаточно знать C++ и уметь вчитываться в документацию!
- К моменту появления идеи о написании туториала у автора попросту не было новой версии юнити.
Что нам необходимо?
- Ну прежде всего хотя бы базовые знания C++ (Достаточно знать его на уровне Си с классами).
- Любая Microsoft Visual Studio с Multibyte MFC Library и Microsoft Build Tools 2013 (v120/v120_xp). Чтобы не морочить себе голову, можно просто установить VS2013.
- Git for Windows или любой другой.
- Steam с установленным Source SDK Base 2013 [Single|Multi]player (также необходимо в свойствах «игры» установить бета-версию upstream, иначе мод будет падать)
- В будущем также знание HLSL, но не сейчас :)
Введение в сурс дела
Репозиторий
Исходный код SDK находится в репозитории на GitHub. Склонируйте его в любое удобное для вас место:
git clone https://github.com/ValveSoftware/source-sdk-2013.git
Выбор ветки
Если вы хотите написать свой первый мод для Half-Life 2/Episode ½, то используйте директорию sp/
и Source SDK Base 2013 Singleplayer.
Если же вы извращенец и хотите написать свой первый мод для Half-Life 2: Deathmatch, то используйте директорию mp/
и Source SDK Base 2013 Multiplayer.
ВАЖНО: Туториал будет рассматривать программирование под ветку SP, поэтому пути, содержащие hl2
в пересчете на MP могут содержать hl2mp
вместо hl2
!!!
Стиль кода
Клиентские (client.dll) классы именуются с префиксом C_
, а серверные (server.dll) — с префиксом C
:
// client.dll
class C_BaseWeapon { ... };
// server.dll
class CBaseWeapon { ... };
Поля класса именуются с префиксом m_, использование венгерской нотации рекомендуется (на то есть свои причины, которые здесь обсуждать нет смысла):
class C_SomeClientClass {
private:
float m_flTime = 0.0;
};
extern float g_flSomeFloat;
static float s_flSomeStaticFloat;
void SomeFunction(float flValue);
Структура кода
SDK, также как и движок, разделён на несколько частей. Вот список проектов, сгенерированных при помощи creategameprojects:
client.dll
Клиентская часть игры.
Отвечает за рендеринг, предсказания и ввод.
Расположена:src/game/client/
server.dll
Серверная часть игры.
Отвечает за игровую логику, ИИ и т.д.
Расположена:src/game/server/
tier1.lib
Библиотека, содержащая в себе множество полезных фич, например UTL («валвовская» версия STL), interface convention и т.д.
Расположена:src/tier1/
raytrace.lib
Библиотека, внезапно содержащая в себе функции и типы, предназначенные для рейтрейсинга. Честно говоря, я так и не понял, что библиотека для компиляторов делает здесь.
Используется компилятором vrad и, судя по утечкам исходных кодов, редактором уровней Valve Hammer Editor.
Расположена:src/raytrace/
mathlib.lib
Библиотека, содержащая в себе множество типов и функций, используемых в «повседневной» математике Source.
Расположена:src/mathlib/
vgui_controls.lib
Библиотека, содержащая в себе реализации разных элементов (кнопки, панели) VGUI2.
Используется почти повсеместно.
Расположена:src/vgui2/vgui_controls/
VPC
Source SDK имеет свой генератор проектов (sln, Makefile, etc.) с блэкджеком и… кхм…
Называется он Valve Project Creator и находится в src/devtools/bin
.
Проекты генерируются автоматически с использованием специальных .VPC файлов. Синтаксис этих файлов прост до безобразия — простой набор пар ключ-значение.
Вот пути до некоторых таких файлов:
src/game/client/client_episodic.vpc
src/tier1/tier1.vpc
src/utils/vrad/vrad_dll.vpc
ВАЖНО: При внесении ЛЮБЫХ изменений в VPC файл решение должно быть заново перегенерировано!
Генерация проектов
Проекты генерируются вызовом скрипта, расположенного в директории src/
.
В самом простом случае — достаточно просто открыть src/creategameprojects.bat
.
После генерации в src/
будет находиться games.sln.
Исключение HL2
SDK имеет внутри себя также разделение на HL2 и Episodic. Использование второго позволит нам иметь некоторые фичи, например отдельную от стамины шкалу заряда фонарика.
И поэтому, чтобы не компилировать лишний код, мы можем просто исключить HL2 из скриптов:
- Откройте
src/creategameprojects.bat
в любом текстовом редакторе. - Удалите из командной строки часть
/hl2
- Сохраните файл и сгенерируйте проект.
Другие скрипты
Рядом с creategameprojects.bat
также лежит его клон для bash, а также два интересных файла — createallprojects.bat
и его клон для bash.
Эти два скрипта заставляют VPC создавать проекты не только для чистых библиотек мода, но и для различных утилит, таких как vrad (Radiosity!) или height2normal.
Сейчас использовать я его вам настоятельно не рекомендую, так как свои собственные компиляторы карт нам пока не нужны.
Первичная сборка и запуск
Сборка
Чтобы удостовериться, что вы всё сделали правильно, необходимо собрать всё сгенерированное решение. Итак, собираем (вы же ведь открыли решение в IDE?):
- Переключите конфигурацию в Release.
ВАЖНО: При сборке в Debug мод крайне нестабилен!!! - Соберите ВСЁ решение (F6)
- Если сборка закончилась с ошибками, повторите шаг 2.
- Если ошибки повторяются, пересоздайте проекты (creategameprojects) и повторите все шаги начиная с 1.
После сборки в папке game/mod_hl2/bin/
или game/mod_episodic/bin/
должны появится наши клиентская и серверная библиотеки!
Запуск — Способ 1 — Steam
- Копируем нашу папку
mod_xxx
впуть/до/Steam/steamapps/sourcemods/
- Перезапускаем Steam (либо запускаем, если еще этого не сделали…)
- Ищем в библиотеке «My First Episodic Mod» или «My First HL2 Mod»
- В свойствах устанавливаем дополнительные параметры командной строки:
-dev -console
- Запускаем, в консоли запускаем карту
sdk_vehicles
(SP) илиdm_lockdown
(MP)
Запуск — Способ 2 — Visual Studio
Я рекомендую использовать именно этот способ — не копировать же бинарники мода каждый раз после сборки!
- Заходим в свойства проекта (не решения!!!) во вкладку Debugging
- В поле Command вписываем:
путь/до/steam/steamapps/common/Source SDK Base 2013 XXXX/hl2.exe
- В поле Working Directory вписываем:
путь/до/steam/steamapps/common/Source SDK Base 2013 XXXX/
- В поле Command Arguments вписываем:
-game "путь/до/репо/xx/game/mod_xxx/" -debug -dev -console
- Сохраняем, запускаем (F5)!
- Запускаем, в консоли запускаем карту
sdk_vehicles
(SP) илиdm_lockdown
(MP)
Если карта загрузилась и вы можете передвигаться и двигать камеру мышью — сборка успешна!
Первая модификация в коде
Функции семейства Msg ()
Функции Msg()
, DevMsg()
, Warning()
, DevWarning()
и ConColorMsg()
являются чем-то вроде классического printf()
, но в мире программирования под Source SDK. Эти функции так или иначе выводят какой-то текст в консоль разработчика и debug output.
// somewhere in tier0/dbg.h
void Msg( const tchar* pMsg, ... );
// somewhere in code
Msg( "This is a message! %d\n", 42 );
Говорящий пистолет!
Давайте научим пистолет писать сообщение с количеством патронов в магазине:
- Откройте
src/game/server/hl2/weapon_pistol.cpp
(Server (Episodic/HL2)/HL2 DLL/weapon_pistol.cpp
) - Найдите там метод
void CWeaponPistol::PrimaryAttack( void )
(Где-то вокруг строки 255) - Аккурат после строчки
BaseClass::PrimaryAttack();
добавьте какое-нибудь сообщение, например:BaseClass::PrimaryAttack(); // где-то на строке 251 Msg( "weapon_pistol: m_iClip1 = %d\n", m_iClip1 );
- Соберите мод, запустите и откройте карту
- Поскольку мы писали в аргументы
-dev
, чит-команды включены по умолчанию, поэтому пишите в консоль пресловутыйimpulse 101
и пробуйте стрелять из пистолета!
Заключение
Чему мы научились?
[Я надеюсь, что] из данного урока мы выяснили:
- Что вообще такое Source SDK и с чем его едят
- Как генерировать проекты используя VPC
- Как печатать что-то в консоль разработчика