GPVars & Conditions¶
Les GPVars (variables de gameplay) permettent aux programmeurs et aux designers de stocker l'état du jeu sur la GameInstance et de le lire ou l'écrire de façon fiable depuis n'importe où — en C++ comme en Blueprint. Comme elles résident sur la GameInstance, une GPVar survit au changement de niveau et reste accessible sans conserver de référence vers l'objet qui l'a créée.
Une GPVar est un fragment d'état minimal et adressable : un booléen, un entier ou un compteur « combien de fois ». Chacune est identifiée par un chemin (voir GPTagPath), ce qui maintient l'ensemble du store bien rangé et parcourable dans le widget de debug runtime.
Le système de GPVars est également ce sur quoi s'appuie le système de dialogues pour mémoriser ce que le joueur a fait — quels dialogues ont été joués, quels choix ont été retenus — et pour piloter le branchement conditionnel.
En bref
Un GPTagPath nomme une variable. Un GPFlag est un booléen, un GPCounter est un entier, et
un CountedGPFlag est un flag qui résiste au fait d'être levé depuis plusieurs endroits à la fois.
Le ULBRGPVarSubsystem possède l'intégralité du store ; les listeners et les delegates
vous notifient lorsqu'une valeur change ; un widget de debug vous permet d'inspecter et
d'éditer le tout en direct.
Un exemple concret¶
Imaginez une valeur de Karma propre à chaque personnage. Vous créez un seul GameplayTag,
Stats.Karma, et vous stockez la valeur par personnage en le combinant à un chemin de personnage :
Characters.Player / Stats.Karma— le karma du joueurCharacters.NPC1 / Stats.Karma— le karma de NPC1
À partir de là, chaque discipline lit et écrit la même variable via le même chemin :
- un narrative designer ajoute
+3lorsqu'un choix de dialogue console un personnage ; - un quest designer verrouille un sanctuaire derrière « karma ≥ 15 » ;
- un game designer retranche
2pour une action peu recommandable ; - un sound designer déclenche un effet lorsque le karma devient négatif ;
- un programmeur fournit « karma ≥ 25 » à une Animation Blueprint pour choisir un cycle de marche ;
- un testeur QA modifie directement le karma dans le widget de debug pour vérifier tout ce qui précède d'un seul coup.
GameplayTags¶
Les GPVars reposent sur les GameplayTags, une fonctionnalité native d'Unreal : des identifiants textuels enregistrés dans une liste sous Project Settings ▸ GameplayTags. Vous choisissez un tag dans une liste déroulante plutôt que de taper une chaîne, ce qui évite les fautes de frappe et rend les renommages sûrs.
Warning
Lorsque vous ajoutez un Gameplay Tag via les Project Settings, pensez à committer le fichier
Config/DefaultGameplayTags.ini qui en résulte.
GPTagPath¶
Un GPTagPath (abréviation de « gameplay tag path ») est un chemin, à la manière d'un chemin de fichier sur disque. Au lieu de dossiers et d'un nom de fichier, c'est une séquence de GameplayTags, par exemple :
Characters.Galeb / Inventory.SC01.JaraReport
Chaque GPVar est identifiée par un GPTagPath. C'est ce qui permet au widget de debug de les disposer en un arbre bien rangé — « Galeb possède l'objet JaraReport » est classé sous la branche du personnage Galeb.
Vous composez un GPTagPath de la même façon que vous choisissez un GameplayTag : en sélectionnant plusieurs tags à la suite. Le sélecteur affiche le chemin en cours de construction en haut, chaque partie étant étiquetée selon sa position dans le chemin.

Des fonctions utilitaires se trouvent sous Gameplay Tag ▸ Utils ▸ GPTagPath.
Chemin unique ou flags groupés
La plupart des fonctions prennent un seul GPTagPath pour identifier une seule GPVar. Les fonctions
qui opèrent sur plusieurs flags à la fois (celles dont le nom contient Flags, au pluriel —
par exemple RaiseGPFlags) prennent en revanche le chemin parent partagé et un conteneur des
flags feuilles à modifier ensemble.
Types de GPVar¶
GPFlag 🏳️¶
Un GPFlag est un booléen.
| Action | Node |
|---|---|
Mettre à true |
RaiseGPFlag |
Mettre à false |
LowerGPFlag |
| Lire | CheckGPFlag |

GPCounter 🔢¶
Un GPCounter est un entier (non décimal).
| Action | Node |
|---|---|
| Définir la valeur | SetGPCounter |
| Lire la valeur | GetGPCounter |

