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, etGrep Tocc|T-occsousDocsne trouve queCAM-COMMUN5-DIAG.md:108etBOSS-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 leDeltaTimedu 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 :WitnessC2l. 342 ignore Room). Établi. - Départ caméra, arrivée tête :
CamLoc = Cam->GetActorLocation()avecCam=Room.CamRoom;Head = Mesh->GetSocketLocation("head")(.cpp:285-286,HeadSocketl. 60). Tracé deCamLocversHead(l. 296). Établi. - Acteurs ignorés :
Player(l. 289),Cam(l. 290),GI.Wall(l. 291-294, nomWalll. 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 unUStaticMeshComponent), acteur, visible 0 ou 1,Hit.Distance,FVector::Dist(CamLoc, Head). Établi. - Journal seulement : aucun effet de bord hors
OcclusionCooldownet leUE_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.hetEngine/StaticMesh.hajoutés (.cpp:10-11).GetStaticMesh() constexiste :Engine\Classes\Components\StaticMeshComponent.h:453, retourneTObjectPtr<UStaticMesh>.Cast<UStaticMeshComponent>sur unconst UPrimitiveComponent*: type complet par ce même en-tête. GetNameSafe: surchargeconst TObjectPtr<T>&(CoreUObject\Public\UObject\UObjectBaseUtility.h:912) etconst UObjectBaseUtility*(l. 893). UnTObjectPtr<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 constructeurFCollisionQueryParams(FName, const TStatId&, bool bInTraceComplex = false, const AActor* = NULL)(l. 238) :trueest bienbTraceComplex. Même forme avecfalsedéjà compilée dansWitnessC2(.cpp:341).LineTraceSingleByChannel(FHitResult&, const FVector&, const FVector&, ECollisionChannel, const FCollisionQueryParams&, …) const(Engine\Classes\Engine\World.h:2161, dansclass UWorld, l. 931). Appelée surUWorld* Worldnon const : valide (World = GI->GetWorld(), l. 276, même forme queWitnessC2l. 316).UPrimitiveComponent::IsVisible() const: hérité deUSceneComponent::IsVisible() constvirtuel, section publique (Engine\Classes\Components\SceneComponent.h:853, section publique des lignes 400 à 872) ;PrimitiveComponent.hne le redéfinit pas (Grep : 0). Appelé viaconst UPrimitiveComponent*: valide.FHitResult::GetComponent() constrendUPrimitiveComponent*(Engine\Classes\Engine\HitResult.h:227) ;GetActor() constrendAActor*(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 ternaireMeshComp ? *GetNameSafe(...) : TEXT("-")(const TCHAR*des deux côtés, même motif que.cpp:264) ; 3*GetNameSafe(Hit.GetActor()); 4Comp && Comp->IsVisible() ? 1 : 0(int, précédence :(Comp && …) ? 1 : 0) ; 5Hit.Distance(float, promu en double) ; 6FVector::Dist(...)(double, UE5). Les temporairesFStringvivent jusqu'à la fin de l'expression complète..h: la méthode est déclarée dans la sectionprivate, hors UHT (pas deUFUNCTION), aprèsWitnessCooldown.OcclusionCooldowninitialisé à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,OcclusionLogIntervaldéfinies une seule fois, Grep surSource). - Limite : lecture seule, pas de compilation. Verdict
PASS-STATIC, pasPASS(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 duWitnessC2existant (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-indexavant/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 sauvegardeLifePlay_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, moduleLifePlaydans 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
- Aucun livrable IMPL
CAM-Tocc-*ni fiche dansetat\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 sauvegardeCAM-Tocc. À fournir avant le ticket du gardien. Source\LifePlay\LPCameraModeSubsystem.cppet.hsont 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).