Документация Steamworks
Файл с внутриигровыми действиями

Введение


Разработчики должны предоставить файл с внутриигровыми действиями (IGA), где определены сами действия, наборы действий и базовая структура настройки ввода для игры. В этой статье описана общая структура этого файла и приведены несколько конкретных примеров из разных игр.

Файлы с примерами


Создание файла с внутриигровыми действиями вручную

Сначала скачайте один из файлов с внутриигровыми действиями по ссылкам выше. Затем создайте папку "controller_config" внутри папки Steam (обычно C:/Program Files (x86)/Steam/controller_config) и поместите файл в эту папку. В папке Steam уже есть папка с похожим названием, поэтому проверьте, что вы поместили его именно в папку controller_config, а не в controller_base. Переименуйте файл следующим образом: game_actions_X.vdf, где X — это AppID вашей игры. Если вы не знаете AppID игры, его можно посмотреть, войдя в свой аккаунт на партнёрском сайте.

Теперь откройте файл в вашем текстовом редакторе. Он использует простой, стандартный для Valve формат, который легко читаем и называется KeyValues. Возможно, вам также будет полезно ознакомиться с одним из наших образцов файлов с внутриигровыми действиями или с файлом с внутриигровыми действиями игры Portal 2.

Создание файла с внутриигровыми действиями для игры, которая использует API ввода Steam


Если у вас есть настройки для любой игры в Steam, сохранённые локально, вы можете найти соответствующие файлы здесь:
[Папка установки Steam]\UserData\[имя пользователя]\241100\remote\controller_config\[AppID]\[имя файла].vdf

Вот пример папки на обычном компьютере с Windows 10, где сохранены локальные настройки автора статьи для Defender's Quest:

whereisvgf.png

Обратите внимание, что эти файлы не являются точными копиями файла с внутриигровыми действиями, загруженного разработчиком, но они дают представление о том, как выглядит исходная структура блоков "actions" и "localization", которые взяты из такого файла.

По ссылке вы можете скачать файл #library_controllersavedefaulttitle_0.vdf, показанный на скриншоте вверху, и сравнить его с файлом с внутриигровыми действиями для Defender's Quest.

Формат файла IGA


У файла с внутриигровыми действиями расширение .vdf. Это собственный формат файла с данными компании Valve, используемый для создания данных о структурированных объектах, записанных в виде строковых пар ключ-значение.

Заготовка


Базовая структура файла — объект-обёртка с названием "In Game Actions" и двумя подобъектами: "actions" и "localization" соответственно.

"In Game Actions" { "actions" { } "localization" { } }

Наборы действий

