# 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_` ; 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` / `Définir` ; `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.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 = )` → `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.