LifePlay-Revival/Docs/Migration/etat/CAM/CAM-B2b-IMPL-F6a.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

200 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Fiche CAM-B2b-F6a — 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-B2b-F6a-IMPL : pilotage de C2, `CircleCamera` et `LeftRight` (B2b-6, partie 1) (2026-10-13)
Consignes : `CAM-B2b-FICHES.md` § « Rubriques communes » (l. 23-63) et § « F6 » (l. 127-132), réduit par la fiche
F6a à `CircleCamera` et `LeftRight` (`ScrollDownUp` passe en F6b). SPEC : `CAM-SPEC.md` § « CAM-B2b », ligne B2b-6
(l. 380). BUILD-GO / UE-GO de Big Boss B2b du 2026-10-13 (cité par l'orchestrateur). Éditeur headless PID 10708, port
8000, connexion `unreal-mcp` partagée (MCPA-T1). Room chargé, F1 à F5 en mémoire, non enregistrés. Un seul `call_tool`
par message. **31 appels MCP** : 9 `create_node`, 2 `break_pins`, 15 `connect_pins`, 1 `set_pin_value`,
3 `get_node_infos`, 1 `compile_blueprint`. Aucun `delete_node`, `save_assets`, `write_graph_dsl` ni
`ProgrammaticToolset`. Aucune écriture par HyperAIStudio.
## 1. Fichiers modifiés
- `Content/BPs/Room.uasset` : modifié **en mémoire de l'éditeur seulement**, non enregistré (pas de `save_assets`
avant F7). Preuve au § 3 : le MD5 du disque après F6a est celui de l'instantané.
- Graphe `/Game/BPs/Room.Room:EventGraph` : événement `CircleCamera` (CE1, x 5296, y 4688) et événement `LeftRight`
(CE4, x 5072, y 3168). Nœuds neufs en x 5650-6050, y 4250-4450 (CircleCamera) et x 5250-5850, y 2750-2950 (LeftRight).
### 1.1 Lecture avant écriture (`get_node_infos` groupé, 5 nœuds existants)
Lecture conforme aux faits de la fiche :
- `K2Node_CustomEvent_1` (`AddEvent|Custom|CircleCamera`) : `then` out 1 → `IfThenElse_26`.execute 0 ; `DeltaSeconds`
out 2 (`Float (double-précision)`) → `CommutativeAssociativeBinaryOperator_26`.1, `_16`.1, `_27`.1.
- `K2Node_CustomEvent_4` (`AddEvent|Custom|LeftRight`) : `then` out 1 → `IfThenElse_9`.execute 0 ; `AxisValue` out 2
(`Float (double-précision)`) → `CommutativeAssociativeBinaryOperator_47`.0, `_13`.0, `_24`.0.
- `K2Node_IfThenElse_26` : execute ← CE1.1 ; Condition ← `CommutativeAssociativeBinaryOperator_19`.0 ; then 0 →
`IfThenElse_19`.0 ; else 1 libre.
- `K2Node_IfThenElse_9` : execute ← CE4.1 ; Condition ← `CommutativeAssociativeBinaryOperator_17`.0 ; then 0 →
`IfThenElse_14`.0 ; else 1 libre.
- `K2Node_PromotableOperator_8` (`Utilitaires|Equal(Object)`) : A ← `CallFunction_439`.0, B ← `VariableGet_268`.0 ;
out 0 (`Booléen`) → `IfThenElse_91`.1.
Les deux paramètres d'événement sont en **double précision** (la fiche prévoyait peut-être de la simple) : aucune
conversion implicite n'est nécessaire.
### 1.2 Nœuds créés (préfixe `refPath` : `/Game/BPs/Room.Room:EventGraph.`)
| Événement | Rôle | `refPath` (suffixe) | `type_id` demandé → relu | Broches relues | Position |
|---|---|---|---|---|---|
| CircleCamera | **Branche** C2 | `K2Node_IfThenElse_96` | `Utilitaires\|ContrôleDeFlux\|Branche` → idem | execute 0, Condition 1 ; then 0, else 1 | 5650, 4450 |
| CircleCamera | Obtenir C2Yaw | `K2Node_VariableGet_292` | `Variables\|Pardéfaut\|ObtenirC2Yaw` → `\|GetC2Yaw` | C2Yaw out 0 (double) | 5650, 4250 |
| CircleCamera | C2Yaw + DeltaSeconds | `K2Node_PromotableOperator_28` | `Utilitaires\|Opérateurs\|Ajouter` → `Math\|Flottant\|float+float` | A 0, B 1 ; out 0 (double) | 5850, 4250 |
| CircleCamera | **Définir C2Yaw** | `K2Node_VariableSet_67` | `Variables\|Pardéfaut\|DéfinirC2Yaw` → `\|SetC2Yaw` | execute 0, C2Yaw 1 ; then 0, Output_Get 1 | 6050, 4400 |
| LeftRight | **Branche** C2 | `K2Node_IfThenElse_97` | `Utilitaires\|ContrôleDeFlux\|Branche` → idem | execute 0, Condition 1 ; then 0, else 1 | 5250, 2950 |
| LeftRight | Obtenir C2Yaw | `K2Node_VariableGet_293` | `Variables\|Pardéfaut\|ObtenirC2Yaw` → `\|GetC2Yaw` | C2Yaw out 0 (double) | 5250, 2750 |
| LeftRight | AxisValue × 2 | `K2Node_PromotableOperator_29` | `Utilitaires\|Opérateurs\|Multiplier` → `Math\|Flottant\|float*float` | A 0, B 1 ; out 0 (double) | 5450, 2850 |
| LeftRight | C2Yaw + produit | `K2Node_PromotableOperator_30` | `Utilitaires\|Opérateurs\|Ajouter` → `Math\|Flottant\|float+float` | A 0, B 1 ; out 0 (double) | 5650, 2750 |
| LeftRight | **Définir C2Yaw** | `K2Node_VariableSet_68` | `Variables\|Pardéfaut\|DéfinirC2Yaw` → `\|SetC2Yaw` | execute 0, C2Yaw 1 ; then 0, Output_Get 1 | 5850, 2900 |
À la création, les opérateurs portent le `type_id` trompeur déjà vu en F3 à F5 : `Utilitaires|Gestiondutemps|
FrameNumber+Int` pour PO28 et PO30, `…|Seconds*FrameRate` pour PO29, avec des broches `Caractère de remplacement`. À la
relecture finale, ils sont typés `float+float` / `float*float` en double précision. PO8 est réutilisé sans copie (nœud pur).
### 1.3 Liens coupés (`break_pins`, 2, tous `{"returnValue":null}`)
| # | Sortie | Entrée |
|---|---|---|
| C1 | CustomEvent_1.then 1 | IfThenElse_26.execute 0 |
| C2 | CustomEvent_4.then 1 | IfThenElse_9.execute 0 |
Aucun autre lien coupé ; dans ces deux événements, rien d'autre n'a été touché.
### 1.4 Liens faits (`connect_pins`, 15, tous `{"returnValue":null}`)
| # | Sortie | Entrée | Événement |
|---|---|---|---|
| L1 | CustomEvent_1.then 1 | IfThenElse_96.execute 0 | CircleCamera |
| L2 | IfThenElse_96.else 1 | IfThenElse_26.execute 0 | CircleCamera |
| L3 | PromotableOperator_8.0 | IfThenElse_96.Condition 1 | CircleCamera |
| L4 | VariableGet_292.0 (`C2Yaw`) | PromotableOperator_28.A 0 | CircleCamera |
| L5 | CustomEvent_1.DeltaSeconds 2 | PromotableOperator_28.B 1 | CircleCamera |
| L6 | PromotableOperator_28.0 | VariableSet_67.C2Yaw 1 | CircleCamera |
| L7 | IfThenElse_96.then 0 | VariableSet_67.execute 0 | CircleCamera |
| L8 | CustomEvent_4.then 1 | IfThenElse_97.execute 0 | LeftRight |
| L9 | IfThenElse_97.else 1 | IfThenElse_9.execute 0 | LeftRight |
| L10 | PromotableOperator_8.0 | IfThenElse_97.Condition 1 | LeftRight |
| L11 | CustomEvent_4.AxisValue 2 | PromotableOperator_29.A 0 | LeftRight |
| L12 | VariableGet_293.0 (`C2Yaw`) | PromotableOperator_30.A 0 | LeftRight |
| L13 | PromotableOperator_29.0 | PromotableOperator_30.B 1 | LeftRight |
| L14 | PromotableOperator_30.0 | VariableSet_68.C2Yaw 1 | LeftRight |
| L15 | IfThenElse_97.then 0 | VariableSet_68.execute 0 | LeftRight |
`VariableSet_67.then` et `VariableSet_68.then` : laissés libres (fin de l'événement côté C2, comme le prescrit la fiche).
### 1.5 Valeurs (`set_pin_value`, 1, `{"returnValue":null}`, relue)
| Broche | Avant (relu à la création) | Après (relu) |
|---|---|---|
| PromotableOperator_29.B 1 | (neuf, `""`, joker) | `2.0` (`Float (double-précision)`) |
Le `set_pin_value` a été posé juste après L11, la liaison de A qui type l'opérateur. Les conditions des Branches 96 et 97
gardent la valeur par défaut `true`, sans effet puisque la broche est liée (L3, L10).
### 1.6 Relecture et chaîne obtenue
`get_node_infos` final groupé sur 15 nœuds : les 9 créés, plus CE1, CE4, IfThenElse_26, IfThenElse_9, PO8 et
`CallFunction_439` (amont de PO8, lu pour la garde). Les 15 liens apparaissent des deux côtés ; la valeur 2.0 est relue.
Liens non touchés, relus intacts :
- CE1.DeltaSeconds → `CommutativeAssociativeBinaryOperator_26`, `_16`, `_27` (plus PO28) ;
- CE4.AxisValue → `CommutativeAssociativeBinaryOperator_47`, `_13`, `_24` (plus PO29) ;
- IfThenElse_26 : Condition ← `CommutativeAssociativeBinaryOperator_19`, then → `IfThenElse_19`, else libre ;
- IfThenElse_9 : Condition ← `CommutativeAssociativeBinaryOperator_17`, then → `IfThenElse_14`, else libre ;
- PO8 : A ← 439, B ← `VariableGet_268`, sortie → `IfThenElse_91`.1 (plus 96.1 et 97.1) ;
- `CallFunction_439` (`Pion|GetViewTarget`) : self ← `VariableGet_262` (`Controller`), sortie → `PromotableOperator_0`.0
et PO8.0.
Aucune divergence.
Chaîne obtenue :
- `CircleCamera` (CE1) → Branche 96 (`GetViewTarget(PC) == CamRoom`). Si vrai : `Définir C2Yaw` (67) := `C2Yaw +
DeltaSeconds`, puis fin. Si faux : `IfThenElse_26`, chaîne d'origine inchangée.
- `LeftRight` (CE4) → Branche 97 (même condition). Si vrai : `Définir C2Yaw` (68) := `C2Yaw + AxisValue × 2`, puis
fin. Si faux : `IfThenElse_9`, chaîne d'origine inchangée.
### 1.7 Compilation
`compile_blueprint {blueprint:{refPath:"/Game/BPs/Room.Room"}, warnings_as_errors:true}` → `{"returnValue":null}`,
aucune exception (critère de la rubrique « Fin de chaque fiche »). `hyper_blueprint_debug_inspect` n'a pas été appelé :
il était absent du serveur le 2026-10-10 (mémoire `unreal-mcp-reconnect`, non revérifié). Le journal de l'éditeur n'a
pas été lu : son chemin `-abslog` n'a pas été fourni. Pas de `save_assets` (réservé à F7).
## 2. Écarts à la SPEC
- Aucun écart de câblage : la ligne B2b-6 (`CAM-SPEC.md:380`), pour `CircleCamera` et `LeftRight`, et la fiche F6
(`CAM-B2b-FICHES.md:127-131`) sont réalisées telles quelles. Seuls les liens CE.then → branche d'origine ont été coupés.
- Fait différent de la fiche, sans effet : `DeltaSeconds` et `AxisValue` sont en double précision, pas en simple. Il n'y
a donc aucune conversion implicite.
- Deux `Obtenir C2Yaw` distincts (292, 293), un par événement, comme le prescrit la fiche (« (N) Obtenir C2Yaw ») ;
PO8 est partagé par trois Branches (91, 96, 97).
- Garde `Accessed None` : aucune `IsValid` ajoutée, car ni la fiche ni la SPEC n'en demandent. Les nœuds neufs ne lisent
que des flottants. En revanche, PO8 (→ 439 `GetViewTarget`, self ← `VariableGet_262` ; → `VariableGet_268`
`CamRoom`) est **désormais évalué à chaque appel** de `CircleCamera` et de `LeftRight`, ce qui n'était pas le cas
avant. Si la cible de 262 (le contrôleur) est nulle à ce moment, un `Accessed None` apparaît là où il n'y en avait
pas. Voir le § 5, points 3 et 4.
- Comportement : identique à l'ancien quand C2 n'est pas la vue (sortie `else` vers la branche d'origine). Quand C2 est
la vue, la chaîne d'origine **n'est plus exécutée** : c'est le changement voulu par la SPEC (« vrai → réglage ; faux
→ branche existante »).
- Positions des nœuds : choisies près des événements (cosmétique, non prescrit). Elles peuvent chevaucher visuellement
des nœuds existants proches, sans effet sur le graphe.
## 3. Instantané
Fait par l'orchestrateur avant F1 (non refait, consigne). Manifeste relu et disque mesuré après F6a :
```
date -Iseconds; md5sum "/d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset"; grep -i "Room.uasset" "/d/Game/LifePlay_Backup_5.5/CAM-B2b/manifest.csv"
2026-10-13T16:01:23+02:00
a5fa970e821dc2d0d9bf220fd43b9de6 */d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset
"Content\BPs\Room.uasset","True","6060745","A5FA970E821DC2D0D9BF220FD43B9DE6","2026-10-13T15:25:45"
```
Le MD5 du disque est celui de l'instantané : rien n'a été enregistré. Retour arrière avant F7 : fermer l'éditeur sans
enregistrer, ce qui perd F1 à F6a. Après F7 : `Tools\Restore.ps1 -Lot CAM-B2b -Only Content\BPs\Room.uasset`, éditeur
fermé, sur décision de l'orchestrateur (jamais lancé ici).
## 4. Ce qui n'a pas été fait
- `ScrollDownUp` (CE55 → IfThenElse_10, `Clamp` de `C2Dist`) : renvoyé à F6b par la fiche.
- F7 (`RotateCamera`, `DownUp`, relecture finale, enregistrement) : hors périmètre.
- `hyper_blueprint_debug_inspect`, journal de l'éditeur : non consultés (§ 1.7).
- `save_assets` : interdit avant F7. F1 à F6a vivent en mémoire de l'éditeur PID 10708 : une fermeture ou un plantage
avant F7 les perd, l'instantané restant intact.
- Comportement à l'exécution : non mesuré (aucune PIE, aucun build) ; seulement déduit du câblage.
- Preuve en jeu (build empaqueté + `LogStats`) : hors rôle.
## 5. Points à confirmer en VAL
1. Vue autre que C2 : `CircleCamera` et `LeftRight` prennent `else` → `IfThenElse_26` / `IfThenElse_9`, chaînes
d'origine inchangées. Établi par le câblage ; à confirmer en jeu (pilotage de l'ancienne caméra identique).
2. Vue C2 : `CircleCamera` ajoute `DeltaSeconds` à `C2Yaw`, et `LeftRight` ajoute `AxisValue × 2`. L'effet sur C2 passe
par `Bdir` (F3, 497) au prochain `ComputeC2Target`. Signes et gains à juger à l'essai (SPEC : « ajustables à
l'essai »).
3. `LogStats` : aucun `Accessed None` nouveau sur `CallFunction_439` / `VariableGet_262`. PO8 est maintenant évalué à
chaque `LeftRight`, événement d'axe probablement appelé à chaque image (estimé, non lu), et à chaque `CircleCamera`.
4. Cas limite (estimé) : si `GetViewTarget` rend `None` et que `CamRoom` est aussi `None` (avant sa création), PO8 vaut
`true` (None == None). Les deux événements écrivent alors `C2Yaw` au lieu de piloter l'ancienne caméra. À vérifier :
`CamRoom` existe-t-elle toujours avant le premier appel possible de ces événements ?
5. `C2Yaw` n'est pas borné (la SPEC ne le borne pas) : il croît sans fin à force de tourner. `RotateVectorAroundAxis`
accepte tout angle ; la précision double suffit (estimé).
6. V5 (`CAM-SPEC.md:382`) pour ces deux événements : `then` → nouvelle branche (96, 97) ; `else` → branche d'origine
(26, 9).
7. Valeur sérialisée après `save_assets` (F7), par dump (`LPDumpFunction`) : `PO29.B = 2.0`.
8. Compilation stricte jugée sur l'absence d'exception seulement ; à recontrôler en F7 et par `CompileAllBlueprints`.
## 6. Fichiers à commiter
- `A Docs/Migration/etat/CAM/CAM-B2b-IMPL-F6a.md` (dépôt du jeu, branche `ue5.8`).
- `Content/BPs/Room.uasset` : rien à commiter pour F6a (non enregistré) ; il le sera après F7 et la VAL.
Tours : 38 / 55 (ce Write et la remise du compte rendu compris ; 31 appels MCP, un par message)
## Constats
- `DeltaSeconds` (CE1) et `AxisValue` (CE4) sont en `Float (double-précision)` : relier A d'un `Ajouter` ou d'un
`Multiplier` à ces broches le type directement en `float+float` / `float*float`, sans conversion.
- `Variables|Pardéfaut|ObtenirC2Yaw` → `|GetC2Yaw` (sortie 0) ; `DéfinirC2Yaw` → `|SetC2Yaw` (execute 0, C2Yaw 1 ;
then 0, Output_Get 1).
- `CallFunction_439` = `Pion|GetViewTarget`, self ← `VariableGet_262` (`Controller`), sortie aussi vers
`PromotableOperator_0`.
- Pour F6b et F7, le même schéma coûte 2 + 4 à 5 créations + 1 lecture + 1 coupure + 7 à 9 liaisons + 0 à 3 valeurs par
événement. Ordre économe : créer tous les nœuds, faire une lecture groupée, puis couper chaque lien et le remplacer
aussitôt.