129 lines
6.1 KiB
Markdown
129 lines
6.1 KiB
Markdown
# 0008 — Services possédés et injectés par la composition
|
|
|
|
- Statut : accepté
|
|
- Date : 2026-08-10
|
|
- Remplace : aucun
|
|
|
|
## Contexte
|
|
|
|
Les réglages, l'accès aux sauvegardes, l'audio et une campagne chargée doivent
|
|
survivre à plusieurs changements d'écran. Godot permet de résoudre ce besoin
|
|
avec des autoloads, des singletons statiques ou un bus de signaux global. Ces
|
|
solutions rendent toutefois les dépendances accessibles depuis n'importe quel
|
|
script, masquent leur durée de vie et compliquent l'isolation des tests.
|
|
|
|
La verticale possède déjà une couche `composition`, seule autorisée à connaître
|
|
les implémentations concrètes de toutes les autres couches. Elle peut donc
|
|
maintenir les objets de longue durée sans les transformer en état global.
|
|
|
|
## Décision
|
|
|
|
### Aucun accès global de gameplay
|
|
|
|
Aucun autoload personnalisé, singleton statique, registre global, service
|
|
locator ou bus de signaux global n'est introduit pour le gameplay de la
|
|
verticale. Une longue durée de vie ne suffit pas à justifier un accès global.
|
|
|
|
Les singletons fournis par Godot restent des détails de plateforme. Seuls les
|
|
adaptateurs autorisés les utilisent ; le domaine et les cas d'usage ne lisent
|
|
pas directement `Input`, `SceneTree`, `AudioServer`, les fichiers ou l'horloge.
|
|
|
|
### Racine persistante
|
|
|
|
`vertical_slice_root.tscn` est la racine de composition persistante de la
|
|
verticale. Elle crée les implémentations concrètes, les relie à leurs ports et
|
|
possède un emplacement destiné à l'écran ou au monde actif. Une transition
|
|
remplace ce contenu enfant sans remplacer la racine et sans demander aux scènes
|
|
de rechercher des services dans l'arbre.
|
|
|
|
La composition est responsable de :
|
|
|
|
- construire les adaptateurs d'infrastructure et les cas d'usage ;
|
|
- charger ou créer l'état de campagne ;
|
|
- injecter les contrats requis avant d'activer une scène ;
|
|
- connecter les sorties d'une scène aux commandes applicatives appropriées ;
|
|
- déconnecter et libérer les dépendances de portée courte lors d'une
|
|
transition ;
|
|
- choisir l'écran suivant à partir d'un résultat applicatif explicite.
|
|
|
|
Une scène ne parcourt pas ses parents, `/root`, un groupe global ou un chemin
|
|
absolu afin de découvrir une dépendance. Elle expose une méthode de
|
|
configuration, des propriétés typées ou un constructeur de composition
|
|
explicite. L'absence d'une dépendance requise échoue immédiatement en
|
|
développement et dans les tests de chargement.
|
|
|
|
### Durées de vie
|
|
|
|
Trois portées sont distinguées :
|
|
|
|
1. **Application** : réglages, localisation, adaptateurs d'entrée et d'audio,
|
|
horloge de plateforme, accès au stockage et liste des sauvegardes. Ils vivent
|
|
tant que la racine existe.
|
|
2. **Campagne** : `CampaignState`, progression de mission et cas d'usage liés à
|
|
une partie. Ils sont créés lors d'une nouvelle partie ou d'un chargement et
|
|
détruits lors de sa fermeture ou de son remplacement.
|
|
3. **Plongée** : `ResolvedDiveRules`, `DiveSession`, acteurs, adaptateurs
|
|
physiques et service sonar courant. Ils sont créés au départ d'une plongée
|
|
et détruits après production de son résultat immuable.
|
|
|
|
Un objet de portée longue peut fournir un port à une portée plus courte. Il ne
|
|
conserve pas en retour une référence implicite vers un acteur ou une scène déjà
|
|
détruite. Les connexions de signaux suivent la même propriété et sont retirées
|
|
avec leur portée.
|
|
|
|
Les services d'infrastructure ne deviennent pas propriétaires des règles. Par
|
|
exemple, le dépôt de sauvegarde écrit un document demandé par un cas d'usage ;
|
|
il ne décide pas quand une mission progresse ou combien d'argent est gagné.
|
|
|
|
### Navigation et communications
|
|
|
|
La présentation traduit une interaction en commande ou appel de cas d'usage.
|
|
Elle consomme ensuite un résultat, un snapshot ou un événement typé. Elle ne
|
|
modifie jamais directement l'état de campagne ou un acteur du monde.
|
|
|
|
Les événements locaux peuvent utiliser les signaux Godot entre objets déjà
|
|
reliés par la composition. Un signal décrit un fait passé et ne sert pas de
|
|
canal global anonyme. Une intention reste une commande nommée.
|
|
|
|
Chaque écran et composition de plongée peut être instancié dans un test avec de
|
|
faux ports, sans charger une campagne réelle, le stockage de la machine ou tous
|
|
les autres écrans.
|
|
|
|
### Évolution
|
|
|
|
Tout nouvel autoload, accès statique global ou exception durable à cette
|
|
politique exige un ADR qui précise son propriétaire, sa durée de vie, son API,
|
|
sa stratégie de réinitialisation et son isolation en test.
|
|
|
|
## Conséquences
|
|
|
|
- Les dépendances et leur durée de vie sont visibles à l'endroit où les scènes
|
|
sont assemblées.
|
|
- Un changement d'écran ne détruit pas les services applicatifs nécessaires à
|
|
la session.
|
|
- Une nouvelle campagne peut remplacer proprement la précédente sans conserver
|
|
ses signaux, caches ou acteurs.
|
|
- Les écrans sont testables avec des doubles légers et ne dépendent pas d'un
|
|
ordre d'initialisation d'autoloads.
|
|
- La composition contient davantage de code d'assemblage explicite et doit
|
|
rester distincte des règles de gameplay.
|
|
- Les transitions doivent libérer leurs objets de portée courte et seront
|
|
couvertes par des tests d'intégration et de fuite de nœuds.
|
|
- Les fonctionnalités transversales passent par des ports nommés plutôt que par
|
|
une commodité globale.
|
|
|
|
## Alternatives considérées
|
|
|
|
- **Un autoload par service** : rejeté, car sauvegarde, campagne, audio et
|
|
navigation deviendraient accessibles et mutables depuis toutes les couches.
|
|
- **Un unique `GameManager` autoload** : rejeté, car il concentrerait
|
|
assemblage, navigation et règles dans un propriétaire générique.
|
|
- **Un bus d'événements global** : rejeté, car producteurs et consommateurs
|
|
seraient reliés par des noms implicites et des durées de vie difficiles à
|
|
vérifier.
|
|
- **Remplacer toute la scène courante à chaque écran** : rejeté comme
|
|
navigation principale, car les services persistants devraient alors être
|
|
globaux ou reconstruits avec un état dupliqué.
|
|
- **Rechercher les services dans les parents ou par groupe Godot** : rejeté,
|
|
car la dépendance resterait cachée et dépendrait de la forme de l'arbre.
|