140 lines
12 KiB
Markdown
140 lines
12 KiB
Markdown
Fiche CAM-B2j-VAL — Niveau N1 — Modèle prévu sonnet | utilisé Sonnet 5.5 (claude-sonnet-5-5) — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate
|
||
# CAM-B2j-VAL : témoin « touche C », validation statique (2026-10-13)
|
||
|
||
Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8` (`git branch --show-current` : `ue5.8`). Sans UE, sans compilation, sans
|
||
build : lecture et diff seulement. Seul fichier écrit : ce livrable.
|
||
|
||
## 1. Fiches amont relues
|
||
- Spécification : `Docs\Migration\etat\CAM\CAM-COMMUN4-DIAG.md` § 5 point 2 (l. 164-174) et complément (l. 180-198).
|
||
- Aucune fiche `CAM-B2j-*` ni IMPL B2j dans `Docs\` (Glob `**/*B2j*` : 0 résultat). Il n'y a donc pas de « point à
|
||
confirmer » d'IMPL à reprendre (voir § 2). `CAM-B2i-IMPL.md` et `CAM-B2i-VAL.md` existent (hors périmètre du diff B2j,
|
||
non relus en détail).
|
||
- Avant : `D:\Game\LifePlay_Backup_5.5\CAM-B2j\Source\LifePlay\` (2 fichiers) ; après : `Source\LifePlay\`.
|
||
- État git : `git status --short` donne `??` pour les deux fichiers (non suivis dans la copie 5.8, donc pas de
|
||
`<lot>-avant` exploitable) ; la comparaison se fait par `git diff --no-index` sur la sauvegarde.
|
||
|
||
## 2. Points à confirmer des IMPL
|
||
| Point | Verdict |
|
||
|---|---|
|
||
| Aucune IMPL B2j écrite, donc aucun point listé | sans objet : aucun livrable IMPL (Glob 0 résultat) ; les points de compilation et de comportement sont traités en § 3 |
|
||
| Compilation réelle (C2xxx, C4996) | reporté (BLOCKED-pas-de-build : non demandé) : à confirmer par la fiche BUILD de B2j |
|
||
| Ligne `Touche C` effectivement émise en jeu | reporté : exige un essai en jeu (passage CharGen en C1, appui sur C) |
|
||
|
||
## 3. Critères rejoués
|
||
|
||
### 3.1 Empreintes
|
||
Commande : `md5sum` des 4 fichiers.
|
||
```
|
||
d8981529e3773fbf50bb7fc1c91bc91f *Source/LifePlay/LPCameraModeSubsystem.cpp
|
||
2e1e245883960c2affc667a9a48fd96d *Source/LifePlay/LPCameraModeSubsystem.h
|
||
61fb558202e9bb3f567bceaa4bf241d3 *…/CAM-B2j/Source/LifePlay/LPCameraModeSubsystem.cpp
|
||
84f9ba303e1abd171c506dfbb4ed9f63 *…/CAM-B2j/Source/LifePlay/LPCameraModeSubsystem.h
|
||
```
|
||
Attendus : `D8981529…`, `2E1E2458…`, `61FB5582…`, `84F9BA30…`. Verdict : **PASS** (4 sur 4).
|
||
|
||
### 3.2 Diff lu en entier
|
||
`git diff --no-index --stat` : `.cpp` 72 lignes (71 ajouts, 1 suppression), `.h` 10 ajouts. Diff complet lu (2 fichiers).
|
||
La seule ligne supprimée est la condition de tête de `Tick` (`if (Label.IsEmpty() || MenuOnScreen(...))`), remplacée par
|
||
une version à `bMenu` calculé en amont (`.cpp:196` : même condition). Aucun Blueprint ni asset dans le diff.
|
||
Verdict : **PASS-STATIC**.
|
||
|
||
### 3.3 Conformité à la spécification (§ 5 point 2)
|
||
| Exigence | Preuve | Verdict |
|
||
|---|---|---|
|
||
| Second FTSTicker à intervalle 0, ajouté dans `Initialize` | `.cpp:163` `AddTicker(... TickSwitchKey), 0.f)` dans `SwitchKeyHandle` | PASS-STATIC |
|
||
| Retiré dans `Deinitialize` | `.cpp:167` `RemoveTicker(SwitchKeyHandle)` avant `TickHandle` | PASS-STATIC |
|
||
| Lecture des `ActionMappings` d'`UInputSettings`, action `SwitchCamera` | `.cpp:224-228` (`GetInputSettings()`, boucle `GetActionMappings()`), `.cpp:230` `Map.ActionName == SwitchCameraAction` (`FName("SwitchCamera")`, `.cpp:45`) | PASS-STATIC |
|
||
| `PlayerInput->IsPressed` | `.cpp:230` | PASS-STATIC |
|
||
| Front montant uniquement | `.cpp:237` `bDown && !bSwitchKeyDown`, puis `.cpp:241` `bSwitchKeyDown = bDown` | PASS-STATIC |
|
||
| Champs de la ligne `Touche C` : BuilderOn, SpaceOn, SexOn, CamC1On, CamC3On, C1Hidden, entree PC, regard ignore, viewport ignore, vue (classe), Room, PC, indicateur | `.cpp:254-258` ; variables : `GIBuilderOn`, `GISpaceOn` (nouveau, `.cpp:43`), `GISexOn`, `RoomCamC1On`, `RoomCamC3On`, `RoomC1Hidden` (nouveau, `.cpp:44`) | PASS-STATIC |
|
||
| Ligne `Indicateur de camera : aucun (vue …, classe …)` hors menu quand le libellé est vide | `.cpp:182-195` : branche `else if (!bMenu)` ; texte `"%s, classe %s"` inséré dans `(vue %s)` | PASS-STATIC |
|
||
| Une seule ligne par changement de vue | `.cpp:189` `ViewText != LastEmptyView` ; `LastEmptyView` remis à zéro dès qu'un libellé non vide existe (`.cpp:178-181`) | PASS-STATIC |
|
||
| `ShownLabel` remis à zéro au changement de vue vide, donc libellé suivant journalisé de nouveau | `.cpp:192` `ShownLabel.Reset()` ; test `.cpp:205` `Label != ShownLabel` puis log `.cpp:209` | PASS-STATIC |
|
||
| Aucun changement de comportement de l'indicateur affiché | remarques R1, R2 ci-dessous | PASS-STATIC |
|
||
| Aucun Blueprint touché | le diff ne porte que sur 2 fichiers C++ | PASS-STATIC |
|
||
|
||
Remarques (non bloquantes) :
|
||
- R1. `MenuOnScreen` est désormais évalué à chaque tick de 0,1 s même quand le libellé est vide (avant : court-circuit par
|
||
`Label.IsEmpty() ||`). La fonction est sans effet de bord (lecture, `TObjectIterator<UUserWidget>`) et déjà exécutée à la
|
||
même cadence quand le libellé est non vide ; l'effet (`SetShown(false)` puis retour) est le même. Estimé : surcoût
|
||
négligeable à 10 Hz.
|
||
- R2. `ShownLabel.Reset()` au changement de vue vide force seulement la réécriture du même texte à la reprise d'un libellé
|
||
non vide, sans effet visible. Estimé.
|
||
- R3 (limite du témoin, estimé). `UGameViewportClient::InputKey` rend la main avant `PlayerInput` si `IgnoreInput()` est
|
||
vrai (`Engine\Private\GameViewportClient.cpp:767-770`). Avec `viewport ignore=1`, la touche n'atteint donc pas
|
||
`PlayerInput->IsPressed` et aucune ligne `Touche C` ne sortira : l'absence de ligne est alors elle-même un indice (H4 côté
|
||
viewport). Les cas `entree PC=0` et `regard ignore=1` restent journalisés.
|
||
|
||
### 3.4 Compilation probable (en-têtes `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\Engine\Classes\…`)
|
||
| Élément | Source | Verdict |
|
||
|---|---|---|
|
||
| Includes `GameFramework/InputSettings.h` (`.cpp:13`) et `GameFramework/PlayerInput.h` (`.cpp:15`) | ajoutés en ordre alphabétique autour de `PlayerController.h` | PASS-STATIC |
|
||
| `UInputSettings::GetInputSettings()` statique ; `GetActionMappings() const` | `GameFramework/InputSettings.h:248`, `:316` | PASS-STATIC |
|
||
| `UPlayerInput::IsPressed(FKey) const` | `GameFramework/PlayerInput.h:745` | PASS-STATIC |
|
||
| `PC->PlayerInput` est un `TObjectPtr<UPlayerInput>` : via `const APlayerController*` le pointé reste non const, `IsPressed const` appelable de toute façon | `GameFramework/PlayerController.h:370` | PASS-STATIC |
|
||
| `APlayerController::InputEnabled() const` | `PlayerController.h:2142` | PASS-STATIC |
|
||
| `AController::IsLookInputIgnored() const` (virtuelle) | `GameFramework/Controller.h:383` | PASS-STATIC |
|
||
| `GetViewTarget() const` | `Controller.h:253`, `PlayerController.h:1911` | PASS-STATIC |
|
||
| `UGameViewportClient::IgnoreInput()` non const | `Engine/GameViewportClient.h:773` (`virtual bool IgnoreInput() override`, sans `const`) | PASS-STATIC |
|
||
| `UGameInstance::GetGameViewportClient() const` rend un pointeur non const, d'où `UGameViewportClient* ViewportClient` | `Engine/GameInstance.h:295` ; `.cpp:252` | PASS-STATIC |
|
||
| `UWorld::GetFirstPlayerController()` rend `APlayerController*`, converti en `const APlayerController*` | `Engine/World.h:2781` | PASS-STATIC |
|
||
| `GetNameSafe(const UObjectBaseUtility*)` accepte `const AActor*`, `const UObject*`, `const APlayerController*` | `Runtime\CoreUObject\Public\UObject\UObjectBaseUtility.h:893` | PASS-STATIC |
|
||
| `LogSwitchKey(...) const` n'appelle que du const : `GetGameInstance()`, `ReadObject` / `ReadBool` (fonctions libres), `IsValid`, `GetViewTarget`, `InputEnabled`, `IsLookInputIgnored`, `GetClass`, `GetGameViewportClient` ; `IgnoreInput` passe par un pointeur non const local | `.cpp:245-259` | PASS-STATIC |
|
||
| `TickSwitchKey` (non const) appelle `LogSwitchKey` (const) | `.cpp:239` | PASS-STATIC |
|
||
| `UE_LOG` « Touche C » : 14 spécificateurs (9 `%d` puis 5 `%s`) pour 14 arguments (3 + 3 `Flag` en `int`, 3 ternaires `? 1 : 0`, puis `*GetNameSafe(View)`, `View ? *…GetName() : TEXT("-")` (`const TCHAR*`), `*GetNameSafe(Room)`, `*GetNameSafe(PC)`, `*ShownLabel`) | `.cpp:254-258` | PASS-STATIC |
|
||
| `UE_LOG` « aucun » : 1 `%s` pour `*ViewText` ; `Printf("%s, classe %s")` : `*GetNameSafe(View)` et `const TCHAR*` | `.cpp:188`, `.cpp:193` | PASS-STATIC |
|
||
| Lambda `Flag` : `[](const UObject* Container, FName Name) { return ReadBool(...) ? 1 : 0; }`, sans capture ; `ReadBool` qualifiée, accepte un conteneur nul ; reçoit `const UGameInstance*` (conversion vers `const UObject*`) ; définie hors de la macro `UE_LOG` | `.cpp:253` ; `ReadBool` `.cpp:77-81` | PASS-STATIC |
|
||
| `class APlayerController;` avant usage en signature | `.h:17`, usage `.h:45` | PASS-STATIC |
|
||
| `.h` : `FTSTicker` (`Containers/Ticker.h` déjà inclus), `FString` via `CoreMinimal.h` | `.h:12-13` | PASS-STATIC |
|
||
| `LogLifePlay` déclaré (`LifePlay.h` inclus `.cpp:17`) | `LifePlay.h:9` | PASS-STATIC |
|
||
| Espace nommé `LPCameraModeLocal` (pas anonyme) ; nouvelles constantes dans cet espace ; appels qualifiés ; commentaire de tête de l'espace | `.cpp:24-45` | PASS-STATIC |
|
||
| `DeltaTime` non utilisé : `(void)DeltaTime;` | `.cpp:242` | PASS-STATIC |
|
||
| Membres initialisés : `SwitchKeyHandle`, `bSwitchKeyDown = false`, `LastEmptyView` | `.h:48-52` | PASS-STATIC |
|
||
|
||
Verdict du bloc : **PASS-STATIC** (aucune erreur de compilation décelée par lecture ; compilation non rejouée).
|
||
Incertain : avertissement d'ombre de nom éventuel (`PC`, `World` locaux dans `Tick` ou `LogSwitchKey`) ; aucun membre
|
||
homonyme dans le `.h`, estimé sans risque.
|
||
|
||
### 3.5 Coût
|
||
Le ticker à intervalle 0 exécute, à chaque image : `GetFirstPlayerController`, `GetInputSettings` (CDO), une boucle sur
|
||
`GetActionMappings()` (une centaine d'entrées au plus, comparaison d'`FName` = comparaison d'entiers) et `IsPressed`
|
||
seulement pour les entrées nommées `SwitchCamera`. Pas d'allocation en régime normal (le `FString` de `LogSwitchKey`
|
||
n'existe que sur front montant). Estimé : de l'ordre de la microseconde par image, **acceptable** pour un témoin de
|
||
diagnostic. Verdict : **PASS-STATIC** (non mesuré). Le témoin est à retirer après le diagnostic.
|
||
|
||
### 3.6 Fins de ligne, BOM
|
||
Commande : `pwsh -NoProfile -Command '& "D:\Game\LifePlay-master 5.8\Tools\FileCheck.ps1" -Path "Source\LifePlay\LPCameraModeSubsystem.cpp","Source\LifePlay\LPCameraModeSubsystem.h"'`, code 0 :
|
||
```
|
||
LF 0 456 0 - D8981529E3773FBF50BB7FC1C91BC91F Source\LifePlay\LPCameraModeSubsystem.cpp
|
||
LF 0 62 0 - 2E1E245883960C2AFFC667A9A48FD96D Source\LifePlay\LPCameraModeSubsystem.h
|
||
fichiers=2 LF=2 alertes=0 introuvables=0
|
||
```
|
||
Recoupé par `tr -cd '\r' | wc -c` : CR = 0 pour les deux fichiers (et 0 pour le `.cpp` d'avant) ; `head -c3 | xxd -p` :
|
||
`2f2f20` (« // »), donc sans BOM. Piège noté : `-Path 'a','b'` passé par `pwsh -File` est lu comme un seul chemin
|
||
(« introuvable ») ; passer par `-Command`. Verdict : **PASS**.
|
||
|
||
### 3.7 Chemins de profil Windows
|
||
Grep `C:\\Users|AppData|<nom du compte>` sur `LPCameraModeSubsystem.*` : 0 occurrence. Le présent livrable n'en contient pas
|
||
(chemins du moteur et de la copie seulement). Verdict : **PASS**.
|
||
|
||
## 4. Diff lu en entier
|
||
- Fichiers : `Source\LifePlay\LPCameraModeSubsystem.cpp` (+71 −1), `Source\LifePlay\LPCameraModeSubsystem.h` (+10).
|
||
- Recompté : `git diff --no-index --stat` donne `72 …+++++++++++++++++++++-` et `10 ++++++++++`. Toutes les lignes
|
||
ajoutées relèvent de la spécification (constantes, includes, ticker, `Tick`, `TickSwitchKey`, `LogSwitchKey`, membres) :
|
||
aucun ajout non demandé.
|
||
|
||
## 5. Verdict
|
||
**PASS-STATIC** : conforme à la spécification et compilable à la lecture, empreintes attendues, LF sans BOM, aucun chemin
|
||
de profil. Non rejoué : compilation, émission de la ligne en jeu (§ 6). Aucun écart bloquant ; 3 remarques (R1 à R3).
|
||
|
||
## 6. Points à confirmer par l'utilisateur (cases)
|
||
- [ ] Compilation `LifePlayEditor` 5.8 sans erreur nouvelle (fiche BUILD B2j, puis `Build.ps1 -FromLog`).
|
||
- [ ] Essai en jeu : passage CharGen en C1, appui sur C, lecture de la ligne `Touche C : …` dans `Saved\Logs\LifePlay.log`.
|
||
- [ ] Lecture de R3 : si aucune ligne `Touche C` n'apparaît après l'appui, la touche n'atteint pas `PlayerInput`
|
||
(viewport ignore ou coupure en amont) ; ce n'est pas un défaut du témoin.
|
||
- [ ] Retrait du témoin (ticker image par image) après le diagnostic.
|
||
|
||
Fichiers à commiter : aucun par cette VAL (livrable `Docs\Migration\etat\CAM\CAM-B2j-VAL.md` à verser par le gardien avec le
|
||
lot ; les deux fichiers C++ sont `??` dans la copie 5.8 et relèvent du ticket du lot).
|
||
|
||
Tours : 12 / 40
|