LifePlay-Revival/Docs/Migration/etat/CAM/CAM-Tocc-VAL.md

122 lines
12 KiB
Markdown
Raw Normal View History

Fiche CAM-Tocc-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-Tocc-VAL : témoin d'occlusion C2, validation statique (2026-10-14)
Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8` (HEAD 0745917). Sans UE et sans compilation : lecture, diff et
en-têtes du moteur seulement. Aucun fichier modifié hors ce livrable. Verdict maximal possible : `PASS-STATIC`.
## 1. Fiches amont relues
- `Docs\Migration\etat\CAM\CAM-COMMUN5-DIAG.md` § 2 (a) (spécification du témoin, l. 70-73) et § 4 (l. 108 : T-occ,
« journal seulement » ; l. 112-114 : MD5 avant écriture).
- Aucun livrable IMPL `CAM-Tocc-*` : `Glob Docs/Migration/etat/CAM/*Tocc*` ne rend aucun fichier, et `Grep Tocc|T-occ`
sous `Docs` ne trouve que `CAM-COMMUN5-DIAG.md:108` et `BOSS-ETAT.md:54`. Les sources livrées servent d'amont (écart 1).
- Code lu en entier : `Source\LifePlay\LPCameraModeSubsystem.cpp` (503 lignes) et `.h` (66 lignes).
## 2. Points à confirmer des IMPL amont
sans objet : aucune IMPL CAM-Tocc n'existe sous `etat\CAM` (voir section 1), donc aucun point à confirmer à reprendre.
Les points à confirmer ouverts par cette VAL sont en section 6.
## 3. Critères rejoués
| # | Contrôle | Commande ou lecture | Résultat | Verdict |
|---|---|---|---|---|
| C1 | MD5 après (.cpp, .h) | `Tools\FileCheck.ps1 -Path` (copie 5.8) | `.cpp` FE9236BD138A46BBC2B63027977B3CD9 ; `.h` 7DA111CB65B267A9E2F7482CBA368BE9 : égaux aux valeurs attendues | PASS |
| C2 | MD5 avant (sauvegarde CAM-Tocc) | même commande sur `D:\Game\LifePlay_Backup_5.5\CAM-Tocc\Source\LifePlay\` | `.cpp` D8981529E3773FBF50BB7FC1C91BC91F ; `.h` 2E1E245883960C2AFFC667A9A48FD96D : égaux à ceux du DIAG (`CAM-COMMUN5-DIAG.md:114`) | PASS |
| C3 | Fins de ligne, BOM | sortie FileCheck : `LF`, CRLF 0, CR 0, BOM `-`, alertes=0 pour les 4 fichiers (503 / 66 / 456 / 62 LF) | LF sans BOM, inchangé par rapport à l'avant | PASS |
| C4 | Pas de chemin de profil Windows | Grep des motifs de dossier de profil (dossier utilisateur, données d'application) et du nom de compte sur `LPCameraModeSubsystem.*` : 0 résultat | aucun | PASS |
| C5 | Diff = ajouts seulement | `git diff --no-index --numstat` : `.cpp` 47 ajouts, 0 retrait (`--stat` : « 47 insertions(+) ») ; `.h` 4 ajouts, 0 retrait | aucune ligne existante modifiée ni retirée | PASS |
| C6 | Conformité à la spécification § 2 (a) | lecture `.cpp:267-306` | voir détail ci-dessous | PASS-STATIC |
| C7 | Déclaration et appel | `.h:55-58` ; `.cpp:217-221` ; Grep `WitnessOcclusion` sur `Source` | méthode privée déclarée dans le `.h` (l. 56) ; un seul appel (`.cpp:220`), dans le bloc `if (Label == LabelC2)`, juste après `WitnessC2(DeltaTime);` (l. 219) | PASS-STATIC |
| C8 | `WitnessC2` et ligne `Touche C` inchangés | diff : aucune ligne retirée, aucun ajout dans `WitnessC2` (l. 308-384) ni `LogSwitchKey` (l. 252-265) ; l'insertion est avant `WitnessC2` | inchangés, ligne « aucun » (`Indicateur de camera : aucun`, l. 198) intacte | PASS |
| C9 | Compilation probable | en-têtes du moteur, voir détail ci-dessous | aucune erreur prévisible | PASS-STATIC |
| C10 | Coût | analyse, voir ci-dessous | acceptable | PASS-STATIC |
| C11 | Comportement et Blueprint | diff | aucun changement de comportement du jeu : lecture par réflexion et un tracé, une ligne de journal ; aucun Blueprint, aucun asset | PASS-STATIC |
### Détail C6 (spécification, point par point)
- C2 seulement : appel dans la branche `Label == LabelC2` (`.cpp:217`), libellé `Camera: C2 Follow` (`.cpp:59`). Établi.
- Toutes les 0,5 s : `OcclusionInterval = 0.5f` (`.cpp:66`), armé à la ligne 274 avant toute sortie anticipée,
décrémenté par le `DeltaTime` du ticker (`.cpp:269`). Estimé : le ticker tourne à 0,1 s (`TickInterval`), la
cadence réelle est un multiple de 0,1 s, donc 0,5 s à l'image près.
- Tracé Visibility complexe, Room compris : `FCollisionQueryParams Query(SCENE_QUERY_STAT(LPCameraOcclusion), true)`
(`.cpp:288`), `ECC_Visibility` (`.cpp:296`). Room n'est pas ajouté aux acteurs ignorés (contraste : `WitnessC2`
l. 342 ignore Room). Établi.
- Départ caméra, arrivée tête : `CamLoc = Cam->GetActorLocation()` avec `Cam` = `Room.CamRoom` ; `Head = Mesh->GetSocketLocation("head")`
(`.cpp:285-286`, `HeadSocket` l. 60). Tracé de `CamLoc` vers `Head` (l. 296). Établi.
- Acteurs ignorés : `Player` (l. 289), `Cam` (l. 290), `GI.Wall` (l. 291-294, nom `Wall` l. 56). Établi.
- Au plus une ligne par seconde : sur contact, `OcclusionCooldown = OcclusionLogInterval = 1.f` (l. 302) ; sans contact,
le délai reste à 0,5 s. Donc le tracé suivant un contact a lieu 1 s plus tard (et non 0,5 s) : voir constat 3.
- Format : « Temoin C2 : joueur masque par %s (%s) de %s, visible=%d, a %.0f cm de la camera (camera a %.0f cm de la tete) »
(l. 303) = texte de la demande. Composant, maille (`-` si ce n'est pas un `UStaticMeshComponent`), acteur,
visible 0 ou 1, `Hit.Distance`, `FVector::Dist(CamLoc, Head)`. Établi.
- Journal seulement : aucun effet de bord hors `OcclusionCooldown` et le `UE_LOG`. Établi.
### Détail C9 (compilation probable, lue dans les en-têtes de `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\…`)
- Includes : `Components/StaticMeshComponent.h` et `Engine/StaticMesh.h` ajoutés (`.cpp:10-11`). `GetStaticMesh() const`
existe : `Engine\Classes\Components\StaticMeshComponent.h:453`, retourne `TObjectPtr<UStaticMesh>`. `Cast<UStaticMeshComponent>`
sur un `const UPrimitiveComponent*` : type complet par ce même en-tête.
- `GetNameSafe` : surcharge `const TObjectPtr<T>&` (`CoreUObject\Public\UObject\UObjectBaseUtility.h:912`) et
`const UObjectBaseUtility*` (l. 893). Un `TObjectPtr<UStaticMesh>` temporaire convient à la surcharge gabarit (correspondance exacte).
Le même appel existe déjà, compilé : `LPShowCoupleSubsystem.cpp:788` (`GetNameSafe(Shell->GetStaticMesh())`).
- `FCollisionQueryParams(SCENE_QUERY_STAT(...), true)` : `SCENE_QUERY_STAT(Q)` se développe en **deux** arguments,
`SCENE_QUERY_STAT_NAME_ONLY(Q), SCENE_QUERY_STAT_ONLY(Q)` (`Engine\Public\CollisionQueryParams.h:39`). L'appel devient
`(FName, TStatId, true)`, qui choisit le constructeur `FCollisionQueryParams(FName, const TStatId&, bool bInTraceComplex = false, const AActor* = NULL)`
(l. 238) : `true` est bien `bTraceComplex`. Même forme avec `false` déjà compilée dans `WitnessC2` (`.cpp:341`).
- `LineTraceSingleByChannel(FHitResult&, const FVector&, const FVector&, ECollisionChannel, const FCollisionQueryParams&, …) const`
(`Engine\Classes\Engine\World.h:2161`, dans `class UWorld`, l. 931). Appelée sur `UWorld* World` non const : valide
(`World = GI->GetWorld()`, l. 276, même forme que `WitnessC2` l. 316).
- `UPrimitiveComponent::IsVisible() const` : hérité de `USceneComponent::IsVisible() const` virtuel, section publique
(`Engine\Classes\Components\SceneComponent.h:853`, section publique des lignes 400 à 872) ; `PrimitiveComponent.h` ne le redéfinit pas (Grep : 0). Appelé via `const UPrimitiveComponent*` : valide.
- `FHitResult::GetComponent() const` rend `UPrimitiveComponent*` (`Engine\Classes\Engine\HitResult.h:227`) ; `GetActor() const` rend `AActor*` (l. 211).
L'affectation à `const UPrimitiveComponent*` est valide.
- `UE_LOG` : 6 spécificateurs (`%s`, `%s`, `%s`, `%d`, `%.0f`, `%.0f`), 6 arguments :
1 `*GetNameSafe(Comp)` (`const TCHAR*`) ; 2 ternaire `MeshComp ? *GetNameSafe(...) : TEXT("-")` (`const TCHAR*` des deux côtés,
même motif que `.cpp:264`) ; 3 `*GetNameSafe(Hit.GetActor())` ; 4 `Comp && Comp->IsVisible() ? 1 : 0` (int, précédence : `(Comp && …) ? 1 : 0`) ;
5 `Hit.Distance` (float, promu en double) ; 6 `FVector::Dist(...)` (double, UE5). Les temporaires `FString` vivent jusqu'à la fin de l'expression complète.
- `.h` : la méthode est déclarée dans la section `private`, hors UHT (pas de `UFUNCTION`), après `WitnessCooldown`. `OcclusionCooldown` initialisé à `0.f`. Aucun nouvel include nécessaire dans le `.h`.
- Espace de noms : constantes ajoutées dans `LPCameraModeLocal` (nommé, `.cpp:29`) : pas de risque C2374 (`OcclusionInterval`, `OcclusionLogInterval` définies une seule fois, Grep sur `Source`).
- Limite : lecture seule, pas de compilation. Verdict `PASS-STATIC`, pas `PASS` (rien n'a été compilé ici).
### Détail C10 (coût)
- Un tracé de ligne **complexe** unique, `LineTraceSingleByChannel`, toutes les 0,5 s (1 s après un contact), en C2 seulement.
Un seul rayon sur le thread de jeu, limité à la caméra et à la tête (quelques mètres). Ce coût est du même ordre que celui du `WitnessC2`
existant (trois balayages sphériques, mais seulement sous 1 m) et reste à la cadence d'un ticker à 0,1 s sans travail à chaque image.
- Lectures par réflexion : 4 `ReadObject` (GI.Room, GI.PlayerCharacter, Room.CamRoom, GI.Wall) = recherche de propriété par nom, toutes les 0,5 s : négligeable.
- Hors C2 (autres modes, menu ouvert) : aucun appel. Acceptable pour un témoin de diagnostic. Estimé (aucune mesure de temps d'image faite).
Rappel du DIAG (`CAM-COMMUN5-DIAG.md:80`) : le coût du tracé complexe est un risque pour l'évitement B2l (sondes fréquentes), pas pour ce témoin à 2 Hz.
## 4. Diff lu en entier
- `.cpp` : `git diff --no-index` avant/après lu en entier : 4 blocs, 47 ajouts, 0 retrait (2 includes, 2 constantes + 1 commentaire,
1 appel, 1 fonction de 40 lignes).
- `.h` : 1 bloc, 4 ajouts, 0 retrait (méthode + membre et leurs deux commentaires).
- Total : 2 fichiers, 51 lignes ajoutées. Recompte par une seconde méthode : `--numstat` (`.h` : `4 0`) et `--stat` (`.cpp` : 47 insertions) ;
longueurs des fichiers 456 → 503 (+47) et 62 → 66 (+4) par FileCheck.
- Les deux fichiers sont **non suivis** par git dans la copie 5.8 (`git status --short` : `??` ; `git ls-files` : 0) : le diff contre HEAD est impossible,
la sauvegarde `LifePlay_Backup_5.5\CAM-Tocc` (MD5 identiques à ceux du DIAG) sert d'état avant.
- Fichiers modifiés d'autres sous-systèmes visibles au `git status` (`LPDebugSubsystem.*`, `LPDirectControlSubsystem.*`, `LPOutdoorRoomSubsystem.*`, `LifePlay.cpp`) :
hors périmètre de cette fiche, non lus, non attribués à CAM-Tocc.
## 5. Verdict
**PASS-STATIC** pour le témoin d'occlusion C2 (CAM-Tocc). Tous les contrôles (C1 à C11) sont conformes ; aucune erreur de compilation prévisible
d'après les en-têtes du moteur 5.8 ; aucune compilation ni essai en jeu n'a été exécuté. Le verdict `PASS` plein exige le BUILD et un essai en C2.
## 6. Points à confirmer par l'utilisateur
- [ ] BUILD de `LifePlay` (éditeur 5.8, `Tools\Build.ps1`) : 0 erreur, module `LifePlay` dans les unités compilées. Non rejoué ici.
- [ ] Essai en jeu en C2 (pub assis, le cas C5-2) : vérifier la ligne `Temoin C2 : joueur masque par …` quand le joueur disparaît, et son absence quand il est visible.
- [ ] Accepter que, après un contact, le tracé suivant ait lieu 1 s plus tard (constat 3).
Tours : 11 / 40
## Constats
Écarts
1. Aucun livrable IMPL `CAM-Tocc-*` ni fiche dans `etat\CAM` (Glob vide) : la traçabilité du « qui a écrit, instantané, fichiers à commiter » manque ; la VAL
s'est appuyée sur le code et la sauvegarde `CAM-Tocc`. À fournir avant le ticket du gardien.
2. `Source\LifePlay\LPCameraModeSubsystem.cpp` et `.h` sont non suivis dans la copie 5.8 (`??`) : le ticket devra les ajouter (`A`), ce que la fiche n'annonce pas.
Observations (sans verdict négatif)
3. Cadence : sur contact, `OcclusionCooldown` passe à 1 s, donc un tracé tous les 1 s tant que le joueur est masqué (au plus une ligne par seconde, conforme) ;
le tracé suivant sans contact revient à 0,5 s. Cohérent avec « au plus une ligne par seconde ».
4. `visible=` reflète `UPrimitiveComponent::IsVisible()` (drapeau du composant), pas `AActor::IsHidden()` : un acteur masqué par `SetActorHiddenInGame`
peut donner `visible=1`. La spécification demande seulement `visible=<0|1>` ; le témoin `WitnessC2` garde son champ `cache=` pour l'acteur.
5. Seuls `Player`, `Cam` et `GI.Wall` sont ignorés (conforme) : un acteur attaché au joueur (vêtement, accessoire) ou un autre personnage dans l'axe
serait signalé comme masquant. Utile comme preuve, à lire avec le nom de l'acteur de la ligne.
6. Le membre et la méthode ajoutés sont placés entre deux membres de données du `.h` (style seulement, sans effet).