Documentation Steamworks
Fichier d'actions en jeu (AEJ)

Présentation


Les équipes de développement doivent fournir un fichier d'actions en jeu (AEJ) qui définit les actions, les groupes d'actions et la structure de base de la configuration des entrées de leur jeu. Cet article décrit la structure générale de ce fichier et fournit plusieurs exemples concrets issus de divers jeux.

Exemples de fichiers


Création manuelle d'un fichier d'actions en jeu

Commencez par télécharger l'un des fichiers d'actions en jeu (AEJ) de démarrage que vous trouverez dans les exemples ci-dessus. Ensuite, créez un répertoire « controller_config » dans le dossier Steam, généralement dans C:/Program Files (x86)/Steam/controller_config, et placez le fichier dans le répertoire. Le dossier Steam contiendra déjà un dossier avec un nom très similaire, donc assurez-vous d'utiliser le dossier « controller_config » et non « controller_base ». Renommez le fichier comme suit : « game_actions_X.vdf », où X est l'AppID de votre jeu Steam. Si vous ne connaissez pas l'AppID Steam de votre jeu, vous pouvez le trouver en vous connectant au site des partenaires Steam.

Ouvrez maintenant le fichier dans votre éditeur de texte préféré. Le fichier est au format standard Valve appelé KeyValues, qui est un format simple et facile à lire. Vous pourriez également trouver utile de télécharger, en guise d'exemple, l'un de nos modèles de fichiers d'actions en jeu ou l'AEJ de Portal 2.

Génération d'un fichier AEJ à partir d'un jeu existant utilisant l'API Steam Input


Si vous enregistrez une configuration pour n'importe quel jeu sur Steam sous la forme d'une configuration dite locale, vous pouvez alors trouver un fichier correspondant dans :
[Répertoire_Steam]\UserData\[votre_ID]\241100\remote\controller_config\[appid]\[nom_de_la_sauvegarde].vdf

Voici un exemple d'emplacement de vos configurations locales pour Defender's Quest sur un ordinateur classique sous Windows 10 :

Répertoire du fichier AEJ

Notez que ces fichiers ne sont pas des répliques exactes du fichier AEJ principal mis à disposition par l'équipe de développement, mais vous pouvez avoir une idée de la structure originale en regardant les blocs « actions » et « localization », directement tirés du fichier principal.

Voici un lien de téléchargement pour le fichier #library_controllersavedefaulttitle_0.vdf montré dans la capture d'écran ci-dessus. Vous trouverez peut-être utile de le comparer au fichier AEJ principal de Defender's Quest.

Format AEJ


Le fichier AEJ correspond à un document au format VDF, le format de données propriétaire de Valve pour la création de structures de données avec des paires clé-valeur sous forme de chaines de caractères.

Ossature


La structure de base du fichier est constituée d'un objet encapsuleur appelé « In Game Actions » (actions en jeu) et de deux sous-objets respectivement nommés « actions » et « localization » (localisation) :

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

Groupes d'actions

Intéressons-nous à l'objet « actions ». Cet objet contiendra vos groupes d'actions. La structure d'un objet « actions » ressemble à ceci :
"actions" { "nom_du_groupe_actions" { "title" "#titre" "StickPadGyro" { } "AnalogTrigger" { } "Button" { } } }

Les chaines nom_du_groupe_actions et #titre sont les seules chaines dans l'exemple ci-dessus qu'il faut remplacer, le reste étant constitué de mots-clés réservés.

La valeur par laquelle vous remplacerez nom_du_groupe_actions correspond au nom du groupe d'actions que vous utiliserez dans l'API Steam Input. Et la valeur par laquelle vous remplacerez #titre correspond au nom du jeton de localisation que vous utilisez dans la section localization qui apparait plus tard dans le fichier. Notez que le caractère « # » est requis ici.

Chaque groupe d'actions doit avoir un nom unique sous forme de chaine de caractères. Vous pouvez ajouter d'autres groupes d'action en créant plus d'objets dans l'objet conteneur « actions ». Aucune virgule ni aucun crochet n'est nécessaire : c'est un fichier VDF, pas JSON.

Il y a trois sous-objets possibles pour chaque objet de groupe d'actions : StickPadGyro, AnalogTrigger et Button. Ce sont les seuls objets que vous pouvez définir. Ils constituent les conteneurs qui abriteront chacune de vos définitions d'action. Il n'est toutefois pas nécessaire de renseigner les trois catégories.

