14 KiB
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 desave_assetsavant F7). Preuve au § 3 : le MD5 du disque après F6a est celui de l'instantané.- Graphe
/Game/BPs/Room.Room:EventGraph: événementCircleCamera(CE1, x 5296, y 4688) et événementLeftRight(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) :thenout 1 →IfThenElse_26.execute 0 ;DeltaSecondsout 2 (Float (double-précision)) →CommutativeAssociativeBinaryOperator_26.1,_16.1,_27.1.K2Node_CustomEvent_4(AddEvent|Custom|LeftRight) :thenout 1 →IfThenElse_9.execute 0 ;AxisValueout 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), pourCircleCameraetLeftRight, 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 :
DeltaSecondsetAxisValuesont en double précision, pas en simple. Il n'y a donc aucune conversion implicite. - Deux
Obtenir C2Yawdistincts (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: aucuneIsValidajoutée, car ni la fiche ni la SPEC n'en demandent. Les nœuds neufs ne lisent que des flottants. En revanche, PO8 (→ 439GetViewTarget, self ←VariableGet_262; →VariableGet_268CamRoom) est désormais évalué à chaque appel deCircleCameraet deLeftRight, ce qui n'était pas le cas avant. Si la cible de 262 (le contrôleur) est nulle à ce moment, unAccessed Noneapparaî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
elsevers 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,ClampdeC2Dist) : 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
- Vue autre que C2 :
CircleCameraetLeftRightprennentelse→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). - Vue C2 :
CircleCameraajouteDeltaSecondsàC2Yaw, etLeftRightajouteAxisValue × 2. L'effet sur C2 passe parBdir(F3, 497) au prochainComputeC2Target. Signes et gains à juger à l'essai (SPEC : « ajustables à l'essai »). LogStats: aucunAccessed Nonenouveau surCallFunction_439/VariableGet_262. PO8 est maintenant évalué à chaqueLeftRight, événement d'axe probablement appelé à chaque image (estimé, non lu), et à chaqueCircleCamera.- Cas limite (estimé) : si
GetViewTargetrendNoneet queCamRoomest aussiNone(avant sa création), PO8 vauttrue(None == None). Les deux événements écrivent alorsC2Yawau lieu de piloter l'ancienne caméra. À vérifier :CamRoomexiste-t-elle toujours avant le premier appel possible de ces événements ? C2Yawn'est pas borné (la SPEC ne le borne pas) : il croît sans fin à force de tourner.RotateVectorAroundAxisaccepte tout angle ; la précision double suffit (estimé).- V5 (
CAM-SPEC.md:382) pour ces deux événements :then→ nouvelle branche (96, 97) ;else→ branche d'origine (26, 9). - Valeur sérialisée après
save_assets(F7), par dump (LPDumpFunction) :PO29.B = 2.0. - 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, brancheue5.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) etAxisValue(CE4) sont enFloat (double-précision): relier A d'unAjouterou d'unMultiplierà ces broches le type directement enfloat+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 versPromotableOperator_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.