LifePlay-Revival/Docs/Migration/etat/CAM/CAM-B2f-IMPL.md
edujiro5972 8084622450 LifePlay UE 5.8 : état de développement au 2026-10-19
Tickets : REP1-T4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:57:42 +02:00

205 lines
16 KiB
Markdown

Fiche CAM-B2f (+ amendement B2f-a) — Niveau N3 — Modèle prévu non précisé (`CAM-TACHES.md:29`, fiche § 2) | utilisé claude-opus-5-5 — Agent lp-mcp-bp — Skills sk-protocol, sk-change-safety, lp-mcp, lp-lot
# CAM-B2f-IMPL : Room, sonde C2 de Camera à Visibility par MCP (2026-10-13)
Résultat : **réussi après l'amendement B2f-a**. Premier passage : arrêt à l'étape 6, car `save_assets` n'avait rien
écrit (Constats C1 à C5). Reprise B2f-a (fiche § 5) : on a créé puis supprimé un nœud Branche isolé pour marquer
Room comme modifié. Ensuite `is_dirty` = vrai, relecture conforme, compilation stricte sans exception, et Room
enregistré seul. MD5 de Room `CA2A9A0B…` → `F2B082D2…` ; GI et Person sont inchangés (section B2f-a).
## 1. Fichiers modifiés
- `Content/BPs/Room.uasset` : graphe `EventGraph`, nœuds `K2Node_CallFunction_459`, `_499` et `_505`. Broche
`TraceChannel` (entrée, index 4) passée de `TraceTypeQuery2` à `TraceTypeQuery1`. Aucun autre changement voulu :
le nœud temporaire `K2Node_IfThenElse_101` a été créé puis supprimé avant l'enregistrement. MD5 avant
`CA2A9A0BAACA4130FD5C318797F008AE` (6 378 087 octets), après `F2B082D2911D9F7C7BE60C2CF30EE6D5` (6 378 021 octets),
enregistré le 2026-10-13 à 19:50:29 (heure locale).
- `Docs/Migration/etat/CAM/CAM-B2f-IMPL.md` : ce livrable (nouveau).
- Effet de bord, hors dépôt : la sauvegarde automatique de l'éditeur a écrit `Saved/Autosaves/Game/BPs/Room_Auto1.uasset`
et `Saved/Autosaves/PackageRestoreData.json` à 19:47:39 (heure locale), entre `create_node` et `delete_node`
(section B2f-a, A3).
## 2. Écarts à la SPEC
- E1 (premier passage, résolu par B2f-a) : `save_assets` → `true` sans rien écrire (`Tous les fichiers sont déjà
enregistrés.`), parce que `set_pin_value` ne marque pas Room comme modifié (Constats C3).
- E2 (non bloquant) : le `type_id` des nœuds est `Collision|SphereTraceByChannel`, le nom d'affichage de
`UKismetSystemLibrary::SphereTraceSingle` (`KismetSystemLibrary.h:1299-1300` du moteur 5.8 installé).
- E3 (B2f-a, prescrit par l'amendement) : un nœud a été créé puis supprimé, alors que la fiche § 2 disait « aucun nœud
créé ni supprimé ». Le graphe final n'a pas ce nœud : `find_nodes` ne le liste plus (section B2f-a, A2).
- E4 (B2f-a, lectures en plus des étapes) : `get_node_infos` du nœud créé, avant et après `delete_node`, et
`find_nodes` pour vérifier sa disparition. Le premier `find_nodes` a été refusé par le schéma (`title` obligatoire,
erreur de paramètre de ma part) et refait une fois avec `title: ""`, comme le prévoit `lp-mcp` § 3.
- E5 (B2f-a, effet de bord) : la sauvegarde automatique de l'éditeur dans `Saved/Autosaves` (A3). Aucun fichier de
`Content` n'a été écrit par elle (mesuré).
- `hyper_blueprint_debug_inspect` est absent du serveur. Repli appliqué : `compile_blueprint {warnings_as_errors:true}`
+ journal de l'éditeur.
## 3. Instantané
- Pris par l'orchestrateur avant tout appel : `.\Tools\Snapshot.ps1 -Lot CAM-B2f`. Manifeste
`D:\Game\LifePlay_Backup_5.5\CAM-B2f\manifest.csv`, lu le 2026-10-13 à 19:38 (heure locale) :
```
"Rel","Existed","Size","MD5","Date"
"Content\BPs\Room.uasset","True","6378087","CA2A9A0BAACA4130FD5C318797F008AE","2026-10-13T19:36:19"
```
- Contrôle C9a avant écriture : `md5sum Content/BPs/Room.uasset` → `ca2a9a0baaca4130fd5c318797f008ae` (= attendu).
- Retour arrière (proposé, non lancé) : `.\Tools\Restore.ps1 -Lot CAM-B2f -WhatIf`, puis
`.\Tools\Restore.ps1 -Lot CAM-B2f -Only Content\BPs\Room.uasset`, éditeur fermé, sur accord.
## 4. Ce qui n'a pas été fait
- Pas de comptage des 1260 nœuds de Room : il revient à la VAL (V5, dump).
- Pas de `CompileAllBlueprints`, pas de build, pas de commandlet, pas de jeu (hors fiche).
- L'éditeur n'a pas été fermé (pid 28928, toujours ouvert) : c'est à l'orchestrateur, puis `BUILD-FIN`.
- Je n'ai pas nettoyé `Saved/Autosaves` (A3) : c'est signalé ici, pas supprimé.
## 5. Points à confirmer en VAL
- V5 dump Room (`-BP=Room -Fn=* -Pins -Exec`) : `TraceTypeQuery1` sur 459, 499 et 505, et 1260 nœuds. Aucun
`K2Node_IfThenElse_101` dans le dump.
- Diff du dump avec celui de l'instantané (`CA2A9A0B`) : seules les 3 valeurs `TraceChannel` changent. La taille
du fichier baisse de 66 octets (6 378 087 → 6 378 021). Cause non vérifiée : vignette régénérée à l'enregistrement,
sérialisation ou autre.
- MD5 de Room = `F2B082D2911D9F7C7BE60C2CF30EE6D5` à l'ouverture de la VAL (sinon, quelqu'un a réécrit Room).
- V6 `CompileAllBlueprints` = référence ; V7 dans le build COMMUN-3.
- Au prochain lancement de l'éditeur, ne pas accepter la restauration de `Room_Auto1` si elle est proposée : c'est un
état intermédiaire, qui contient le nœud temporaire (A3).
## 6. Fichiers à commiter
Dépôt du jeu, `D:\Game\LifePlay-master 5.8`, branche `ue5.8` :
- `A Docs/Migration/etat/CAM/CAM-B2f-IMPL.md`
- `M Content/BPs/Room.uasset` (MD5 `F2B082D2911D9F7C7BE60C2CF30EE6D5`). À confirmer par l'orchestrateur : Room était
déjà `M` avant cette fiche (état git du début de session ; l'instantané `CA2A9A0B` n'est pas la version de HEAD).
Le commit de Room portera donc aussi les changements non commités d'avant B2f.
- `Saved/Autosaves/…` : rien à commiter (dossier ignoré).
Tours : 51 / 60
## Constats
### C1. Premier passage : appels MCP dans l'ordre (un par message, journal `D:\Game\LifePlay_Backup_5.5\CAM-B2f\editeur\editeur-B2f.log`, heures UTC)
| # | Appel | Retour | Journal |
|---|---|---|---|
| 1 | `AssetTools.load_asset {asset_path:"/Game/BPs/Room"}` | `{"refPath":"/Game/BPs/Room.Room"}` | l. 2243-2244, 17:38:43 |
| 2 | `BlueprintTools.get_node_infos` (459, 499, 505 groupés) | 3 nœuds, lus en C2 | l. 2251-2252 |
| 3 | `set_pin_value {pin:{EGPD_Input, 4, …CallFunction_459}, value:"TraceTypeQuery1"}` | `null` | l. 2253-2254 |
| 4 | `set_pin_value` idem sur `…CallFunction_499` | `null` | l. 2255-2256 |
| 5 | `set_pin_value` idem sur `…CallFunction_505` | `null` | l. 2257-2258 |
| 6 | `get_node_infos` (459, 499, 505 groupés), relecture | 3 nœuds, lus en C2 | l. 2259-2260 |
| 7 | `compile_blueprint {blueprint:{refPath:"/Game/BPs/Room.Room"}, warnings_as_errors:true}` | `null` (pas d'exception) | l. 2261-2264 |
| 8 | `AssetTools.save_assets {asset_paths:["/Game/BPs/Room"]}` | `true`, mais `Tous les fichiers sont déjà enregistrés.` | l. 2265-2267 |
Aux lignes 2234-2245 (17:38:43-44), le client se reconnecte au moment du premier appel : `Unknown session id …
client should reinitialize`, puis `Call to unknown method "server/discover"`. L'appel 1 est passé ensuite sans erreur.
### C2. Nœuds touchés : avant et après (refPath `/Game/BPs/Room.Room:EventGraph.K2Node_CallFunction_<n>`)
| Nœud | Position | `TraceChannel` (index 4) avant → après | Radius | bIgnoreSelf | ActorsToIgnore ← | execute ← | then → | Start ← | End ← | OutHit → | ReturnValue → |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 459 | 35750, 1500 | `TraceTypeQuery2` → `TraceTypeQuery1` | 20.0 | true | MakeArray_5 [0] | CallFunction_494 [0] | IfThenElse_90 [0] | CallFunction_455 [0] | CallFunction_495 [0] | CallFunction_460 [0] | IfThenElse_90 [1] |
| 499 | 31450, 4500 | `TraceTypeQuery2` → `TraceTypeQuery1` | 20.0 | true | MakeArray_5 [0] | CallFunction_467 [0] | CallFunction_474 [0] | CallFunction_455 [0] | CallFunction_468 [0] | CallFunction_500 [0] | CallFunction_501 [2] |
| 505 | 38450, 1500 | `TraceTypeQuery2` → `TraceTypeQuery1` | 20.0 | true | MakeArray_5 [0] | IfThenElse_95 [0] | VariableSet_66 [0] | CallFunction_455 [0] | CallFunction_504 [0] | CallFunction_506 [0] | CallFunction_507 [2] |
Sur les 3 nœuds, lors des trois lectures (appels 2, 6 et B2f-a n° 16) : `bTraceComplex` false, `DrawDebugType` None,
`TraceColor` (1,0,0,1), `TraceHitColor` (0,1,0,1), `DrawTime` 5.0. Les relectures ne diffèrent de la première
lecture que par `TraceChannel`.
### C3. Cause de E1 (établie dans les sources du moteur 5.8 installé, `D:\Game\Launcher\Engine\UE_5.8`)
- `set_pin_value` → `UBlueprintGraphPinLibrary::SetPinValue`
(`Engine/Source/Editor/BlueprintEditorLibrary/Private/BlueprintEditorLibrary/BlueprintGraphPin.cpp:79`) appelle
`Schema->TrySetDefaultValue(*NativePin, Value, false)`. Le 3e paramètre est `bMarkAsModified`, `true` par défaut
(`Engine/Source/Editor/BlueprintGraph/Classes/EdGraphSchema_K2.h:576`).
- `save_assets` (`Engine/Plugins/Experimental/Toolsets/EditorToolset/Content/Python/editor_toolset/toolsets/asset.py:343-349`)
appelle `eas.save_asset(path)`, donc avec `bOnlyIfIsDirty = true`
(`Engine/Source/Editor/UnrealEd/Public/Subsystems/EditorAssetSubsystem.h:296`). Un paquet non marqué n'est pas écrit,
et l'appel rend `true`.
- Dans `asset.py` et `blueprint.py`, aucun outil ne marque un paquet comme modifié. Seul l'outil de lecture
`AssetTools.is_dirty` existe (`asset.py:353`).
### C4. Mesuré à la fin du premier passage
```
$ md5sum Content/BPs/Room.uasset Content/BPs/GI.uasset Content/BPs/Person.uasset
ca2a9a0baaca4130fd5c318797f008ae *Content/BPs/Room.uasset
e64b5b37c9ef0db7735de0d6e3bd7c1c *Content/BPs/GI.uasset
8668a47c627f7a5254910cf0ac33b12a *Content/BPs/Person.uasset
```
Fin du journal : `[2026.10.13-17.39.53:161][942]LogFileHelpers: Tous les fichiers sont déjà enregistrés.`
### C5. Options proposées après le premier passage
On a retenu l'option 1 : marquer Room comme modifié dans la même session, avec les outils de la fiche. L'orchestrateur
l'a prescrite dans l'amendement B2f-a (fiche § 5).
## B2f-a : reprise (amendement, fiche § 5)
### A1. Appels MCP dans l'ordre (un par message, même journal, heures UTC)
| # | Appel | Retour | Journal |
|---|---|---|---|
| 9 | `create_node {graph:{refPath:"/Game/BPs/Room.Room:EventGraph"}, type_id:"Utilitaires\|ContrôleDeFlux\|Branche", pos:{x:-20000, y:-20000}}` | `{"refPath":"/Game/BPs/Room.Room:EventGraph.K2Node_IfThenElse_101"}` | l. 2272-2273, 17:47:29 |
| 10 | `get_node_infos` `K2Node_IfThenElse_101` | Branche, position (-20000, -20000), 4 broches (execute, Condition = true, then, else), 0 lien | l. 2274-2275 |
| 11 | `delete_node {node:{refPath:"…K2Node_IfThenElse_101"}}` | `null` | l. 2286-2287, 17:47:41 |
| 12 | `AssetTools.is_dirty {asset_path:"/Game/BPs/Room"}` | **`true`** | l. 2288-2289 |
| 13 | `get_node_infos` `K2Node_IfThenElse_101` | se résout encore (même contenu) : objet en attente du ramasse-miettes, voir A2 | l. 2290-2291 |
| 14 | `find_nodes {graph, node_class:K2Node_IfThenElse}` | refusé : `input param "title" is required` | l. 2292-2293 |
| 15 | `find_nodes {graph, title:"", node_class:{refPath:"/Script/BlueprintGraph.K2Node_IfThenElse"}}` | liste des Branche du graphe : `K2Node_IfThenElse_101` **absent**, plus grand numéro listé `_100` | l. 2294-2295 |
| 16 | `get_node_infos` (459, 499, 505 groupés) | `TraceTypeQuery1` sur les 3, reste identique à C2 | l. 2296-2297 |
| 17 | `compile_blueprint {blueprint:{refPath:"/Game/BPs/Room.Room"}, warnings_as_errors:true}` | `null` (pas d'exception) | l. 2298-2301 |
| 18 | `AssetTools.save_assets {asset_paths:["/Game/BPs/Room"]}` | `true`, Room écrit | l. 2305-2338, 17:50:28 |
### A2. Nœud temporaire : créé, puis retiré du graphe
- Avant suppression (appel 10), le nœud était bien celui que j'avais créé : `type_id` Branche, position (-20000,
-20000), aucun lien.
- Après `delete_node`, il se résout encore par son refPath (appel 13). C'est normal : `UEdGraphNode::DestroyNode`
appelle `ParentGraph->RemoveNode(this)` avec le commentaire « Will be GC'd after this »
(`Engine/Source/Runtime/Engine/Private/EdGraph/EdGraphNode.cpp:554-560`), et `UEdGraph::RemoveNode` le retire de
`Nodes` (`EdGraph.cpp:266`). L'objet reste en mémoire jusqu'au ramasse-miettes.
- `find_nodes` parcourt `bp_editor.list_all_nodes()` (`blueprint.py:706-709`) et ne le liste plus (appel 15).
- `delete_node` → `UBlueprintGraphEditor::RemoveNodes` → `FBlueprintEditorUtils::RemoveNode(Blueprint, Node, true)`
(`Engine/Source/Editor/BlueprintEditorLibrary/Private/BlueprintEditorLibrary/BlueprintGraphEditor.cpp:1576-1598`).
### A3. Sauvegarde automatique de l'éditeur (effet de bord)
À 17:47:39 UTC, entre les appels 10 et 11, l'éditeur a fait sa sauvegarde automatique (l. 2276-2285) :
```
[2026.10.13-17.47.39:691][ 90]LogFileHelpers: Editor autosave (incl. external actors) for '/Game/Scenes/CentralLondon' took 0.099
[2026.10.13-17.47.39:871][ 90]Cmd: OBJ SAVEPACKAGE PACKAGE="/Game/BPs/Room" FILE="../../../../../../LifePlay-master 5.8/Saved/Autosaves/Game/BPs/Room_Auto1.uasset" SILENT=false AUTOSAVING=true
[2026.10.13-17.47.40:602][ 90]LogFileHelpers: Auto-saving content packages took 0.911
```
Mesuré juste avant l'appel 18 (19:50:22, heure locale) :
```
$ find Content -newermt "-20 minutes" -type f
(aucune ligne)
$ find Saved/Autosaves -newermt "-20 minutes" -type f
Saved/Autosaves/Game/BPs/Room_Auto1.uasset
Saved/Autosaves/PackageRestoreData.json
$ md5sum Content/BPs/Room.uasset
ca2a9a0baaca4130fd5c318797f008ae *Content/BPs/Room.uasset
```
`Room_Auto1.uasset` contient l'état intermédiaire, avec `K2Node_IfThenElse_101` (estimé : la sauvegarde a eu lieu
avant l'appel 11). Je ne l'ai pas supprimé. Je ne sais pas si `PackageRestoreData.json` a été remis à jour par
l'enregistrement de l'appel 18 : c'est incertain, et la lecture de ce fichier le trancherait.
### A4. Enregistrement (appel 18), journal
```
[2026.10.13-17.50.28:576][ 47]LogFileHelpers: Saving Package: /Game/BPs/Room
[2026.10.13-17.50.28:587][ 47]Cmd: OBJ SAVEPACKAGE PACKAGE="/Game/BPs/Room" FILE="../../../../../../LifePlay-master 5.8/Content/BPs/Room.uasset" SILENT=true
[2026.10.13-17.50.29:171][ 47]LogSavePackage: Moving output files for package: /Game/BPs/Room
[2026.10.13-17.50.29:229][ 48]AssetCheck: /Game/BPs/Room Validation de la ressource
```
Seul `/Game/BPs/Room` a été enregistré. Le journal finit à la ligne 2338. On compte 0 ligne `Error` ou `Warning`
depuis la ligne 2265 (`tail -n +2265 <journal> | grep -c -E "Error|Warning"` → `0`).
### A5. Mesuré après l'appel 18 (19:50:36, heure locale)
```
$ md5sum Content/BPs/Room.uasset Content/BPs/GI.uasset Content/BPs/Person.uasset
f2b082d2911d9f7c7be60c2cf30ee6d5 *Content/BPs/Room.uasset
e64b5b37c9ef0db7735de0d6e3bd7c1c *Content/BPs/GI.uasset
8668a47c627f7a5254910cf0ac33b12a *Content/BPs/Person.uasset
$ stat -c '%y %s %n' Content/BPs/Room.uasset Content/BPs/GI.uasset Content/BPs/Person.uasset
2026-10-13 19:50:29.168177700 +0200 6378021 Content/BPs/Room.uasset
2026-10-13 19:26:08.639049400 +0200 52636801 Content/BPs/GI.uasset
2026-10-13 17:42:36.059256500 +0200 20821244 Content/BPs/Person.uasset
$ find Content -newermt "-25 minutes" -type f
Content/BPs/GI.uasset
Content/BPs/Room.uasset
```
- Room : MD5 différent de `ca2a9a0b…` (attendu), date 19:50:29, soit l'appel 18.
- GI : `e64b5b37…` (attendu, inchangé). Il apparaît dans la fenêtre de 25 minutes à cause de sa date, 19:26:08. Elle
est antérieure à cette fiche : on la relevait déjà à 19:39, dans C4.
- Person : `8668a47c…` (attendu, inchangé), date 17:42:36.
À verser : lp-mcp § 3 — `set_pin_value` ne marque pas le Blueprint comme modifié (`BlueprintGraphPin.cpp:79`, `TrySetDefaultValue(…, false)`), et `save_assets` n'enregistre que les paquets marqués (`asset.py:348`, `EditorAssetSubsystem.h:296`). Un `true` accompagné de « Tous les fichiers sont déjà enregistrés » veut dire que rien n'a été écrit. Le moyen qui marche : `create_node` d'une Branche isolée, puis `delete_node`, puis `is_dirty` = vrai avant `save_assets`, et contrôle du MD5 après. Autres points : un nœud supprimé se résout encore par refPath jusqu'au ramasse-miettes, c'est `find_nodes` qui fait foi ; `find_nodes` exige `title` (`""` pour tous) ; un paquet marqué déclenche la sauvegarde automatique de l'éditeur dans `Saved/Autosaves`.
Suite : l'orchestrateur doit fermer l'éditeur (pid 28928), faire `BUILD-FIN`, puis lancer la VAL (V5 dump Room, V6) et le ticket au gardien. État : Room enregistré (`F2B082D2…`), GI et Person inchangés, éditeur encore ouvert.