173 lines
15 KiB
Markdown
173 lines
15 KiB
Markdown
Fiche CAM-B2r-VAL — Niveau N1 — Modèle prévu sonnet | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate
|
||
# CAM-B2r-VAL : remise de `SpaceOn` / `MainMenuOn` après CharGen et témoins C1, VAL statique sans compilation (2026-10-14)
|
||
|
||
Date : 2026-10-14. Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8`, UE 5.8 (`D:\Game\Launcher\Engine\UE_5.8`).
|
||
Portée : VAL **statique** (lecture et commandes de lecture seule). Aucune compilation, aucun éditeur, aucun commandlet,
|
||
aucun MCP, aucun git en écriture. Seul fichier écrit : ce livrable.
|
||
|
||
## 1. Fiches amont relues
|
||
|
||
| Fichier | Lu | Remarque |
|
||
|---|---|---|
|
||
| `Docs/Migration/etat/CAM/CAM-B2r-FICHE.md` (81 lignes) | oui, en entier | R1, R2, R3, essais CAM-50 à CAM-53, retour arrière |
|
||
| `Docs/Migration/etat/CAM/CAM-B2r-IMPL.md` (47 lignes) | oui, en entier | voir écart de gabarit en Constats C-7 |
|
||
| `D:\Game\LifePlay_Backup_5.5\CAM-B2r\manifest.csv` + copies `Source\LifePlay\LPCameraModeSubsystem.{cpp,h}` | oui | instantané d'avant, date 2026-10-14 07:46 |
|
||
| `Source/LifePlay/LPCameraModeSubsystem.cpp` (662 lignes) et `.h` (77 lignes) actuels | oui, en entier | |
|
||
| `lp-doc/gabarits.md` (gabarit VAL) | oui | sections 1 à 6 ci-dessous |
|
||
|
||
## 2. Points à confirmer des IMPL
|
||
|
||
L'IMPL ne contient pas de section « points à confirmer » (écart de gabarit, C-7). Je reprends à la place ses deux
|
||
écarts déclarés et son seul « non fait ».
|
||
|
||
| Identifiant | Point | Résultat |
|
||
|---|---|---|
|
||
| IMPL-E1 | Critère « vue = caméra de pièce » par le libellé de `ComputeLabel` (C1, C2, C3 plafond, C3 ancienne), `Birdview` exclu, pas d'écriture pendant un menu | PASS-STATIC : libellés de `RoomCameraLabels` (cpp 79-81) égaux, caractère par caractère, aux retours de `ComputeLabel` (cpp 564, 576, 582, 594) ; `Birdview` rend « Camera: Overview » (cpp 564), absent de la table. Plus strict que la fiche pour le cas Builder (voir 6.R1) : acceptable |
|
||
| IMPL-E2 | R3 : si l'axe de visée de `FirstPerson_C` n'est pas son X local, une ligne par seconde en C1 (bruit sans effet) | PASS-STATIC pour le risque (journal seulement, aucune écriture dans WitnessC1) ; l'axe lui-même : reporté à l'essai CAM-53 (BLOCKED sans jeu) |
|
||
| IMPL-N1 | Compilation (COMMUN-7, jeton UE) | reporté : critère « Build.ps1 : 0 erreur, aucun avertissement nouveau » de la fiche non vérifié ici (BLOCKED-jeton-UE, voulu) |
|
||
| IMPL-N2 | Essais CAM-50 à CAM-53 | reporté (V7, build suivant) |
|
||
|
||
## 3. Critères rejoués (commande → résultat)
|
||
|
||
| N° | Contrôle | Commande | Sortie brute (courte) | Verdict |
|
||
|---|---|---|---|---|
|
||
| 1 | MD5 avant (instantané) | `md5sum <Backup>/CAM-B2r/Source/LifePlay/LPCameraModeSubsystem.*` | `fe9236bd138a46bbc2b63027977b3cd9` (.cpp), `7da111cb65b267a9e2f7482cba368be9` (.h) ; manifest.csv : `FE9236BD…`, `7DA111CB…` | PASS : égaux aux valeurs annoncées |
|
||
| 1 | MD5 après (fichiers actuels) | `md5sum "<copie>/Source/LifePlay/LPCameraModeSubsystem.*"` | `124336d3293ef06befcf076d10956234` (.cpp), `61a3e06280bf7226adb52ecfdd9173de` (.h) | PASS : égaux à `124336D3…` et `61A3E062…` annoncés |
|
||
| 2 | Diff complet | `diff -u <instantané> <actuel>` pour les deux fichiers, lu en entier | .h : 1 hunk, +11 −0 ; .cpp : 7 hunks, +154 non vides (+7 lignes vides), −2 ; 503→662 lignes, 66→77 | PASS-STATIC : tout dans le périmètre (section 4) |
|
||
| 3 | Fins de ligne | `tr -cd '\r' < f \| wc -c` | avant : .cpp 0, .h 0 ; après : .cpp 0, .h 0 ; espaces en fin de ligne : 0 et 0 (`grep -c "[[:space:]]$"`) | PASS : LF avant et après |
|
||
| 4 | Compilation « à l'œil » | relecture ligne à ligne + lecture des en-têtes UE 5.8 | voir détail 3.a | PASS-STATIC, aucun bloquant |
|
||
| 5 | Sûreté | lecture + `Grep WriteBool\(` | `WriteBool` : définition cpp 116, appels cpp 336 et 341 seulement, tous deux dans `RepairAfterCharGen` (cpp 297-344) | PASS-STATIC (détail 3.b) |
|
||
| 6 | Cohérence fiche / IMPL | comparaison R1, R2, R3 | voir section 6 | PASS-STATIC avec 3 écarts non déclarés non bloquants (C-1, C-2, C-3) |
|
||
|
||
### 3.a Détail du contrôle 4 (types, signatures, const, format)
|
||
- `FBoolProperty::SetPropertyValue_InContainer(void*, bool, int32) const` : `UnrealType.h:2710` (UE 5.8). `WriteBool` prend
|
||
`UObject*` (non const) et une `const FBoolProperty*` : correct (cpp 116-123).
|
||
- `FTimerHandle::StaticStruct()` : `USTRUCT` (`Engine/TimerHandle.h:10-13`) ; la fonction est `inline` dans
|
||
`TimerHandle.generated.h:26` et appelle `ENGINE_API Z_Construct_UScriptStruct_FTimerHandle` (ligne 22) : pas de risque
|
||
d'édition de liens depuis le module LifePlay. `TimerManager.h:13` inclut `Engine/TimerHandle.h`.
|
||
- `FTimerManager::IsTimerActive(FTimerHandle) const` : `TimerManager.h:331` ; `UWorld::GetTimerManager() const` :
|
||
`World.h:4289`. `TimerActive` prend `const UWorld*` : correct (cpp 126-134). `ContainerPtrToValuePtr<FTimerHandle>`
|
||
sur `const UObject*` : même motif que `ReadVector` existant (cpp 143).
|
||
- `FRotator::NormalizeAxis` : `static`, `Rotator.h:432` (modèle `T`, double en LWC). `YawGap` et `Distance` sont des
|
||
`double` ; `CameraRotation.Pitch/Yaw` sont des `double` (FRotator UE5). `FVector::Dist` rend un double.
|
||
- `UWidget::IsInViewport() const` (`Widget.h:549`), `GetVisibility() const` (`Widget.h:586`),
|
||
`GetGameInstance() const` (`Widget.h:871`) : `WidgetOnScreen` (cpp 211-227) travaille sur `const UUserWidget*` sans
|
||
appel non const. `TObjectIterator::operator bool` est `explicit` (`UObjectIterator.h:286`), accepté dans `It && GI`
|
||
(conversion contextuelle).
|
||
- Const-correctness : aucune fonction `const` nouvelle. `LogSwitchKey` (const) n'appelle que `ReadBool`, `GetNameSafe`,
|
||
`GetGameViewportClient` (déjà présents) ; la lambda `Flag` prend `const UObject*` et reçoit `GI` / `PC` / `Room` const.
|
||
`RepairAfterCharGen` et `WitnessC1` sont non const dans le .h (61, 67) et le cpp (297, 346) : déclarations égales aux
|
||
définitions (types `const FString&, bool, float` / `float`).
|
||
- Format `UE_LOG`, spécificateurs contre arguments :
|
||
- cpp 328 : `%s`, `%s` ← `*GetNameSafe(View)`, `*Label` (2/2) ;
|
||
- cpp 337 : `%s`, `%s` ← idem (2/2) ;
|
||
- cpp 342 : aucun spécificateur, aucun argument ;
|
||
- cpp 375-378 : `%.0f %+.0f %+.0f %d %d` ← `Distance` (double), `Pitch` (double), `YawGap` (double), deux `? 1 : 0` int (5/5) ;
|
||
- cpp 417-423 (R2) : 19 spécificateurs (14 d'origine + 5 nouveaux `%d`), 19 arguments : 3+3+3 `int`, 5 `%s` en `TCHAR*`
|
||
(`*GetNameSafe`, `View ? *… : TEXT("-")`, `*ShownLabel`), puis 5 `Flag(...)` int. Comptés à la main, un par un.
|
||
- Unité de compilation unitaire : `Grep` de tous les noms nouveaux (`WriteBool`, `TimerActive`, `WidgetOnScreen`,
|
||
`MainMenuClass`, `LabelC1`, `RoomCameraLabels`, `GICharGenOn`, `GIMainMenuOn`, `GIJournalOn`, `GIContactsOn`,
|
||
`PCMoveCamera`, `PlayerFirstPersonSM`, `PlayerOccupyingFnt`, `RoomCamTimer`, `LeftEyeSocket`, `RightEyeSocket`,
|
||
`C1Interval`, `C1LogInterval`, `C1MaxEyeDistance`, `C1MaxPitch`, `C1MaxYawGap`, `CharGenRepairDelay`) dans tout
|
||
`Source/` : `LPCameraModeSubsystem.cpp:39` et aucun autre fichier. `LPCameraModeLocal` n'apparaît que dans ce fichier
|
||
(61 occurrences). Tous les appels sont qualifiés `LPCameraModeLocal::` (cpp 250-378, 417-423 ; les seuls appels
|
||
non qualifiés sont à l'intérieur de l'espace nommé, il n'y en a aucun de nouveau).
|
||
- Ombrage (C4458) : les locaux nouveaux (`GI`, `World`, `PC`, `View`, `Camera`, `Mesh`, `Player`, `Eyes`, `Distance`,
|
||
`Label`) ne portent le nom d'aucun membre de classe (membres : `Text`, `Root`, `Viewport`, `ShownLabel`, `bShown`, …).
|
||
- Pas de variable inutilisée : `View` (cpp 316) sert aux deux journaux ; `RoomObject` (cpp 373) sert à `TimerActive`.
|
||
|
||
### 3.b Détail du contrôle 5 (sûreté)
|
||
- Pointeurs : `GI` testé nul (cpp 300) ; `World`, `PC`, `View` chaînés par `? :` (cpp 314-316) ; `GetNameSafe` accepte
|
||
nul ; `ReadBool` / `ReadObject` / `WriteBool` / `TimerActive` testent `Container` (cpp 105, 111, 118, 128).
|
||
`WitnessC1` : `Player` par `IsValid`, `Mesh` et `Camera` par test, `PC` par test, `Room` par `IsValid` avant
|
||
`TimerActive`, `World` testé dans `TimerActive` (cpp 354-363, 373, 378). Aucune déréférence nue.
|
||
- `WriteBool` : seulement dans `RepairAfterCharGen` (cpp 336, 341).
|
||
- Une seule réparation : `bCharGenSeen = false` est posé en cpp 333, **avant** les écritures ; le seul autre chemin qui
|
||
le remet à faux est le délai (cpp 327). `bCharGenSeen` ne repasse à vrai que par `CharGenOn` vrai (cpp 306).
|
||
- Jamais hors caméra de pièce ou avec un menu : la sortie `if (!bRoomCamera || bMenu)` (cpp 322-331) précède toute
|
||
écriture et rend la main. `Birdview` donne « Camera: Overview », absent de `RoomCameraLabels` : jamais réparé.
|
||
`bMenu` vient de `MenuOnScreen` (inchangé), qui inclut `MainMenu_C` (cpp 98) : le contrôle `WidgetOnScreen` du cpp 339
|
||
est une double garde (voir C-5).
|
||
- Seules écritures du correctif : deux booléens de GI (`SpaceOn` à vrai, `MainMenuOn` à faux), chacun seulement s'il
|
||
vaut l'inverse (cpp 334, 339). `WitnessC1` et `LogSwitchKey` ne font que lire.
|
||
|
||
## 4. Diff lu en entier
|
||
|
||
Commande : `diff -u` entre la copie d'instantané et le fichier actuel, deux fichiers, lu intégralement.
|
||
Comptes : .h +11 −0 (1 hunk) ; .cpp +161 (dont 7 lignes vides) −2 (7 hunks). Les −2 sont la ligne `UE_LOG` de
|
||
`LogSwitchKey` (format) et sa dernière ligne d'arguments, réécrites pour R2 ; aucune autre ligne d'origine n'est modifiée.
|
||
|
||
| Hunk | Contenu | Dans le périmètre de la fiche ? |
|
||
|---|---|---|
|
||
| .h | `RepairAfterCharGen`, `bCharGenSeen`, `CharGenRepairTimeout`, `WitnessC1`, `C1Cooldown` | oui (membres du .h de R1 et R3) |
|
||
| .cpp 21 | `#include "TimerManager.h"` | oui |
|
||
| .cpp 67-95 | constantes R1 et R3 (`GICharGenOn`, `GIMainMenuOn`, `GIJournalOn`, `GIContactsOn`, `PCMoveCamera`, `MainMenuClass`, `CharGenRepairDelay`, `RoomCameraLabels`, `LabelC1`, `PlayerFirstPersonSM`, `PlayerOccupyingFnt`, `RoomCamTimer`, `LeftEyeSocket`, `RightEyeSocket`, `C1*`) | oui. `MainMenuClass`, `RoomCameraLabels`, `LabelC1` sont des aides de R1/R3, non nommées dans la fiche mais demandées par le contrôle 2 (constantes) |
|
||
| .cpp 115-134 | `WriteBool`, `TimerActive` | oui |
|
||
| .cpp 210-227 | `WidgetOnScreen` | oui |
|
||
| .cpp 250, 290-293 | appel de `RepairAfterCharGen` dans `Tick` ; branche `else if (Label == LabelC1)` | oui |
|
||
| .cpp 297-379 | corps de `RepairAfterCharGen` (R1) et de `WitnessC1` (R3) | oui |
|
||
| .cpp 416-423 | extension de `LogSwitchKey` (R2) | oui, texte égal à la fiche : ` ; MainMenuOn=%d JournalOn=%d ContactsOn=%d CharGenOn=%d MoveCamera=%d` |
|
||
|
||
Ajouts non demandés : aucun fonctionnel. Ajouts mineurs hors lettre de la fiche : mot « indicateur » dans les journaux
|
||
(C-1), `IsInViewport`-et-visibilité dans `WidgetOnScreen` (calqué sur `MenuOnScreen`, cohérent). Le .cpp est non suivi par
|
||
git (`??`, `git ls-files --error-unmatch` : « did not match any file(s) known to git »), donc `git diff <lot>-avant` est
|
||
inutilisable ; la référence est l'instantané. `git status --short -- Source` ne montre pas d'autre fichier source
|
||
nouveau lié au lot (les `M` de `LPDebugSubsystem`, `LPDirectControlSubsystem`, `LPOutdoorRoomSubsystem`, `LifePlay.cpp`
|
||
préexistent et ne relèvent pas de ce lot : non lus ici).
|
||
|
||
## 5. Verdict
|
||
|
||
**PASS-STATIC avec réserves** (réserves non bloquantes, section Constats). Aucun défaut bloquant. Non rejoué : compilation
|
||
(`Build.ps1`), `LPTestStringCompat`, essais CAM-50 à CAM-53 (BLOCKED-jeton-UE, voulu par la fiche et l'IMPL).
|
||
Le fichier n'est pas encore prouvé compilable : seule la lecture des en-têtes UE 5.8 (section 3.a) le soutient.
|
||
|
||
## 6. Points à confirmer par l'utilisateur (cases)
|
||
|
||
- [ ] R1 (cohérence fiche) : la fiche définit « caméra de pièce » par `CamC1On` / `CamRoom` / `SceneCamera` + `CamC3On` ;
|
||
l'IMPL utilise les libellés. Différences : le libellé exclut `Camera: Scene` / `POV` (`SexOn`) et `Camera: Builder`
|
||
(scène Builder avec `SceneCamera` et `CamC3On`). Plus sûr ; accepter ? **Avis du validateur : acceptable.**
|
||
- [ ] R1/R2/R3 sont écrits conformément à la fiche pour le texte de R2 et les seuils de R3 (8 cm, ±25°, 30°, 0,5 s,
|
||
1 s, 10 s) : confirmé par relecture (cpp 78, 90-94, 417).
|
||
- [ ] Libellés des journaux de R1 : la fiche dit `(vue %s)`, le code écrit `(vue %s, indicateur '%s')` (C-1). Accepter ?
|
||
La sous-chaîne attendue par CAM-50 (« CharGen : SpaceOn remis a vrai ») reste présente.
|
||
- [ ] `K2_IsTimerActiveHandle` (fiche) remplacé par `FTimerManager::IsTimerActive` (C-2) : accepter ?
|
||
- [ ] Compilation sous jeton UE (COMMUN-7) puis essais CAM-50 à CAM-53 : à faire ; le verdict ci-dessus ne les couvre pas.
|
||
|
||
## Tours : 12 / 40
|
||
|
||
## Constats
|
||
|
||
Bloquants : **aucun**.
|
||
|
||
Non bloquants (ligne exacte dans `Source/LifePlay/LPCameraModeSubsystem.cpp`) :
|
||
- **C-1** (cpp 328 et 337) : les deux journaux ajoutent `indicateur '%s'` au texte de la fiche (`vue %s`). Écart non
|
||
déclaré dans l'IMPL ; sans effet fonctionnel ; le préfixe testé par CAM-50 est conservé.
|
||
- **C-2** (cpp 133) : la fiche R3 prescrit `UKismetSystemLibrary::K2_IsTimerActiveHandle` ; l'IMPL appelle
|
||
`World->GetTimerManager().IsTimerActive(Handle)` après vérification de `Prop->Struct == FTimerHandle::StaticStruct()`.
|
||
Écart non listé dans « Écart à la fiche » de l'IMPL (il figure seulement dans la liste des écritures). Équivalent
|
||
attendu (estimé : la fonction Kismet délègue au gestionnaire de minuteries du monde ; non relu dans le moteur) et plus
|
||
simple (pas d'objet de contexte).
|
||
- **C-3** (cpp 322-329) : quand la vue est une caméra de pièce mais qu'un menu est à l'écran, le délai de 10 s s'écoule
|
||
quand même ; à l'échéance le journal dit « sortie sans camera de piece » alors que la cause est le menu, et la
|
||
réparation est abandonnée. Si un menu reste ouvert plus de 10 s juste après CharGen, `SpaceOn` n'est pas remis.
|
||
Cas rare, conforme à « jamais pendant un menu » ; message trompeur seulement.
|
||
- **C-4** (cpp 364) : si les douilles `lEye` / `rEye` n'existent pas, `GetSocketLocation` rend la position du composant
|
||
et le témoin C1 peut écrire une ligne par seconde (bruit, journal seulement). Cousin du risque déclaré IMPL-E2.
|
||
- **C-5** (cpp 339) : `WidgetOnScreen(MainMenu_C)` est redondant avec `bMenu` (qui contient `MainMenu_C`) : quand on
|
||
arrive à cette ligne, `bMenu` est déjà faux. Inoffensif (double garde) ; à garder pour la lisibilité ou à retirer
|
||
plus tard, sur décision de l'orchestrateur.
|
||
- **C-6** (cpp 1) : l'en-tête du .cpp porte toujours « Lot CAM-B2c » (inchangé, pré-existant) ; rien de B2r n'y est
|
||
mentionné. Cosmétique.
|
||
- **C-7** (gabarit) : `CAM-B2r-IMPL.md` ne suit pas le gabarit IMPL de `lp-doc/gabarits.md` : pas de tête
|
||
« Fiche … Niveau … Modèle … Agent … Skills », sections 1 à 6 absentes ou non numérotées (pas de « Points à confirmer
|
||
en VAL », pas de « Fichiers à commiter », pas de ligne « Tours »). Les informations utiles (MD5, écarts, non fait) y
|
||
sont. Le présent livrable déduit donc ses « points à confirmer » de la section « Écart à la fiche » et de « Non fait ».
|
||
- **C-8** (dépôt) : `LPCameraModeSubsystem.cpp` et `.h` sont non suivis par git (`??`) : pour le gardien, ils seront
|
||
`A` (nouveaux pour git), pas `M`. Le retour arrière du lot passe par l'instantané (`Restore.ps1 -Lot CAM-B2r`).
|
||
|
||
Fichiers à commiter (par le gardien, sur ticket ; non suivis par git donc `A`) :
|
||
- `A Source/LifePlay/LPCameraModeSubsystem.cpp`
|
||
- `A Source/LifePlay/LPCameraModeSubsystem.h`
|
||
- `A Docs/Migration/etat/CAM/CAM-B2r-VAL.md` (ce livrable)
|
||
|
||
Fichier écrit par le validateur : `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\CAM\CAM-B2r-VAL.md` (seul).
|