Steamworks-dokumentaatio
Steam-syötteen peliohjainemulaatio: parhaat käytännöt
Steam-syöte mahdollistaa minkä tahansa peliohjaimen käytön peleissä, joissa on ohjaintuki. Steam-syöte kääntää käyttäjän syötteen pelin tunnistamiksi toiminnoiksi käyttämällä peliohjainemulaatiota, hiiri- ja näppäimistöemulaatiota tai Steam-syötteen ohjelmointirajapintaa. Tässä tapauksessa pureudumme siihen, miten Steam-syötteen peliohjainemulaatiota voidaan hyödyntää parhaiten laajentamaan pelin olemassa olevaa ohjaintukea.

Mitä on peliohjainemulaatio?
  • Windows-käyttöjärjestelmällä Steamin yhteisönäkymä käyttää perinteisiä peliohjainsyötteen ohjelmointirajapintoja kuten XInput, DirectInput, RawInput ja Windows.Gaming.Input, joihin lisätään emuloitu Xbox-ohjain. MacOS- ja Linux-järjestelmillä ajuri tarjoaa emuloidun ohjainsyötteen.
  • Ohjain näkyy pelissä Xbox-ohjaimena. Jos ohjaimessa on useampia painikkeita, ylimääräiset painikkeet määritetään olemassa olevien syötteiden kopioiksi. Esimerkiksi PlayStation-ohjaimella kosketuslevyn painallus ja Options-painike tulkitaan molemmat XInputin Start-painikkeeksi.
  • Normaalin ohjainsyötteen lisäksi Switch-, PlayStation- ja Steam-ohjaimen gyrosyötteen pystyy määrittämään hiiriemulaatioksi ja liikeohjaukseksi. Tämä toimii vain paikallisissa yksinpeleissä, koska hiirisyötteitä on vain yksi ja emulointi vaatii, että peli hyväksyy samanaikaisen hiiri- ja ohjainsyötteen. Jos haluat ohittaa nämä rajoitukset, harkitse Steam-syötteen ohjelmointirajapinnan lisäämistä.
  • Kyselyllä voit ottaa selvää, minkälainen ohjain on kyseessä, jotta pelissä näkyvät ohjainkuvakkeet ovat asianmukaisia. Tämä pätee kuitenkin ainoastaan Steamworks SDK:n tukemiin ohjaintyyppeihin. Jos haluat ohjainkuvakkeiden tuen jatkuvan tulevaisuudessa, käytä Steam-syötteen ohjelmointirajapintaa.
  • Jotkut käyttäjät saattavat käyttää Steam-syötettä jopa pelin tukemilla ohjaimilla, koska Steam Remote Play käyttää sitä syötteen tarjoamiseen suoratoiston aikana. Lisäksi suuri osa käyttäjistä on ottanut Steam-syötteen käyttöön pystyäkseen määrittämään ohjaimensa kaikille Steam-peleille. Vuonna 2020 noin neljäsosa ohjaimella pelaavista käyttäjistä käyttivät Steam-syötettä. Heistä melkein puolet pelasivat PlayStation-ohjaimella.

Yli 2 000 Steam-peliä käyttää peliohjainemulaatiota ainakin yhdelle ohjaintyypille. Näihin kuuluu tunnettuja pelejä kuten Monster Hunter: World, Ace Combat 7, Dragon Quest XI, Into the Breach ja Middle Earth: Shadow of War, vaikka niistä kaikki eivät noudatakaan Steamin suosittelemia parhaita käytäntöjä. Into the Breach on hyvä esimerkki pelistä, joka noudattaa parhaita käytäntöjä esimerkillisesti.

Laitteiden asiaankuuluvat kuvakkeet