CountedGPFlag 🎌¶
Un CountedGPFlag se comporte presque comme un GPFlag, mais il tolère d'être levé depuis plusieurs
endroits sans écraser les autres. Si vous levez le même CountedGPFlag n fois, le checker
renvoie true jusqu'à ce qu'il ait été abaissé ces mêmes n fois.
Les nodes appelables en Blueprint sont RaiseCountedGPFlag, LowerCountedGPFlag et ClearCountedGPFlag (plus un check).
Info
En interne, il n'existe pas de stockage « CountedGPFlag » distinct. C'est la combinaison d'un
GPFlag et d'un GPCounter classés au même GPTagPath — reflétée par les champs de
FGPVarNode, qui contient à la fois un conteneur GPFlags et une map GPCounters. Ne triturez
pas ces deux moitiés à la main si vous les utilisez comme un CountedGPFlag, sous peine de
désynchroniser le compteur.
Nodes 🪢¶
Les Nodes sont les dossiers de ce système : ils sont générés automatiquement à la création d'une
GPVar et existent uniquement pour organiser l'arbre. Un node n'est pas une GPVar. Par exemple, dans
Characters.Emem / Gameplay.Attributes.Mental, le compteur est la GPVar, tandis que Characters.Emem
n'est qu'un node de stockage.
Valeurs par défaut¶
Vous pouvez définir des GPFlags et des GPCounters qui sont positionnés automatiquement au premier lancement du jeu et à chaque démarrage PIE.
- Valeurs par défaut à l'échelle du projet : Project Settings ▸ Libretto - GPVars ▸
Default GPVarsNodes (adossées à
ULBRGPVarSettings, sauvegardées dans la configLibretto). - Valeurs par défaut par machine, rien que pour vous : Editor Preferences ▸ Libretto - GPVars ▸
Default GPVarsNodes (adossées à
ULBRGPVarLocalSettings).
Chaque entrée est une paire FGPTagPath → FGPVarNode : la clé est le chemin parent (elle peut
être vide si le chemin entier tient en un seul tag), et la valeur liste les GPFlags à lever et les
GPCounters à initialiser.

