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

142 lines
11 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.

# CAM-B2b : fiches lp-mcp-bp (2026-10-13)
GO d'écriture de Big Boss du 2026-10-13 : option 1, écritures par `lp-mcp-bp`, un appel MCP à la fois. SPEC :
`CAM-SPEC.md` § « CAM-B2b » (amendement B2b, MD5 `0f801b71`). Room seul.
## Découpage et barème
Budget : 75 tours par agent ; ≈ 3 appels par nœud. B2b compte ≈ 70 nœuds, soit ≈ 200 appels. Il est découpé en
7 fiches d'environ 50 appels, exécutées l'une après l'autre dans le même éditeur. Chaque fiche :
- grille a1 b1 c1 d1 e1 f1 = 6 → N2, ajustée à N3 (agent `lp-mcp-bp`, écriture MCP sous instantané) ;
- S = C3 1 (`lp-mcp` § 3) + f 1 = 2 < 3 : pas de scission supplémentaire.
| Fiche | Contenu (SPEC B2b) | Appels estimés |
|---|---|---|
| F1 | B2b-0 (5 variables) + `ComputeRoomBox`, partie XY | ≈ 55 |
| F2 | `ComputeRoomBox`, partie Z, extérieur et affectations | ≈ 45 |
| F3 | B2b-2 (appel de la boîte, borne de `Desired`, rayon 20) + B2b-5 (lacet, distance, hauteur) | ≈ 50 |
| F4 | B2b-4 (trajectoire protégée de la poursuite) | ≈ 40 |
| F5 | B2b-3 (repli vers le haut) | ≈ 55 |
| F6 | B2b-6 : `CircleCamera`, `LeftRight`, `ScrollDownUp` | ≈ 50 |
| F7 | B2b-6 : `RotateCamera`, `DownUp` ; compilation stricte finale ; `save_assets` | ≈ 40 |
Après F7, l'orchestrateur ferme l'éditeur, puis lance V5 et V6.
## Rubriques communes à toutes les fiches
- **Préalables** : BUILD-GO de Big Boss (2026-10-13, conditions 1 à 6) ; instantané `Backup_5.5\CAM-B2b\` fait par
l'orchestrateur (Room `A5FA970E`) ; éditeur headless **déjà ouvert** (port 8000) ; la session qui te lance est
connectée à `unreal-mcp`. Charge `select:mcp__unreal-mcp__call_tool` par ToolSearch. Outil absent : `BLOCKED-MCP`.
- **Règle absolue** : un seul appel `mcp__unreal-mcp__call_tool` par message, lectures comprises. Jamais deux.
- **Graphe** : `{"refPath":"/Game/BPs/Room.Room:EventGraph"}` ; nœud : `/Game/BPs/Room.Room:EventGraph.K2Node_<Nom>` ;
broche : `{"direction":"EGPD_Input|EGPD_Output","index_id":n,"node":{"refPath":…}}`.
- **Outils** (toolset `editor_toolset.toolsets.blueprint.BlueprintTools`) : `create_node {graph, type_id, pos}`,
`connect_pins {output_pin, input_pin}`, `break_pins`, `set_pin_value {pin, value}` (vecteur : "x,y,z"),
`get_node_infos {nodes:[{refPath}]}`, `find_node_types {graph, type_id_filter, context_pins:[]}`,
`add_variable {blueprint:{refPath:"/Game/BPs/Room.Room"}, name, type_name}`,
`add_event {blueprint, event_name, position}`, `compile_blueprint {blueprint, warnings_as_errors}`.
Toolset `editor_toolset.toolsets.asset.AssetTools` : `save_assets {asset_paths:["/Game/BPs/Room"]}`, F7 seulement.
- **Identifiants connus** (éditeur en français) :
- `Utilitaires|ContrôleDeFlux|Branche` (exécution 0, Condition 1 ; then 0, else 1) ;
- `Utilitaires|Opérateurs|Ajouter` / `Soustraire` / `Multiplier` / `Inférieurà(<)` (typés à la 1re liaison) ;
- `Math|Vecteur|BreakVector` (X 0, Y 1, Z 2) / `MakeVector` ;
- `Math|Vecteur|VectorBoundedtoBox` / `SelectVector` / `RotateVectorAroundAxis` / `VectorGetAbs` / `Distance(Vector)` ;
- `Transformation|GetWorldLocation` / `GetActorLocation` / `GetWorldScale` ;
- `Collision|SphereTraceByChannel` (Start 1, End 2, Radius 3, TraceChannel 4, ActorsToIgnore 6 ; then 0, OutHit 1,
ReturnValue 2) ; `Collision|BreakHitResult` (Location 4, Normal 6) ;
- `Variables|Pardéfaut|Obtenir<Var>` / `Définir<Var>` ; `Appelerunefonction|<Événement>`.
Un identifiant inconnu se cherche par `find_node_types` avec un filtre court (ex. « Clamp », « SelectFloat », « Abs »).
Après chaque `create_node`, relire les index de broches par `get_node_infos` avant de câbler.
- **Nœuds existants** (relus en B2) : 455 `GetSocketLocation(Mesh,'head')` (out 0) ; 458 `MakeVector` = `Desired`
(out 0 → 459.End et 62.in1) ; 459 `SphereTraceByChannel` ; 460 `BreakHitResult` ; PO3 `vector*vector` (A ← 454
`Normalize2D`, B = (−175,−175,−175), out → PO4.B) ; PO5 `float+float` (A ← 457.Z, B 60, out → 458.Z) ; PO6 (Normal ×
(12,12,12)) ; PO7 (Location + PO6, out → 61.in1) ; 61 / 62 = `Définir C2Target` ; MakeArray_5 = [MC, CamRoom] ;
CE47 `ComputeC2Target` (then 1 → 459) ; 467 appel `ComputeC2Target` (then → 474) ; 468 `VInterpTo` (out → 474.in2 et
473.in0) ; 473 `FindLookAtRotation` ; 474 `SetActorLocationAndRotation` ; 268 `Obtenir CamRoom` ; 261 `PlayerCharacter` ;
PO8 = `GetViewTarget(GI.PC) == CamRoom` (bool, réutilisable).
- **Interdits** : aucun autre asset ; ne touche à aucun nœud hors fiche ; ni `delete_node` ni `break_pins` hors des
liens nommés ; pas de `write_graph_dsl` ; pas de `ProgrammaticToolset` pour écrire ; pas de `save_assets` avant F7 ;
pas de git ; tu ne fermes pas l'éditeur.
- **Arrêt** : refus de permission, erreur inattendue, écart à la SPEC ou index de broche différent de la fiche →
arrêt et compte rendu (état de reprise : nœuds créés, liens faits), sans contourner.
- **Fin de chaque fiche** : `compile_blueprint {warnings_as_errors:true}` sur Room. Une exception → arrêt.
Puis `get_node_infos` des nœuds créés.
- **Livrable** : ajoute ta section à `Docs\Migration\etat\CAM\CAM-B2b-IMPL-F<n>.md` (un fichier par fiche, un seul
Write) : nœuds créés (`refPath`, `type_id`), liens, valeurs, compilation, écarts, tours.
- **Compte rendu** : court, en français, avec les noms des nœuds créés (utiles à la fiche suivante).
## F1 — variables et `ComputeRoomBox`, partie XY
1. `add_variable` ×5 : `C2BoxMin` Vector ; `C2BoxMax` Vector ; `C2Yaw` float ; `C2Height` float ; `C2Dist` float.
Le défaut de `C2Dist` (175) se règle en F3 par la valeur d'entrée des nœuds, pas par le CDO : voir F3.
2. `add_event` `ComputeRoomBox` (position x 38000, y 0).
3. Nœuds (positions x 38000-40000, y 0-800) :
- getters `StaticMeshComponent`, `Wall2`, `Wall4` → `GetWorldLocation` ×3 (sol, W2, W4) ;
- `GetActorLocation` (self vide = Room) → `R` ;
- `Soustraire` vecteur `W2 − sol` → `BreakVector` → X ;
- `Soustraire` vecteur `W4 − sol` → `BreakVector` → Y ;
- `MakeVector(X, Y, 0)` → `VectorGetAbs` → `Soustraire` vecteur, B = (30,30,0) → `E` ;
- `Min0` = `R − E` (Soustraire) ; `Max0` = `R + E` (Ajouter).
4. Laisser `Min0` et `Max0` non affectés (F2 termine). Compilation stricte : `Min0` et `Max0` sans consommateur ne
donnent aucun avertissement (nœuds purs).
Compte rendu : noms des nœuds `sol` (`GetWorldLocation`), `Min0`, `Max0`, du `CustomEvent` de `ComputeRoomBox`.
## F2 — `ComputeRoomBox`, partie Z, extérieur et affectations
1. `BreakVector(Min0)`, `BreakVector(Max0)`, `BreakVector(sol)` ; getter `WallT` → `GetWorldLocation` → `BreakVector`.
2. `ZMin` = `sol.Z + 50` ; `ZTopIn` = `WallT.Z − 25`.
3. Extérieur : `GetWorldScale(StaticMeshComponent)` → `BreakVector` → `Z < 0.05` (`Inférieurà(<)`) →
`SelectFloat(A = 1000000, B = ZTopIn, bPickA = <résultat>)` → `ZTop`. Chercher `SelectFloat` par `find_node_types`.
4. `MakeVector(Min0.X, Min0.Y, ZMin)` → `Définir C2BoxMin` ; `MakeVector(Max0.X, Max0.Y, ZTop)` → `Définir C2BoxMax`.
5. Exécution : `ComputeRoomBox.then` → `Définir C2BoxMin` → `Définir C2BoxMax`.
## F3 — B2b-2 (appel de la boîte, borne de `Desired`) et B2b-5 (lacet, distance, hauteur)
1. `break_pins` CE47.then (out 1) → 459.execute (in 0) ; (N) `Appelerunefonction|ComputeRoomBox` ; CE47.then → (N).
Puis (N).then → 459.execute.
2. (N) `Obtenir C2BoxMin`, `Obtenir C2BoxMax` ; (N) `VectorBoundedtoBox(InVect ← 458, Min, Max)` = `DesiredB`.
- `break_pins` 458 → 459.End ; `DesiredB` → 459.End (in 2) ;
- `break_pins` 458 → 62.in1 ; `DesiredB` → 62.in1.
3. `set_pin_value` 459.Radius (in 3) = "20.0" ; PO6.B (in 1) = "20.0,20.0,20.0".
4. (N) `VectorBoundedtoBox(PO7, Min, Max)` : `break_pins` PO7 → 61.in1, puis (N) → 61.in1.
5. B2b-5 :
- `break_pins` 454 → PO3.A ; (N) `Multiplier` vecteur (A ← 454, B = "-1,-1,-1") ;
- (N) `RotateVectorAroundAxis(InVect ← ce produit, AngleDeg ← Obtenir C2Yaw, Axis = "0,0,1")` = `Bdir`
→ PO3.A ;
- PO3.B, aujourd'hui une constante (−175 ×3) : (N) `Obtenir C2Dist` → (N) `Ajouter` float (A ← C2Dist, B = 175)
→ (N) `MakeVector(d, d, d)` → PO3.B. Comme le défaut de `C2Dist` vaut 0, la distance réelle est 175 + C2Dist ;
les bornes deviennent C2Dist ∈ [−75, 125] (F6) ;
- hauteur : `break_pins` PO5 → 458.Z (in 2) ; (N) `Ajouter` float (A ← PO5, B ← `Obtenir C2Height`) → 458.Z.
6. Contrôle : à `C2Yaw` = 0, `C2Height` = 0, `C2Dist` = 0, `Desired` = la valeur de B2.
## F4 — B2b-4 (trajectoire protégée de la poursuite)
1. `break_pins` 467.then (out 0) → 474.execute (in 0) ; (N) `SphereTraceByChannel` (Start ← 455, End ← 468,
Radius 20, TraceChannel "TraceTypeQuery2", ActorsToIgnore ← MakeArray_5) ; 467.then → (N).exec ;
(N).then → 474.exec.
2. (N) `BreakHitResult` ← OutHit ; (N) `Multiplier` vecteur (Normal × "20,20,20") ; (N) `Ajouter` (Location +
ce produit) ; (N) `SelectVector(A ← cette somme, B ← 468, bPickA ← trace.ReturnValue)` ;
(N) `VectorBoundedtoBox(← SelectVector, C2BoxMin, C2BoxMax)` = `Safe`.
3. `break_pins` 468 → 474.NewLocation (in 2) et 468 → 473.Start (in 0) ; `Safe` → 474.in2 et 473.in0.
## F5 — B2b-3 (repli vers le haut)
1. Après 61 et 62, qui n'ont pas de `then` : (N) Branche ; 61.then → Branche.exec ; 62.then → Branche.exec.
2. Condition : (N) `Obtenir C2Target` → (N) `Distance(Vector)` (← C2Target, ← 455) → (N) `Inférieurà(<)`, B = 80.
3. Vrai :
- `Desired2` = `VectorBoundedtoBox(455 + (0,0,100) + Bdir × (60,60,60), Min, Max)`, avec `Bdir` (nœud F3)
multiplié par "60,60,60" ;
- (N) `SphereTraceByChannel(Start ← 455, End ← Desired2, 20, TraceTypeQuery2, MakeArray_5)` ;
- `BreakHitResult` ; `Location + Normal × (20,20,20)` ; `SelectVector(somme, Desired2, ReturnValue)` ;
`VectorBoundedtoBox` ;
- (N) `Définir C2Target`.
Faux → fin.
## F6 — B2b-6 : `CircleCamera` (CE1 → IfThenElse_26), `LeftRight` (CE4 → IfThenElse_9), `ScrollDownUp` (CE55 → IfThenElse_10)
Pour chacun : `break_pins` CE.then (out 1) → branche d'origine ; (N) Branche (Condition ← PO8) ; CE.then → (N) ;
(N).else → branche d'origine ; (N).then → réglage :
- `CircleCamera` : `Définir C2Yaw` ← `C2Yaw + DeltaSeconds` (paramètre de CE1, out 2) ;
- `LeftRight` : `Définir C2Yaw` ← `C2Yaw + AxisValue × 2` ;
- `ScrollDownUp` : `Définir C2Dist` ← `Clamp(C2Dist − Values × 15, −75, 125)` (nœud `Clamp` float : chercher « Clamp »).
## F7 — B2b-6 : `RotateCamera` (CE19 → IfThenElse_25), `DownUp` (CE8 → IfThenElse_8) ; fin
Même schéma que F6 :
- `RotateCamera` : `Définir C2Height` ← `Clamp(C2Height + DeltaSeconds × 3, −40, 150)` ;
- `DownUp` : `Définir C2Height` ← `Clamp(C2Height + AxisValue × 3, −40, 150)`.
Puis :
- relecture `get_node_infos` : CE1, CE4, CE8, CE19, CE55, 459, 467, 474, 61, 62 ;
- compilation stricte ;
- `save_assets` `/Game/BPs/Room` seul.
Fin : ne ferme pas l'éditeur.