Steam-syötteen peliohjainemulaatiolla on muutama tapa tunnistaa käytössä oleva ohjain ja käyttää sille kuuluvia painikekuvakkeita. Yksi tapa on peleille, jotka pystyvät ajonaikaisesti lataamaan tulevaisuusvarmoja kuvakkeita (mikä tarkoittaa, että Steamin päivittämät Steam-syötteen kuvat voidaan noutaa päivittämättä itse peliä). Kaksi muuta tapaa ovat peleille, joissa kuvat ovat osa peliin koodattuja visuaalisia elementtejä tai peleille joissa käytetään konsoliversioiden tyyliteltyjä kuvakkeita. Into the Breach -pelissä käytetään pelistudion omaa kuvitusta Xbox- ja Steam-ohjaimia varten:

intothebreach_xbox.PNG

PlayStation:

intothebreach_ps4.PNG

ja Nintendo Switch -ohjaimia varten:

intothebreach_switchpro.PNG
Huomaa: Vaikka käyttäisit omaa kuvitustasi, suosittelemme turvautumaan Steamin tarjoamiin kuvakkeisiin, jos et tunnista ohjaintyyppiä. Voit myös käyttää apufunktiota, jolla noudetaan lähin mahdollinen vaihtoehto, joka oli saatavilla pelin julkaisun aikana. Näin uusille yhdistetyille laitteille tarjotaan järkeenkäyvät kuvakkeet.

Steamin tulevaisuusvarmat kuvakkeet

Käytä hyväksesi seuraavia funktioita:

Esimerkki koodista:

// Alusta käyttöliittymä, ennen kuin alat käyttämään yksittäisiä funktioita – tämä kutsu on tehtävä vain kerran! SteamInput()->Init() // ... // SteamAPI_RunCallbacks() kutsuu RunFrame-funktiot kaikille alustetuille käyttöliittymille, ja useimmat // pelit lähettävät tämän kutsun säännöllisesti. Jos et tee niin, sinun on päivitettävä manuaalisesti // Steam-syötteen käyttöliittymä SteamInput()->RunFrame(); // ... // Korvaa XInput-paikalla, jolle kysely lähetetään. Tämä numero on nollan ja kolmen välillä // Jos käytössä on RawInput laitteen tunnistamiseksi, ennen kuin päätät, mitä ohjelmointirajapintaa käytät, tarkasta // osio "Using RawInput For Device Detection". int nXinputSlot = 0; // Korvaa painikkeella, jota kysely koskee EXboxOrigin eXboxButtonToGetGlyphFor = k_EXboxOrigin_A; EInputActionOrigin buttonOrigin = k_EInputActionOrigin_XBoxOne_A; // Jos ohjain on määritetty Steam-syötteellä – käännä tämä painike InputHandle_t controller1Handle = SteamInput()->GetControllerForGamepadIndex( nXinputSlot ); if ( controller1Handle > 0 ) { // Kelpaavien kahvojen arvon tulee olla muu kuin nolla. Tämä ohjain on määritetty Steam-syötteellä // Huomaa: Ohjaimet, jotka käyttävät Steam-syötteen ohjelmointirajapintaa, eivät palauta kahvaa funktiossa GetControllerForGamepadIndex() buttonOrigin = SteamInput()->GetActionOriginFromXboxOrigin( controller1Handle, k_EXboxOrigin_A ); } else { // Kelpaavien kahvojen arvon tulee olla muu kuin nolla. Tämä on normaali Xbox-ohjain // Jatka alkuperäisen painikkeen käyttöä } // EInputActionOrigin -arvot nousevat, kun Steamin tarjoama tuki laajenee, mutta se ei haittaa, sillä // tässä esimerkissä noudamme laitteen kuvakkeet Steamistä, mikä tarjoaa myös uuden kuvakkeen // Nouda kuvake Steam-asiakasohjelmalta const char *localGlyphPath = SteamInput()->GetGlyphForActionOrigin( buttonOrigin ); printf( "path = %s\n", localGlyphPath ); // "path = C:\Program Files (x86)\Steam\tenfoot\resource\images\library\controller\api\ps4_button_x.png" // Korvaa tämä pelin funktiolla, joka muuttaa tiedostopolun käyttökelpoiseksi pelitekstuuriksi glyphTextureID = loadButtonGlyphTextureFromLocalPath( localGlyphPath );

