From 4da0ce352581fb71c0db65c4fe812b67e2635ff0 Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 6 Oct 2026 19:36:31 +0200 Subject: [PATCH] docs: ADR 0012 authored heightfield dive sites Co-Authored-By: Claude Fable 5.1 --- .../0012-authored-heightfield-dive-sites.md | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 docs/adr/0012-authored-heightfield-dive-sites.md diff --git a/docs/adr/0012-authored-heightfield-dive-sites.md b/docs/adr/0012-authored-heightfield-dive-sites.md new file mode 100644 index 0000000..d554564 --- /dev/null +++ b/docs/adr/0012-authored-heightfield-dive-sites.md @@ -0,0 +1,68 @@ +# 0012 — Sites de plongée en champ de hauteur authoré + +- Statut : accepté +- Date : 2026-10-06 +- Remplace : aucun + +## Contexte + +Le seul terrain de production est une formule analytique codée dans +`vehicle_test_environment.gd`. La tranche 3 exige un site conçu à la main, +lisible au sonar (ADR 0010 : surface unique), avec une route sûre et une route +risquée, et le sonar a besoin de distinguer roche et sable par cellule, pas par +corps. Il faut un contrat de données pour le terrain, son stockage dans le +dépôt et sa production. + +## Décision + +1. Un site de plongée est décrit par une ressource typée `DiveSiteDefinition` + (`game/domain/sites/`) : identifiant, terrain, limites jouables, point de + départ, placements d'objets et routes de contrôle. +2. Le terrain est un champ de hauteur à surface unique `SiteTerrainData` : + grille régulière de `columns × rows` cellules de `cell_size_m` mètres, + élévations en mètres (axe Y monde, négatif sous la surface) dans un + `PackedFloat32Array`, matériau sonar par cellule dans un `PackedByteArray` + (`SonarMaterial.Value`, ROCK ou SAND). Repère : +X est, +Z sud, +Y haut ; + la colonne croît avec +X, la ligne avec +Z ; la cellule `(0, 0)` est à + `(origin_x_m, origin_z_m)`. +3. Les données sont cuites hors exécution par `tools/bake_site_terrain.gd` à + partir d'une recette déclarative de primitives géomorphologiques nommées + (plateau, crête, piton, sillon, rupture de pente, rides, rugosité + déterministe par graine). La recette est le document d'auteur versionné ; + le résultat est écrit en `.res` binaire sous `content/sites/`. Le jeu ne + génère jamais de terrain à l'exécution. +4. Un PNG 16 bits n'est pas utilisé pour les hauteurs : le chargeur d'images + de Godot ramène les PNG 16 bits en 8 bits, soit des marches de 0,27 m sur + 68 m de dénivelé. Un PNG 8 bits de prévisualisation est produit pour la + revue humaine seulement. +5. Un seul acteur de monde, `BathymetricTerrainActor`, construit le maillage + visuel et la `HeightMapShape3D` depuis le même champ ; un test compare les + deux. Il expose `sonar_material_at(position)` et + `sonar_reflectivity_at(position)` que l'acquisition sonar privilégie sur + les métadonnées de corps. +6. Les limites de la zone jouable sont une règle applicative + (`PlayableBoundsRule`) qui produit un avertissement ; elles ne sont jamais + un mur de terrain (ADR 0010). + +## Conséquences + +- L'environnement de test du véhicule devient une définition de site cuite, + sans formule analytique dans `game/`. +- Toute modification de terrain passe par la recette puis une cuisson ; les + fichiers `.res` sont des artefacts dérivés mais versionnés pour que le + chargement du site reste sous 3 s et que le jeu n'ait pas besoin de l'outil. +- Les tests de contrat de contenu peuvent vérifier profondeur, position et + dégagement des placements contre le champ de hauteur réel. +- Une sculpture manuelle (Blender) ultérieure devra ré-exporter vers le même + `SiteTerrainData` ; le contrat ne change pas. + +## Alternatives considérées + +- **Plugin de terrain externe** : rejeté, dépendance et ADR supplémentaires + sans besoin démontré ; une heightmap tuilée suffit à la V1. +- **Génération à l'exécution depuis la recette** : rejeté, le plan impose un + site conçu à la main et un chargement borné ; la cuisson garantit un + artefact figé et revu. +- **Heightmap PNG 16 bits** : rejeté pour la raison de précision ci-dessus. +- **Maillage sculpté sans champ de hauteur** : rejeté, le sonar et les tests + ont besoin d'une requête de hauteur et de matériau par position.