LifePlay-Revival/Docs/Migration/etat/CAM/CAM-B2e-IMPL.md

240 lines
17 KiB
Markdown
Raw Normal View History

Fiche CAM-B2e — Niveau N3 — Modèle prévu opus | utilisé claude-opus-5-5 (Opus 5.5) — Agent lp-mcp-bp — Skills sk-protocol, sk-change-safety, lp-mcp, lp-lot
# CAM-B2e-IMPL : boîte de pièce sur les faces intérieures des murs (2026-10-13)
Consignes : `CAM-B2e-FICHE.md` (règle, nœuds existants, écritures 1 à 8) ; rubriques communes de `CAM-B2b-FICHES.md`
(l. 23-63). UE-GO de Big Boss pour le passage Room B2d + B2e (2026-10-13, cité par l'orchestrateur). Éditeur headless
PID 22060, port 8000, connexion `unreal-mcp` partagée (MCPA-T1) ; Room chargé, B2d en mémoire (non touché).
Un seul `call_tool` par message. **60 appels MCP** : 21 `create_node`, 2 `get_node_infos`, 29 `connect_pins`,
4 `set_pin_value`, 1 `compile_blueprint`, 1 `save_assets`, 2 `ObjectTools.get_properties` (dont 1 en erreur de
schéma). Aucun `break_pins` (§ 2 E1), `delete_node`, `write_graph_dsl` ni `ProgrammaticToolset`. Aucune écriture par
HyperAIStudio.
## 1. Fichiers modifiés
- `Content/BPs/Room.uasset` : **enregistré** (`save_assets {asset_paths:["/Game/BPs/Room"]}` → `true`), B2d et B2e
ensemble. MD5 avant `e0517c63…` (= instantané), après `ca2a9a0baaca4130fd5c318797f008ae` (§ 3).
- Graphe `/Game/BPs/Room.Room:EventGraph`, nouveaux nœuds en x 38000-39150, y 1200-2000 (sous `ComputeRoomBox`).
### 1.1 Nœuds créés (préfixe `refPath` : `/Game/BPs/Room.Room:EventGraph.`)
| Chaîne | Rôle | `refPath` (suffixe) | `type_id` relu | Position |
|---|---|---|---|---|
| Wall1 (−X) | getter `Wall1` | `K2Node_VariableGet_297` | `\|GetWall1` (créé par `Variables\|Pardéfaut\|ObtenirWall1`) | 38000, 1200 |
| | `GetComponentBounds(Wall1)` | `K2Node_CallFunction_525` | `Collision\|GetComponentBounds` | 38300, 1200 |
| | O + E | `K2Node_PromotableOperator_37` | `Math\|Vecteur\|vector+vector` | 38650, 1200 |
| | + (30,30,0) | `K2Node_PromotableOperator_38` | `Math\|Vecteur\|vector+vector` | 38900, 1200 |
| | `BreakVector` → X | `K2Node_CallFunction_530` | `Math\|Vecteur\|BreakVector` | 39150, 1200 |
| Wall2 (+X) | `GetComponentBounds(283)` | `K2Node_CallFunction_526` | `Collision\|GetComponentBounds` | 38300, 1400 |
| | O − E | `K2Node_PromotableOperator_39` | `Math\|Vecteur\|vector-vector` | 38650, 1400 |
| | − (30,30,0) | `K2Node_PromotableOperator_40` | `Math\|Vecteur\|vector-vector` | 38900, 1400 |
| | `BreakVector` → X | `K2Node_CallFunction_531` | `Math\|Vecteur\|BreakVector` | 39150, 1400 |
| Wall3 (−Y) | getter `Wall3` | `K2Node_VariableGet_298` | `\|GetWall3` (créé par `Variables\|Pardéfaut\|ObtenirWall3`) | 38000, 1600 |
| | `GetComponentBounds(Wall3)` | `K2Node_CallFunction_527` | `Collision\|GetComponentBounds` | 38300, 1600 |
| | O + E | `K2Node_PromotableOperator_41` | `Math\|Vecteur\|vector+vector` | 38650, 1600 |
| | + (30,30,0) | `K2Node_PromotableOperator_42` | `Math\|Vecteur\|vector+vector` | 38900, 1600 |
| | `BreakVector` → Y | `K2Node_CallFunction_532` | `Math\|Vecteur\|BreakVector` | 39150, 1600 |
| Wall4 (+Y) | `GetComponentBounds(284)` | `K2Node_CallFunction_528` | `Collision\|GetComponentBounds` | 38300, 1800 |
| | O − E | `K2Node_PromotableOperator_43` | `Math\|Vecteur\|vector-vector` | 38650, 1800 |
| | − (30,30,0) | `K2Node_PromotableOperator_44` | `Math\|Vecteur\|vector-vector` | 38900, 1800 |
| | `BreakVector` → Y | `K2Node_CallFunction_533` | `Math\|Vecteur\|BreakVector` | 39150, 1800 |
| WallT | `GetComponentBounds(285)` | `K2Node_CallFunction_529` | `Collision\|GetComponentBounds` | 38300, 2000 |
| | O − E (face inférieure) | `K2Node_PromotableOperator_45` | `Math\|Vecteur\|vector-vector` | 38650, 2000 |
| | `BreakVector` → Z | `K2Node_CallFunction_534` | `Math\|Vecteur\|BreakVector` | 39150, 2000 |
Broches relues avant câblage (`get_node_infos` groupé, 7 créés + 492, 493, PO_15, 283, 284, 285) :
`GetComponentBounds` : Component in 0 (`Scene Component Référence d'objet`), Origin out 0 (Vector), BoxExtent out 1
(Vector), SphereRadius out 2 (`Float (simple précision)`, non relié) ; getters out 0 (`Static Mesh Component Référence
d'objet`) ; opérateurs A 0, B 1, sortie 0 (génériques à la création, typés `Vector` à la première liaison) ;
`BreakVector` InVec 0, X 0 / Y 1 / Z 2. État relu avant écriture : 492.X ← 484.0, 492.Y ← 484.1, 492.Z ← PO_14 ;
493.X ← 485.0, 493.Y ← 485.1, 493.Z ← 491 ; PO_15.A ← 488.2, PO_15.B = 25.0 ; 283 → 476, 284 → 477, 285 → 487
(conforme aux rapports F1, F2 et à la fiche).
### 1.2 Liens faits (`connect_pins`, 29, tous `{"returnValue":null}`)
| # | Sortie (nœud.broche index) | Entrée (nœud.broche index) | Fiche |
|---|---|---|---|
| L1 | VariableGet_297.0 | CallFunction_525.Component 0 | 1 |
| L2 | CallFunction_525.Origin 0 | PromotableOperator_37.A 0 | 1 |
| L3 | CallFunction_525.BoxExtent 1 | PromotableOperator_37.B 1 | 1 |
| L4 | PromotableOperator_37.0 | PromotableOperator_38.A 0 | 1 |
| L5 | PromotableOperator_38.0 | CallFunction_530.InVec 0 | 1 |
| L6 | CallFunction_530.X 0 | **CallFunction_492.X 0** (remplace 484.X) | 1 |
| L7 | VariableGet_283.0 | CallFunction_526.Component 0 | 2 |
| L8 | CallFunction_526.Origin 0 | PromotableOperator_39.A 0 | 2 |
| L9 | CallFunction_526.BoxExtent 1 | PromotableOperator_39.B 1 | 2 |
| L10 | PromotableOperator_39.0 | PromotableOperator_40.A 0 | 2 |
| L11 | PromotableOperator_40.0 | CallFunction_531.InVec 0 | 2 |
| L12 | CallFunction_531.X 0 | **CallFunction_493.X 0** (remplace 485.X) | 2 |
| L13 | VariableGet_298.0 | CallFunction_527.Component 0 | 3 |
| L14 | CallFunction_527.Origin 0 | PromotableOperator_41.A 0 | 3 |
| L15 | CallFunction_527.BoxExtent 1 | PromotableOperator_41.B 1 | 3 |
| L16 | PromotableOperator_41.0 | PromotableOperator_42.A 0 | 3 |
| L17 | PromotableOperator_42.0 | CallFunction_532.InVec 0 | 3 |
| L18 | CallFunction_532.Y 1 | **CallFunction_492.Y 1** (remplace 484.Y) | 3 |
| L19 | VariableGet_284.0 | CallFunction_528.Component 0 | 4 |
| L20 | CallFunction_528.Origin 0 | PromotableOperator_43.A 0 | 4 |
| L21 | CallFunction_528.BoxExtent 1 | PromotableOperator_43.B 1 | 4 |
| L22 | PromotableOperator_43.0 | PromotableOperator_44.A 0 | 4 |
| L23 | PromotableOperator_44.0 | CallFunction_533.InVec 0 | 4 |
| L24 | CallFunction_533.Y 1 | **CallFunction_493.Y 1** (remplace 485.Y) | 4 |
| L25 | VariableGet_285.0 | CallFunction_529.Component 0 | 5 |
| L26 | CallFunction_529.Origin 0 | PromotableOperator_45.A 0 | 5 |
| L27 | CallFunction_529.BoxExtent 1 | PromotableOperator_45.B 1 | 5 |
| L28 | PromotableOperator_45.0 | CallFunction_534.InVec 0 | 5 |
| L29 | CallFunction_534.Z 2 | **PromotableOperator_15.A 0** (remplace 488.Z) | 5 |
Valeurs (`set_pin_value`, toutes `{"returnValue":null}`, relues `"value":"30,30,0"`) : B 1 de PromotableOperator_38,
_40, _42 et _44 = `30,30,0`. PromotableOperator_15.B reste `25.0` (relu).
### 1.3 Liens coupés
Les 5 liens remplacés, coupés par `connect_pins` sur une entrée déjà reliée (§ 2 E1) : 484.X 0 → 492.X 0 ;
484.Y 1 → 492.Y 1 ; 485.X 0 → 493.X 0 ; 485.Y 1 → 493.Y 1 ; 488.Z 2 → PO_15.A 0. Aucun autre lien touché.
### 1.4 Relecture (`get_node_infos` groupé final, 24 nœuds : 21 créés + 492, 493, PO_15)
Les 29 liens apparaissent des deux côtés. Entrées cibles, un seul lien chacune : 492.X ← 530.X ; 492.Y ← 532.Y ;
492.Z ← PO_14 (inchangé) ; 493.X ← 531.X ; 493.Y ← 533.Y ; 493.Z ← 491 (inchangé) ; PO_15.A ← 534.Z, B = 25.0,
sortie → 491.B 1 (inchangée). Sorties de 492 → VariableSet_64.1 et de 493 → VariableSet_65.1 inchangées. Les huit
opérateurs sont typés (`vector+vector` 37, 38, 41, 42 ; `vector-vector` 39, 40, 43, 44, 45), A et B en `Vector`.
Aucune divergence avec la fiche.
Chaîne obtenue (`ComputeRoomBox`) :
- `C2BoxMin := (W1.O.X + W1.E.X + 30, W3.O.Y + W3.E.Y + 30, sol.Z + 50)` ;
- `C2BoxMax := (W2.O.X − W2.E.X − 30, W4.O.Y − W4.E.Y − 30, SelectFloat(1000000, WallT.O.Z − WallT.E.Z − 25, Ext))`.
Les anciens nœuds de calcul (PO_9 à PO_13, 476 à 485, 487, 488) restent en place, sans consommateur en aval de 484,
485 et 488 (fiche, point 6) ; purs, ils ne sont plus évalués.
### 1.5 Compilation et enregistrement
- `compile_blueprint {blueprint:{refPath:"/Game/BPs/Room.Room"}, warnings_as_errors:true}` → `{"returnValue":null}`,
aucune exception (B2d + B2e en mémoire). `hyper_blueprint_debug_inspect` non appelé (absent du serveur le
2026-10-10, mémoire `unreal-mcp-reconnect`, non revérifié) ; journal de l'éditeur non lu (chemin `-abslog` non
fourni).
- `AssetTools.save_assets {asset_paths:["/Game/BPs/Room"]}` → `{"returnValue":true}`, Room seul.
### 1.6 Lecture de la collision (point 7, lecture seule, arrêtée à Wall1 faute de tours)
`ObjectTools.get_properties {instance:{refPath:"/Game/BPs/Room.Room_C:Wall1_GEN_VARIABLE"}, properties:["BodyInstance"]}`
(gabarit du composant de Wall1 dans la classe générée), extrait tel quel :
```
"objectType":"ECC_WorldDynamic","collisionEnabled":"QueryAndPhysics", ... "collisionProfileName":"Custom",
"collisionResponses":{"responseArray":[]}, ... "bSimulatePhysics":false
```
Le premier appel (`object`, `property_names`) a échoué sur le schéma ; il a rendu le schéma exact
(`instance`, `properties`). Wall2, Wall3, Wall4 et WallT : **non lus** (budget atteint).
Lecture (estimé, non vérifié) : profil `Custom` avec `responseArray` vide, donc aucune réponse surchargée. Le canal
Camera garderait la réponse par défaut du conteneur, `ECR_Block` sauf réglage contraire dans
`DefaultEngine.ini`. Ce point est à confirmer : il faut lire `DefaultEngine.ini` (`DefaultChannelResponses`) et les
instances placées. Une instance de niveau ou le C++ (`LPOutdoorRoomSubsystem`) peuvent changer la collision à
l'exécution.
## 2. Écarts à la SPEC
- **E1 (procédure, même résultat)** : la fiche prescrit `break_pins` avant de relier 492.X (point 1) et PO_15.A
(point 5), et par extension 493.X, 492.Y et 493.Y. Les 5 coupures sont faites par `connect_pins` lui-même. Preuve
par les sources du moteur installé : `connect_pins` appelle `out.try_create_connection(inp)`
(`D:\Game\Launcher\Engine\UE_5.8\Engine\Plugins\Experimental\Toolsets\EditorToolset\Content\Python\editor_toolset\toolsets\blueprint.py:1067`).
Cet appel aboutit à `UEdGraphSchema_K2::TryCreateConnection`
(`…\Engine\Source\Editor\BlueprintEditorLibrary\Private\BlueprintEditorLibrary\BlueprintGraphPin.cpp:92-102`). Pour
une entrée de donnée déjà reliée, le schéma répond `CONNECT_RESPONSE_BREAK_OTHERS_*`
(`…\Engine\Source\Editor\BlueprintGraph\Private\EdGraphSchema_K2.cpp:2086-2088`) : l'ancien lien est coupé, puis le
nouveau est fait. Le § 1.4 vérifie le résultat : chaque entrée n'a qu'un lien, le nouveau. Motif : le budget. Les
5 `break_pins` auraient porté l'enregistrement au-delà des 65 tours (même motif que B2d E2).
- **E2 (ordre)** : la lecture des nœuds existants est faite après la création des 21 nœuds et avant tout câblage, en
un seul appel groupé avec les nœuds créés, comme en B2d (§ 1.2 de `CAM-B2d-IMPL.md`). Créer des nœuds non reliés ne
touche aucun nœud existant.
- Garde `Accessed None` : aucune `IsValid` ajoutée (ni la SPEC ni la fiche n'en demandent). Lectures nouvelles :
`Wall1` (297) et `Wall3` (298) dans `ComputeRoomBox`. `Wall1` a un gabarit de composant dans la classe générée
(`Room_C:Wall1_GEN_VARIABLE`, lu au § 1.6). C'est un composant de la construction, « vide » n'y est pas un état
normal (estimé). `Wall3` est supposé du même type, sans lecture. `Wall2`, `Wall4` et `WallT` étaient déjà lus
(476, 477, 487).
- Comportement : changement voulu (faces intérieures au lieu des centres des murs). `ZMin`, le choix extérieur (491)
et les affectations (64, 65) sont inchangés (relus).
- Aucun nœud de B2d touché (513-524, PO28, PO30, 96, 97, CE48) : aucun appel ne les vise.
## 3. Instantané
Fait par l'orchestrateur (non refait, consigne) : `D:\Game\LifePlay_Backup_5.5\CAM-B2d\`. Relevé avant écriture :
```
date -Iseconds; md5sum "/d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset"; grep -i "Room.uasset" "/d/Game/LifePlay_Backup_5.5/CAM-B2d/manifest.csv"; git -C "/d/Game/LifePlay-master 5.8" rev-parse --short HEAD
2026-10-13T17:24:45+02:00
e0517c63541f249bd9dbda5c39815ba5 */d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset
"Content\BPs\Room.uasset","True","6318319","E0517C63541F249BD9DBDA5C39815BA5","2026-10-13T17:11:26"
0745917
```
Relevé après `save_assets` :
```
date -Iseconds; md5sum "/d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset"; ls -l "/d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset"; git -C "/d/Game/LifePlay-master 5.8" status --short -- Content Source Config
2026-10-13T17:29:45+02:00
ca2a9a0baaca4130fd5c318797f008ae */d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset
-rw-r--r-- 1 <compte> 197609 6378087 Oct 13 17:29 /d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset
M Content/BPs/Person.uasset
M Content/BPs/Room.uasset
M Source/LifePlay/LPDebugSubsystem.cpp
M Source/LifePlay/LPDebugSubsystem.h
M Source/LifePlay/LPOutdoorRoomSubsystem.cpp
M Source/LifePlay/LPOutdoorRoomSubsystem.h
?? Source/LifePlay/LPCameraModeSubsystem.cpp
?? Source/LifePlay/LPCameraModeSubsystem.h
```
Le MD5 diffère de `E0517C63` (attendu). Le git status correspond à l'état annoncé par l'orchestrateur : Person,
LPDebugSubsystem.*, LPOutdoorRoomSubsystem.* et LPCameraModeSubsystem.* viennent d'autres fiches et ne sont pas
touchés ici. Retour arrière, proposé et jamais lancé : `Tools\Restore.ps1 -Lot CAM-B2d -Only Content\BPs\Room.uasset`,
éditeur fermé, sur décision de l'orchestrateur. Il ramène Room à `E0517C63`, l'état B2b, et perd B2d et B2e.
## 4. Ce qui n'a pas été fait
- Point 7 : collision de Wall2, Wall3, Wall4 et WallT non lue (budget). Réponse effective au canal Camera non établie
(§ 1.6).
- Anciens nœuds (point 6) laissés en place, conformément à la fiche (nettoyage plus tard).
- `hyper_blueprint_debug_inspect`, journal de l'éditeur : non consultés (§ 1.5).
- Valeurs de `C2BoxMin` / `C2BoxMax` à l'exécution : non mesurées (pas de PIE ni de build) ; preuve en jeu (build
empaqueté + `LogStats`) hors rôle. Éditeur laissé ouvert (fermeture : orchestrateur, puis `BUILD-FIN`).
## 5. Points à confirmer en VAL
1. V5 (fiche) par dump après fermeture de l'éditeur : `GetComponentBounds` ≥ 5 dans `ComputeRoomBox` (525 à 529) ;
492.X ← 530.X, 492.Y ← 532.Y, 493.X ← 531.X, 493.Y ← 533.Y ; PO_15.A ← 534.Z (O − E de WallT) ; valeurs
`30,30,0` sérialisées sur PO_38, _40, _42, _44.
2. Orientation (estimé, risque) : la règle suppose des pièces sans rotation, Wall1 en −X du monde et Wall2 en +X.
Une Room tournée de 180° en lacet donne MinX > MaxX : la boîte est croisée. Une Room tournée de 90° fait que X et Y
ne correspondent plus aux murs. L'ancienne formule (`Abs`, F1) supportait 180°. Il faut vérifier que les pièces
placées ou générées ont toutes un lacet de 0.
3. Bornes croisées : la garde `Vector_ComponentMax` de F1 (483) n'est plus sur le chemin. Une pièce de moins de
60 unités utiles entre les faces (ou WallT − 25 < sol + 50) donne Min > Max dans `VectorBoundedToBox`. Ce
comportement n'est pas vérifié.
4. Extérieur : les murs sont écrasés en Z (échelle 0,01) mais gardent leur emprise XY. `WallT` est toujours évalué
(pur) même quand `SelectFloat` choisit 1000000 : aucun `Accessed None` attendu, à vérifier par `LogStats`.
5. Lectures nouvelles `Wall1` (297), `Wall3` (298) : à vérifier par `LogStats` (aucun `Accessed None` sur
`ComputeRoomBox`).
6. Collision : réponse au canal Camera de Wall1 à Wall4 et WallT (gabarits et instances), et `DefaultEngine.ini`
(§ 1.6). Wall1 : `Custom`, `responseArray` vide.
7. Essai de la fiche : dos au mur des 4 côtés, dans un coin, en hauteur, et dans une pièce redimensionnée. Aucune vue
de l'extérieur ne doit apparaître.
8. Compilation stricte jugée sur l'absence d'exception seulement : à recontrôler par `CompileAllBlueprints`, éditeur
fermé (V6).
## 6. Fichiers à commiter
- `A Docs/Migration/etat/CAM/CAM-B2e-IMPL.md` (dépôt du jeu, branche `ue5.8`).
- `M Content/BPs/Room.uasset` (dépôt du jeu, branche `ue5.8`) : B2d et B2e enregistrés ensemble, MD5 `ca2a9a0b…`.
Commit après VAL et essai, sur ticket de l'orchestrateur.
Tours : 65 / 65 (63 de travail ; le livrable et le compte rendu sont dans la marge)
## Constats
- À verser : `lp-mcp` § 3. `connect_pins` passe par `UEdGraphSchema_K2::TryCreateConnection`
(`blueprint.py:1067`, `BlueprintGraphPin.cpp:92-102`). Sur une entrée de donnée déjà reliée, il remplace l'ancien
lien (`EdGraphSchema_K2.cpp:2086-2088`) : aucun `break_pins` préalable n'est nécessaire, à relire ensuite.
`break_pins` vérifie le lien puis appelle `break_single_pin_link` (`blueprint.py:1074-1087`).
- À verser : `lp-mcp` § 3. Lecture d'un composant de Blueprint :
`ObjectTools.get_properties {instance:{refPath:"/Game/BPs/X.X_C:<Composant>_GEN_VARIABLE"}, properties:[…]}`.
Code des outils Epic : `D:\Game\Launcher\Engine\UE_5.8\Engine\Plugins\Experimental\Toolsets\EditorToolset\Content\Python\editor_toolset\toolsets\`.
- À verser : `lp-mcp` § 3. `Collision|GetComponentBounds` : Component in 0 ; Origin out 0, BoxExtent out 1,
SphereRadius out 2 (nœud pur). `Variables|Pardéfaut|ObtenirWall1` / `ObtenirWall3` acceptés tels quels.
- Ordre efficace (60 appels pour 21 nœuds et 29 liens) : toutes les créations, puis une lecture groupée (créés +
existants), puis le câblage chaîne par chaîne, `set_pin_value` juste après le typage de l'opérateur, puis une
relecture finale groupée.