Le store : ULBRGPVarSubsystem¶
L'ensemble du store de GPVars du jeu appartient au ULBRGPVarSubsystem (module LBRTags),
accessible depuis le C++ comme depuis le Blueprint. Tous les nodes ci-dessus sont de fines enveloppes
autour de ses méthodes Static_*, si bien que vous n'avez jamais besoin d'une référence au subsystem
pour les appeler.
Sauvegarde¶
Le store n'est pas sauvegardé pour vous. C'est un subsystem engine : il survit au changement de niveau, mais il repart vide à chaque session de jeu (et, dans l'éditeur, à chaque session PIE).
Pour le sauvegarder, sérialisez le subsystem (ULBRGPVarSubsystem::GetGPVarSubsystem()) avec une
archive SaveGame (ArIsSaveGame = true) dans vos propres données de sauvegarde, et relisez-le de
la même façon. Ses nodes de GPVars sont des propriétés SaveGame. Les GPVars sous le tag racine
Transient sont supprimés au chargement d'une sauvegarde : placez-y ce qui ne doit jamais
survivre à la session.
Sauvegardez l'historique des conditions (ULBRConditionHistorySubsystem) dans la même
sauvegarde : les GPVars et les résultats de conditions en cache vont ensemble. La recette complète,
avec le code, est dans la FAQ :
Je veux sauvegarder et restaurer l'état de Libretto avec ma sauvegarde.
Réagir aux changements¶
Vous voulez souvent exécuter une vérification une seule fois, juste après le changement d'une valeur, plutôt que de la sonder à chaque frame. Deux mécanismes vous permettent de vous brancher immédiatement après la modification d'une GPVar.
Listeners 👂¶
Un listener est un objet qui filtre les GPVars qui vous intéressent et déclenche un événement à
chaque changement. Le plugin fournit les classes de base natives UGPFlagListener et
UGPCounterListener ; un projet les enveloppe généralement dans des acteurs listeners que vous
déposez dans un niveau, auxquels vous donnez un GPTagPath et que vous câblez dans le Level Blueprint :
- OnFlagChanged
GPFlagPaths— tous les flags modifiés dans le même lot.Changed—truesi le flag a été levé,falses'il a été abaissé.
- OnCounterChanged
GPCounterPath— le compteur qui a changé.PreviousValue/NewValue— les valeurs avant et après.

Tip
Vous n'êtes pas limité à un chemin par acteur. Les listeners peuvent surveiller plusieurs variables à la fois, ou fonctionner sans aucun acteur — prenez les listeners fournis comme modèle, ou demandez à un programmeur.
Delegates 🗳️¶
Vous pouvez aussi vous lier directement aux delegates du subsystem — par exemple
BindEventToOnGPFlagChangedPerPaths / BindEventToOnGPCounterChangedPerPaths (et leurs homologues
Unbind). C'est plus bas niveau : c'est vous qui gérez l'enregistrement et le désenregistrement,
et vous filtrez les chemins vous-même. Les paramètres reflètent les événements des listeners ci-dessus.
Le widget de debug runtime¶
Un widget de debug (le GPVarEditor) affiche l'état vivant du store : quels flags sont levés et ce qu'indique chaque compteur, avec la possibilité d'ajouter, de supprimer et d'éditer des GPVars pendant que le jeu tourne. Il est précieux pour les tests :
- un narrative designer ajuste les stats d'un personnage pour atteindre une option de dialogue précise ;
- un testeur QA dépose un objet dans un inventaire pour vérifier son utilisation ;
- un programmeur bascule un état pour confirmer qu'un pouvoir se débloque au bon moment.
L'ouvrir¶
En cours de partie (PIE ou jeu packagé), ouvrez la console et lancez :
Libretto.GPVar.OpenDebugWidget
Relancez-la pour la fermer — la commande bascule le widget. Elle affiche le widget défini dans
Project Settings ▸ Libretto – GPVars ▸ Debug ▸ Debug Widget Class, qui pointe par défaut sur celui
livré avec le plugin (WBP_GPVarEditor, sous Content/GPVars/GPTagEditor/, adossé aux classes natives
UGPVarCreatorWidget / SGPVarCreator du module LBRTags). Pointez ce réglage vers votre propre
widget pour personnaliser l'inspecteur.
Associez-le à une touche
Pour un usage fréquent, associez le même comportement à une touche dans un Level ou player Blueprint (créez le widget et ajoutez-le au viewport) plutôt que de taper la commande console à chaque fois.

Disposition¶
Le widget comporte trois parties :
- un contrôle pour ajouter de nouvelles GPVars (« Create new GPVar », avec Expand all / Collapse all) ;
- les contrôles de la TreeView ;
- la TreeView du store proprement dit.
Lire l'arbre¶
La hiérarchie est construite à partir des GPTagPaths des GPVars. Le symbole de gauche indique l'état du node :
| Symbole | Signification |
|---|---|
> |
replié, peut être déplié |
v |
déplié |
- |
node feuille, ne contient aucune GPVar |
Un GPFlag levé n'affiche que son GameplayTag ; un GPCounter affiche en plus sa valeur à droite, dans un champ éditable.
Édition¶
+en haut ajoute une GPVar à la racine du store.+sur la ligne d'un node ajoute une GPVar à l'intérieur de ce node de stockage.xsur une ligne supprime cette GPVar ou ce node.
Appuyer sur + ouvre la popup GPVarCreator, qui affiche le chemin en cours de construction, une
liste déroulante de type (type de GPVar, ou Node pour un simple node de stockage — plus un champ
de valeur lors de la création d'un GPCounter), un bouton Add, et le même sélecteur de GPTagPath
utilisé partout ailleurs.

Comment les GPVars se relient aux dialogues¶
Le système de dialogues utilise les GPVars comme mémoire. Trois éléments les relient : les tags par asset générés automatiquement, les flags et compteurs runtime écrits pendant la partie, et les conditions sur les lignes qui relisent ces valeurs.
Tags de dialogue générés automatiquement¶
Plutôt que de vous faire taper des chaînes, le système de dialogues génère un GameplayTag unique pour chaque Dialogue, Subdialogue, Choice et Reply (voir Dynamic tag identification dans le Dialogue Editor) :
Libretto.Dialogues.DialogueName[.SubdialogueName]
Libretto.Dialogues.DialogueName.Choice_ID[.Reply_ID]
Ils sont produits par le LBRDialogueTagsSubsystem au chargement du projet (désactivez-le via sa
valeur bUseSubsystem dans le .ini, auquel cas les tags sont écrits dans
Config/Tags/Dialogues/….ini en solution de repli). Ils vous permettent de suivre chaque choix que
fait un joueur et de piloter la sélection de subdialogue, le tout sans chaînes tapées à la main.
L'info-bulle qui identifie les sélecteurs de subdialogue d'un dialogue est portée par le sous-tag
<dialogue>.SubdialogueSelectors.

Flags & compteurs runtime écrits pendant la partie¶
À mesure qu'un dialogue se joue, le système enregistre la progression dans le store de GPVars :
| Ce qui est enregistré | Comment |
|---|---|
| Un dialogue a été joué | Un CountedGPFlag sous la catégorie Done (flag + compteur) — le compteur = combien de fois il a été joué. Levé à la fin du dialogue. |
| Un subdialogue a été joué | Idem, indexé par le tag du subdialogue. Levé à la fin de chaque subdialogue. |
| Une reply a été choisie | Un CountedGPFlag écrit à plat à la racine (sans catégorie), indexé par le tag de la reply — levé à chaque fois que cette reply est retenue. |
Jouez un dialogue une fois, ouvrez le widget de debug, et vous verrez ces entrées apparaître d'elles-mêmes — exactement ce que vous auriez créé à la main.

La disposition du tag Done
Le chemin du tag Done est construit comme Libretto.RuntimeFlags.Done + <tag de dialogue ou de
subdialogue>, de sorte que Done est la catégorie parente et le tag de
dialogue/subdialogue est la feuille flag+compteur (ULBRDialogue::Static_GetDialogueDoneGPTagPath,
ULBRSubdialogue::GetSubdialogueDoneGPTagPath).
Pour tester si un dialogue est terminé, utilisez la condition dédiée ULBRDialogueDoneCondition
— elle prend directement les tags de dialogue / subdialogue (avec une bascule bCheckAll pour
tous vs au moins un) et connaît cette disposition. Il existe aussi
ULBRDialogueDoneCountedCondition (dérivée de ULBRCheckGPCounter) pour comparer combien de
fois un dialogue a été joué. Préférez celles-ci aux conditions sur chemin de GPVar écrites à la main.
La liste déroulante des conditions¶
Sur une Reply, un Subdialogue ou une branche If/ElseIf/Else, vous pouvez attacher une condition qui lit un état dynamique — y compris les GPVars ci-dessus. La liste déroulante des conditions propose des combinateurs logiques et une famille de checks de GPVar (module LBRConditions) :
| Condition | Ce qu'elle vérifie |
|---|---|
None, AND, OR, XOR, NOT, FALSE, Empty |
Structure logique / combinateurs. |
Check All / Any / Not GPFlags |
Si les flags feuilles donnés sont (tous/au moins un/aucun) levés au sein d'un chemin partagé. |
Check All / Any / Not GPPaths |
Le même test, mais chaque entrée est un chemin complet donné directement. |
Count GPFlags / Count GPPaths |
Compter combien des flags/chemins donnés sont levés et comparer. |
Check GPCounter |
Comparer un compteur à un chemin par rapport à une valeur. |
Dialogue Done |
(2026) Les dialogues/subdialogues donnés ont-ils été joués ? — le remplacement ci-dessus, conscient de la disposition. |
Dialogue Done Counted |
(2026) Comparer combien de fois un dialogue/subdialogue a été joué. |

GPFlags vs. GPPaths
Les deux familles font le même travail avec une ergonomie différente. Les conditions GPFlags
prennent un chemin parent partagé plus un conteneur de tags feuilles — pratique pour tester
plusieurs valeurs sous le même chemin en une seule condition. Les conditions GPPaths prennent
un tableau de chemins complets — pratique lorsque les éléments que vous testez résident dans des
endroits sans lien. Les deux exposent une bascule Exact Match (activée par défaut) et, héritées
de la classe de base ULBRCondition, un Comment en texte libre ainsi que Cache Success /
Cache Failure (un résultat positif/négatif court-circuite la suite de l'évaluation).
Condition d'affichage vs. de disponibilité¶
Une Reply expose deux emplacements de condition, et la différence compte :
| Emplacement | Effet lorsque la condition est fausse |
|---|---|
| Display Condition | La reply n'est pas du tout proposée — ni affichée, ni sélectionnable. |
| Availability Condition | La reply est affichée, mais grisée et non sélectionnable. |

Verrouiller une reply derrière une première partie
Placez une ULBRDialogueDoneCondition sur la Display Condition d'une reply, en visant le tag
du dialogue courant. Au premier passage, le dialogue n'est pas encore Done, donc la reply est
masquée ; rejouez le dialogue et — maintenant que Done est levé — la reply apparaît.