Oman kuvituksen käyttö: kuvakkeiden paletti

Jos käytät useita kuvakepaletteja, jotka valitaan ohjaintyypin perusteella, voit kysyä Steamiltä tätä tietoa XInput-paikasta käyttämällä seuraavaa:

Esimerkki koodista:
// Alusta käyttöliittymä, ennen kuin alat käyttämään yksittäisiä funktioita – tämä kutsu on tehtävä vain kerran! SteamInput()->Init() // ... // SteamAPI_RunCallbacks() kutsuu RunFrame-funktiot kaikille alustetuille käyttöliittymille, ja useimmat // pelit lähettävät tämän kutsun säännöllisesti. Jos et tee niin, sinun on päivitettävä manuaalisesti // Steam-syötteen käyttöliittymä SteamInput()->RunFrame(); // ... // Korvaa XInput-paikalla, jolle kysely lähetetään. Tämä numero on nollan ja kolmen välillä // Jos käytössä on RawInput laitteen tunnistamiseksi, ennen kuin päätät, mitä ohjelmointirajapintaa käytät, tarkasta // osio "Using RawInput For Device Detection". int nXinputSlotIndex = 0; InputHandle_t inputHandle = SteamInput()->GetControllerForGamepadIndex( nXinputSlotIndex ); if ( inputHandle == 0 ) { // Kelpaavien kahvojen arvon tulee olla muu kuin nolla. Tämä on normaali Xbox-ohjain. } else { // Steam palauttaa aina luetteloarvon, joka toimi SDK-versiossasi. ESteamInputType inputType = SteamInput()->GetInputTypeForHandle( inputHandle ); switch( inputType ) { case k_ESteamInputType_Unknown: printf( "unknown!\n" ); break; case k_ESteamInputType_SteamController: printf( "Steam controller!\n" ); break; case k_ESteamInputType_XBox360Controller: printf( "XBox 360 controller!\n" ); break; case k_ESteamInputType_XBoxOneController: printf( "XBox One controller!\n" ); break; case k_ESteamInputType_GenericXInput: printf( "Generic XInput!\n" ); break; case k_ESteamInputType_PS4Controller: printf( "PS4 controller!\n" ); break; } }

Omien kuvakkeiden käyttö: Painikkeiden kuvat

Jos käytät yksittäistä hakutaulukkoa, jossa toiminnot yhdistetään syötelähteeseen, voit käyttää näitä funktioita laitekohtaisia kuvakkeita varten ja kääntää tuntemattomat ohjaimet lähimmäksi samantyyppiseksi ohjaimeksi.

