LifePlay-Revival/Docs/Migration/etat/CAM/CAM-B2n-IMPL.md

237 lines
14 KiB
Markdown
Raw Normal View History

Fiche CAM-B2n — Niveau N3 — Modèle prévu non indiqué par la fiche | utilisé claude-opus-5-5 — Agent A-MCP-BP (implémenteur Blueprint par MCP) — Skills sk-protocol, sk-change-safety, lp-mcp, lp-lot
# CAM-B2n-IMPL : orbite de la caméra de scène autour du couple, Room (2026-10-14)
Résultat : **fait**, avec l'amendement B2n-a (option A). Les 7 nœuds et les 14 liens sont posés (L1 à L13, L11
remplacé par L11a et L11b). L'axe vaut `0,0,1`. Tous les nœuds touchés ont été relus. La compilation stricte n'a
donné aucun diagnostic, et seul Room a été sauvegardé. Le travail s'est fait en deux passages dans le même éditeur
(pid 1272) :
- premier passage : arrêt sur l'écart E1, après la création de 101 et 535 ;
- reprise : sur décision de l'orchestrateur, consignée dans `CAM-B2n-FICHE.md` § « Amendement B2n-a ».
## 1. Fichiers modifiés
- `Content/BPs/Room.uasset` (dépôt du jeu, copie 5.8). Sauvegardé par `save_assets` le 2026-10-14 ; journal de
l'éditeur l. 2481 à 2487.
- MD5 avant B2n (état laissé par B2k) : `6be71e0110c4187fa02d7ac9c1c92306` ;
- MD5 après B2n : `3a451fddf991ac01a699af7bd1fbdc12`.
- `Docs/Migration/etat/CAM/CAM-B2n-IMPL.md` (ce livrable).
## 2. Écarts à la SPEC
- **E1 (amendé, option A)** : `GetActorArrayAverageLocation` est `BlueprintCallable`, il a des broches d'exécution.
Source : `D:/Game/Launcher/Engine/UE_5.8/Engine/Source/Runtime/Engine/Classes/Kismet/GameplayStatics.h:76`.
Il est donc placé dans le fil d'exécution : L11a `101.then` → `535.execute`, puis L11b `535.then` → `538.execute`.
Ces deux liens remplacent L11.
- **E2 (amendé)** : la soustraction et l'addition passent par les opérateurs génériques
`Utilitaires|Opérateurs|Soustraire` et `Ajouter`, de classe `K2Node_PromotableOperator`.
- À la création, leur type_id affiché est `Utilitaires|Gestiondutemps|FrameNumber-Int` (`+Int`), avec des broches
de type « Caractère de remplacement ».
- Après le branchement d'un vecteur, ils deviennent `Math|Vecteur|vector-vector` et `Math|Vecteur|vector+vector`,
avec des broches `Vector` (relu).
- **Ordre des écritures** : j'ai posé L3 juste après la reprise, avant de créer les 5 autres nœuds, parce que c'était
la condition d'arrêt et qu'un refus aurait ainsi laissé le moins d'écritures possible. J'ai posé L5 juste après la
création de Soustraire, pour vérifier le typage vecteur avant de poursuivre. Le graphe final est celui de la fiche
amendée.
- **Tours** : 63 au total pour un budget de 60, sous le plafond de 75. Le dépassement vient de la reprise ordonnée en
cours de route, sans nouveau budget, et de deux lectures du journal avant la sauvegarde.
## 3. Instantané
`D:\Game\LifePlay_Backup_5.5\CAM-B2kmn\manifest.csv` (instantané commun du passage, pris par l'orchestrateur) :
```
"Rel","Existed","Size","MD5","Date"
"Content\BPs\Room.uasset","True","6387514","18565365B1195BF2416A1048BF9051B6","2026-10-14T00:59:11"
"Content\BPs\PC.uasset","True","3404928","A19510E613F31905437BAB48F38C6154","2026-10-14T00:59:11"
```
Retour arrière, éditeur fermé : `.\Tools\Restore.ps1 -Lot CAM-B2kmn -Only Content\BPs\Room.uasset`. Il ramène Room
à l'état d'avant B2k (`18565365…`), ce qui annule aussi B2k. L'état de B2k seul (`6be71e01…`) n'a pas d'instantané
séparé.
## 4. Ce qui n'a pas été fait
- `hyper_blueprint_debug_inspect` : outil absent du serveur. Je l'ai remplacé par `compile_blueprint
{warnings_as_errors:true}` et la lecture du journal.
- Ni `CompileAllBlueprints`, ni build, ni jeu : cela revient à la VAL et au BUILD, éditeur fermé.
- Aucun `IsValid` ajouté (voir § Garde en Constats).
## 5. Points à confirmer en VAL
- V5, dump de Room comparé à l'état de B2k :
- 7 nœuds de plus : `IfThenElse_101`, `CallFunction_535` à `_538`, `PromotableOperator_46` et `_47` ;
- 14 liens de plus (§ Liens) et `537.Axis` = (0, 0, 1) ;
- aucune autre différence ; le nœud 512 de B2k est présent et inchangé.
- `537.Axis` est enregistré sous la chaîne `0,0,1`, alors que 497 porte `0.0,0.0,1.0`. Le dump doit montrer Z = 1.
- `CustomEvent_1.DeltaSeconds` (Float double précision) alimente `537.AngleDeg` (Float simple précision). La
conversion implicite a été acceptée sans diagnostic. Elle est à voir dans V6.
- V6 : `CompileAllBlueprints` éditeur fermé = référence.
- V7 (`CAM-COMMUN-6-TESTS.md`), à l'essai en jeu :
- pendant le sexe, la souris fait tourner la caméra autour du couple, cadrage gardé ;
- hors sexe, rien ne change ;
- surveiller le cas `SexPersons` vide pendant `SexOn` (orbite autour de l'origine).
- L'éditeur a fait une sauvegarde automatique de Room dans `Saved/Autosaves/Game/BPs/Room_Auto1.uasset` (journal
l. 2407, pendant l'arrêt du premier passage). Elle n'est pas dans Content ; à ignorer.
## 6. Fichiers à commiter
Dépôt du jeu (copie 5.8, branche ue5.8) :
```
M Content/BPs/Room.uasset
A Docs/Migration/etat/CAM/CAM-B2n-IMPL.md
```
`Room.uasset` contient aussi la modification de B2k (nœud 512), qui ne peut pas en être séparée : le ticket au gardien
doit le dire.
Tours : 63 / 60
## Constats
### Appels MCP (un par message)
Premier passage :
1. `AssetTools.load_asset {"asset_path":"/Game/BPs/Room"}` → `/Game/BPs/Room.Room`.
2. `get_node_infos` sur 149, 148, 147, 146, `CommutativeAssociativeBinaryOperator_26`, `IfThenElse_19`,
`IfThenElse_26`, `VariableGet_102`, `VariableGet_86`, `VariableGet_106`, `CustomEvent_1` → conforme à « État ».
3. `find_node_types` (filtre par sous-chaîne du type_id) :
- `ActorLocation`, contexte 102 Out0 → `Transformation|GetActorLocation` et `Transformation|SetActorLocation` ;
- `AverageLocation` → `Transformation|GetActorArrayAverageLocation` ;
- `vector-vector` → `[]` ; `RotateAngleAxis` → `[]` ; `Math|Vecteur|` → sans `+` ni `-` ;
- `Subtract`, puis `-` avec contexte → sans rapport ;
- `Opérat` → `Utilitaires|Opérateurs|Soustraire` et `Ajouter`.
4. `get_node_infos` 497 → `Math|Vecteur|RotateVectorAroundAxis` ; `PromotableOperator_17` et `_3` →
`Math|Vecteur|vector*vector`.
5. `create_node` Branche (7200, 4704) → `K2Node_IfThenElse_101`, relu.
6. `create_node` `Transformation|GetActorArrayAverageLocation` (7200, 5200) → `K2Node_CallFunction_535`, relu :
execute et then présents, **arrêt (E1)**. `is_dirty` → `true`.
Reprise (amendement B2n-a) :
7. `get_node_infos` 101, 535, 106 → inchangés.
8. `connect_pins` L3, puis relecture : accepté (`Matrice de Person` vers `Matrice de Acteur`). 106 sort toujours vers
`MacroInstance_13`.
9. `create_node` `Transformation|GetActorLocation` (7200, 5350) → `K2Node_CallFunction_536`, relu.
10. `create_node` `Utilitaires|Opérateurs|Soustraire` (7550, 5300) → `K2Node_PromotableOperator_46`, relu (générique).
Puis L5 et relecture → `Math|Vecteur|vector-vector`.
11. `create_node` `Math|Vecteur|RotateVectorAroundAxis` (7800, 5300) → `K2Node_CallFunction_537`, relu.
12. `create_node` `Utilitaires|Opérateurs|Ajouter` (8100, 5250) → `K2Node_PromotableOperator_47`, relu (générique).
13. `create_node` `Transformation|SetActorLocation` (8400, 4704) → `K2Node_CallFunction_538`, relu. `bSweep` et
`bTeleport` valent `false` par défaut ; je ne les ai pas modifiés.
14. `connect_pins`, dans l'ordre : L1, L2, L11a, L11b, L4, L6, L7, L8. Ensuite `set_pin_value` `537.Axis` =
`0,0,1`, accepté du premier coup. Puis L9, L10, L12, L13. Chaque appel a renvoyé `null`.
15. Relecture `get_node_infos` de 17 nœuds : 149, 101, 535 à 538, 46, 47, 102, 86, 106, `CustomEvent_1`, 19, 26, 29,
96, `MacroInstance_13`. Résultat conforme (§ Relecture).
16. `AssetTools.is_dirty {"asset_path":"/Game/BPs/Room"}` → `true`.
17. `BlueprintTools.compile_blueprint {"blueprint":{"refPath":"/Game/BPs/Room.Room"},"warnings_as_errors":true}` →
`{"returnValue":null}`, sans erreur.
18. `AssetTools.save_assets {"asset_paths":["/Game/BPs/Room"]}` → `{"returnValue":true}`.
### Les 7 nœuds (préfixe `/Game/BPs/Room.Room:EventGraph.`)
| Nœud | refPath | type_id relu | Position |
|---|---|---|---|
| Branche | `K2Node_IfThenElse_101` | `Utilitaires|ContrôleDeFlux|Branche` | 7200, 4704 |
| Moyenne | `K2Node_CallFunction_535` | `Transformation|GetActorArrayAverageLocation` | 7200, 5200 |
| Position caméra | `K2Node_CallFunction_536` | `Transformation|GetActorLocation` | 7200, 5350 |
| Soustraction | `K2Node_PromotableOperator_46` | `Math|Vecteur|vector-vector` | 7550, 5300 |
| Rotation | `K2Node_CallFunction_537` | `Math|Vecteur|RotateVectorAroundAxis` | 7800, 5300 |
| Addition | `K2Node_PromotableOperator_47` | `Math|Vecteur|vector+vector` | 8100, 5250 |
| Déplacement | `K2Node_CallFunction_538` | `Transformation|SetActorLocation` | 8400, 4704 |
### PinID des nœuds créés (direction, index)
- 101 : execute In0, Condition In1, then Out0, else Out1 (vide).
- 535 : execute In0, Actors In1 (« Matrice de Acteur »), then Out0, ReturnValue Out1 (Vector).
- 536 : self In0, ReturnValue Out0 (Vector).
- 46 et 47 : A In0, B In1, ReturnValue Out0 (Vector après typage).
- 537 : InVect In0, AngleDeg In1 (Float simple précision), Axis In2, ReturnValue Out0.
- 538 :
- entrées : execute In0, self In1, NewLocation In2, bSweep In3 (`false`), bTeleport In4 (`false`) ;
- sorties : then Out0 (vide), SweepHitResult Out1, ReturnValue Out2.
- Broches existantes utilisées :
- 149 then Out0 ;
- 86 SexOn Out0 ;
- 106 SexPersons Out0 ;
- 102 SceneCamera Out0 ;
- `CustomEvent_1` DeltaSeconds Out2.
### Liens posés (14)
| Lien | Sortie | Entrée |
|---|---|---|
| L1 | `CallFunction_149` Out0 (then) | `IfThenElse_101` In0 (execute) |
| L2 | `VariableGet_86` Out0 (SexOn) | `IfThenElse_101` In1 (Condition) |
| L3 | `VariableGet_106` Out0 (SexPersons) | `CallFunction_535` In1 (Actors) |
| L4 | `VariableGet_102` Out0 (SceneCamera) | `CallFunction_536` In0 (self) |
| L5 | `CallFunction_536` Out0 | `PromotableOperator_46` In0 (A) |
| L6 | `CallFunction_535` Out1 | `PromotableOperator_46` In1 (B) |
| L7 | `PromotableOperator_46` Out0 | `CallFunction_537` In0 (InVect) |
| L8 | `CustomEvent_1` Out2 (DeltaSeconds) | `CallFunction_537` In1 (AngleDeg) |
| L9 | `CallFunction_535` Out1 | `PromotableOperator_47` In0 (A) |
| L10 | `CallFunction_537` Out0 | `PromotableOperator_47` In1 (B) |
| L11a | `IfThenElse_101` Out0 (then) | `CallFunction_535` In0 (execute) |
| L11b | `CallFunction_535` Out0 (then) | `CallFunction_538` In0 (execute) |
| L12 | `VariableGet_102` Out0 (SceneCamera) | `CallFunction_538` In1 (self) |
| L13 | `PromotableOperator_47` Out0 | `CallFunction_538` In2 (NewLocation) |
Valeur posée : `CallFunction_537` In2 (Axis) = `0,0,1`, relue `0,0,1`.
### Relecture (étape 5 de la fiche)
- `149.then` → 101 seul. Ses entrées sont inchangées : execute ← 19 Out1, self ← 102, NewRotation ← 148.
- 102 Out0 → 146, 149, 229, 228, 536, 538.
- 86 Out0 → `CommutativeAssociativeBinaryOperator_19`, 29, 28, 453, 101 ; self ← 103.
- 106 Out0 → `MacroInstance_13` In1, 535 In1 ; self ← 105.
- `CustomEvent_1` :
- DeltaSeconds Out2 → `CommutativeAssociativeBinaryOperator_26`, `_16`, `_27`, `PromotableOperator_28`, 537 ;
- then Out1 → 96.
- Inchangés :
- 19 : then → 29, else → 149 ;
- 26 : then → 19, else vide, Condition ← `CommutativeAssociativeBinaryOperator_19` ;
- 29 : then → `MacroInstance_13`, else → `IfThenElse_21` ;
- 96 : then → `CallFunction_516`, else → 26 ;
- `MacroInstance_13` : LoopBody → 153, Array Element → 150 et 153, Array ← 106.
- Nœuds créés : tous leurs liens correspondent au tableau ci-dessus. 101.else et 538.then sont vides.
### Compilation
`compile_blueprint` en mode strict (`warnings_as_errors:true`) → `null`, sans erreur. Journal de l'éditeur :
- l. 2476 : `LogBlueprint: Compiling Blueprint '/Game/BPs/Room.Room'` ;
- l. 2477 : `LogUObjectHash`, puis plus aucune ligne d'erreur ou d'avertissement jusqu'à l'appel suivant.
C'est la même forme que la compilation de B2k (l. 2273-2274).
### Sauvegarde
Journal de l'éditeur `D:\Game\LifePlay_Backup_5.5\CAM-B2kmn\editeur\editeur-B2kmn.log` :
```
2481 [2026.10.13-23.14.29:576][908]LogFileHelpers: Saving Package: /Game/BPs/Room
2485 ...Cmd: OBJ SAVEPACKAGE PACKAGE="/Game/BPs/Room" FILE=".../LifePlay-master 5.8/Content/BPs/Room.uasset" SILENT=true
2486 ...LogSavePackage: Moving output files for package: /Game/BPs/Room
```
Dans les lignes 2478 à 2511, aucun autre paquet n'est sauvegardé, et il n'y a ni `Error` ni `Warning`. Les horodatages
du journal sont en UTC.
### MD5 (2026-10-14, `md5sum` dans la copie 5.8, après la sauvegarde)
```
3a451fddf991ac01a699af7bd1fbdc12 *Content/BPs/Room.uasset
f45be57a39d13d3eb19d0b543153ab0b *Content/BPs/PC.uasset
e64b5b37c9ef0db7735de0d6e3bd7c1c *Content/BPs/GI.uasset
8668a47c627f7a5254910cf0ac33b12a *Content/BPs/Person.uasset
```
- Room diffère de `6be71e01…`.
- PC (`f45be57a…`), GI (`e64b5b37…`) et Person (`8668a47c…`) sont inchangés.
- `git status --short -- Content/` affiche les 4 fichiers en `M`. Pour PC, GI et Person, ces modifications sont
antérieures à B2n.
### Garde `Accessed None`
- Aucun `IsValid` ajouté :
- `SceneCamera` est déjà lu sans garde par 146 et 149 sur ce chemin ;
- `GI.SexPersons` n'est lu que si `SexOn` est vrai (101, puis 535). Avant B2n, `GI` était déjà lu sur ce chemin par
86, via 103. 106 le lit via un autre getter, 105 : il s'agit probablement de la même variable (estimé).
- `SexPersons` vide pendant `SexOn` : la moyenne vaut (0, 0, 0), sans `Accessed None`. Ce cas est à surveiller en V7.
### À verser
lp-mcp § 3 :
- `GetActorArrayAverageLocation` est `BlueprintCallable` (`GameplayStatics.h:76`) et doit être mis dans le fil
d'exécution ;
- les opérateurs vectoriels se créent par `Utilitaires|Opérateurs|Ajouter` / `Soustraire`. À la création, le type_id
affiché est `Utilitaires|Gestiondutemps|FrameNumber±Int`, avec des broches génériques ; il devient
`Math|Vecteur|vector±vector` dès qu'un vecteur est branché ;
- `RotateAngleAxis` a pour type_id `Math|Vecteur|RotateVectorAroundAxis` ;
- `find_node_types` filtre par sous-chaîne du type_id ;
- `connect_pins`, `set_pin_value` et `compile_blueprint` renvoient `null` en cas de succès : seule la relecture
prouve le résultat ;
- `AssetTools.is_dirty {asset_path}` fonctionne ;
- un tableau de `Person` se branche sur un tableau d'`Actor` ;
- `set_pin_value` d'un vecteur accepte `0,0,1`.