LifePlay-Revival/Docs/Migration/etat/REL/STM1/STM1-SPEC-03.md

187 lines
17 KiB
Markdown
Raw Normal View History

Fiche STM1-SPEC-03 — Niveau N2 — Modèle prévu opus medium | utilisé claude-opus-5-5 — Agent session « Medium · STM1 » (pas de sous-agent) — Skills sk-protocol, lp-ue-compat
# STM1-SPEC-03 : SPEC exécutable du pilote Londres, option O-B (eau par maillage) (2026-10-20)
Ordre : Big Boss (`local_104ff22d`). Décisions de l'utilisateur sur STM1-SPEC-02, citées par Big Boss : « un pilote sur Londres d'abord » ;
« l'accord pour télécharger des extraits OSM : approuvé » ; « eau visible aussi en mode classique oui » ; « appouve O-B ».
Consignes : annoncer la source exacte, la taille et la licence de chaque extrait **avant** tout téléchargement ; téléchargement dans un
dossier neuf hors dépôt ; fichiers jamais exécutés, lus par un outil séparé ; **pas d'IMPL ni de copie UE sans GO**. Rien n'a été téléchargé ni modifié par cette fiche.
## 0. Annonce des extraits (à relayer à l'utilisateur avant téléchargement)
| # | Extrait | Source exacte | Taille | Licence |
|---|---|---|---|---|
| D1 | **Eau** de la boîte de Londres : `natural=water`, `water=*`, `waterway=riverbank`, `landuse=reservoir/basin`, voies **et relations**, avec géométrie | API Overpass publique, `POST https://overpass-api.de/api/interpreter`, requête Q1 (§ 2.1), sortie XML `out geom` | **estimée 2 à 10 Mo** (plafond imposé dans la requête : `[maxsize:52428800]`, 50 Mo) ; taille réelle notée au téléchargement | données © OpenStreetMap contributors, **ODbL 1.0** (https://www.openstreetmap.org/copyright) ; usage de l'API selon la politique des instances publiques (https://wiki.openstreetmap.org/wiki/Overpass_API, usage raisonnable, deux requêtes) |
| D2 | **Bâtiments nommés** de la même boîte (`way["building"]["name"]`), avec géométrie, pour le recalage | même API, requête Q2 (§ 2.1) | **estimée 15 à 60 Mo** (plafond `[maxsize:209715200]`, 200 Mo) | idem, ODbL 1.0 |
| (écarté) | extrait complet Grand Londres Geofabrik | `https://download.geofabrik.de/europe/united-kingdom/england/greater-london-latest.osm.pbf` | 123 Mo (page Geofabrik : « File size: 123 MB », données jusqu'au 2026-10-18T20:25:06Z) | ODbL 1.0 |
L'extrait Geofabrik n'est **pas proposé** : format PBF, illisible par le lecteur XML du plugin (`OSMFile.cpp`) ; il faudrait installer un outil
tiers (osmium). Les deux requêtes Overpass donnent du XML directement lisible.
**Dossier de téléchargement** (neuf, hors dépôt) : `D:\Game\LifePlay_Data\OSM\STM1-PILOTE-20261020\` (`q1-eau.osm.xml`, `q2-batiments.osm.xml`,
plus les deux requêtes en `.txt` et un `LISEZMOI.txt` : source, date, taille, MD5, licence). Téléchargement par `curl --data-urlencode` dans une commande à part.
Les fichiers ne sont **jamais exécutés** : seul le commandlet du § 3 les lit, comme du XML.
## 1. Données établies (lecture, sans copie UE)
- Projection des cartes : sinusoïdale, relative à l'origine `(RelLat, RelLon)` du `.osm` d'origine (moyenne des nœuds), en centimètres :
`x = (Lon − RelLon) · cos(Lat) · k`, `y = −(Lat − RelLat) · k`, avec `k = 40 075 036 / 360 × 100` cm par degré
(`Plugins/StreetMap/Source/StreetMapImporting/StreetMapFactory.cpp:8-9, 53-80`). L'origine n'est **pas** stockée (STM1-SPEC-02 § 1).
- `UStreetMap` CentralLondon : 49 425 bâtiments, dont **12 092 nommés**, et 0 eau (CSV U8-T7b) ; `BoundsMin/BoundsMax` disponibles (`StreetMap.h:173-177`).
- Maillage `Static/CentralLondon` : 11 232 × 8 090 m, hauteur 310 m (`L7h_meshes_55.csv`), une section, `StreetMapMasked`.
- Triangulation avec trous : `UE::Geometry::TConstrainedDelaunay2<double>` (`Add(TPolygon2, bIsHole)`, `EFillRule`, `Triangulate()`, sortie `Triangles`) ou
`ConstrainedDelaunayTriangulate(TGeneralPolygon2)` : `Engine/Plugins/Runtime/GeometryProcessing/Source/GeometryAlgorithms/Public/ConstrainedDelaunay2.h:25-166`.
Plugin `GeometryProcessing` monté dans l'éditeur (`Saved/Logs/LifePlay.log` : « Mounting Engine plugin GeometryProcessing ») mais **absent** de `LifePlay.uproject`.
- Création de maillage : `UStaticMesh::BuildFromMeshDescriptions` (`StaticMesh.h:1891`).
- Cuisson : `+DirectoriesToAlwaysCook=(Path="/Game")` (`Config/DefaultGame.ini:51`) : un asset sous `/Game/Heavy/StreetMap/Water/` est cuit sans réglage de plus.
- `LifePlayEditorTools.Build.cs` a `MeshDescription` et `StreetMapRuntime`, mais **pas** `XmlParser` ni `GeometryAlgorithms` ni `StaticMeshDescription`.
## 2. Étapes du pilote
### 2.1 Données (D1, D2), après accord relayé par Big Boss
Boîte englobante généreuse, l'origine étant inconnue (la carte fait 11,2 × 8,1 km autour du centre de Londres) : **sud 51,44 ; ouest −0,25 ; nord 51,58 ; est 0,05**
(≈ 15,5 × 20,9 km). Le recalage (§ 2.2) ne garde que ce qui tombe dans les bornes de la carte.
Q1 (eau) :
```
[out:xml][timeout:180][maxsize:52428800][bbox:51.44,-0.25,51.58,0.05];
( way["natural"="water"]; relation["natural"="water"];
way["water"]; relation["water"];
way["waterway"="riverbank"]; relation["waterway"="riverbank"];
way["landuse"~"^(reservoir|basin)$"]; relation["landuse"~"^(reservoir|basin)$"]; );
out geom;
```
Q2 (bâtiments nommés) :
```
[out:xml][timeout:300][maxsize:209715200][bbox:51.44,-0.25,51.58,0.05];
way["building"]["name"];
out tags geom;
```
### 2.2 Recalage (seuil 2 m)
1. Apparier par nom exact, sans tenir compte de la casse : les bâtiments nommés de l'`UStreetMap` (`Name`, `BuildingPoints`) contre ceux de D2. On écarte les noms ambigus (plus d'une occurrence d'un côté ou de l'autre).
2. Pour chaque paire : centroïde de l'asset `(x, y)` (moyenne des points) et centroïde OSM `(Lat, Lon)` (moyenne des nœuds) ;
`RelLat_i = Lat + y / k` ; `RelLon_i = Lon − x / (k · cos Lat)`.
3. Origine = **médiane** des `RelLat_i` et des `RelLon_i`. Résidu de chaque paire = distance entre `(x, y)` et la projection de `(Lat, Lon)` avec l'origine retenue.
4. **Critères d'acceptation** (version initiale) : au moins 500 paires ; résidu médian **≤ 2 m (200 cm)** ; au moins 80 % des paires sous 5 m. Sinon : arrêt, rapport, aucun asset écrit.
**Changement (décision de Big Boss, 2026-10-20, après le DryRun R1 : 4 523 paires, médiane 129 cm, 79,2 % sous 5 m)** :
- **estimation** en deux passes : origine de passe 1 sur toutes les paires ; rejet des paires au-delà de médiane + 3 × MAD ; origine de passe 2 sur les paires retenues ; nombre d'écartées noté ;
- **critères** : au moins 500 paires **retenues** ; résidu médian (paires retenues) ≤ 2 m ; **taux de paires retenues ≥ 70 %** des paires appariées.
Motif cité : appliquer « ≥ 80 % sous 5 m » aux seules paires retenues après rejet le rendrait vrai par construction (critère circulaire).
Rapportés pour information : la part sous 5 m sur **toutes** les paires avec l'origine corrigée, et le déplacement de l'origine entre les deux passes (cm).
Le juge final reste l'essai visuel du pilote (eau sur les quais).
Les centres de boîte remplacent les centroïdes : l'extrait D2 ne contient que les `<bounds>` (STM1-B2-FIN § 2-6).
5. Contrôle croisé : les bornes du maillage `Static/CentralLondon` doivent recouvrir celles de l'`UStreetMap` (écart d'au plus 1 m). Cela vérifie que le maillage partage le repère des données. Sinon : arrêt.
### 2.3 Polygones et triangulation
- Q1 `out geom` : une voie fermée = un polygone ; une relation = assemblage des membres `outer` et `inner` (chaînage par extrémités communes ; anneaux non fermés : arrêt du polygone, compté dans le rapport).
- Projection avec l'origine du § 2.2, puis découpe à la boîte de la carte (`BoundsMin/BoundsMax` + 50 m).
- Triangulation : `TConstrainedDelaunay2<double>`, extérieurs `bIsHole=false`, intérieurs `bIsHole=true`, `FillRule = Positive` après orientation (extérieurs dans le sens trigonométrique), `Triangulate()`.
- Rapport : nombre de polygones, de trous, de triangles et de sommets ; aire totale d'eau en km². Attendu indicatif pour la Tamise dans la carte : plusieurs km².
### 2.4 Commandlet `ULPBuildCityWaterCommandlet` (`Source/LifePlayEditorTools`, neuf)
- Ligne : `-run=LPBuildCityWater -City=CentralLondon -Water=<q1> -Buildings=<q2> [-DryRun] [-Report=<chemin .md sous etat\REL\STM1\>]`.
- Lecture XML par `FXmlFile` (module `XmlParser`), recalage (§ 2.2), triangulation (§ 2.3).
- Création du `StaticMesh` `/Game/Heavy/StreetMap/Water/CentralLondon` par `FMeshDescription` et `BuildFromMeshDescriptions` :
- une section, matériau `M_LP_Water` ;
- normales vers le haut, UV en mètres ;
- sans collision, sans lightmap (`bGenerateLightmapUVs = false`) ;
- Z = 0 dans le repère de la carte.
- `-DryRun` : rapport seul, aucun asset. Sans `-DryRun` : instantané `Tools\Snapshot.ps1` d'abord (nouveau dossier : instantané vide, noté), puis sauvegarde du paquet.
- `Build.cs` : ajouter `XmlParser`, `GeometryAlgorithms`, `GeometryCore`, `StaticMeshDescription` aux dépendances privées.
- `LifePlay.uproject` : **non touché** dans l'option G1 recommandée (§ 5 bis). L'ajout du plugin `GeometryProcessing` (G2) demanderait une décision de l'utilisateur.
### 2.5 Matériau `M_LP_Water` (neuf, `/Game/Heavy/StreetMap/Water/M_LP_Water`)
Opaque, **deux faces** (`TwoSided`, pour ne pas dépendre de l'enroulement des triangles), `MSM_DefaultLit`, couleur de base (0,03 ; 0,18 ; 0,32), rugosité 0,15, spéculaire 0,5. Pas de normale animée au pilote (option ensuite).
Créé par MCP (`MaterialTools.create_material` et `connect_to_output`) sous instantané, ou à la main. Aucun matériau existant touché.
### 2.6 Sous-système de pose `ULPCityWaterSubsystem` (`Source/LifePlay`, neuf, **présent aussi en Shipping**)
- `UGameInstanceSubsystem` ; ticker de 0,25 s, même détection que la trace : maillage de `GI.StreetMapStatic.StaticMeshComponent` (lecture par réflexion, aucun appel ni écriture dans le GI).
- Au changement de maillage :
- déduire le nom de la ville du maillage (`/Game/Heavy/StreetMap/Static/<Ville>`) ;
- charger `/Game/Heavy/StreetMap/Water/<Ville>` s'il existe (sinon, rien) ;
- créer ou réutiliser **un** `UStaticMeshComponent` attaché à la racine de `StreetMap_Static`, sans collision, sans ombre.
- **Hauteur Z** : au-dessus du sol pavé (`Plane` de `MapMarkers`, lu par réflexion) de **+2 cm**. Repli si le plan n'est pas trouvé : le Z mesuré au pilote, écrit en constante.
- **Visible aussi en mode classique** (décision de l'utilisateur) : aucune dépendance à `ClassicMap`.
- Ville sans eau : composant masqué.
- Ligne de journal `LogLifePlay` à chaque pose : ville, asset, Z. La trace `[LPCity]` reste inchangée.
### 2.7 Lecture préalable (PIE, lecture seule, avec jeton)
Avant l'IMPL du § 2.6 : en PIE, relever la transformation du `Plane` de `MapMarkers` (Z monde, échelle) et celle de `StreetMap_Static` après `MoveCity`.
Elle n'a pas pu être lue hors PIE (CART-04 § 5). Si la PIE est refusée, on prend le repli constant et on règle le Z à l'essai.
## 3. Ordre et jetons
| Étape | Fiche | Copie UE | Écrit |
|---|---|---|---|
| 1 | téléchargement D1, D2 (après accord relayé) | non | dossier hors dépôt seulement |
| 2 | IMPL commandlet + `Build.cs` + `uproject` (§ 2.4) | non (code) | sources sous instantané, CHG |
| 3 | BUILD éditeur (lp-builder) | **oui** | — |
| 4 | commandlet `-DryRun` : rapport de recalage (critères § 2.2) | **oui** | rapport seul |
| 5 | matériau `M_LP_Water` et commandlet réel | **oui** | 2 assets sous `Content/Heavy/StreetMap/Water/` (hors git, instantané) |
| 6 | lecture PIE (§ 2.7) | **oui** | — |
| 7 | IMPL sous-système (§ 2.6), BUILD, VAL distincte | oui (build) | sources, CHG |
| 8 | essai utilisateur (build Development) : vue de la Tamise, modes par défaut et classique ; captures | — | — |
## 4. Critères d'acceptation du pilote
| # | Critère | Preuve |
|---|---|---|
| P1 | recalage : au moins 500 paires, résidu médian ≤ 2 m, au moins 80 % sous 5 m | rapport du commandlet |
| P2 | maillage d'eau créé, triangles > 0, aire ≥ 1 km², sans collision | rapport, lecture MCP |
| P3 | en jeu, mode par défaut : la Tamise apparaît bleue, alignée sur les quais (écart visuel < 5 m) ; pas de scintillement avec le pavé | captures de l'utilisateur |
| P4 | en mode classique : eau visible aussi | capture |
| P5 | autres villes inchangées (pas d'asset d'eau = rien), `000Dummy` sans eau | essai sur une autre ville, journal |
| P6 | aucun asset existant modifié (GI, MapMarkers, StreetMap_*, matériaux, 280 cartes) | `CopieEtat` (MD5) |
| P7 | crédits : ligne ODbL avec source exacte (Overpass, date, requête) prête pour la DOC | brouillon de crédits |
## 5. Risques et parades
- **Recalage raté** : les données de 2020 ne correspondent plus (noms changés) → critères P1, arrêt avant tout asset.
- **Relations incomplètes** (membres coupés par la boîte) : la boîte est large, et les anneaux non fermés sont comptés et ignorés.
- **Scintillement** avec le `Plane` : 2 cm, réglable ; `TranslucencySortPriority` sans objet (opaque).
- **Eau recouvrant des pontons ou des ponts** (bâtiments dans le fleuve, CART-03 § 3) : attendu ; les bâtiments, plus hauts, restent au-dessus.
- **Charge sur l'API Overpass** : deux requêtes seulement, une seule fois.
- **Licence** : attribution ODbL ; les crédits du projet sont à compléter (règle « source exacte »).
## 5 bis. Téléchargement fait (étape 1, 2026-10-20) et point GeometryProcessing
Accord de l'utilisateur cité par Big Boss : « Oui, STM1 peut télécharger D1 et D2 depuis overpass-api.de dans D:\Game\LifePlay_Data\OSM\STM1-PILOTE-20261020\. »
| Fichier | HTTP | Taille | Annonce | Erreur Overpass | MD5 | Contenu |
|---|---|---|---|---|---|---|
| `q1-eau.osm.xml` (2026-10-20T08:04:13Z, `osm_base` 08:03:42Z) | 200 | 2 308 011 o | 2 à 10 Mo (plafond 50) : **conforme** | 0 `<remark>` | `4e9722b9db2539fc023cf830bf403538` | 713 voies, 88 relations ; `water=river` 78 (dont 4 relations multipolygones sans nom), `pond` 259, `basin` 56, `canal` 54, `lake` 24, `lock` 21, `reservoir` 8 ; `waterway=dock` 30 |
| `q2-batiments.osm.xml` (2026-10-20T08:04:59Z) | 200 | 15 484 375 o | 15 à 60 Mo (plafond 200) : **conforme** | 0 `<remark>` | `d441164aef0677f711a2e788cda5db16` | 29 246 bâtiments nommés |
Dossier : `D:\Game\LifePlay_Data\OSM\STM1-PILOTE-20261020\`, avec `q1-eau.txt`, `q2-batiments.txt` et `LISEZMOI.txt` (URL, requête, date, taille, MD5, licence). Deux requêtes, une fois chacune. Aucun fichier exécuté.
Restent aussi `d1-date.txt` et `d2-date.txt` (une ligne de date chacun, repris dans le LISEZMOI) : leur retrait a été refusé par la permission, sans autre tentative.
**GeometryProcessing et `LifePlay.uproject` (local, non commité par décision de l'utilisateur)**
Constat : `GeometryProcessing.uplugin` ne déclare pas `EnabledByDefault`. Le plugin est monté parce que des plugins actifs en dépendent : `ChaosVD`,
`Dataflow`, `MeshLODToolset`, `ChaosClothAssetEditorCore`, … (`grep -rl '"GeometryProcessing"'` sur les `.uplugin` du moteur ; journal : « Mounting Engine plugin GeometryProcessing »).
| Option | Principe | Pour | Contre |
|---|---|---|---|
| **G1 (recommandée)** | dépendance de module seulement : `GeometryAlgorithms`, `GeometryCore` dans `LifePlayEditorTools.Build.cs` (éditeur seulement) ; `LifePlay.uproject` non touché | aucune modification du `.uproject` local ; le module est déjà présent dans la cible éditeur par dépendance transitive (estimé) | fragile si l'un de ces plugins est désactivé un jour ; à **prouver au BUILD** (une erreur UBT « module introuvable » ferait passer à G2 ou G3) |
| G2 | ajouter `{"Name": "GeometryProcessing", "Enabled": true, "TargetAllowList": ["Editor"]}` au `.uproject` | explicite et robuste | le `.uproject` est local : **décision de l'utilisateur** requise, ligne à reporter à chaque copie |
| G3 | se passer de GeometryProcessing : triangulation par oreilles de `GeometryCore` (`CompGeom/PolygonTriangulation.h`, `Polygon2.h`), avec les trous raccordés à la main | seulement `GeometryCore` (module du moteur, sans plugin) | plus de code, et plus fragile sur les relations complexes (îles, docks) |
Seul le commandlet (éditeur) triangule ; le sous-système de jeu (§ 2.6) ne dépend d'aucun module de géométrie. La copie 5.8 n'est donc pas concernée en Shipping.
## 6. Incertitudes, écarts, fichiers
- Non vérifié : tailles réelles de D1 et D2 (estimées) ; Z et échelle du `Plane` (§ 2.7) ; repère commun maillage `Static` et `UStreetMap` (contrôle § 2.2.5) ; disponibilité de `TConstrainedDelaunay2` hors éditeur (seul le commandlet en a besoin : éditeur seulement).
- Fichiers écrits : `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\REL\STM1\STM1-SPEC-03.md` (A) ; `STM1-TACHES.md` (M).
Tours : ≈ 6 / 40 (déclaré ; `FicheStats.py` fait foi).
Suite : Big Boss doit relayer l'annonce du § 0 à l'utilisateur ; après son accord, téléchargement D1 et D2 (étape 1, sans copie UE), puis GO de l'IMPL du commandlet. État : SPEC prête, rien téléchargé.