Esimerkki koodista:
// Alusta käyttöliittymä, ennen kuin alat käyttämään yksittäisiä funktioita – tämä kutsu on tehtävä vain kerran! SteamInput()->Init() // ... // SteamAPI_RunCallbacks() kutsuu RunFrame-funktiot kaikille alustetuille käyttöliittymille, ja useimmat // pelit lähettävät tämän kutsun säännöllisesti. Jos et tee niin, sinun on päivitettävä manuaalisesti // Steam-syötteen käyttöliittymä SteamInput()->RunFrame(); // ... // Korvaa XInput-paikalla, jolle kysely lähetetään. Tämä numero on nollan ja kolmen välillä // Jos käytössä on RawInput laitteen tunnistamiseksi, ennen kuin päätät, mitä ohjelmointirajapintaa käytät, tarkasta // osio "Using RawInput For Device Detection". int nXinputSlot = 0; // Korvaa painikkeella, jota kysely koskee EXboxOrigin eXboxButtonToGetGlyphFor = k_EXboxOrigin_A; EInputActionOrigin buttonOrigin = k_EInputActionOrigin_XBoxOne_A; // Jos ohjain on määritetty Steam-syötteellä – käännä tämä painike InputHandle_t controller1Handle = SteamInput()->GetControllerForGamepadIndex( nXinputSlot ); if ( controller1Handle > 0 ) { // Kelpaavien kahvojen arvon tulee olla muu kuin nolla. Tämä ohjain on määritetty Steam-syötteellä // Huomaa: Ohjaimet, jotka käyttävät Steam-syötteen ohjelmointirajapintaa eivät palauta kahvaa funktiossa GetControllerForGamepadIndex() buttonOrigin = SteamInput()->GetActionOriginFromXboxOrigin( controller1Handle, k_EXboxOrigin_A ); //i.e, k_EInputActionOrigin_PS4_X } else { // Kelpaavien kahvojen arvon tulee olla muu kuin nolla. Tämä on normaali Xbox-ohjain // Jatka alkuperäisen painikkeen käyttöä } // Steam jatkaa toimintolähteiden lisäämistä, ja myöhemmät ohjaimet ylittävät nykyisen rajan // Voit testata esittämällä, ettei Switch-/PS5-ohjainta ole yhdistetty ja muuttamalla tämän seuraavasti: // if ( buttonOrigin >= k_EInputActionOrigin_XBox360_Reserved10 ) if ( buttonOrigin >= k_EInputActionOrigin_Count ) { // Pelillä ei ole kuvitusta tälle lähdetyypille! Steam on ilmeisesti lisännyt tuen // uudelle ohjaimelle. Haetaan lähin arvo, jota tuettiin käyttämässämme SDK:ssa buttonOrigin = SteamInput()->TranslateActionOrigin( k_ESteamInputType_Unknown, buttonOrigin ); } // Korvaa tämä pelin funktiolla, jolla noudetaan painikkeen kuvake int glyphTextureID = getHardCodedButtonGlyphTexture( buttonOrigin );

RawInputin käyttö laitteen tunnistamiseen

Joissain peleissä RawInputia käytetään tukemaan yli neljää ohjainta tai määrittämään, onko kytketty ohjain PlayStation-ohjain. Tämä ohjelmointirajapinta palauttaa ohjainten lisäksi muutkin laitteet. Sillä ei ole luotettavaa hakemistoa Steam-syötteen toimintojen suoraan määrittämiseen. Voit hakea nämä tiedot kysymällä RIDI_DEVICENAME-merkkijonoa funktiolla GetRawInputDeviceInfo(), joka on koodattu oikean laitteen USB VID/PID -tunnisteella, peliohjaimen indeksillä ja Steam-syötteen kahvalla seuraavassa muodossa:
\\.\pipe\HID#VID_045E&PID_028E&IG_00#{Real device VID}&{Real Device PID}&{Steam Input API handle}#{Steam Input Gamepad Index}#{ProcessID}
Esimerkiksi \\.\pipe\HID#VID_045E&PID_028E&IG_00#045E&0B00&00045EB00704DAF3#0#20160 Xbox One -ohjaimelle, jonka VID/PID on 0x45e/0x0b00.