Par exemple, cette structure est parfaitement valide :
"actions" { "ActionSetName1" { "title" "#Title1" "AnalogTrigger" { } "Button" { } } "ActionSetName2" { "title" "#Title2" "StickPadGyro" { } } "ActionSetName3" { "title" "#Title3" "Button" { } } }

StickPadGyro

Ce bloc de groupe d'actions est destiné aux actions analogiques qui auront jusqu'à deux axes de mouvement. C'est le type de mouvements qu'on associe généralement à un joystick, un trackpad ou un gyroscope. De même, tout ce que pourriez vouloir contrôler avec une souris ou tout autre périphérique du même type doit se trouver dans ce bloc.

AnalogTrigger

Ce bloc de groupe d'actions est destiné aux actions analogiques qui n'auront qu'un seul axe de mouvement. C'est le type de mouvement qu'on associe en général à une gâchette analogique.

Button

Ce bloc de groupe d'actions est purement destiné aux actions numériques, qui ne renvoient qu'un état activé/désactivé. Bien que le nom de ce bloc soit « button » (bouton), les actions numériques peuvent être associées à n'importe quelle entrée physique, y compris celles initialement prévues pour produire des données analogiques en sortie (comme les joysticks, les trackpads, etc.).

Actions


Pour qu'un fichier AEJ fonctionne, il faut y ajouter des actions. Alors, allons-y !

Actions StickPadGyro

Commençons par ajouter des actions analogiques sur deux axes dans le bloc StickPadGyro. Puis ajoutons quelque chose pour déplacer le personnage, que nous appellerons « Move », et quelque chose pour contrôler la caméra, que nous appellerons « Camera » :

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

Comme vous pouvez le voir, la structure abstraite d'une action StickPadGyro correspond à :
"nom_action" { "title" "#titre_action" "input_mode" "mode_analogique" }

Les seules valeurs qu'on peut modifier dans cette structure sont celles que nous avons nommées « nom_action », « #titre_action » et « mode_analogique ». Elles correspondent respectivement au nom (chaine de caractères) de l'action à utiliser dans l'API Steam Input, à la clé de localisation à utiliser dans la section « localization » de ce fichier et au mode de source d'entrée régissant la manière dont les données analogiques sont traitées et interprétées.

La propriété input_mode dispose de deux valeurs possibles pour les actions StickPadGyro :

  • joystick_move ;
  • absolute_mouse.

Nous vous conseillons d'utiliser joystick_move pour une action dont les valeurs sont interprétées comme un joystick (déviation constante depuis un point central), et d'utiliser absolute_mouse pour une action analogique plus flexible à usage général. En cas de doute, utilisez absolute_mouse.

joystick_move ou absolute_mouse ?

Nous ne saurions trop insister sur le fait que lors de la création d'une entrée caméra pour votre jeu à la première/troisième personne ou tout autre jeu basé sur l'utilisation d'un curseur, vous devez toujours utiliser le type absolute_mouse et réagir aux deltas comme s'il s'agissait d'une souris.

