Dokumentacja Steamworks
Plik z działaniami w grze

Wprowadzenie


Producenci muszą dostarczyć plik z działaniami w grze (IGA), który definiuje działania, zestawy działań oraz podstawową strukturę konfiguracji danych wejściowych ich gry. Ten artykuł opisuje ogólną strukturę tego pliku oraz przedstawia kilka konkretnych przypadków z różnych gier.

Przykładowe pliki


Ręczne tworzenie pliku z działaniami w grze

Zacznij od pobrania jednego z początkowych plików z działaniami w grze (IGA) z powyższych przykładów. Następnie w folderze Steam stwórz katalog „controller_config” – zazwyczaj ścieżką będzie C:/Pliki programów (x86)/Steam/controller_config, po czym umieść plik w tym katalogu. Folder Steam będzie już mieć katalog o podobnej nazwie, więc upewnij się, że umieścisz plik w folderze „controller_config”, a nie „controller_base”. Zmień nazwę pliku w następujący sposób: „game_actions_X.vdf”, gdzie X to ID aplikacji Steam dla twojej gry. Jeżeli nie znasz ID aplikacji Steam dla swojej gry, znajdziesz je po zalogowaniu się na swoją stronę partnerską Steamworks.

Teraz otwórz plik w swoim ulubionym edytorze tekstowym. Plik ten jest w standardowym formacie Valve o nazwie KeyValues, który jest prosty i łatwy w odczycie. Przydatne może też być pobranie jednego z naszych szablonów dla plików z działaniami w grze lub pliku z działaniami w grze Portal 2.

Generowanie pliku IGA z istniejącej gry korzystającej z API Steam Input


Jeśli zapiszesz konfigurację dla dowolnej gry na Steam jako „lokalną” konfigurację, to odpowiedni plik znajdziesz w tym folderze:
[folder instalacji Steam]\UserData\[twoja nazwa użytkownika]\241100\remote\controller_config\[ID aplikacji]\[nazwa pliku].vdf

Oto przykład, gdzie znajdują się moje lokalne konfiguracje dla Defender's Quest na typowym komputerze z systemem Windows 10:

whereisvgf.png

Zauważ, że te pliki nie są dokładnymi kopiami głównego pliku IGA przesłanego przez producenta, ale dzięki niemu rozeznasz się w oryginalnej strukturze, patrząc na bloki „actions” i „localization”, które są wzięte bezpośrednio z finalnego pliku.

Oto plik #library_controllersavedefaulttitle_0.vdf pokazany na powyższym zrzucie ekranu – porównanie go do głównego pliku IGA gry Defender's Quest może być dla ciebie przydatne.

Format IGA


Plik IGA przyjmuje postać dokumentu w formacie VDF, który jest formatem danych autorstwa Valve dla tworzenia danych o obiektach strukturalnych z parami stringów klucz/wartość.

Szkielet


Podstawową strukturą pliku jest obiekt opakowujący o nazwie „In Game Actions” i odpowiednio dwa podobiekty: „actions” i „localization”:

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

Zestawy działań

Zacznijmy od obiektu „actions”. Będzie on zawierał twoje zestawy działań. Jego struktura wygląda następująco:
"actions" { "ActionSetNameGoesHere" { "title" "#TitleGoesHere" "StickPadGyro" { } "AnalogTrigger" { } "Button" { } } }

Stringi "ActionSetNameGoesHere" i "#TitleGoesHere" są jedynymi znajdującymi się w powyższym przykładzie stringami, które powinny zostać zastąpione przez użytkownika – reszta to zarezerwowane słowa kluczowe.

Wartość zastępująca "ActionSetNameGoesHere" będzie nazwą zestawu działań, z której korzystasz w API Steam Input. Wartość zastępująca "#TitleGoesHere" będzie tokenem lokalizacji używanym w sekcji "localization" w dalszej części pliku. Pamiętaj, że znak „#” jest tutaj wymagany.

Każdy zestaw działań powinien mieć unikalny string z nazwą. Możesz dodać ich więcej, tworząc więcej obiektów w obrębie obiektu-kontenera "actions". Przecinki i nawiasy nie są potrzebne – to plik VDF, nie JSON.

Istnieją trzy możliwe podobiekty dla każdego obiektu zestawu działań. Są to "StickPadGyro", "AnalogTrigger" i "Button". Są to jedyne możliwe obiekty, jakie możesz zdefiniować i są one kontenerami, które będą przechowywać twoje indywidualne definicje działań. Nie musisz natomiast korzystać ze wszystkich trzech kategorii.