Esimerkki koodista:
#define VALVE_DIRECTINPUT_GAMEPAD_VID 0x28DE #define VALVE_DIRECTINPUT_GAMEPAD_PID 0x11FF #define STEAM_INPUT_VID_INDEX 37 #define STEAM_INPUT_PID_INDEX 42 #define STEAM_INPUT_SIAPI_HANDLE_INDEX 47 #define STEAM_INPUT_GAMEPAD_INDEX 64 #define MAX_PATH 260 //... void YourFunction() { PRAWINPUTDEVICELIST devices = NULL; UINT i, j, device_count = 0; if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!device_count)) { return; /* oh well. */ } devices = (PRAWINPUTDEVICELIST)malloc(sizeof(RAWINPUTDEVICELIST) * device_count); if (devices == NULL) { return; } if (GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)) == -1) { free(devices); return; /* niinpä niin. */ } for (i = 0; i < device_count; i++) { RID_DEVICE_INFO rdi; char devName[MAX_PATH]; UINT rdiSize = sizeof(rdi); UINT nameSize = MAX_PATH; rdi.cbSize = sizeof(rdi); if ( devices[i].dwType == RIM_TYPEHID && GetRawInputDeviceInfoA( devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize ) != (UINT)-1 && GetRawInputDeviceInfoA( devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize ) != (UINT)-1 ) { if ( rdi.hid.dwVendorId == VALVE_DIRECTINPUT_GAMEPAD_VID && rdi.hid.dwProductId == VALVE_DIRECTINPUT_GAMEPAD_PID ) { uint32 ulVID = strtoul( &devName[STEAM_INPUT_VID_INDEX], NULL, 16 ); uint32 ulPID = strtoul( &devName[STEAM_INPUT_PID_INDEX], NULL, 16 ); uint64 ulDeviceHandle = strtoull( &devName[STEAM_INPUT_SIAPI_HANDLE_INDEX], NULL, 16 ); uint32 unGamepadIndex = strtoul( &devName[STEAM_INPUT_GAMEPAD_INDEX], NULL, 16 ); [/i][/i][/i] Log( "Raw input device: VID = 0x%x, PID = 0x%x, handle = 0x%llx, index = 0x%x, %s\n", ulVID, ulPID, ulDeviceHandle, unGamepadIndex, devName ); // Nyt voit käyttää VID- tai PID-tunnusta laitteen tunnistamiseksi tai ulDeviceHandle -kahvaa funktiossa GetInputTypeForHandle ESteamInputType inputType = SteamInput()->GetInputTypeForHandle( ulDeviceHandle ); switch( inputType ) { case k_ESteamInputType_Unknown: printf( "unknown!\n" ); break; case k_ESteamInputType_SteamController: printf( "Steam controller!\n" ); break; case k_ESteamInputType_XBox360Controller: printf( "XBox 360 controller!\n" ); break; case k_ESteamInputType_XBoxOneController: printf( "XBox One controller!\n" ); break; case k_ESteamInputType_GenericGamepad: printf( "Generic Gamepad(DirectInput)!\n" ); break; case k_ESteamInputType_PS3Controller: case k_ESteamInputType_PS4Controller: case k_ESteamInputType_PS5Controller: printf( "PlayStation controller!\n" ); break; } } else { // Laite ei ole ohjain Steam-syötteessä. Käytä normaalia ohjaintunnisteen logiikkaa continue; } } } free(devices); }

Steamworks-asetusten määrittäminen

Ensimmäinen vaihe on määrittää, mitkä ohjaimet käyttävät Steam-syötettä Steamworks-asetusten Osallistu-osiossa kohdassa Sovellus > Steam-syöte. Normaalia Xbox-ohjainta tukevia pelejä varten kannattaa ruksia Xbox-valintaruudun lisäksi kaikki muutkin vaihtoehdot:

steamworks_steam_input_optin_settings.png

Jos pelisi tukee lento- tai rattiohjaimia, poista rasti valintaruudusta Yleinen/DirectInput-ohjaimet, koska Steam ei tue kyseisten laitteiden uudelleenmääritystä.

Määritysten valinta

Voit luoda omat määrityksesi tai valita valmiiksi luodun mallipohjan. Sinun ei ole pakko luoda omia ohjainmäärityksiä, paitsi jos aiot muokata oletusmäärityksiä tai merkitä yksittäisiä määrityksiä niiden pelitoiminnoilla. Steam-syötteen sisäänrakennetut mallit on lokalisoitu kaikille Steamin tukemille kielille. Muista siis lokalisoida omat määrityksesi, jotta englanninkielistä tekstiä ei näytetä muita kieliä käyttäville pelaajille.

Mallin valitseminen

