237 lines
14 KiB
Markdown
237 lines
14 KiB
Markdown
|
|
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`.
|