L'API exécutera automatiquement la bonne action pour les entrées basées sur le stick. Vous disposerez donc toujours d'une entrée de stick personnalisable si votre caméra est assignée à un stick analogique (de style PS4/Xbox), avec des zones mortes entières, des courbes de réponse, etc. que vous pouvez spécifier dans votre configuration par défaut. La même entrée fonctionnera sur les joysticks, les trackpads, ou les gyroscopes de contrôle de mouvement (Steam Controller/PS4) ainsi que les souris (une fois qu'elles seront prises en charge).

Vous ne devez pas utiliser la méthode d'entrée basée sur joystick_move pour votre caméra. En effet, il n'est pas possible d'obtenir des données utiles à l'échelle 1:1 pour le trackpad, le gyroscope, la souris et les contrôles de mouvement en mappant la direction opposée.

Ceci s'applique aussi aux entrées basées sur le curseur, car absolute_mouse fonctionnera parfaitement pour les entrées basées sur le stick. Si vous en avez besoin, il est donc inutile de créer votre propre curseur basé sur le stick.

Si vous le souhaitez, vous pouvez envoyer des évènements de souris de bas niveau en même temps que vos données analogiques. Votre jeu ne sera pas capable de distinguer ces évènements de souris de ceux générés par votre système d'exploitation. Il suffit pour cela d'ajouter la valeur os_mouse et de lui attribuer la valeur 1.

Voici un exemple :
"StickPadGyro" { "Mouse" { "title" "#Action_Mouse" "input_mode" "absolute_mouse" "os_mouse" "1" } }


Actions AnalogTrigger
Les actions AnalogTrigger sont des actions analogiques 1D qui peuvent être liées aux gâchettes d'un contrôleur. Si, pour une action comme un tir d'arme ou le démarrage du mode « Visée vers le bas », vous utilisez un simple seuil de déclenchement, nous vous recommandons de privilégier une action Button plutôt qu'une action AnalogTrigger : vous offrirez ainsi une plus large sélection de réassociations possibles aux utilisateurs et utilisatrices.

Les actions AnalogTrigger ont une zone morte configurable dans l'interface utilisateur de réassociation et sont redimensionnées de 0 à 1,0 entre ces valeurs. Les contrôleurs équipés de gâchettes numériques, comme la Nintendo Switch Pro, enverront 0 ou 1,0. Vérifiez que votre titre ne comporte pas de code qui nécessiterait un changement progressif de la gâchette au fil du jeu.

Les actions AnalogTrigger ont un format simple, avec le nom de l'action comme clé et le jeton de localisation comme valeur. Comme ceci :
"AnalogTrigger" { "AccelerationAxis" "#Action_Accelerate" "BreakingAxis" "#Action_Brake" }

Actions Button

Les actions Button ont un format similaire, qui reprend le nom de l'action et son jeton de localisation :
"Button" { "digital_action_1_name_here" "#DigitalAction1TitleHere" "digital_action_2_name_here" "#DigitalAction2TitleHere" }

Si nécessaire, vous pouvez définir un évènement natif d'entrée matérielle de bas niveau (comme un clic de souris natif) qui se déclenchera en même temps que l'action. C'est utile dans certains cas limites où votre jeu se base, par exemple, sur un empilement d'entrées méticuleux haut de sept couches qui ne traite jamais tout à fait les évènements de souris simulés depuis votre couche d'application de la même façon que les évènements directement générés par le système d'exploitation :

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

Ceci permet au jeu d'émettre un véritable évènement qui produit un clic gauche au niveau du système d'exploitation chaque fois que l'action « fancy_clic » se déclenche.

Attention !

Vous ne devez jamais utiliser cette astuce comme un moyen de forcer des associations d'entrées fixes spécifiques sur vos actions. Ceci va à l'encontre de l'objectif du paradigme « actions, pas entrées » et du fait de donner au public le contrôle total sur sa configuration. Si vous vous retrouvez à utiliser cette fonctionnalité pour faire plus que corriger quelques rares cas particuliers, c'est probablement que vous en abusez.

Couches de groupes d'actions

En plus des groupes d'actions, vous pouvez ajouter des changements incrémentiels sur le groupe d'actions actif en y apposant un nouveau groupe d'actions. Cette méthode permet de gérer les spécialisations d'un mode général (par exemple, une couche de tireur d'élite peut être apposée sur des commandes de marche), ou de gérer les cas où une interface utilisateur apparait en jeu, superposée à la partie (comme les écrans de vote). Les couches doivent être déclarées dans leur propre section, par exemple :
"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" } } }

Localisation


Le fichier AEJ principal devrait inclure une section « localization » en plus des définitions des groupes d'actions. Les sous-objets de l'objet localization seront les langues (sous forme de chaines de caractères) prises en charge par Steam. Assurez-vous d'inclure au moins un bloc contenant les titres d'action en anglais :

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

Veuillez noter que les noms des propriétés doivent correspondre aux clés de localisation que vous avez indiquées dans les sections précédentes, sans le caractère « # ».

Pour ajouter des langues supplémentaires, ajoutez simplement d'autres blocs de langue avec les traductions de chaque entrée :

"localization" { "english" { "move" "Move" "camera" "Camera" } "spanish" { "move" "Mover" "camera" "Cámara" } "norwegian" { "move" "Bevege" "camera" "Kamera" } }
Le jeton de chaque langue doit correspondre à la valeur du « code langue de l'API », par exemple, « schinese » pour le chinois simplifié. La liste complète des langues prises en charge est disponible ici.

Utilisation de votre fichier AEJ par Steam


Le fichier AEJ principal que vous créez ne sera utilisé que pendant la phase de développement (mais il doit néanmoins être enregistré, tenu à jour, stocké dans votre contrôle de version, etc.). Lorsque vous créez une configuration d'entrées officielle pour votre jeu au cours du développement, le client Steam utilise votre fichier AEJ principal pour générer un modèle de départ.