Na przykład taka struktura jest całkowicie poprawna:
"actions" { "ActionSetName1" { "title" "#Title1" "AnalogTrigger" { } "Button" { } } "ActionSetName2" { "title" "#Title2" "StickPadGyro" { } } "ActionSetName3" { "title" "#Title3" "Button" { } } }

StickPadGyro

Ten blok zestawu działań jest przeznaczony dla działań analogowych, które będą posiadać maksymalnie dwie osie ruchu – czyli takie, do których możesz chcieć przypisać drążek (joystick), panel dotykowy (trackpad) lub żyroskop (gyroscope). Ponadto powinno się tu znaleźć wszystko, czym chcesz sterować myszką lub podobnymi urządzeniami.

AnalogTrigger

Ten blok zestawu działań jest przeznaczony dla działań analogowych, które będą posiadać tylko jedną oś ruchu – czyli takie, do których możesz chcieć przypisać analogowy spust.

Button

Ten blok zestawu działań przeznaczony jest dla działań wyłącznie cyfrowych, które posiadają tylko stan włącz/wyłącz. Pomimo tego, że ten blok nazywa się „Button”, to działania cyfrowe można przypisać praktycznie do każdego elementu wejściowego – w tym takich oryginalnie zaprojektowanych do wysyłania danych analogowych (np. drążki, panele dotykowe itp.).

Działania


Plik IGA nie będzie w zasadzie nic robił, póki nie będzie posiadał zdefiniowanych działań, więc dodajmy kilka!

Działania w sekcji „StickPadGyro”

Zacznijmy od dodania kilku działań typu StickPadGyro (2-osiowych analogowych). Niech jeden odpowiada za poruszanie postacią – nazwijmy go "Move" – a drugi za sterowanie kamerą – nazwijmy go "Camera".

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

Jak widzisz, abstrakcyjna struktura dla działania typu StickPadGyro to:
"ActionNameHere" { "title" "#ActionTitleHere" "input_mode" "<tryb analogowy>" }

W tej strukturze jedynymi wartościami, jakie może edytować użytkownik, to te oznaczone jako "ActionNameHere", "#ActionTitleHere" i "<tryb analogowy>". Tyczą się one, odpowiednio, nazwy działania do użycia w API Steam Input, klucza lokalizacji do użycia w sekcji lokalizacji pliku oraz trybie źródła wejścia, który steruje przetwarzaniem i interpretacją danych analogowych.

Właściwość "input_mode" ma dwie możliwe wartości dla działania typu StickPadGyro:

  • "joystick_move"
  • "absolute_mouse"

"joystick_move" powinno być używane dla działania, którego wartości są interpretowane jako drążek (ciągłe odchylenie od punktu środkowego), a z "absolute_mouse" korzysta się w przypadku analogowego działania o bardziej ogólnym, wszechstronnym przeznaczeniu. W razie wątpliwości użyj "absolute_mouse".

Kiedy używać "joystick_move", a kiedy "absolute_mouse"?

Pamiętaj, że podczas tworzenia wejścia dla kamery dla twojej gry z perspektywą pierwszej/trzeciej osoby lub jakiejkolwiek z kursorem, zawsze powinno się wybierać typ "absolute_mouse" i reagować na delty, tak jakby to była mysz.

API automagicznie wykona wszystko poprawnie dla danych wprowadzanych za pomocą drążków, więc wciąż będziesz mieć pod ręką dane z możliwością dostrojenia, jeżeli twoja kamera zostanie zastosowana do drążka analogowego (w stylu kontrolera PS4/Xbox) z pełnymi martwymi strefami, krzywymi reakcji itp., które możesz określić w twojej domyślnej konfiguracji. W związku z tym to samo wejście będzie działać w przypadku różnych drążków, paneli dotykowych lub żyroskopów dla sterowania ruchem (Steam Controller/kontroler PS4) oraz przyszłej obsługi myszy.

Nie powinno się korzystać z metody wejścia opierającej się na "joystick_move" dla kamery, gdyż zmapowanie przeciwnego kierunku w celu uzyskania przydatnych danych 1:1 dla panelu dotykowego/żyroskopu/myszy/sterowania ruchem nie jest możliwe.

Tyczy się to również wejścia opartego na kursorze – "absolute_mouse" jako kursor będzie działał dobrze na wejściach korzystających z drążka. W związku z tym nie musisz przejmować się tworzeniem swojego własnego kursora opartego na drążku, jeżeli taki byłby potrzebny.

Możesz opcjonalnie wysłać niskopoziomowe zdarzenia myszy wraz ze swoimi danymi analogowymi. Gra nie będzie w stanie odróżnić tych zdarzeń myszy od tych generowanych przez twój system operacyjny. Aby to zrobić, należy dodać parametr "os_mouse" i przypisać mu wartość "1".

