20 KiB
Fiche CAM-B2p-E-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-B2p-E-VAL : borne dure du couple pendant le sexe, VAL statique (2026-10-14, reprise incluse)
Copie D:\Game\LifePlay-master 5.8, branche ue5.8. Aucune compilation, aucun éditeur, aucun MCP, aucun jeu. Rien n'a été modifié hors ce livrable. LPCameraModeSubsystem.cpp et .h sont non suivis par git (??) : la comparaison se fait à l'instantané, pas à git diff <tag>.
Verdict final (après reprise, § 7) : PASS-STATIC. La première passe rendait FAIL (§ 5, B1 : local Root qui masque un membre). B1 est corrigé et le contrôle d'ombrage de tout le fichier (§ 7.3) ne trouve aucun autre masquage. La compilation reste à faire (COMMUN-10).
1. Fiches amont relues
Docs/Migration/etat/CAM/CAM-B2p-E-IMPL.md(lu en entier).Docs/Migration/etat/CAM/CAM-COMMUN9-DIAG.md§ 3 (causes) et § 4 (E1 à E4), § 5 (essais CAM-64 à CAM-68).- Précédents cités pour la méthode :
CAM-B2p-D-VAL.md:104(contrôle d'ombrage « aucun local ne porte le nom d'un membre »),CAM-B2r-VAL.md:75. - Instantané d'avant :
D:\Game\LifePlay_Backup_5.5\CAM-B2p-E\Source\LifePlay\(2 fichiers +manifest.csv).
2. Points à confirmer des IMPL (IMPL § 3)
| Point | Résultat |
|---|---|
Compilation : AActor::IsHidden |
PASS-STATIC : Engine/Classes/GameFramework/Actor.h:4523 bool IsHidden() const { return bHidden; } |
Compilation : TNumericLimits<double> |
PASS-STATIC : Core/Public/Math/NumericLimits.h:270 (spécialisation double), Max() l. 279, Lowest() l. 284, static constexpr |
Compilation : FBox(ForceInit) |
PASS-STATIC : Core/Public/Math/Box.h:80 explicit constexpr TBox(EForceInit) ; Min, Max : Box.h:39,42 |
| Compilation globale (COMMUN-10) | BLOCKED (non compilé). B1 (C4458 attendu) est corrigé à la reprise ; ombrage de tout le fichier vérifié (§ 7.3) |
En jeu : Box.Bounds.Max.Z = dessus du sol (LPDebug −102,2) |
reporté V7 (CAM-64 à CAM-68) |
En jeu : limites XY de Box couvrent tout le sol |
reporté V7 |
| En jeu : aucune pose légitime remontée à tort | reporté V7 (CAM-67) |
3. Critères rejoués (première passe ; les valeurs de la reprise sont en § 7)
| # | Critère | Commande / lecture | Résultat brut (première passe) | Verdict |
|---|---|---|---|---|
| 1a | MD5 .cpp |
md5sum LPCameraModeSubsystem.cpp |
6192495e9f25b0475654563538de8619 (annoncé alors 6192495E…8619) ; remplacé à la reprise, § 7.1 |
PASS (périmé) |
| 1b | MD5 .h |
md5sum LPCameraModeSubsystem.h |
0edc1f76b7eec0d135ea046da2269be0 (annoncé 0EDC1F76…9BE0) ; inchangé à la reprise |
PASS |
| 1c | Lignes | wc -l |
.cpp 1163, .h 121 |
PASS |
| 1d | CR | tr -cd '\r' | wc -c |
0 et 0 (LF) |
PASS |
| 1e | Instantané | md5sum + wc -l sur la copie d'avant |
.cpp d60632646bf1cf7d200e3bea833d8d72, 1044 l. ; .h 6585d7f67a7be3aea377b8e93cfa14d8, 112 l. |
PASS |
| 2a | Ampleur du diff | git diff --no-index --numstat |
.cpp 121 2, .h 9 0 ; 1044 + 121 − 2 = 1163 ; 112 + 9 = 121 |
PASS |
| 2b | Seuls ces 2 fichiers diffèrent de l'instantané | diff -rq <instantané>\Source\LifePlay Source/LifePlay |
…Subsystem.cpp differ, …Subsystem.h differ (autres lignes : « Only in », hors instantané) |
PASS |
| 2c | Contenu du diff | lecture en entier (voir § 4) | uniquement : 4 constantes, appel dans TickSwitchKey, TickCoupleBounds, lambda TraceDown + 4 déclarations, 6 membres .h |
PASS |
| 3 | Relecture C++ UE 5.8 | voir § 3.1 | un défaut en première passe (B1), corrigé (§ 7) | PASS-STATIC après reprise |
| 4 | Logique (a à j) | voir § 3.2 | conforme, 3 remarques non bloquantes | PASS-STATIC |
| 5 | Cohérence DIAG / IMPL | voir § 3.3 | écarts déclarés acceptables ; 2 écarts non déclarés (mineurs) | PASS-STATIC |
3.1 Relecture C++ (UE 5.8, D:\Game\Launcher\Engine\UE_5.8\Engine\Source)
- Ombrage d'un membre (B1) : voir § 5 et § 7.
Cast<AActor>(Room)avecconst UObject* Room(TickCoupleMouse,.cpp:752) :Runtime/CoreUObject/Public/Templates/Casts.h:88-89template <To, From> TCopyQualifiersFromTo_T<From, To>* Cast(From* Src)donneconst AActor*.RoomActorest déclaréeconst AActor*(.cpp:752) ;IsHidden() constl'accepte. PASS-STATIC.Cast<UPrimitiveComponent>(ReadObject(...))→UPrimitiveComponent*rangé dans unconst UPrimitiveComponent*;Floor->Bounds.GetBox():Core/Public/Math/BoxSphereBounds.h:226TBox<T> GetBox() const(T = double),FBox=TBox<double>; même appel que B2p-D (.cpp:862). TernairebFloorKnown ? …GetBox() : FBox(ForceInit): deuxFBox. PASS-STATIC.Mesh->GetComponentLocation().Z,Character->GetMesh()(const) : même motif que.cpp:799-801.FVector::Dist:Vector.h:1015statique ;SizeSquared() const:Vector.h:571. PASS-STATIC.FMath::Clamp/Min/Max: arguments de même type (double/double/double ; float/float pour les cooldowns).Pivot /= Couple.Num(): motif déjà présent.cpp:638. PASS-STATIC.UE_LOG(un spécificateur = un argument) :- « couple deplace hors prise » : 8 spécificateurs, 8 arguments. OK.
- « pas de borne » :
%d,%s;IsHidden()?1:0,*GetNameSafe(Floor). OK. - « couple ramene » :
%+.0f×3,%.0f×2,%d;Correction.X/Y/Z,FloorTop,FloorTop + CoupleCeilingHeight(double),CoupleGrabMode(int32,.h:86). OK.
AxisValue(PC, …)avecPCnul :.cpp:211-214renvoie 0.f.bShift:PC && PC->PlayerInput && (…). OK.- Captures :
TraceDownest[&], déclarée aprèsbFloorKnownetFloorBox(.cpp:753-755), lus seulement. OK. - Qualification : tous les appels d'aides de
TickCoupleBoundset du lambda portentLPCameraModeLocal::. OK. - Nullité :
Couple.Num() > 0avant/=;IsValid(Room)avantRoom->IsHidden();IsValid(Floor)avantFloor->Bounds;GI,Worldtestés ;ReadActorsfiltre parIsValid(.cpp:199). DansTickCoupleMouse,RoomActortesté nul avant usage. OK.
3.2 Logique (4a à 4j)
| Cas | Lecture | Verdict |
|---|---|---|
| (a) rien hors sexe, état oublié | .cpp:508-513 : sans SexOn, bHasLastPivot=false, bHiddenRoomWarned=false, retour |
PASS-STATIC |
| (b) borne pendant les menus | TickCoupleBounds est appelée par TickSwitchKey (.cpp:499), sans retour anticipé avant l'appel (.cpp:475-500) et sans la garde bMenuOnScreen de TickSexCamera (.cpp:607) ; ticker à chaque image (.cpp:328) |
PASS-STATIC |
| (c) pas de borne si Room cachée / sans Box, une ligne par scène | .cpp:542-555 ; bHiddenRoomWarned posé à la première ligne, remis à faux hors sexe |
PASS-STATIC (N2) |
| (d) XY : même marge que B2p-D | .cpp:558 CoupleFloorMargin (30 cm), même test > 2*Margin que .cpp:864 ; B2p-D borne déjà Target : rien à corriger pendant un glisser |
PASS-STATIC |
| (e) Z : remontée / descente, jamais les deux | .cpp:575-582 : if (Lowest < FloorTop - 5) remonte de FloorTop - Lowest ; else if (Highest > FloorTop + 350) redescend (N3) |
PASS-STATIC |
| (f) un seul vecteur | Correction unique appliqué à toutes les Couple (.cpp:583-588), Pivot += Correction |
PASS-STATIC |
| (g) E2 | .cpp:760-771 : impact + au-dessus du sol → max(impact, FloorBox.Max.Z) ; pas d'impact + au-dessus du sol → FloorBox.Max.Z ; hors du sol ou bFloorKnown faux : comportement précédent. Effet voulu (N1) : sans impact au-dessus du sol, bGrabHasHeight devient vrai |
PASS-STATIC |
| (h) témoin E4 | .cpp:529-539 : seulement CoupleGrabMode == 0, Dist > 5 cm, CoupleMoveCooldown <= 0 puis cooldown 1 s ; PC nul toléré |
PASS-STATIC |
| (i) déréférences nulles | voir § 3.1 | PASS-STATIC |
| (j) boucle de rétroaction | le témoin compare le pivot lu en début d'image à LastCouplePivot, écrit en fin d'image après Pivot += Correction (.cpp:597, et .cpp:552 pour la Room cachée) : la correction de l'image N n'est pas vue comme un déplacement à l'image N+1. Le glisser (TickCoupleMouse avant TickCoupleBounds, CoupleGrabMode != 0 pendant la prise) met aussi LastCouplePivot à jour. Les chemins à Room invalide remettent bHasLastPivot à faux |
PASS-STATIC |
3.3 Cohérence DIAG / IMPL
- E1, E2, E3, E4 conformes au DIAG § 4.
- Écarts déclarés (IMPL § 2) : champs E4 sur la ligne « hors prise » ; plafond 350 cm estimé ; borne aussi pendant une prise B2p-D (sans conflit). Acceptables.
- Écarts non déclarés (mineurs, acceptables) : le DIAG place E1 « à la fin de
TickSexCamera», l'IMPL l'appelle depuisTickSwitchKeyaprèsTickSexCamera(nécessaire :TickSexCamerasort en menu) ; la ligne E1 écritprise=%det non « source probable … ». - DIAG « Room.bHidden » : l'IMPL lit
AActor::IsHidden()(=bHiddennatif,Actor.h:4523). À confirmer en V7 que la variable Blueprint de Room est bien celle deAActor.
4. Diff lu en entier
.h: +9 lignes (TickCoupleBounds,LastCouplePivot,bHasLastPivot,bHiddenRoomWarned,CoupleBoundsCooldown,CoupleMoveCooldown, commentaires), 0 suppression..cpp: +121 / −2 en 6 hunks (-U0) :@@ -130,0 +131,8(4 constantes),@@ -490,0 +499(appel),@@ -493,0 +503,98(TickCoupleBounds),@@ -641,0 +749,6(E2, déclarations),@@ -647 +760,3et@@ -651 +766,5(TraceDown, 2 lignes remplacées).- Aucun ajout non demandé. Aucune édition par script déclarée ; LF inchangées (0 CR).
5. Verdict de la première passe : FAIL (corrigé, voir § 7)
Défaut bloquant (première passe)
B1 — Root masque un membre de la classe : erreur C4458 attendue à la compilation (ancien .cpp:571-573, dans TickCoupleBounds).
- Le membre existe :
LPCameraModeSubsystem.h:114TSharedPtr<SWidget> Root;. - Le projet traite l'ombrage en erreur :
Source/LifePlay.Target.cs:11DefaultBuildSettings = BuildSettingsVersion.V7;CppCompileWarnings.cs:89-93(moteur) défautWarningLevel.Errordès V2,/we4458; confirmé dans la ligne de commande réelle de la cible :Intermediate\Build\Win64\x64\LifePlayEditor\Development\Core\SharedPCH.Core.Cpp20.h.obj.rsp:55contient/we4458.LifePlay.Build.cset les.Target.csn'ont aucun réglage d'ombrage. - Établi : nom du membre, nom du local,
/we4458actif. Estimé : le déclenchement de C4458 pour un local de fonction membre (non compilé). - État après reprise : corrigé (
RootZ), voir § 7.
Défauts non bloquants (inchangés)
- N1 (
.cpp:759-770, E2) :bGrabHasHeightdevient vrai dès que le pivot est au-dessus du sol sans impact ; voulu par le DIAG, à noter en V7. - N2 (
.cpp:544-549) :bHiddenRoomWarnedn'est remis à faux qu'en sortie de sexe ; deux scènes consécutives sans passageSexOnfaux n'écrivent qu'une ligne. - N3 (
.cpp:575-582) : couple dont les racines sont écartées de plus de 355 cm : seule la remontée est faite. - N4 (
.cpp:859-869, B2p-D, hors diff) : la borne XY du glisser n'a pas la garde « Room cachée » deTickCoupleBounds. Hérité de B2p-D. - N5 : la borne XY ne s'applique que si
Boxfait plus de 60 cm dans les deux sens (comme B2p-D).
6. Points à confirmer par l'utilisateur
- Corriger B1 (renommer
RootdansTickCoupleBounds) : fait, vérifié en § 7. - BUILD COMMUN-10 : 0 erreur, aucun avertissement C4456/C4457/C4458 nouveau.
- V7 :
Box.Bounds.Max.Z= dessus du sol (LPDebug −102,2) ;Boxcouvre tout le sol ; CAM-64 à CAM-68. - V7 :
Room.bHiddendu Blueprint est bienAActor::bHidden(ligne « pas de borne du couple (Room cachee=…) »). - V7 : hauteur de plafond de 350 cm (
CoupleCeilingHeight) adaptée aux pièces du jeu.
Non rejoué : compilation, LPTestStringCompat, ouverture de l'éditeur, essais en jeu (VAL statique demandée).
7. Reprise (2026-10-14) : correction de B1 et ombrage de tout le fichier
Demande : revérifier la correction de B1, puis contrôler l'ombrage (C4458, C4456, C4457) sur tout le .cpp, B2r, B2p-C et B2p-D compris (jamais compilés).
7.1 Valeurs recomptées
| Élément | Annoncé | Recompté | Commande | Verdict |
|---|---|---|---|---|
MD5 .cpp |
FFF0FBB45D493B931B08780BF09547C8 |
fff0fbb45d493b931b08780bf09547c8 |
md5sum LPCameraModeSubsystem.cpp |
confirmé |
Lignes .cpp |
1163 | 1163 | wc -l |
confirmé |
MD5 .h |
0EDC1F76… (inchangé) |
0edc1f76b7eec0d135ea046da2269be0 |
md5sum |
confirmé |
Lignes .h |
121 | 121 | wc -l |
confirmé |
| CR | 0 | 0 et 0 | tr -cd '\r' | wc -c |
confirmé |
| Diff chiffré | idem avant reprise | .cpp 121 2, .h 9 0 |
git diff --no-index --numstat |
confirmé |
| Fichiers qui diffèrent de l'instantané | 2 | 2 (.cpp, .h) |
diff -rq |
confirmé |
7.2 Les 3 substitutions
Lecture de .cpp:571-573 et recherche \bRootZ?\b :
571: const double RootZ = Mesh ? Mesh->GetComponentLocation().Z : Person->GetActorLocation().Z;
572: LowestRoot = FMath::Min(LowestRoot, RootZ);
573: HighestRoot = FMath::Max(HighestRoot, RootZ);
Les autres occurrences de Root (l. 1112, 1130, 1140, 1144, 1147, 1156, 1161) sont le membre, dans EnsureWidget, RemoveWidget, SetShown, sans changement. Diff -U0 revu (sortie rangée dans le dossier temporaire de session) : mêmes 6 hunks que la première passe (8, 1, 98, 6, 3, 5 lignes ajoutées ; 2 supprimées) ; la seule différence de contenu est Root → RootZ aux lignes 85-87 du diff (= .cpp:571-573). Établi pour la forme du diff et ces 3 lignes ; estimé pour « rien d'autre » (je n'ai pas conservé de copie de l'état d'avant la reprise : le MD5 seul ne le prouve pas, mais les compteurs de lignes et de hunks sont identiques).
7.3 Contrôle d'ombrage sur tout le fichier
Méthode :
- Membres du
.h(35) :TickHandle,SwitchKeyHandle,bSwitchKeyDown,LastEmptyView,WitnessCooldown,OcclusionCooldown,bCharGenSeen,CharGenRepairTimeout,C1Cooldown(B2r) ;bMenuOnScreen,SexKeysCooldown(B2p) ;CoupleGrabMode,bLeftWasDown,bRightWasDown,bGrabMoved,bGrabHasHeight,GrabHeight,GrabOffset,GrabMouseStart,GrabLastMouseX,GrabTurned,GrabCamera,GrabCameraLocation,GrabCameraRotation,bCursorWarned(B2p-D) ;LastCouplePivot,bHasLastPivot,bHiddenRoomWarned,CoupleBoundsCooldown,CoupleMoveCooldown(B2p-E) ;Root,Text,Viewport,ShownLabel,bShown(B2c). Plus les fonctions membres (Tick,ComputeLabel, …). - Recherche par motif
Grepd'une déclaration de l'un de ces noms (<type> NOM =|;|:|{|)|,) sur tout le.cpp: 0 déclaration (les 3 seules lignes remontées, 529, 851, 883, sont des usages&& CoupleGrabMode ==). Témoin positif du motif : 9 déclarations deHit,Margin,Floortrouvées. - Lecture de toutes les fonctions du fichier (l. 26-1163) : paramètres, locaux, variables d'
for/if, paramètres et locaux de lambdas, comparés aux membres, aux locaux englobants et aux paramètres.
Résultat par fonction (aucun masquage) :
| Fonction (lignes) | Noms déclarés | C4458 membre | C4456/C4457 local ou paramètre |
|---|---|---|---|
LPCameraModeLocal::* (l. 146-320, fonctions libres) |
Container, Name, Prop, Inner, Array, Index, Actor, Out, Value, Down, Map, Settings, Keys, It, Widget, Visibility, ClassName, Menu, Focused |
sans objet (pas de classe) | aucun ; ClassName est local dans MenuOnScreen et paramètre dans WidgetOnScreen, jamais les deux |
Initialize/Deinitialize (323-337) |
Collection |
aucun | aucun |
Tick (339) |
Label, bMenu, World, PC, View, ViewText |
aucun | aucun |
RepairAfterCharGen (391) |
params Label, bMenu, DeltaTime ; GI, World, PC, View, bRoomCamera, RoomLabel |
aucun | aucun |
WitnessC1 (440) |
GI, World, PC, Player, Mesh, Camera, Eyes, Distance, CameraRotation, YawGap, RoomObject |
aucun | aucun |
TickSwitchKey (475) |
GI, World, PC, Settings, bDown, Map |
aucun (bSwitchKeyDown ≠ bDown) |
aucun |
TickCoupleBounds (502-599) |
GI, Room, Couple, Pivot, Person (3 boucles sœurs), World, PC, bShift, Moved (bloc E4), Floor, Box, FloorTop, Margin, Correction, LowestRoot, HighestRoot, Character, Mesh, RootZ |
aucun (Root n'existe plus comme local) |
aucun : World, PC, bShift, Moved ne sont pas redéclarés dans la portée englobante |
TickSexCamera (601-695) |
Step, GI, World, PC, View, Forward, Right, Wheel, RoomObject, Room, Couple, Pivot, Person, bKeys, bGrabbing, SceneCamera, Angle, Offset, Distance, Direction, Rotation (2 branches sœurs), Look, Arrows, bShift, bButtons |
aucun | aucun |
ReleaseCoupleGrab (697) |
— | aucun | aucun |
TickCoupleMouse (705-907) |
params GI, PC, View, Room, Couple, Pivot ; Input, bLeft, bRight, bLeftPressed, bRightPressed, World, bScene, Query, Wall, CamRoom, FloorComponent, RoomActor, bFloorKnown, FloorBox, MouseX, MouseY, bMouse ; bloc prise : bShiftHeld, MousePoint, bOnCouple, Person, Character, Mesh, Low, High, LowScreen, HighScreen, SurfaceZ, Aim ; bloc dépose : Rotation ; blocs glisser/rotation : Aim, Target, Floor, Box, Margin, SurfaceZ, Delta, Person, Turn, Offset, Rotation, Camera |
aucun (Camera ≠ GrabCamera, Rotation ≠ GrabCameraRotation, Turn ≠ GrabTurned) |
aucun : les Aim, SurfaceZ, Rotation, Person sont dans des portées sœurs ; aucune variable de fonction n'est redéclarée dans un bloc imbriqué |
lambda TraceCursor (736) |
Out ; Origin, Direction, Hit |
aucun | aucun : la fonction englobante n'a ni Origin, Direction ni Hit |
lambda TraceDown (755) |
At, OutZ ; Hit, Start, End, bHit, bOverFloor |
aucun | aucun : la fonction englobante n'a aucun de ces noms (SurfaceZ ≠ OutZ) |
LogSwitchKey (909) |
param PC ; GI, RoomObject, Room, View, ViewportClient, Flag ; lambda Flag : Container, Name |
aucun (ViewportClient ≠ Viewport) |
aucun |
WitnessOcclusion (927) |
GI, World, Room, Player, Cam, Mesh, Head, CamLoc, Query, Wall, Hit, Comp, MeshComp |
aucun | aucun |
WitnessC2 (968) |
GI, World, Room, Player, Cam, Mesh, Head, CamLoc, Distance, Dir, Query, Wall, Probe, CameraText, VisibilityText, PC, Back, BackText, Target, TargetText, Offset, BoxText, BoxMin, BoxMax, Margin ; lambda Probe : params Channel, Direction ; locaux Hit, Owner |
aucun | aucun : Hit et Direction du lambda n'ont pas d'homonyme dans WitnessC2 (Dir ≠ Direction) |
ComputeLabel (1046) |
GI, World, PC, View, Birdview, RoomObject, Room, PlayerCharacter, bC3, CamRoom, SceneCamera, bSceneCamera |
aucun | aucun |
EnsureWidget (1104) |
GI, ViewportClient, NewText, NewRoot |
aucun (NewRoot ≠ Root, NewText ≠ Text, ViewportClient ≠ Viewport) |
aucun |
RemoveWidget (1138) |
ViewportClient (if-init) |
aucun | aucun |
SetShown (1154) |
param bShow |
aucun (bShow ≠ bShown) |
aucun |
Limites du contrôle (à dire) :
- Les membres hérités (
UObject,USubsystem,UGameInstanceSubsystem) n'ont pas été énumérés un par un : aucun nom déclaré ci-dessus n'est un nom de donnée connu de ces classes (NamePrivate,ClassPrivate,OuterPrivatesont les seuls à ressembler à des noms usuels, et aucun local ne les porte). Estimé, non établi. - C4459 (local qui masque un nom global ou d'un autre fichier en compilation unitaire) : non énuméré contre les globaux du moteur ; l'espace de noms nommé
LPCameraModeLocallimite le risque (commentaire.cpp:27-29). Non établi. - Les macros
SNew/SAssignNew(.cpp:1119-1128) déclarent leurs propres noms internes : non examinées. - Aucune compilation : tout reste « estimé » jusqu'au BUILD COMMUN-10.
7.4 Verdict de la reprise
PASS-STATIC. B1 est corrigé, le diff contre l'instantané est inchangé hormis Root → RootZ (3 lignes), aucun masquage C4458, C4456 ou C4457 dans le fichier entier. Autres rubriques de la VAL inchangées (§ 3 à 6). Prochaine étape : BUILD COMMUN-10, critère : 0 erreur, aucun avertissement C4456/C4457/C4458 nouveau.
Tours : 26 / 40