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

239 lines
17 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-F6b — 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-F6b-IMPL : pilotage de C2, `ScrollDownUp` et `RotateCamera` (B2b-6, partie 2) (2026-10-13)
Consignes : `CAM-B2b-FICHES.md` § « Rubriques communes » (l. 23-63), § « F6 » (l. 127-132, `ScrollDownUp`) et § « F7 »
(l. 134-136, `RotateCamera` seulement). `DownUp` et la fin de F7 passent à la fiche suivante. SPEC : `CAM-SPEC.md` § « CAM-B2b »,
ligne B2b-6 (l. 380). Modèle suivi : `CAM-B2b-IMPL-F6a.md` et son ordre économe : créer tous les nœuds, faire une lecture
groupée, puis couper chaque lien et le remplacer aussitôt.
Contexte : 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 à F6a en mémoire, non enregistrés. Un seul `call_tool` par
message. **43 appels MCP** : 3 `get_node_infos`, 1 `find_node_types`, 12 `create_node`, 2 `break_pins`,
18 `connect_pins`, 6 `set_pin_value` et 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` est modifié **en mémoire de l'éditeur seulement**, sans enregistrement (pas de `save_assets`
avant F7). Le § 3 le prouve : le MD5 du disque après F6b est celui de l'instantané.
- Graphe `/Game/BPs/Room.Room:EventGraph` :
- événement `ScrollDownUp` (CE55, x 4896, y 2544) : nœuds neufs en x 5100-5950, y 2150-2350 ;
- événement `RotateCamera` (CE19, x 5184, y 5232) : nœuds neufs en x 5400-6250, y 5550-5800.
### 1.1 Lecture avant écriture (`get_node_infos` groupé, 5 nœuds existants)
La lecture est conforme aux faits de la fiche :
- `K2Node_CustomEvent_55` (`AddEvent|Custom|ScrollDownUp`) :
- `then` out 1 → `IfThenElse_10`.execute 0 ;
- `Values` out 2 (`Float (double-précision)`) → `CommutativeAssociativeBinaryOperator_2`.0, `CallFunction_26`.2,
`CommutativeAssociativeBinaryOperator_20`.0, `_10`.0 et `_22`.0.
- `K2Node_CustomEvent_19` (`AddEvent|Custom|RotateCamera`) :
- `then` out 1 → `IfThenElse_25`.execute 0 ;
- `DeltaSeconds` out 2 (`Float (double-précision)`) → `CommutativeAssociativeBinaryOperator_45`.1, `_12`.1 et `_15`.1.
- `K2Node_IfThenElse_10` : execute ← CE55.1 ; Condition ← `CommutativeAssociativeBinaryOperator_17`.0 ; then 0 →
`IfThenElse_12`.0 ; else 1 libre.
- `K2Node_IfThenElse_25` : execute ← CE19.1 ; Condition ← `CommutativeAssociativeBinaryOperator_19`.0 ; then 0 →
`IfThenElse_18`.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, `_96`.1 et `_97`.1.
Recherche du Clamp : `find_node_types {type_id_filter:"Clamp"}` sur le graphe. Le résultat flottant est
`Math|Flottant|Clamp(Float)`, à côté de `Math|Integer|Clamp(Integer)`, `Math|Integer64|Clamp(Integer64)`, `Math|Flottant|
ClampAngle`, `MapRangeClamped` et d'autres.
### 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 |
|---|---|---|---|---|---|
| ScrollDownUp | **Branche** C2 | `K2Node_IfThenElse_98` | `Utilitaires\|ContrôleDeFlux\|Branche` → idem | execute 0, Condition 1 ; then 0, else 1 | 5100, 2350 |
| ScrollDownUp | Obtenir C2Dist | `K2Node_VariableGet_294` | `Variables\|Pardéfaut\|ObtenirC2Dist` → `\|GetC2Dist` | C2Dist out 0 (double) | 5100, 2150 |
| ScrollDownUp | Values × 15 | `K2Node_PromotableOperator_31` | `Utilitaires\|Opérateurs\|Multiplier` → `Math\|Flottant\|float*float` | A 0, B 1 ; out 0 (double) | 5300, 2250 |
| ScrollDownUp | C2Dist − produit | `K2Node_PromotableOperator_32` | `Utilitaires\|Opérateurs\|Soustraire` → `Math\|Flottant\|float-float` | A 0, B 1 ; out 0 (double) | 5500, 2150 |
| ScrollDownUp | Clamp | `K2Node_CallFunction_509` | `Math\|Flottant\|Clamp(Float)` → idem | Value 0, Min 1, Max 2 ; ReturnValue out 0 (double) | 5700, 2200 |
| ScrollDownUp | **Définir C2Dist** | `K2Node_VariableSet_69` | `Variables\|Pardéfaut\|DéfinirC2Dist` → `\|SetC2Dist` | execute 0, C2Dist 1 ; then 0, Output_Get 1 | 5950, 2300 |
| RotateCamera | **Branche** C2 | `K2Node_IfThenElse_99` | `Utilitaires\|ContrôleDeFlux\|Branche` → idem | execute 0, Condition 1 ; then 0, else 1 | 5450, 5800 |
| RotateCamera | Obtenir C2Height | `K2Node_VariableGet_295` | `Variables\|Pardéfaut\|ObtenirC2Height` → `\|GetC2Height` | C2Height out 0 (double) | 5400, 5550 |
| RotateCamera | DeltaSeconds × 3 | `K2Node_PromotableOperator_33` | `Utilitaires\|Opérateurs\|Multiplier` → `Math\|Flottant\|float*float` | A 0, B 1 ; out 0 (double) | 5600, 5650 |
| RotateCamera | C2Height + produit | `K2Node_PromotableOperator_34` | `Utilitaires\|Opérateurs\|Ajouter` → `Math\|Flottant\|float+float` | A 0, B 1 ; out 0 (double) | 5800, 5550 |
| RotateCamera | Clamp | `K2Node_CallFunction_510` | `Math\|Flottant\|Clamp(Float)` → idem | Value 0, Min 1, Max 2 ; ReturnValue out 0 (double) | 6000, 5600 |
| RotateCamera | **Définir C2Height** | `K2Node_VariableSet_70` | `Variables\|Pardéfaut\|DéfinirC2Height` → `\|SetC2Height` | execute 0, C2Height 1 ; then 0, Output_Get 1 | 6250, 5700 |
À la création, les opérateurs portent le `type_id` trompeur déjà vu en F3 à F6a, avec des broches `Caractère de
remplacement` :
- `Utilitaires|Gestiondutemps|Seconds*FrameRate` pour PO31 et PO33 ;
- `…|FrameNumber-Int` pour PO32 ;
- `…|FrameNumber+Int` pour PO34.
À la relecture finale, ils sont typés `float*float`, `float-float` et `float+float`, en double précision. À la création,
le Clamp a pour défauts Min `0.0` et Max `1.0`, remplacés ensuite (§ 1.5). 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_55.then 1 | IfThenElse_10.execute 0 |
| C2 | CustomEvent_19.then 1 | IfThenElse_25.execute 0 |
Aucun autre lien n'a été coupé, et rien d'autre n'a été touché dans ces deux événements.
### 1.4 Liens faits (`connect_pins`, 18, tous `{"returnValue":null}`)
| # | Sortie | Entrée | Événement |
|---|---|---|---|
| L1 | CustomEvent_55.then 1 | IfThenElse_98.execute 0 | ScrollDownUp |
| L2 | IfThenElse_98.else 1 | IfThenElse_10.execute 0 | ScrollDownUp |
| L3 | PromotableOperator_8.0 | IfThenElse_98.Condition 1 | ScrollDownUp |
| L4 | CustomEvent_55.Values 2 | PromotableOperator_31.A 0 | ScrollDownUp |
| L5 | VariableGet_294.0 (`C2Dist`) | PromotableOperator_32.A 0 | ScrollDownUp |
| L6 | PromotableOperator_31.0 | PromotableOperator_32.B 1 | ScrollDownUp |
| L7 | PromotableOperator_32.0 | CallFunction_509.Value 0 | ScrollDownUp |
| L8 | CallFunction_509.0 | VariableSet_69.C2Dist 1 | ScrollDownUp |
| L9 | IfThenElse_98.then 0 | VariableSet_69.execute 0 | ScrollDownUp |
| L10 | CustomEvent_19.then 1 | IfThenElse_99.execute 0 | RotateCamera |
| L11 | IfThenElse_99.else 1 | IfThenElse_25.execute 0 | RotateCamera |
| L12 | PromotableOperator_8.0 | IfThenElse_99.Condition 1 | RotateCamera |
| L13 | CustomEvent_19.DeltaSeconds 2 | PromotableOperator_33.A 0 | RotateCamera |
| L14 | VariableGet_295.0 (`C2Height`) | PromotableOperator_34.A 0 | RotateCamera |
| L15 | PromotableOperator_33.0 | PromotableOperator_34.B 1 | RotateCamera |
| L16 | PromotableOperator_34.0 | CallFunction_510.Value 0 | RotateCamera |
| L17 | CallFunction_510.0 | VariableSet_70.C2Height 1 | RotateCamera |
| L18 | IfThenElse_99.then 0 | VariableSet_70.execute 0 | RotateCamera |
Les sorties `VariableSet_69.then` et `VariableSet_70.then` restent libres : elles marquent la fin de l'événement côté C2,
comme le schéma de la fiche (identique à F6a).
### 1.5 Valeurs (`set_pin_value`, 6, tous `{"returnValue":null}`, relues)
| Broche | Avant (relu à la création) | Après (relu) |
|---|---|---|
| PromotableOperator_31.B 1 | (neuf, `""`, joker) | `15.0` (`Float (double-précision)`) |
| CallFunction_509.Min 1 | `0.0` | `-75.0` |
| CallFunction_509.Max 2 | `1.0` | `125.0` |
| PromotableOperator_33.B 1 | (neuf, `""`, joker) | `3.0` (`Float (double-précision)`) |
| CallFunction_510.Min 1 | `0.0` | `-40.0` |
| CallFunction_510.Max 2 | `1.0` | `150.0` |
Chaque `set_pin_value` sur un opérateur a été posé juste après la liaison de A, qui type l'opérateur (L4, L13). Les
conditions des Branches 98 et 99 gardent leur valeur par défaut `true`, sans effet puisque la broche est liée (L3, L12).
### 1.6 Relecture et chaîne obtenue
`get_node_infos` final groupé sur 17 nœuds : les 12 créés, plus CE55, CE19, IfThenElse_10, IfThenElse_25 et PO8. Les
18 liens apparaissent des deux côtés et les 6 valeurs sont relues. Liens non touchés, relus intacts :
- CE55.Values → `CommutativeAssociativeBinaryOperator_2`.0, `CallFunction_26`.2, `_20`.0, `_10`.0, `_22`.0 (plus PO31.0) ;
- CE19.DeltaSeconds → `CommutativeAssociativeBinaryOperator_45`.1, `_12`.1, `_15`.1 (plus PO33.0) ;
- IfThenElse_10 : Condition ← `CommutativeAssociativeBinaryOperator_17`, then → `IfThenElse_12`, else libre ;
- IfThenElse_25 : Condition ← `CommutativeAssociativeBinaryOperator_19`, then → `IfThenElse_18`, else libre ;
- PO8 : A ← 439, B ← `VariableGet_268`, sortie → `IfThenElse_91`, `_96`, `_97` (plus 98.1 et 99.1).
Aucune divergence.
Chaîne obtenue :
- `ScrollDownUp` (CE55) → Branche 98 (`GetViewTarget(PC) == CamRoom`).
- Vrai : `Définir C2Dist` (69) := `Clamp(C2Dist − Values × 15, −75, 125)`, puis fin.
- Faux : `IfThenElse_10`, chaîne d'origine inchangée.
- `RotateCamera` (CE19) → Branche 99 (même condition).
- Vrai : `Définir C2Height` (70) := `Clamp(C2Height + DeltaSeconds × 3, −40, 150)`, puis fin.
- Faux : `IfThenElse_25`, chaîne d'origine inchangée.
### 1.7 Compilation
`compile_blueprint {blueprint:{refPath:"/Game/BPs/Room.Room"}, warnings_as_errors:true}` a renvoyé
`{"returnValue":null}`, sans exception : c'est le critère de la rubrique « Fin de chaque fiche ».
`hyper_blueprint_debug_inspect` n'a pas été appelé, car 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, faute du chemin `-abslog`. Pas de
`save_assets` : il est réservé à F7.
## 2. Écarts à la SPEC
- **Aucun écart de câblage.** La ligne B2b-6 (`CAM-SPEC.md:380`) et la fiche (`CAM-B2b-FICHES.md:132` et `:136`) sont
réalisées telles quelles pour `ScrollDownUp` et `RotateCamera`. Seuls les liens CE.then → branche d'origine ont été
coupés.
- **Formules** : `C2Dist := Clamp(C2Dist − Values × 15, −75, 125)` et `C2Height := Clamp(C2Height + D × 3, −40, 150)`.
Les opérandes ne sont pas inversés : A de PO32 = C2Dist, B = produit, relu.
- **Typage** : `Values` et `DeltaSeconds` sont en double précision, comme `Clamp(Float)` (Value, Min, Max et sortie en
double) : aucune conversion implicite.
- **Nœuds par événement** : un `Obtenir` et un `Clamp` distincts dans chacun, comme le prescrit la fiche (« (N) »).
PO8 est désormais partagé par cinq Branches (91, 96, 97, 98, 99).
- **Garde `Accessed None`** : aucune `IsValid` ajoutée, car ni la fiche ni la SPEC n'en demandent, et 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 `ScrollDownUp` et de `RotateCamera`, ce qui n'était pas le cas
avant. Même réserve qu'en F6a (§ 5, points 3 et 4).
- **Comportement** : identique à l'ancien quand C2 n'est pas la vue (sortie `else` → 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 proches : nœuds `LeftRight` de F6a (x 5250-5850, y 2750-2950), `IfThenElse_25` (5888, 5328).
Sans effet sur le graphe.
## 3. Instantané
Fait par l'orchestrateur avant F1 (non refait, consigne). Manifeste relu et disque mesuré après F6b :
```
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:06:13+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 à F6b ;
- 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
- `DownUp` (CE8 → IfThenElse_8, `Clamp(C2Height + AxisValue × 3, −40, 150)`) : renvoyé à la fiche suivante (F7).
- Fin de F7 : relecture de CE1, CE4, CE8, CE19, CE55, 459, 467, 474, 61 et 62, compilation stricte, puis `save_assets`
de `/Game/BPs/Room` seul. Hors périmètre.
- `hyper_blueprint_debug_inspect` et journal de l'éditeur : non consultés (§ 1.7).
- `save_assets` : interdit avant F7. F1 à F6b 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** : `ScrollDownUp` et `RotateCamera` prennent `else` → `IfThenElse_10` / `IfThenElse_25`, avec leurs
chaînes d'origine inchangées. Établi par le câblage ; à confirmer en jeu (zoom et tangage de l'ancienne caméra
identiques).
2. **Vue C2** :
- `ScrollDownUp` retire `Values × 15` à `C2Dist`, borné à [−75, 125] (distance 100 à 300 cm selon la SPEC) ;
- `RotateCamera` ajoute `DeltaSeconds × 3` à `C2Height`, borné à [−40, 150].
L'effet passe par `ComputeC2Target` (F3) au prochain appel. Signes et gains sont à juger à l'essai (SPEC : « ajustables
à l'essai »).
3. **`LogStats`** : aucun `Accessed None` nouveau sur `CallFunction_439` / `VariableGet_262`. PO8 est maintenant évalué à
chaque `ScrollDownUp` et à chaque `RotateCamera` ; ce dernier est probablement appelé à chaque image pendant la
rotation (estimé, appelant non lu).
4. **Cas limite (estimé, déjà noté en F6a)** : si `GetViewTarget` rend `None` et que `CamRoom` est aussi `None`, PO8 vaut
`true` (None == None), et ces événements écrivent alors `C2Dist` / `C2Height` au lieu de piloter l'ancienne caméra.
5. **`RotateCamera.DeltaSeconds`** est un delta de tangage selon la fiche, pas un temps (nom hérité). Si l'appelant passe
une valeur par image, le gain ×3 dépend de la fréquence d'image. Estimé, à juger à l'essai.
6. **V5 (`CAM-SPEC.md:382`)** pour ces deux événements : `then` → nouvelle branche (98, 99) ; `else` → branche d'origine
(10, 25).
7. **Valeurs sérialisées** après `save_assets` (F7), à relire par dump (`LPDumpFunction`) : PO31.B = 15.0 ; 509 Min −75.0,
Max 125.0 ; PO33.B = 3.0 ; 510 Min −40.0, Max 150.0.
8. **Compilation stricte** jugée sur la seule absence d'exception ; à recontrôler en F7 et par `CompileAllBlueprints`.
## 6. Fichiers à commiter
- `A Docs/Migration/etat/CAM/CAM-B2b-IMPL-F6b.md` (dépôt du jeu, branche `ue5.8`).
- `Content/BPs/Room.uasset` : rien à commiter pour F6b (non enregistré) ; il le sera après F7 et la VAL.
Tours : 48 / 60 (ce Write et la remise du compte rendu compris ; 43 appels MCP, un par message)
## Constats
- `Math|Flottant|Clamp(Float)` crée un `K2Node_CallFunction`. Broches : Value 0 (défaut 0.0), Min 1 (défaut 0.0),
Max 2 (défaut 1.0), ReturnValue out 0, toutes en `Float (double-précision)` dès la création (pas de joker).
- Correspondances relevées :
- `Variables|Pardéfaut|ObtenirC2Dist` → `|GetC2Dist` ; `ObtenirC2Height` → `|GetC2Height` ;
- `DéfinirC2Dist` → `|SetC2Dist` ; `DéfinirC2Height` → `|SetC2Height` ; broches comme `SetC2Yaw` (execute 0, valeur 1 ;
then 0, Output_Get 1).
- `Utilitaires|Opérateurs|Soustraire` naît en `Utilitaires|Gestiondutemps|FrameNumber-Int`. Lier A à un double le type
en `Math|Flottant|float-float` (A − B, A index 0).
- `DownUp` (F7), dans le même schéma : 6 créations, 1 coupure, 9 liaisons, 3 valeurs, soit 19 appels plus 1 lecture
groupée. Le Clamp se crée directement par `Math|Flottant|Clamp(Float)`, sans `find_node_types`.
- À verser : lp-mcp § 3 — `type_id` `Math|Flottant|Clamp(Float)` et index Value 0 / Min 1 / Max 2 / sortie 0 ;
`Soustraire` naît en `FrameNumber-Int` puis devient `float-float` à la liaison de A.