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

294 lines
22 KiB
Markdown
Raw Normal View History

Fiche CAM-B2s — Niveau N3 — Modèle prévu non précisé par la fiche | utilisé claude-opus-5-5 — Agent lp-mcp-bp (A-MCP-BP) — Skills sk-protocol, sk-change-safety, lp-mcp, lp-lot
# CAM-B2s-IMPL : orientation de C1 recalée à chaque passage (P5) et pose avant le retour de la vue (P6), Room enregistré (2026-10-14)
Résultat : **réussi**, P5 et P6, en un passage dans l'éditeur headless déjà lancé par l'orchestrateur (pid 22200, port 8000).
- L'état lu est conforme au tableau « État attendu avant écriture ».
- 4 nœuds créés, 11 liens posés (L1 à L11). L5 remplace bien `449.then → 434`.
- Relecture conforme. Compilation stricte sans diagnostic. `save_assets` de Room seul.
- Room passe de `3a451fdd…` à `c5ab7241…`. GI, PC et Person sont inchangés et n'ont pas été chargés.
Spécification : `Docs/Migration/etat/CAM/CAM-B2s-FICHE.md` (parties P5 et P6, étapes 1 à 6). UE-GO accordé par Big Boss à la
session CAM (message de l'orchestrateur). Préfixe des nœuds : `/Game/BPs/Room.Room:EventGraph.`. Un seul appel MCP par
message, aucun en parallèle. Outils : `editor_toolset.toolsets.asset.AssetTools` (AT) et
`editor_toolset.toolsets.blueprint.BlueprintTools` (BT). Aucune écriture par HyperAIStudio.
Abréviations : `n` = `K2Node_CallFunction_n` ; `PO_n` = `K2Node_PromotableOperator_n` ; `8x` = `K2Node_IfThenElse_8x` ;
`265` = `K2Node_VariableGet_265`. PinID écrit `{direction, index_id}` sur le nœud nommé ; refPath complet = préfixe + nom.
## 1. Fichiers modifiés
- `Content/BPs/Room.uasset` : 4 nœuds créés, 11 liens posés. Un seul lien existant a été remplacé (`449.then → 434`,
voulu par L5).
- MD5 avant : `3a451fddf991ac01a699af7bd1fbdc12` (6 408 870 octets).
- MD5 après : `c5ab724101fa898457293d64059d21a9` (6 422 095 octets, 2026-10-14 08:41:19 locale).
- Seule sauvegarde au journal de l'éditeur : l. 2354, `LogFileHelpers: Saving Package: /Game/BPs/Room`.
- `Content/BPs/GI.uasset` = `e64b5b37…`, `PC.uasset` = `f45be57a…`, `Person.uasset` = `8668a47c…` : identiques avant
et après. Aucun n'a été chargé (0 ligne `/Game/BPs/(GI|PC|Person)` au journal de l'éditeur).
- `Docs/Migration/etat/CAM/CAM-B2s-IMPL.md` : ce livrable.
### 1.1 Étapes de la fiche
| Étape | Contenu | Statut |
|---|---|---|
| Entrée | MD5 de Room = `3A451FDD…` (manifeste et disque), revérifié juste avant la première écriture | fait |
| 1 | `load_asset` ; `get_node_infos` sur les 6 nœuds du tableau (+ 524, 148, 80 à 83, 329, 440, 441) | fait, conforme (§ 1.4) |
| 2 | Types : `Transformation|SetWorldRotation` et `Math|Rotateur|MakeRotator`, contrôlés après création | fait (§ 1.3) |
| 3 | P5 : R1, W1, L1 à L4 ; R1 Pitch et Roll à 0, W1 bSweep et bTeleport faux (défauts, aucun `set_pin_value`) | fait |
| 4 | P6 : L6, W6, L5 à L11 | fait |
| 5 | Relecture (512, 265, 514.Yaw, PO_2, 449, 434, R1, W1, L6, W6 ; 80, 81, 82, 83, 329, 440, 441) | fait, conforme (§ 1.5) |
| 6 | `is_dirty` = `true` ; `compile_blueprint` strict ; `save_assets` Room seul ; `Saving Package` ; MD5 | fait (§ 1.6) |
### 1.2 Appels MCP, dans l'ordre (30)
| # | Appel | Arguments | Retour |
|---|---|---|---|
| 1 | AT.`load_asset` | `{asset_path:"/Game/BPs/Room"}` | `{"refPath":"/Game/BPs/Room.Room"}` |
| 2 | BT.`get_node_infos` | 512, 514, 265, 449, 434, PO_2 | état avant, conforme |
| 3 | BT.`get_node_infos` | 524, 148, 80, 81, 82, 83, 329, 440, 441 | état avant des voisins |
| 4 | BT.`find_node_types` | `{graph:"…:EventGraph", type_id_filter:"SetWorldRotation", context_pins:[265 {EGPD_Output,0}]}` | `["Transformation|SetWorldRotation"]` |
| 5 | BT.`find_node_types` | `{graph:"…:EventGraph", type_id_filter:"MakeRotator", context_pins:[]}` | 13 types, dont `Math|Rotateur|MakeRotator` (= 148) |
| 6 | BT.`create_node` | `Math|Rotateur|MakeRotator`, pos (31950, 3550) | `K2Node_CallFunction_539` (R1) |
| 7 | BT.`create_node` | `Transformation|SetWorldRotation`, pos (32350, 3800) | `K2Node_CallFunction_540` (W1) |
| 8 | BT.`get_node_infos` | 539, 540 | broches libres, défauts (§ 1.3) |
| 9 | BT.`connect_pins` L1 | 512 `{EGPD_Output,0}` then → 540 `{EGPD_Input,0}` execute | `null` |
| 10 | BT.`connect_pins` L2 | 265 `{EGPD_Output,0}` FirstPersonSM → 540 `{EGPD_Input,1}` self | `null` |
| 11 | BT.`connect_pins` L3 | 539 `{EGPD_Output,0}` ReturnValue → 540 `{EGPD_Input,2}` NewRotation | `null` |
| 12 | BT.`connect_pins` L4 | 514 `{EGPD_Output,2}` Yaw → 539 `{EGPD_Input,2}` Yaw | `null` |
| 13 | BT.`get_node_infos` | 539, 540 | P5 conforme |
| 14 | BT.`create_node` | `Transformation|SetWorldLocation`, pos (34550, 900) | `K2Node_CallFunction_541` (L6) |
| 15 | BT.`create_node` | `Transformation|SetWorldRotation`, pos (34950, 900) | `K2Node_CallFunction_542` (W6) |
| 16 | BT.`get_node_infos` | 541, 542 | broches libres, défauts (§ 1.3) |
| 17 | BT.`connect_pins` L5 | 449 `{EGPD_Output,0}` then → 541 `{EGPD_Input,0}` execute | `null` |
| 18 | BT.`get_node_infos` | 449, 434 | 449.then → 541 seul ; 434.execute ← 80 seul (lien 449 → 434 remplacé, voulu) |
| 19 | BT.`connect_pins` L6 | 541 `{EGPD_Output,0}` then → 542 `{EGPD_Input,0}` execute | `null` |
| 20 | BT.`connect_pins` L7 | 542 `{EGPD_Output,0}` then → 434 `{EGPD_Input,0}` execute | `null` |
| 21 | BT.`get_node_infos` | 434 | execute ← 80 [0] et 542 [0] : l'entrée depuis 80 est gardée |
| 22 | BT.`connect_pins` L8 | 265 `{EGPD_Output,0}` → 541 `{EGPD_Input,1}` self | `null` |
| 23 | BT.`connect_pins` L9 | PO_2 `{EGPD_Output,0}` ReturnValue → 541 `{EGPD_Input,2}` NewLocation | `null` |
| 24 | BT.`connect_pins` L10 | 265 `{EGPD_Output,0}` → 542 `{EGPD_Input,1}` self | `null` |
| 25 | BT.`connect_pins` L11 | 539 `{EGPD_Output,0}` → 542 `{EGPD_Input,2}` NewRotation | `null` |
| 26 | BT.`get_node_infos` | 512, 265, 514, PO_2, 449, 434, 539, 540, 541, 542 | relecture finale, conforme (§ 1.5) |
| 27 | BT.`get_node_infos` | 80, 81, 82, 83, 329, 440, 441 | identiques à l'appel 3 |
| 28 | AT.`is_dirty` | `{asset_path:"/Game/BPs/Room"}` | `true` |
| 29 | BT.`compile_blueprint` | `{blueprint:{refPath:"/Game/BPs/Room.Room"}, warnings_as_errors:true}` | `null` (pas d'exception) |
| 30 | AT.`save_assets` | `{asset_paths:["/Game/BPs/Room"]}` | `true`, confirmé par le journal et le MD5 |
Aucun `break_pins`, `delete_node` ni `set_pin_value`. Le journal de l'éditeur compte 30 lignes `Dispatching toolset tool`
(l. 2291 à 2352) : 1 `load_asset`, 9 `get_node_infos`, 2 `find_node_types`, 4 `create_node`, 11 `connect_pins`,
1 `is_dirty`, 1 `compile_blueprint`, 1 `save_assets`.
### 1.3 Nœuds créés
| Rôle | refPath | type_id | Position | Broches (PinID) |
|---|---|---|---|---|
| R1 `MakeRotator` | `/Game/BPs/Room.Room:EventGraph.K2Node_CallFunction_539` | `Math|Rotateur|MakeRotator` | (31950, 3550) | entrées Roll `{EGPD_Input,0}` = 0.0, Pitch `{EGPD_Input,1}` = 0.0, Yaw `{EGPD_Input,2}` ; sortie ReturnValue `{EGPD_Output,0}` (Rotator) ; aucune broche d'exécution |
| W1 `K2_SetWorldRotation` | `/Game/BPs/Room.Room:EventGraph.K2Node_CallFunction_540` | `Transformation|SetWorldRotation` | (32350, 3800) | entrées execute `{EGPD_Input,0}`, self `{EGPD_Input,1}` (Scene Component), NewRotation `{EGPD_Input,2}`, bSweep `{EGPD_Input,3}` = false, bTeleport `{EGPD_Input,4}` = false ; sorties then `{EGPD_Output,0}`, SweepHitResult `{EGPD_Output,1}` |
| L6 `K2_SetWorldLocation` | `/Game/BPs/Room.Room:EventGraph.K2Node_CallFunction_541` | `Transformation|SetWorldLocation` | (34550, 900) | mêmes broches que 512 : execute 0, self 1, NewLocation 2, bSweep 3 = false, bTeleport 4 = false ; then 0, SweepHitResult 1 |
| W6 `K2_SetWorldRotation` | `/Game/BPs/Room.Room:EventGraph.K2Node_CallFunction_542` | `Transformation|SetWorldRotation` | (34950, 900) | mêmes broches que 540 |
Contrôle des types :
- `get_node_infos` ne donne pas le nom C++ de la fonction : il donne le `type_id`, les broches et leurs types.
- W1 et W6 : catégorie `Transformation`, self `Scene Component`, broches NewRotation, bSweep, SweepHitResult,
bTeleport. C'est la déclaration de `USceneComponent::K2_SetWorldRotation`
(`D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\Engine\Classes\Components\SceneComponent.h:573-574` :
`Category="Transformation"`, `ScriptName="SetWorldRotation"`). `find_node_types` ne rend qu'un seul type pour ce filtre.
- R1 : même `type_id` que le `MakeRotator` existant 148. La déclaration est
`D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\Engine\Classes\Kismet\KismetMathLibrary.h:2252-2253`
(`UFUNCTION(BlueprintPure, Category="Math|Rotator"…) MakeRotator(`). R1 est donc **pur** (aucune broche d'exécution
à la relecture) et il est réévalué à chaque appel de W1 et de W6.
- L6 : même `type_id` et mêmes broches que 512 (`K2_SetWorldLocation`, établi en B2k).
- Le nom exact de la UFunction appelée par chaque nœud est **estimé** sur ces preuves. Le dump de V5 le tranchera.
- Les noms `K2Node_CallFunction_539` à `_542` sont absents du dump de référence (Grep sur
`CAM-B2kmn-VAL_LPDumpFunction_20261014-011706.txt` : 0 occurrence). Ils sont donc nouveaux au diff de V5.
### 1.4 État lu avant écriture (appels 2 et 3), comparé au tableau de la fiche
| Nœud | Lu | Tableau |
|---|---|---|
| 512 `Transformation|SetWorldLocation` (31550, 3800) | execute ← `83` [0] ; **then `{EGPD_Output,0}` vide** ; self ← `265` [0] ; NewLocation ← `PO_2` [0] ; bSweep, bTeleport false | conforme |
| 514 `Math|Rotateur|BreakRotator` (34000, 1900) | InRot ← `524` [0] ; Yaw `{EGPD_Output,2}` → `PO_28` [0], `PO_30` [0] ; Roll [0] et Pitch [1] libres | conforme |
| 524 `Pion|GetControlRotation` (33700, 2200) | self ← `VariableGet_262` [0] (Controller) ; ReturnValue → `513` [0] et `514` [0] | conforme (le lien vers 513 est hors tableau, laissé tel quel) |
| 265 `|GetFirstPersonSM` (30200, 2400) | self ← `VariableGet_261` [0] ; FirstPersonSM `{EGPD_Output,0}` → 430, 431, 433, 446, 512 `[1]` | conforme |
| 449 `Utilitaires|Contrôledeflux|DelayUntilNextFrame` (34200, 700) | execute ← `VariableSet_53` [0] ; then `{EGPD_Output,0}` → `434` [0] | conforme |
| 434 `Jeu|Joueur|SetViewTargetWithBlend` (32200, 600) | execute ← `449` [0] et `80` [0] ; self ← `262` ; NewViewTarget ← `261` ; then → `329` [0] | conforme |
| PO_2 `Math|Vecteur|vector*vector` (31450, 1050) | A ← `PO_1` ; B = `0.5,0.5,0.5` ; ReturnValue `{EGPD_Output,0}` → `446` [2], `512` [2] | conforme |
| 148 `Math|Rotateur|MakeRotator` | Roll [0], Pitch [1], Yaw [2] ; ReturnValue → `149` [2] | référence du type, non touché |
| 80, 81, 82, 83, 329, 440, 441 | voir § 1.5 (identiques avant et après) | hors tableau |
Aucun écart : l'écriture a commencé.
### 1.5 Relecture finale (appels 26 et 27)
| Broche | Avant | Après |
|---|---|---|
| `512` then `{EGPD_Output,0}` | vide | **→ `540` [0]** ; execute, self, NewLocation identiques |
| `265` FirstPersonSM `{EGPD_Output,0}` | → 430, 431, 433, 446, 512 | → 430, 431, 433, 446, 512, **540, 541, 542** (`[1]`, 8 liens) ; self ← 261 identique |
| `514` Yaw `{EGPD_Output,2}` | → PO_28 [0], PO_30 [0] | → PO_28 [0], PO_30 [0], **539 [2]** ; InRot ← 524 identique |
| `PO_2` ReturnValue `{EGPD_Output,0}` | → 446 [2], 512 [2] | → 446 [2], 512 [2], **541 [2]** ; A, B identiques |
| `449` then `{EGPD_Output,0}` | → 434 [0] | **→ 541 [0]** seul |
| `434` execute `{EGPD_Input,0}` | ← 449 [0], 80 [0] | ← **80 [0], 542 [0]** ; self, NewViewTarget, then → 329 identiques |
| `539` (R1) | absent | Yaw ← 514 [2] ; Roll, Pitch 0.0 libres ; ReturnValue → 540 [2], 542 [2] |
| `540` (W1) | absent | execute ← 512 [0] ; self ← 265 [0] ; NewRotation ← 539 [0] ; bSweep, bTeleport false ; then libre |
| `541` (L6) | absent | execute ← 449 [0] ; self ← 265 [0] ; NewLocation ← PO_2 [0] ; bSweep, bTeleport false ; then → 542 [0] |
| `542` (W6) | absent | execute ← 541 [0] ; self ← 265 [0] ; NewRotation ← 539 [0] ; bSweep, bTeleport false ; then → 434 [0] |
| `80` | execute ← 78 [1] ; Condition ← 267 ; then → 434 ; else → 430 | identique |
| `81` | execute ← 91 [1] ; Condition ← 258 ; then vide ; else → 82 | identique |
| `82` | execute ← 81 [1] ; Condition ← 269 ; then → 83 ; else → 440 | identique |
| `83` | execute ← 82 [0] ; Condition ← PO_0 ; then → 512 ; else → 440 | identique |
| `329` | execute ← 434 [0], 94 [0] ; Delegate ← CustomEvent_45 ; Time 0.016 ; bLooping true ; then → VariableSet_54 | identique |
| `440` | execute ← 83 [1], 82 [1] ; then → 441 | identique |
| `441` | execute ← 440 ; Handle ← VariableGet_274 ; then vide | identique |
Chaîne obtenue :
- P5, chaque passage de la minuterie en C1 : `83.then → 512 (SetWorldLocation) → 540 (SetWorldRotation, Yaw de contrôle)`.
- P6, entrée en C1 : `VariableSet_53 → 449 → 541 (SetWorldLocation) → 542 (SetWorldRotation) → 434 (SetViewTargetWithBlend) → 329`.
### 1.6 Compilation et sauvegarde (journal `D:\Game\LifePlay-master 5.8\Saved\Logs\portage\CAM-B2s-editeur_20261014-083521.log`)
- Avant l'appel 1, le journal compte 2289 lignes, aucune ligne `Saving Package` et aucune ligne `Dispatching toolset tool`.
- `is_dirty` (appel 28) = `true`. La procédure B2f-a n'a pas été nécessaire.
- Appel 29 : l. 2349, `LogBlueprint: Compiling Blueprint '/Game/BPs/Room.Room'`. Aucune exception côté outil.
- Aucune ligne `error` ou `warning` (insensible à la casse) de la l. 2290 à la fin (l. 2384), compilation, sauvegarde
et validation comprises.
- `hyper_blueprint_debug_inspect` n'a pas été appelé : il est absent du serveur. Repli : `warnings_as_errors` et le
journal.
- Sauvegarde, l. 2354 : `Saving Package: /Game/BPs/Room`. Ensuite, le fichier temporaire
`Saved/Room704350214F5C610295BDF5A0F0F51841.tmp` est déplacé vers `Content/BPs/Room.uasset`, puis
`AssetCheck: /Game/BPs/Room Validation de la ressource`. Le journal n'a pas d'autre ligne `Saving Package`.
### 1.7 Garde `Accessed None` (lp-mcp § 1 règle 4)
- Aucun `IsValid` ajouté : la fiche n'en prévoit pas.
- W1, L6 et W6 lisent `265` (`PlayerCharacter.FirstPersonSM`) et `PO_2` (`GetSocketLocation` sur les yeux). La voie C1
lit déjà ces deux valeurs sans garde, par 446, 512 et 431/433.
- R1 lit `514`, donc `524` `GetControlRotation` sur `VariableGet_262` (PC). `524` et `514` sont déjà lus sans garde
par `513` et par `PO_28` / `PO_30` (fiche, § Garde).
- Que la voie `VariableSet_53 → 449` lisait déjà `524` avant P6 est **non vérifié** ici (estimé par la fiche). Ce point
est repris au § 5.
## 2. Écarts à la SPEC
- Aucun écart sur l'état lu, les types, les nœuds, les liens, la relecture, la compilation ni la sauvegarde.
- Positions : 434 (32200) est à gauche de 449 (34200) dans le graphe. « Entre 449 et 434 » a donc été pris dans l'ordre
d'exécution : L6 et W6 sont posés à droite de 449, en (34550, 900) et (34950, 900). R1 et W1 sont à droite de 512 (§ 1.3).
Ce choix est cosmétique.
- Lectures en plus de la fiche :
- avant écriture : 524, 148 et les voisins 80 à 83, 329, 440, 441, pour avoir leur état avant (étape 5) ;
- pendant l'écriture : trois relectures intermédiaires (appels 13, 18, 21), pour s'arrêter au premier écart. L'appel 18
a confirmé le remplacement de L5 ; l'appel 21 a confirmé que 434 garde 80.
- Total : 30 appels, pour environ 35 estimés.
- Types : la fiche demande un contrôle par `get_node_infos`. Cet outil ne donne pas le nom C++ de la fonction : le
contrôle s'est fait sur le `type_id`, les broches et la déclaration du moteur (§ 1.3).
- GI, PC et Person n'ont pas été ouverts. Ni build, ni commandlet, ni jeu. L'éditeur n'a été ni lancé ni arrêté.
## 3. Instantané
- `D:\Game\LifePlay_Backup_5.5\CAM-B2s\manifest.csv` (pris par l'orchestrateur), relu :
`"Content\BPs\Room.uasset","True","6408870","3A451FDDF991AC01A699AF7BD1FBDC12","2026-10-14T07:53:13"`.
- MD5 sur le disque = manifeste, au début de la fiche et juste avant l'appel 6 (première écriture).
- Retour arrière **proposé, non lancé**. L'orchestrateur le fait, éditeur fermé, sur accord :
1. `.\Tools\Snapshot.ps1 -Lot CAM-B2s-retour -Path Content\BPs\Room.uasset` ;
2. `.\Tools\Restore.ps1 -Lot CAM-B2s -Only Content\BPs\Room.uasset -WhatIf` ;
3. `.\Tools\Restore.ps1 -Lot CAM-B2s -Only Content\BPs\Room.uasset`.
Contrôle : `md5sum Content/BPs/Room.uasset` = `3a451fdd…`.
- Entrée de journal :
`2026-10-14 | CAM-B2s, P5 (512.then → K2_SetWorldRotation, Yaw de contrôle) et P6 (449 → SetWorldLocation →
SetWorldRotation → 434) | Content/BPs/Room.uasset | retour arrière : Restore.ps1 -Lot CAM-B2s -Only
Content\BPs\Room.uasset | instantané : D:\Game\LifePlay_Backup_5.5\CAM-B2s | vérification : relecture conforme,
compilation stricte 0 diagnostic, Room = c5ab7241…`.
## 4. Ce qui n'a pas été fait
- Le nombre de nœuds de l'EventGraph (V5 : 1276 attendu) n'a pas été compté, car `find_nodes` n'a pas été appelé.
- `VariableSet_53`, `513`, `PO_28` et `PO_30` n'ont pas été relus : seules les extrémités côté 449 et 514 l'ont été.
- `is_dirty` n'a pas été relu après la sauvegarde : la fiche ne le demande pas.
- Hors fiche (lp-mcp § 1 règles 3 et 5) : `CompileAllBlueprints` éditeur fermé, build empaqueté, `LogStats` et essai en
jeu.
- L'éditeur n'est pas fermé : c'est le rôle de l'orchestrateur, puis `BUILD-FIN`.
## 5. Points à confirmer en VAL
- Room = `c5ab724101fa898457293d64059d21a9`. GI = `e64b5b37…`, PC = `f45be57a…` et Person = `8668a47c…` sont inchangés.
- V5 : EventGraph 1272 → 1276 nœuds.
- V5 : nœuds nouveaux et fonction appelée :
- `K2Node_CallFunction_539` : `KismetMathLibrary::MakeRotator`, Roll et Pitch à 0 ;
- `_540` : `SceneComponent::K2_SetWorldRotation` ;
- `_541` : `SceneComponent::K2_SetWorldLocation` ;
- `_542` : `SceneComponent::K2_SetWorldRotation`.
Pour les trois derniers, bSweep et bTeleport valent false.
- V5 : diff des liens limité au § 1.5, c'est-à-dire :
- `512.then → 540` ;
- sorties de `265` (+540, 541, 542), de `514.Yaw` (+539) et de `PO_2` (+541) ;
- `449.then → 541` au lieu de 434 ; `434.execute ← 80, 542` ;
- liens propres à 539 à 542.
- 80, 81, 82, 83, 329, 440, 441 : liens inchangés.
- V6 : `CompileAllBlueprints` = référence (3 erreurs `CR_FaceExpRig`, 420 compilations réussies).
- V7 : cas de la fiche (CAM-49 ; bar, assis puis levé ; après une scène ; sortie de CharGen).
- V7, en plus : `LogStats` sans `Accessed None` nouveau sur `Room` (`UpdateRoomCam` et voie d'entrée en C1 par 449,
où R1 lit maintenant `GetControlRotation`, § 1.7).
## 6. Fichiers à commiter
- M `Content/BPs/Room.uasset` (dépôt du jeu, branche ue5.8).
- A `Docs/Migration/etat/CAM/CAM-B2s-IMPL.md` (dépôt du jeu, branche ue5.8).
- GI, PC et Person ne sont pas à commiter ici : leur `M` dans `git status` existait au début de la session (lots
antérieurs) et leur MD5 n'a pas changé.
## Mesuré
```
$ md5sum Content/BPs/Room.uasset Content/BPs/GI.uasset Content/BPs/PC.uasset Content/BPs/Person.uasset (avant l'appel 1)
3a451fddf991ac01a699af7bd1fbdc12 *Content/BPs/Room.uasset
e64b5b37c9ef0db7735de0d6e3bd7c1c *Content/BPs/GI.uasset
f45be57a39d13d3eb19d0b543153ab0b *Content/BPs/PC.uasset
8668a47c627f7a5254910cf0ac33b12a *Content/BPs/Person.uasset
$ wc -l <journal> ; grep -c "Saving Package" ; grep -c "Dispatching toolset tool" (avant l'appel 1)
2289
0
0
$ md5sum Content/BPs/Room.uasset (avant l'appel 6, première écriture)
3a451fddf991ac01a699af7bd1fbdc12 *Content/BPs/Room.uasset
$ wc -l ; grep -c "Saving Package" ; grep -c "Dispatching toolset tool" (avant l'appel 29)
2346
0
28
$ tail -n +2347 <journal> (après l'appel 29, extrait)
[2026.10.14-06.41.10:175][884]LogBlueprint: Compiling Blueprint '/Game/BPs/Room.Room'
$ grep -n "Saving Package" <journal> (après l'appel 30)
2354:[2026.10.14-06.41.18:625][275]LogFileHelpers: Saving Package: /Game/BPs/Room
$ tail -n +2290 <journal> | grep -ciE "error|warning"
0
$ grep -o "Dispatching toolset tool: '[^']*'" <journal> | sort | uniq -c
1 …AssetTools.is_dirty
1 …AssetTools.load_asset
1 …AssetTools.save_assets
1 …BlueprintTools.compile_blueprint
11 …BlueprintTools.connect_pins
4 …BlueprintTools.create_node
2 …BlueprintTools.find_node_types
9 …BlueprintTools.get_node_infos
$ grep -cE "/Game/BPs/(GI|PC|Person)\b" <journal>
0
$ md5sum Content/BPs/Room.uasset Content/BPs/GI.uasset Content/BPs/PC.uasset Content/BPs/Person.uasset (après l'appel 30)
c5ab724101fa898457293d64059d21a9 *Content/BPs/Room.uasset
e64b5b37c9ef0db7735de0d6e3bd7c1c *Content/BPs/GI.uasset
f45be57a39d13d3eb19d0b543153ab0b *Content/BPs/PC.uasset
8668a47c627f7a5254910cf0ac33b12a *Content/BPs/Person.uasset
$ stat -c "%s %y" Content/BPs/Room.uasset
6422095 2026-10-14 08:41:19.340416100 +0200
$ git status --short -- Content/BPs/
M Content/BPs/GI.uasset
M Content/BPs/PC.uasset
M Content/BPs/Person.uasset
M Content/BPs/Room.uasset
```
`<journal>` = `D:\Game\LifePlay-master 5.8\Saved\Logs\portage\CAM-B2s-editeur_20261014-083521.log`.
Tours : 46 / 60
## Constats
- Sur une entrée d'exécution, `connect_pins` **ajoute** le lien sans remplacer les liens existants : `434.execute` garde
`80.then` (appel 21). Sur une sortie d'exécution, il **remplace** le lien existant : `449.then` a perdu 434 (appel 18).
Les deux cas ont été vérifiés aujourd'hui.
- `type_id` vérifiés dans la copie 5.8, éditeur en français :
- `Transformation|SetWorldRotation` (filtre `SetWorldRotation` avec `context_pins` sur une sortie de composant :
1 seul résultat) ;
- `Math|Rotateur|MakeRotator` (filtre `MakeRotator` sans contexte : 13 résultats, dont des types PCG et caméra).
- `create_node` a numéroté les nœuds `_539` à `_542`, à la suite des numéros existants.
- Le crochet `ecriture-gardien` refuse une commande Bash qui contient `>` même dans un programme `awk` (`$1>2289`) : il
le prend pour une redirection. Contournement non tenté : la commande a été réécrite sans comparaison.
- À verser :
- `lp-mcp` § 3 : `type_id` `Transformation|SetWorldRotation` et `Math|Rotateur|MakeRotator` ; `connect_pins` ajoute
sur une entrée d'exécution et remplace sur une sortie d'exécution ; `get_node_infos` ne donne pas la UFunction, à
croiser avec la déclaration du moteur (`SceneComponent.h:573`, `KismetMathLibrary.h:2252`) ;
- mémoire `hook-ecriture-gardien` : `>` dans un `awk` est refusé.