LifePlay-Revival/Docs/Migration/etat/CAM/CAM-Tocc-VAL.md
edujiro5972 8084622450 LifePlay UE 5.8 : état de développement au 2026-10-19
Tickets : REP1-T4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:57:42 +02:00

12 KiB

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).