Konsoliohjaimet eivät huomioi peliohjainmallien eroja, mutta näillä asetuksilla on väliä Steam-ohjainta käyttäessä. Tässä on selitys mallipohjista ja siitä, minkälaisille peleille ne on suunniteltu:
  • Peliohjain – Tämä emuloi Xbox-ohjainta. Oikea kosketuslevy emuloi ohjainsauvaa. Sopii hyvin twin-stick -räiskintään, tasohyppelyyn tai urheilupeleihin.
  • Peliohjain, jossa on tarkka kamera tai tähtäin – Tämä määritys sopii hyvin FPS-peleihin tai mihin tahansa peliin, jossa pelaaja ohjaa kameraa. Ennen kuin valitset tämän, testaa että pelisi tukee samanaikaista peliohjaimen ja hiiren käyttöä. Testaa toimivuus myös pelin eri ikkunoissa, kuten kartassa tai tavaraluettelossa.
  • Peliohjain, jolla ohjataan kameraa – Tämä määritys ottaa hiirityyppisen syötteen kosketuslevystä ja muuntaa sen emuloidun ohjainsauvan pyyhkäisyiksi. Jos pelin asetuksissa voidaan määrittää erittäin herkkä ohjainsauva ilman kuollutta aluetta ja lineaarisella kiihtyvyydellä, tämä määritys voi toimia hyvin. Muussa tapauksessa kannattaa harkita hiiri-/näppäimistömääritystä.

steam_input_gamepad_templates.png

Vaiheet mallipohjan julkaisemiseksi pelillesi Steamworksissä löytyvät täältä

Räätälöityjen määrityksien luominen

Määritykset voidaan muuntaa automaattisesti eri ohjaintyyppien välillä, mutta kannattaa luoda ainakin Steam-ohjaimen ja Xbox-ohjaimen määritykset.
Huomaa: jos haluat hyödyntää ohjaimien erikoisominaisuuksia, kuten liikeohjausta, sinun on tehtävä määritykset PlayStation 4- tai Nintendo Switch -ohjaimille.

Tekstisyöte


Näytölle syötettävä teksti ei teknisesti kuulu ISteamInput-ohjelmointirajapintaan (eli Steam-syötteeseen). Sitä varten on ISteamUtils. Tätä käytetään tällä hetkellä vain silloin, kun pelaaja käynnistää pelin televisiotilassa.

Muistutuksena:

Määritysten lokalisointi
Määritysten lokalisointi on hiukan hankalampaa, jos et käytä Steam-syötteen ohjelmointirajapintaa, mutta se on silti mahdollista.
  • Varmista aluksi, ettet ole muokannut määrityksiä sen jälkeen, kun lähetit ne viimeksi. Avaa määritysikkuna ja tee muokkaus (voit perua muutoksen heti jälkikäteen).
  • Avaa Steam\Logs\controller_ui.txt -loki ja etsi seuraavan näköinen merkkijono:
    Steam Controller Saving Controller Configuration Autosave for [CONTROLLER SERIAL NUMBER]- AppID: [YOUR APPID]. Loaded Config for Local Selection Path for App ID [YOUR APPID], Controller 0: F:\ProgramFiles\Steam\client\userdata\[STEAMID]\config\controller_configs\apps\[YOUR APPID]\[CONTROLLER SERIAL]\guest\controller_configuration.vdf
  • Syötä lokalisointitunnukset niihin määrityksiin, jotka haluat lokalisoida
    • Title/Description:
      "controller_mappings" { "version" "3" "revision" "5" "title" "#title" "description" "#description" ...
    • Button bindings:
      "button_a" { "activators" { "Full_Press" { "bindings" { "binding" "xinput_button A, #abutton" } } } } ...
  • Syötä vastaavat arvot jokaiselle kielelle lokalisointilohkoon:
    "localization" { "english" { "title" "This is a localized title" "description" "This is a localized description. Painikekuvakkeiden määrityksillä on myös lokalisoidut nimet." "abutton" "Oma nimi tänne 1" "bbutton" "Oma nimi tänne 2" "xbutton" "Oma nimi tänne 3" "ybutton" "Oma nimi tänne 4" } ...
  • Voit nyt viedä määrityksen ja asettaa sen kumppanisivulle seuraamalla näitä ohjeita. Kannattaa asettaa "käytä toimintoestoa" -valintaruutu yhdelle määrityksellesi.

Esimerkkimääritystä voi tarkastella Steam-asiakasohjelmassa tästä URL-osoitteesta: steam://controllerconfig/681280/1744110334. VDF-tiedosto löytyy täältä