LifePlay-Revival/Docs/Migration/etat/CAM/CAM-B2p-E-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

20 KiB
Raw Blame History

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) avec const UObject* Room (TickCoupleMouse, .cpp:752) : Runtime/CoreUObject/Public/Templates/Casts.h:88-89 template <To, From> TCopyQualifiersFromTo_T<From, To>* Cast(From* Src) donne const AActor*. RoomActor est déclarée const AActor* (.cpp:752) ; IsHidden() const l'accepte. PASS-STATIC.
  • Cast<UPrimitiveComponent>(ReadObject(...)) → UPrimitiveComponent* rangé dans un const UPrimitiveComponent* ; Floor->Bounds.GetBox() : Core/Public/Math/BoxSphereBounds.h:226 TBox<T> GetBox() const (T = double), FBox = TBox<double> ; même appel que B2p-D (.cpp:862). Ternaire bFloorKnown ? …GetBox() : FBox(ForceInit) : deux FBox. PASS-STATIC.
  • Mesh->GetComponentLocation().Z, Character->GetMesh() (const) : même motif que .cpp:799-801. FVector::Dist : Vector.h:1015 statique ; 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, …) avec PC nul : .cpp:211-214 renvoie 0.f. bShift : PC && PC->PlayerInput && (…). OK.
  • Captures : TraceDown est [&], déclarée après bFloorKnown et FloorBox (.cpp:753-755), lus seulement. OK.
  • Qualification : tous les appels d'aides de TickCoupleBounds et du lambda portent LPCameraModeLocal::. OK.
  • Nullité : Couple.Num() > 0 avant /= ; IsValid(Room) avant Room->IsHidden() ; IsValid(Floor) avant Floor->Bounds ; GI, World testés ; ReadActors filtre par IsValid (.cpp:199). Dans TickCoupleMouse, RoomActor testé 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 depuis TickSwitchKey après TickSexCamera (nécessaire : TickSexCamera sort en menu) ; la ligne E1 écrit prise=%d et non « source probable … ».
  • DIAG « Room.bHidden » : l'IMPL lit AActor::IsHidden() (= bHidden natif, Actor.h:4523). À confirmer en V7 que la variable Blueprint de Room est bien celle de AActor.

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,3 et @@ -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:114 TSharedPtr<SWidget> Root;.
  • Le projet traite l'ombrage en erreur : Source/LifePlay.Target.cs:11 DefaultBuildSettings = BuildSettingsVersion.V7 ; CppCompileWarnings.cs:89-93 (moteur) défaut WarningLevel.Error dè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:55 contient /we4458. LifePlay.Build.cs et les .Target.cs n'ont aucun réglage d'ombrage.
  • Établi : nom du membre, nom du local, /we4458 actif. 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) : bGrabHasHeight devient vrai dès que le pivot est au-dessus du sol sans impact ; voulu par le DIAG, à noter en V7.
  • N2 (.cpp:544-549) : bHiddenRoomWarned n'est remis à faux qu'en sortie de sexe ; deux scènes consécutives sans passage SexOn faux 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 » de TickCoupleBounds. Hérité de B2p-D.
  • N5 : la borne XY ne s'applique que si Box fait plus de 60 cm dans les deux sens (comme B2p-D).

6. Points à confirmer par l'utilisateur

  • Corriger B1 (renommer Root dans TickCoupleBounds) : 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) ; Box couvre tout le sol ; CAM-64 à CAM-68.
  • V7 : Room.bHidden du Blueprint est bien AActor::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 :

  1. 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, …).
  2. Recherche par motif Grep d'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 de Hit, Margin, Floor trouvées.
  3. 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, OuterPrivate sont 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é LPCameraModeLocal limite 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