Oto przykład:
"StickPadGyro" { "Mouse" { "title" "#Action_Mouse" "input_mode" "absolute_mouse" "os_mouse" "1" } }


Działania w sekcji „AnalogTrigger”
Działania sekcji AnalogTrigger są jednowymiarowymi działaniami analogowymi, które można przypisać do spustów. Jeżeli używasz prostego progu spustu dla czegoś takiego jak strzelanie z broni lub tryb celowania przez przyrządy, to raczej będziesz chcieć skorzystać z działania sekcji Button niż AnalogTrigger, by użytkownicy mieli więcej swobody w zmianie sterowania.

Działania AnalogTrigger mają konfigurowalną martwą strefę w interfejsie przypisań i są skalowane z wartości między 0 – 1.0f. Kontrolery z cyfrowymi przyciskami spustu (np. Nintendo Switch Pro Controller) będą wysyłać wartość albo 0, albo 1.0, więc lepiej sprawdź, czy twoja gra nie posiada kodu rozgrywki polegającego na stopniowych zmianach w stanie spustu w czasie.

Działania AnalogTrigger mają prosty format, obejmuje on nazwę działania jako klucz oraz token lokalizacji jako wartość. Tak jak poniżej:
"AnalogTrigger" { "AccelerationAxis" "#Action_Accelerate" "BreakingAxis" "#Action_Brake" }

Działania w sekcji „Button”

Działania Button również mają podobny format, używając nazwy działania i tokenu lokalizacji:
"Button" { "digital_action_1_name_here" "#DigitalAction1TitleHere" "digital_action_2_name_here" "#DigitalAction2TitleHere" }

Jeżeli to konieczne, możesz zdefiniować natywne, niskopoziomowe zdarzenie sprzętowe (np. natywne kliknięcie myszą), które będzie uruchamiane wraz z działaniem. Jest to przydatne w niektórych skrajnych przypadkach, np. gdy gra opiera się na drobiazgowym schemacie sterowania składającym się z siedmiu warstw, które nigdy nie traktują symulowanych zdarzeń myszy z twojej warstwy aplikacji do końca w ten sam sposób co te wygenerowane bezpośrednio przez system operacyjny.

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

Spowoduje to, że gra wygeneruje rzeczywiste kliknięcie lewym przyciskiem myszy na poziomie systemu operacyjnego za każdym razem, gdy zdarzenie "fancy_click" zostanie uruchomione.

Ostrzeżenie!

Nie powinno się nigdy używać tej sztuczki w celu wymuszenia konkretnych, stałych przypisań wejścia dla twoich działań. Jest to całkowicie sprzeczne z założeniem „działania, nie wejścia” i odbiera użytkownikowi całkowitą kontrolę nad swoją konfiguracją. Jeśli korzystasz z tej funkcji częściej niż tylko po to, by naprawić kilka rzadkich skrajnych przypadków, to prawdopodobnie korzystasz z niej za często.

Warstwy z zestawami działań

Oprócz korzystania z zestawów działań możesz też nakładać inkrementalne zmiany do aktywnego zestawu działań dzięki warstwie z zestawem działań. Możesz użyć warstwy, by zarządzać wyszczególnionymi elementami ogólnego trybu (np. warstwa dla karabinu snajperskiego nałożona na sterowanie postacią pieszo) lub by zarządzać przypadkami, gdy elementy interfejsu wyskakują podczas normalnej rozgrywki (np. ekrany głosowania). Warstwy są deklarowane w swojej własnej sekcji, np.:
"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" } } }

Lokalizacja


Główny plik IGA powinien również zawierać sekcję lokalizacji oraz definicje zestawów działań. Poszczególne podobiekty obiektu „localization” będą jednym ze stringów języków, które Steam obsługuje. Upewnij się, że załączysz przynamniej jeden blok zawierający angielskie nazwy działań.

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

Pamiętaj, że nazwy własności powinny odpowiadać kluczom lokalizacji określonym przez ciebie w poprzednich sekcjach z wyjątkiem tych bez znaku „#”.

Aby dodać kolejne języki, po prostu dodaj więcej bloków języków ze zlokalizowanym tekstem dla każdego wpisu:

"localization" { "english" { "move" "Move" "camera" "Camera" } "spanish" { "move" "Mover" "camera" "Cámara" } "norwegian" { "move" "Bevege" "camera" "Kamera" } }
The token for each language should match the "API language code" value, ex: "schinese" for Simplified Chinese. The full list of supported languages can be found here.

Jak Steam korzysta z twojego pliku IGA


The master IGA file you create will only ever be during development (but it should still be saved, maintained, and stored in your version control, etc). When you create an official input configuration for your game during development, the steam client uses your master IGA file to generate a starting template.