Начнём с объекта "actions". Он содержит наборы действий. Структура объекта "actions" выглядит следующим образом:
"actions" { "НаборДействий" { "title" "#НазваниеНабора; "StickPadGyro" { } "AnalogTrigger" { } "Button" { } } }

Строки НаборДействий и #НазваниеНабора в примере выше — единственные строки, которые должен заменить пользователь. Остальные являются зарезервированными ключами.

Значением, которым вы заменяете НаборДействий, должно быть название набора действий, который вы используете в API ввода Steam. Значением, которым вы заменяете #НазваниеНабора, должен быть ключ локализации, который используется позже в разделе "localization". Обратите внимание, что знак # здесь обязателен.

Каждый набор действий должен иметь уникальное строковое название, и для создания дополнительных наборов просто добавьте новые объекты в контейнер "actions". Запятые и квадратные скобки не нужны — это VDF, а не JSON.

Для каждого набора действий есть три допустимых подобъекта. Это "StickPadGyro", "AnalogTrigger" и "Button". Вы можете определить только эти подобъекты, они являются контейнерами для определений отдельных действий. Впрочем, задавать все три категории необязательно.

К примеру, такая структура абсолютно допустима:
"actions" { "НаборДействий1" { "title" "#НазваниеНабора1" "AnalogTrigger" { } "Button" { } } "НаборДействий2" { "title" "#НазваниеНабора2" "StickPadGyro" { } } "НаборДействий3" { "title" "#НазваниеНабора3" "Button" { } } }

StickPadGyro

Этот блок набора действий предназначен для аналоговых действий, у которых есть до двух осей движения, и которые можно привязать к джойстику, трекпаду или гироскопу (joystick, trackpad, gyroscope). Кроме того, это относится к действиям, которые контролируются мышью или подобными устройствами.

AnalogTrigger

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

Button

Этот блок набора действий предназначен для цифровых действий, которые передают состояния «вкл.» / «выкл.». Несмотря на то, что этот блок называется "button", цифровые действия могут быть привязаны к любым элементам устройства ввода, включая те, которые изначально спроектированы для вывода аналоговых данных (такие как джойстики, трекпады и пр.).

Действия


Файл с внутриигровыми действиями будет бесполезен до тех пор, пока в него не будут добавлены действия, так что давайте их добавим!

Действия "StickPadGyro"

Начнём с добавления двухосных аналоговых действий в раздел StickPadGyro. Как насчёт набора для движения персонажа? Назовём это "Move". А также понадобится набор для управления камерой: назовём это "Camera".

"actions" { "FPSControls" { "title" "#Set_FPSControls" "StickPadGyro" { "Move" { "title" "#Action_Move" "input_mode" "joystick_move" } "Camera" { "title" "#Action_Camera" "input_mode" "absolute_mouse" } } } }

Как видите, абстрактная структура для действий StickPadGyro такова:
"Действие" { "title" "#НазваниеДействия" "input_mode" "<аналоговый_режим>" }

В этой структуре единственные значения, которые вводит пользователь, — это "Действие", "#НазваниеДействия" и "<аналоговый_режим>". Они соответствуют используемому в API ввода Steam строковому названию действия, ключу локализации, используемому в разделе локализации этого файла, и режиму источника ввода, который управляет тем, как обрабатываются и интерпретируются аналоговые данные.

Свойство "input_mode" может иметь два возможных значения для действий типа StickPadGyro:

  • "joystick_move"
  • "absolute_mouse"

"joystick_move" используется для действий, значения которых интерпретируются как джойстик (постоянное отклонение от центральной точки), а "absolute_mouse" — для более гибких аналоговых действий общего назначения. Если сомневаетесь, используйте "absolute_mouse".

"joystick_move" или "absolute_mouse"

Мы не можем не обратить ваше внимание на то, что при создании ввода с камеры для игры от первого или третьего лица или чего-либо, основанного на курсоре, необходимо всегда использовать "absolute_mouse" и реагировать на дельты, как если бы это была мышь.

API автоматически сделает всё правильно для ввода со стика, так что вы получите настраиваемый ввод со стика, если игровая камера применена к аналоговому стику (в стиле PS4/Xbox) с полной поддержкой мёртвых зон, кривыми чувствительности и т. д., которые можно задать в вашей официальной раскладке. Тот же ввод будет затем работать с джойстиками, трекпадами, гироскопами для движения (Steam Controller/PS4), равно как и будущая поддержка мыши.

Для камеры нельзя использовать основанный на "joystick_move" ввод, поскольку задание противоположного направления для получения данных в масштабе 1 к 1 для управления с трекпада/гироскопа/мыши невозможно.

Это также справедливо и для ввода, основанного на курсоре: "absolute_mouse" как средство управления курсором будет прекрасно работать для ввода со стика, так что вам не нужно беспокоиться о создании управления курсором со стика, если вам он потребуется.

По своему усмотрению вы можете отправлять низкоуровневые события с мыши вместе с аналоговыми данными. Игра не сможет отличать эти события с мыши от тех, которые отправляются операционной системой. Чтобы сделать это, добавьте "os_mouse" и установите значение «1».

Пример:
"StickPadGyro" { "Mouse" { "title" "#Action_Mouse" "input_mode" "absolute_mouse" "os_mouse" "1" } }


Действия "AnalogTrigger"
Действия "AnalogTrigger" — это одноосные аналоговые действия, которые могут быть привязаны к триггерам. Если вы используете простую точку срабатывания триггера, например, для выстрела из оружия или перехода в режим прицеливания, то можете применить действие Button вместо AnalogTrigger, так как это даст пользователям больше возможностей для изменения элементов управления.

У действий AnalogTrigger есть мёртвая зона, которую можно настроить при изменении раскладки, а их масштабирование осуществляется в диапазоне 0 – 1.0f между этими значениями. Контроллеры с цифровым триггером, например Nintendo Switch Pro, посылают либо 0, либо 1.0, поэтому вам может понадобиться дополнительно проверить, что в геймплее нет кода, который зависел бы от постепенных изменений значений триггера.

Действия "AnalogTrigger" имеют простой формат, в котором в качестве ключа указывается название действия, а в качестве значения — строка локализации. Например:
"AnalogTrigger" { "AccelerationAxis" "#Action_Accelerate" "BreakingAxis" "#Action_Brake" }

Действия "Button"

Действия "Button" имеют похожий формат, в котором используются названия действий и строки локализации:
"Button" { "digital_action_1_name_here" "#DigitalAction1TitleHere" "digital_action_2_name_here" "#DigitalAction2TitleHere" }

При необходимости вы можете определить низкоуровневое событие ввода с физического устройства (например щелчок мыши), которое срабатывает одновременно с действием. Это может пригодиться в некоторых случаях, в частности, когда игра полагается на очень разборчивый ввод, запрятанный под семью уровнями, который никогда не обрабатывает эмулированные события мыши, получаемые от приложения, так же как и те, что отправляются операционной системой.

"Button" { "simple_click" "#simple_click" "fancy_click" "#fancy_click, mouse_button LEFT" }

Такое описание позволяет игре сгенерировать настоящее событие, соответствующее щелчку левой кнопкой мыши на уровне операционной системы, каждый раз, когда срабатывает действие "fancy_click".

Внимание!

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

Слои наборов действий

Вы можете применять постепенные изменения к активному набору действий с помощью наложения слоя наборов действий. Это может быть полезным для случаев, когда требуется использовать слой Sniper поверх параметров OnFoot или когда элементы внутриигрового интерфейса появляются поверх обычного геймплея (например окно для голосования). Слои определяются в отдельном разделе, например:
"action_layers" { "IngameModalLayer" { "title" "#Layer_IngameModal" "legacy_set" "0" "set_layer" "1" "parent_set_name" "InGame" "AnalogTrigger" { } "Button" { "Modal_Accept" "#Action_Modal_Accept" "Modal_Decline" "#Action_Modal_Decline" } } }

Локализация


Помимо определений наборов действий в основном файле с внутриигровыми действиями (IGA) должен быть раздел локализации. Отдельные подобъекты объекта "localization" — это языковые варианты, поддерживаемые в Steam. Необходимо включить по меньшей мере один блок: с названиями действий на английском языке ("english").

"localization" { "english" { "move" "Move" "camera" "Camera" } }

Обратите внимание, что названия свойств должны совпадать с ранее заданными ключами локализации, исключая знак "#".

Чтобы добавить дополнительные языки, добавьте соответствующие им блоки:

"localization" { "english" { "move" "Move" "camera" "Camera" } "spanish" { "move" "Mover" "camera" "Cámara" } "russian" { "move" "Движение" "camera" "Камера" } }
Токен каждого языка должен соответствовать значению «языкового кода API», например, для упрощённого китайского языка — schinese. Полный список поддерживаемых языков можно найти здесь.

Как Steam использует файл IGA


Основной файл игровых действий потребуется только во время разработки (но всё равно нужно поддерживать его актуальность, хранить его в системе контроля версий и так далее). Когда вы создаёте официальную раскладку во время разработки, клиент Steam использует ваш файл для генерации начального шаблона.