34 KiB
Fiche CAM-B2p-H-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-H-VAL : validation statique de G-e (pose sur le lit), G-f (surfaces admises), G-g (clic molette), maillage dans les refus, renommage de Reach (2026-10-14)
Portée : VAL statique (aucune compilation, aucun jeu, aucun éditeur, aucun commandlet, aucun MCP, aucune écriture git), par un validateur distinct de l'auteur.
Copie D:\Game\LifePlay-master 5.8, branche ue5.8 (git branch --show-current : ue5.8), UE 5.8, BuildSettingsVersion V7 (/we4456 /we4458 /we4459).
LPCameraModeSubsystem.cpp et .h sont non suivis par git (git status --short : ??), donc pas de tag CAM-B2p-H-avant : chaque point est jugé sur le diff de son instantané à l'instantané suivant (git diff --no-index), comme pour CAM-B2p-G-VAL.md.
Convention des instantanés : CAM-B2p-Hn est l'état d'avant le point Hn ; le point Hn est donc le diff CAM-B2p-Hn vers CAM-B2p-H(n+1) (H5 : vers l'état final).
Niveaux de preuve : établi = lecture ou commande rejouée aujourd'hui ; estimé = déduit ; incertain = non vérifié (essai nommé).
1. Fiches amont relues
Docs/Migration/etat/CAM/CAM-B2p-H-IMPL.md(100 lignes, lue en entier ; seule IMPL du lot).Docs/Migration/etat/CAM/CAM-B2p-G-SPEC.md§ 5 (l. 94-165 : DIAG 5.1, G-e 5.2, G-f 5.3, G-g 5.4, essais 5.5).Docs/Migration/etat/CAM/CAM-B2p-G-VAL.md(183 lignes, lue en entier : N7 et forme d'une VAL statique C++ de ce lot).- Lu en lecture seule :
Source/LifePlay/LPShowCoupleSubsystem.cppl. 25-70 (IsBedMeshl. 38-62),Source/LifePlay/LPDirectControlSubsystem.cppl. 48-62 (espace anonyme,Reachl. 58),Intermediate/Build/Win64/x64/*/*/LifePlay/Module.LifePlay.cpp. - Gabarit VAL lu :
D:\Game\LifePlay-Sandbox\Tools\claude\skills\lp-doc\gabarits.md. - Écart de gabarit de l'IMPL (N5 ci-dessous) : l'IMPL n'a ni tête commune, ni section « Écarts à la SPEC », ni « Ce qui n'a pas été fait », ni « Points à confirmer en VAL », ni ligne
Tours :. Les points à confirmer sont donc pris dans ses § 3 (risques R1 à R4) et § 4 (essais CAM-81 à CAM-85), plus la liste de la fiche.
2. Points à confirmer des IMPL (un par ligne)
| # | Point | Verdict | Preuve |
|---|---|---|---|
| P-H1 | N7 : Reach renommé ObstacleReach, rien d'autre ; symbole STG confirmé ; aucun Reach local restant |
PASS-STATIC | § 3 contrôles 5 à 7 ; .cpp l. 969-974 ; LPDirectControlSubsystem.cpp:58 |
| P-H2 | ComponentMesh, IsAdmittedBed, DescribeComponent ; règle des lits identique à IsBedMesh ; CoupleSpotFree même comportement, texte du bloqueur changé |
PASS-STATIC | .cpp l. 478-500, 526, 530 ; LPShowCoupleSubsystem.cpp:56-59 |
| P-H3 | G-e : tracé ECC_Pawn, OutSurface nul pour le sol, E2 conservé, racine la plus basse à surface + 3 cm, ligne de prise ; écart SPEC (racine la plus basse) |
PASS-STATIC, écart jugé acceptable | .cpp l. 133-134, 465-476, 1210-1241, 1296-1306, 1361-1369 |
| P-H4 | G-f : sol et lits seuls en pièce connue ; couple immobile sinon ; une ligne par changement ; remise à vide à la prise ; pièce cachée sans G-f | PASS-STATIC | .cpp l. 1288, 1364-1395 ; .h l. 121-122 |
| P-H5 | G-g : TickPanelClick pendant le sexe hors menu seulement ; hors sexe rien ne change ; 0,2 s / 5 px ; FindFunction + NumParms == 0 + ProcessEvent(…, nullptr) ; appui né dans un menu |
PASS-STATIC (réserve N1) | .cpp l. 176-178, 987-992, 998-1003, 1027-1044, 1122-1155 ; .h l. 137-144 |
| R1 (IMPL § 3) | Le tracé Pawn peut toucher la tête de lit (même maillage) : couple posé dessus | reporté V7 (CAM-81) | géométrie des assets non lisible en statique ; code conforme à la règle de la SPEC (aucun plafond de hauteur, « non fait » annoncé) |
| R2 | Capsules des PNJ sur le canal Pawn : place refusée | PASS-STATIC | une capsule est un UCapsuleComponent : ComponentMesh rend nul (l. 481-482), IsAdmittedBed faux (l. 489-491), refus l. 1376-1385 |
| R3 | Curseur sans position pendant le clic molette : seul le délai compte | PASS-STATIC | .cpp l. 1127, 1132, 1139-1140 : le mouvement n'est mesuré que si bMiddleHadMouse && bPanelMouse |
| R4 | ProcessEvent de LeftMouseSexOn hors boucle du monde (FTSTicker) |
forme de l'appel PASS-STATIC ; contexte d'appel incertain : reporté V7 | précédent d'appel identique LPDirectControlSubsystem.cpp:595 (Player->ProcessEvent(Function, nullptr)) ; contexte (tick du monde ou ticker) non relu ; essai : CAM-83 |
| CAM-81 à CAM-84 | Essais en jeu (lit, commode, clics, hors sexe) | reporté V7 (build COMMUN-12) | aucune exécution possible ici |
| CAM-85 | Ligne place refusee avec maillage ; compilation sans C4456 / C4458 / C4459 |
ligne : PASS-STATIC (l. 530 puis 1399) ; compilation : BLOCKED-compilation (BUILD) | § 3 contrôles 9 à 11 |
3. Critères rejoués (commande → résultat)
Les commandes PowerShell sont des fichiers de travail du dossier temporaire de session (scratchpad), pas des fichiers du dépôt.
| # | Contrôle | Commande / lecture | Résultat brut | Verdict |
|---|---|---|---|---|
| 1 | MD5 final | Get-FileHash -Algorithm MD5 |
.cpp 210B665AA8D5D628B8C1AC429A339B74 ; .h 239DA6094E7401E0E3B3699A635A8150 |
PASS : égalent la fiche et l'IMPL |
| 2 | Lignes, fins de ligne, BOM | lecture des octets (comptage de 13 et de 10, sans grep -c) |
.cpp size 73384, CR=0, LF=1687, premiers octets 2f2f20, dernier 0a ; .h size 8471, CR=0, LF=152, 2f2f20, 0a |
PASS : 1687 et 152 lignes, LF pur, sans BOM, fin de ligne finale |
| 3 | MD5 et lignes des instantanés | idem sur D:\Game\LifePlay_Backup_5.5\CAM-B2p-H1 à H5 |
H1 A5F041FF…/00D43993… (1575/141 lignes) ; H2 747FA007… (1576) ; H3 756C95F0… (1596) ; H4 91FD48F0… (1624), .h BBB45AD0… (142) ; H5 48F20ED7… (1637), .h 924B63F8… (144) ; CR=0 partout |
PASS : égalent le tableau de l'IMPL § 0 et chaque manifest.csv ; chaque dossier contient 3 fichiers (manifest.csv, .cpp, .h) |
| 4 | Diff brut et répartition | git diff --no-index --numstat puis recompte par -U0 (lignes +/- hors en-têtes) |
voir tableau ci-dessous | PASS : somme des points = global, à une ligne remplacée près, expliquée |
| 5 | Reach restant |
Grep \bReach\b sur Source/LifePlay (*.cpp, *.h) |
LPCameraModeSubsystem.cpp:970 (commentaire) ; LPDirectControlSubsystem.cpp:58, :1357, :1379 |
PASS : plus aucun Reach de code dans CameraMode (l. 970 est un commentaire) |
| 6 | Symbole STG | Read LPDirectControlSubsystem.cpp l. 48-62 |
l. 53 namespace, l. 54 {, l. 58 const float Reach = 150.f; : espace de noms anonyme |
PASS : confirmé |
| 7 | Ordre des unités unifiées | Grep de Module.LifePlay.cpp (UnrealEditor Development, UnrealGame Shipping) |
LPDirectControlSubsystem.cpp inclus (l. 37 / 36), LPShowCoupleSubsystem.cpp (l. 53 / 52) ; LPCameraModeSubsystem.cpp absent des unités générées (compilé seul quand il est modifié) |
PASS : ObstacleReach écarte tout C4459 quel que soit l'ordre des unités |
| 8 | Signatures et symboles | Grep des 24 noms nouveaux sur Source/LifePlay ; Grep namespace LPCameraModeLocal sur Source |
TickPanelClick : .h:139 et .cpp:1122 (même signature), un seul appel .cpp:1043 ; namespace LPCameraModeLocal : un seul fichier |
PASS : pas de doublon de symbole externe |
| 9 | C4456 / C4457 (locaux englobants) | lecture de TickCoupleMouse (l. 1166-1427), TickSexCamera (980-1121), TickPanelClick, CoupleLowestRoot, IsAdmittedBed, DescribeComponent |
détail ci-dessous | PASS-STATIC |
| 10 | C4458 (membres de la classe) | lecture du .h en entier (152 lignes) contre chaque nouveau local et paramètre |
détail ci-dessous | PASS-STATIC |
| 11 | C4459 (globaux et espaces anonymes de tous les .cpp) | Grep des noms nouveaux dans tout Source/LifePlay |
seuls hits hors CameraMode : Lowest (LPDebugSubsystem.cpp:508, local de fonction), Toggle (LPModInfoSubsystem.cpp:113, 288, locaux), Refused (LPHairstyleSubsystem.cpp:230, local) |
PASS-STATIC (résidu engine : N6) |
| 12 | Types, includes, API 5.8 | lectures du moteur (détail ci-dessous) | aucune erreur de type trouvée | PASS-STATIC |
| 13 | Formats UE_LOG / Printf |
comptage % contre arguments (détail ci-dessous) |
tous cohérents | PASS-STATIC |
| 14 | Non-régression B2p-C à B2p-G | liste des hunks (§ 4) contre les fonctions des lots précédents | aucun hunk dans TickCoupleBounds, TickSceneCamera, ComputeLabel, NotifyCoupleTeleported (G3 l. 1321-1335 hors diff) |
PASS-STATIC |
| 15 | Fichiers STG / STE | git status --short et dates ; instantanés ne contenant que CameraMode |
LPDirectControlSubsystem.* modifiés 12:05:58, LPShowCoupleSubsystem.* 12:43:20 ; CameraMode 14:08:43 ; instantanés H1 à H5 de 14:06:24 à 14:08:05 |
PASS : aucune écriture STG/STE après le début de H (établi par les dates ; l'instantané ne les contient pas, donc pas de preuve par octets) |
Contrôle 4 : bilan brut et répartition par point
| Point | Diff | .cpp ajoutées / retirées (numstat et -U0 concordent) |
Lignes .cpp avant vers après (LF) |
.h |
|---|---|---|---|---|
| H1 | H1 vers H2 | +3 / −2 | 1575 vers 1576 (+1, ok) | 0 |
| H2 | H2 vers H3 | +26 / −6 | 1576 vers 1596 (+20, ok) | 0 |
| H3 | H3 vers H4 | +41 / −13 | 1596 vers 1624 (+28, ok) | +2 / −1 (141 vers 142) |
| H4 | H4 vers H5 | +15 / −2 | 1624 vers 1637 (+13, ok) | +2 / −0 (142 vers 144) |
| H5 | H5 vers final | +52 / −2 | 1637 vers 1687 (+50, ok) | +8 / −0 (144 vers 152) |
| Somme | +137 / −25 | 1575 vers 1687 (+112, ok) | +12 / −1 | |
| Global | H1 vers final | +136 / −24 | +112, ok | +12 / −1 |
- Écart de la somme au global : +1 / −1 sur le
.cpp, expliqué : la ligneif (TraceDown(Target, SurfaceZ, Surface))est ajoutée par H3 (en remplacement deif (bGrabHasHeight && TraceDown(Target, SurfaceZ))) puis retirée par H4 (remplacée parconst bool bSurface = …;etif (bSurface)) : elle compte une fois en ajout et une fois en retrait dans la somme, et jamais dans le global. Net identique (+112). Le.hretombe exactement (12 / 1). - Retraits de H3 (13), recomptés par nature : tracé vertical et E2, 6 (2 lignes de commentaire E2, signature du lambda, ligne du canal
ECC_Visibility,if (bOverFloor),OutZ = FMath::Max(…)) ; prise, 4 (bGrabHasHeight = TraceDown(Pivot, SurfaceZ);,GrabHeight = …, format duUE_LOG, ligne du ternairePrintf) ; glisser, 3 (commentaire,if (bGrabHasHeight && TraceDown(…)),Target.Z = SurfaceZ + GrabHeight;) : 6 + 4 + 3 = 13, conforme au diff lu. Les retraits de H2 (6) sont les 6 lignes deCoupleSpotFreedéplacées dansComponentMesh/IsAdmittedBed/DescribeComponentou remplacées ; ceux de H4 (2) et de H5 (2) sont des lignes remplacées par une version plus longue (ifde G1 devenuelse if, commentaires). - Sorties collées (recompte
-U0) :cpp H1 vers FINAL : +136 -24eth H1 vers FINAL : +12 -1;numstat:136 24et12 1.
Contrôles 9 à 11 : ombrage (détail)
Nouveaux noms et leur portée :
| Nom | Portée | C4456/C4457 | C4458 | C4459 |
|---|---|---|---|---|
Lowest, Person, Character, Mesh |
CoupleLowestRoot (l. 466-476), Lowest hors boucle, les trois autres dans la boucle |
aucun homonyme dans la fonction (paramètre Couple seul) |
aucun membre (fonction de l'espace de noms) | Lowest seulement local ailleurs (LPDebugSubsystem.cpp:508) ; Person, Character, Mesh existaient déjà comme locaux compilés (l. 1057, 1268-1269) |
Comp, Mesh, MeshComp, MeshName |
ComponentMesh, IsAdmittedBed, DescribeComponent (l. 479-500) |
aucun homonyme (un Mesh par fonction) |
sans objet | Comp, MeshComp, MeshName existaient (code compilé de CoupleSpotFree) |
OutSurface |
paramètre du lambda TraceDown (l. 1218) |
aucun OutSurface englobant |
aucun membre | aucun hit hors CameraMode |
GrabSurface |
bloc de prise CoupleGrabMode == 0 (l. 1298) |
aucun homonyme (SurfaceZ voisin, nom distinct) |
aucun membre | aucun hit |
Surface, bSurface, Refused |
bloc du glisser (l. 1364-1380) | locaux englobants relus (Input, bLeft…, World, Query, TraceCursor, FloorComponent, RoomActor, bFloorKnown, FloorBox, TraceDown, MouseX, MouseY, bMouse, bHeld, Aim, Target, Interior, Area, Margin, Blocker, LeadCharacter, LeadMesh, RootOffset) : aucun |
LastSurfaceRefused est le membre, Refused en est distinct |
Refused : local ailleurs (LPHairstyleSubsystem.cpp:230, indentation d'une tabulation = corps de fonction) |
bMiddle, PanelMouseX, PanelMouseY, bPanelMouse, Toggle ; paramètres PC, DeltaTime |
TickPanelClick (l. 1122-1155) |
aucun doublon dans la fonction | membres bMiddleWasDown, bMiddleHadMouse, bMiddleMoved, MiddleHeld, MiddleStart : noms différents des locaux ; aucun membre PC ni DeltaTime |
Toggle : locaux de fonction ailleurs (LPModInfoSubsystem.cpp:113, 288) |
ObstacleReach |
RecenterSceneCamera (l. 972) |
aucun homonyme | aucun membre | aucun hit |
- Aucun nom de portée globale ou d'espace anonyme n'est ajouté : constantes et fonctions sont dans
LPCameraModeLocal(espace nommé) ; les constantesconstont de plus un lien interne.Grepd'unToggle/Surface/Lowest/Refusedisolé sur une ligne dansEngine/Classes/*.h(5.8) : 0 résultat (limité à ce dossier, voir N6).
Contrôle 12 : types, includes, API (sources 5.8 lues)
UObject::FindFunction(FName) const:CoreUObject/Public/UObject/Object.h:1258;ProcessEvent(UFunction*, void*):Object.h:1490;UFunction::NumParms(uint8) :Class.h:2574; précédents du projet :LPDirectControlSubsystem.cpp:582-595,LPDataCompat.cpp:149-164.FHitResult::GetComponent() constrendUPrimitiveComponent*:Engine/Classes/Engine/HitResult.h:227;OutSurface = bHit ? Hit.GetComponent() : nullptr;(l. 1230) :UPrimitiveComponent*versconst UPrimitiveComponent*&, aucun problème. Le lambda reçoit exactementconst UPrimitiveComponent*(GrabSurfacel. 1298,Surfacel. 1364) : la référence se lie.APlayerController::GetMousePosition(float&, float&) const:PlayerController.h:1623(surchargedouble&à côté, pas d'ambiguïté avec desfloat).FVector2D::Distance,FVector2D(float, float): même emploi qu'à.cppl. 1289 et 1344.bMiddleMoved |= (bool && bool && bool): même forme quebGrabMoved |=l. 1344.- Includes déjà présents (l. 5-28) :
UObject/UnrealType.h(doncUFunction),GameFramework/PlayerInput.h(EKeys::MiddleMouseButton, commeLeftMouseButtondéjà utilisé),Components/StaticMeshComponent.h,Engine/StaticMesh.h,GameFramework/Character.h,Components/SkeletalMeshComponent.h. Aucun include à ajouter.TNumericLimits<double>::Max():CoreMinimal(même usageLPDebugSubsystem.cpp:508). - Ternaires :
Mesh ? *Mesh->GetName() : TEXT("sans maillage statique")(l. 499) =const TCHAR*/ tableau, se réduisent enconst TCHAR*; l. 1305-1306 :bGrabHasHeight ? *FString::Printf(…) : TEXT("? cm")puis!bGrabHasHeight ? TEXT("inconnue") : GrabSurface ? *DescribeComponent(GrabSurface) : TEXT("sol"): imbriqué à droite, chaque branche finaleconst TCHAR*; lesFStringtemporaires vivent jusqu'à la fin de l'expression complète (l'appelUE_LOG), comme le motif déjà compilé qu'ils remplacent.Comp ? Comp->GetOwner() : nullptr:AActor*versconst UObjectBaseUtility*deGetNameSafe(précédent l. 1259). const UStaticMesh* ComponentMesh(…):MeshComp ? MeshComp->GetStaticMesh() : nullptr:UStaticMesh*converti enconst UStaticMesh*.Mesh->GetName()sur pointeur const :UObjectBaseUtility::GetName() const.double/float:Target.Z = Pivot.Z + (SurfaceZ + CoupleRootAboveSurface − CoupleLowestRoot(Couple)):double+ (double+float−double) ;FMath::Min(Lowest, cond ? double : double): deuxdouble;Distance(…) > PanelClickMaxMove:doublecontrefloat;MiddleHeld <= PanelClickMaxHold:floatcontrefloat..h:void TickPanelClick(APlayerController* PC, float DeltaTime);(APlayerControllerdéclaré en avant l. 18) ;FVector2D MiddleStart = FVector2D::ZeroVector;même forme queGrabMouseStart(l. 97). Zoneprivate:(l. 33).- Non-ASCII : uniquement des commentaires (l. 494 neuve avec « », comme les l. 74, 146, 536, 1328 déjà compilées) ; tous les
TEXT(...)neufs sont en ASCII.
Contrôle 13 : formats
- Prise (l. 1303-1306) :
%s,%.0f×3,%s,%s= 6 ; arguments : ternairedeplacement/rotation,Pivot.X,.Y,.Z(double), ternairePrintf/? cm, ternaire surface = 6.Printfinterne%+.0favecGrabHeight(double) = 1/1. DescribeComponent(l. 498-499) :%s/%s (%s)= 3 ; arguments : 2*GetNameSafe(…)+ ternaire = 3.- Refus de surface (l. 1384) :
%s= 1,*Refused. Clic molette (l. 1146) :%.2f= 1,MiddleHeld(float promu en double). Absence de l'événement (l. 1151) : aucun argument, aucun%.
Point par point : lecture du code
H1 (N7), diff H1 vers H2, +3 / −2. Le diff complet est de 3 lignes ajoutées (1 commentaire // ObstacleReach, pas Reach : … et les 2 lignes remplacées) et 2 retirées : const double Reach = … devient const double ObstacleReach = … (même expression, mêmes arguments) et Desired = Target + Axis * Reach; devient … * ObstacleReach; (.cpp l. 970-973). Aucun autre hunk. Verdict PASS-STATIC (contrôles 5 à 7 : STG:58 est bien dans l'espace anonyme l. 53-54 ; plus aucun Reach de code dans CameraMode ; Axis n'a pas changé).
H2 (maillage dans les refus), diff H2 vers H3, +26 / −6.
ComponentMesh(l. 478-483),IsAdmittedBed(l. 485-492),DescribeComponent(l. 494-500) ajoutées avantCoupleSpotFree, dansLPCameraModeLocal.- Règle des lits identique à
IsBedMesh(LPShowCoupleSubsystem.cpp:56-59) :Contains("bed", IgnoreCase),Contains("fnt_ext011"),Equals("fnt_new045"),Equals("fnt_new235"): mêmes quatre tests, mêmes littéraux, même ordre (.cppl. 490-491). Mesh nul :IsBedMeshrend faux (:40-43),IsAdmittedBedaussi (Mesh && (...),MeshNamevide). Seule différence : STE met le résultat en cache parFName(:44-60), sans effet sur le résultat. Équivalence : établie par lecture caractère par caractère. CoupleSpotFreemême comportement : le bloc d'origine (calcul deMeshComp,Mesh,MeshNamepuis les quatre tests) est remplacé parif (IsAdmittedBed(Comp)) continue;(l. 526-529) ; la condition, lecontinueet lereturn falsesont inchangés ; seule la ligneOutBlocker = Comp->GetName();devientOutBlocker = DescribeComponent(Comp);(l. 530) : le texte du bloqueur passe deRoom_C_0/NODE_…àPropriétaire/composant (maillage). L'appelant compareBlocker != LastSpotBlocker(l. 1396) : même logique, la clé est plus fine (le maillage s'ajoute au nom). Verdict PASS-STATIC.
H3 (G-e), diff H3 vers H4 (cpp +41 / −13, h +2 / −1).
- Canal :
LineTraceSingleByChannel(…, ECC_Pawn, Query)(l. 1223) ;Queryest la même requête que le tracé du curseur (couple, vue,Wall,CamRoomignorés, l. 1186-1196) ;ECC_Pawndéjà employé l. 517. OutSurface:bHit ? Hit.GetComponent() : nullptr(l. 1230), puis nul si E2 relève le point au sol (l. 1231-1235), puis nul si le composant estFloorComponent(l. 1236-1239) : nul pour le sol dans les deux cas (impact sous le dessus du sol, ouRoom.Box).- E2 conservé : l'ancien
OutZ = Max(OutZ, FloorBox.Max.Z)(si au-dessus du sol connu) équivaut àif (bOverFloor && OutZ <= FloorBox.Max.Z) OutZ = FloorBox.Max.Z: identique pour toute valeur deOutZ. Les retoursfalse(aucun impact et hors du sol) sont inchangés (l. 1225-1228). - Hauteur :
Target.Z = Pivot.Z + (SurfaceZ + 3 − CoupleLowestRoot(Couple))(l. 1368).Pivotest la moyenne des positions des acteurs, recalculée à chaque image (l. 1056-1064) et le déplacement est une translation rigideDelta = Target − Pivotappliquée à chaque personne (l. 1390-1394) : la racine la plus basse du couple arrive donc exactement àSurfaceZ + 3 cm(CoupleRootAboveSurface, l. 133-134).CoupleLowestRoot(l. 465-476) : Z du composant de maillage duACharacter, acteur à défaut ;Couplenon vide dans le glisser (bSceneexigeCouple.Num() > 0, l. 1177) ; même mesure queRecenterSceneCamera/ E3 (HighestRootl. 840 en est le pendant). Le gardebGrabHasHeight &&du glisser est retiré (l. 1365-1369) : sans impact ni sol,Target.ZrestePivot.Zcomme avant. - Ligne de prise (l. 1303-1306) :
Sexe : couple pris (deplacement|rotation) a (x, y, z), racine a +N cm de la surface <sol | Propriétaire/composant (maillage) | inconnue>;GrabHeight = CoupleLowestRoot − SurfaceZ(l. 1300) ;.hl. 91-92 : commentaire mis à jour (journal seulement). - Écart avec la SPEC jugé (§ 5.2 : « surface + écart racine-acteur + 3 cm » du meneur ; IMPL : racine la plus basse du couple). Lecture : pour la translation rigide d'un couple, les deux formulations donnent la même hauteur dès que la racine du meneur est la plus basse (cas du sol et de la plupart des poses). Si l'autre personne a la racine plus basse, la formulation de la SPEC la laisserait de ce côté sous la surface (couple enfoncé dans le matelas) alors que celle de l'IMPL la pose à surface + 3 cm ; si au contraire le meneur est plus bas, les deux coïncident. L'IMPL est donc au moins aussi sûre que la SPEC, cohérente avec E3 et le recadrage (mêmes racines), et l'écart est annoncé (IMPL § 1 H3). Acceptable (estimé, par lecture ; l'essai CAM-81 le confirmera sur le lit). Il est à porter à la connaissance de Big Boss, non à corriger.
- Verdict PASS-STATIC.
H4 (G-f), diff H4 vers H5 (cpp +15 / −2, h +2 / −0).
- Condition (l. 1376) :
bFloorKnown && bSurface && Surface && !IsAdmittedBed(Surface).bFloorKnown= sol valide et Room non cachée (l. 1216) : « pièce connue » ;Surfaceest nul pour le sol (H3) : le sol passe ; un lit admis passe ; tout le reste (commode, bureau, armoire, capsule de PNJ) est refusé. - Le couple ne bouge pas : la branche G-f (l. 1377-1386) ne contient que le journal ; le déplacement (l. 1390-1394) est dans la branche
else if (CoupleSpotFree(…))qui n'est pas atteinte ;Blockerreste vide etelse if (Blocker != LastSpotBlocker)(l. 1396) n'est pas atteint non plus (chaîneif / else if / else if, une seule branche s'exécute). - Une ligne par changement :
if (Refused != LastSurfaceRefused)puis affectation etUE_LOG(l. 1381-1385) ;.hl. 121-122 (membreFString). Remis à vide à chaque prise :LastSurfaceRefused.Reset();(l. 1288), juste aprèsLastSpotBlocker.Reset();(l. 1287), dans le bloc de sélection (CoupleGrabMode == 0). - Pièce cachée sans G-f :
bFloorKnownfaux (Room cachée ou sol invalide) : la condition est fausse, on passe àCoupleSpotFreeavecFloornul, comme avant ; G-e s'applique si le tracé touche (bSurface). - Sol sans impact au-dessus :
Surfacenul, G1 comme avant. - Verdict PASS-STATIC (réserves N2 et N3).
H5 (G-g), diff H5 vers final (cpp +52 / −2, h +8 / −0).
- Appel seulement pendant le sexe hors menu :
TickPanelClick(PC, DeltaTime)n'a qu'un appel,.cppl. 1043, placé après le retour de la l. 1027-1037 (if (!bSexOn || bMenuOnScreen) { …; return; }) et conditionné parPCnon nul. Chemins vérifiés : (1) hors sexe :bSexOnfaux, retour avant l'appel (l. 1027) ; (2) menu à l'écran : idem ; (3)GInul :bSexOnfaux ; (4)PCnul : pas d'appel, retour l. 1045. - Hors sexe, rien ne change (tous les chemins) :
- appel : voir ci-dessus, jamais hors sexe/menu ;
- H1 étendu : la détection du clic molette (l. 1001-1003) est dans le
elsedeif (!bSexOn)(l. 987-993 / 993-1026) : évaluée pendant le sexe seulement ; hors sexe, le bloc H1/H2 n'est pas exécuté ; en sexe,bClickne sert qu'au retour du focus (l. 1007-1011, 1019, 1020-1025) ; - remises à faux de
bMiddleWasDown: l. 991 (hors sexe) et l. 1031 (hors sexe ou menu) : écritures d'un membre qui n'a aucun autre lecteur queTickPanelClick; aucune valeur de PC/GI/Room, aucun appel, aucune ligne de journal ; TickPanelClickne lit ni n'écrit rien du PC hors la bascule du panneau (ProcessEventconditionné par le clic) ;- la fonction ne s'appelle pas depuis un autre ticker (
Grep TickPanelClick:.cpp1043, 1122 ;.h139).
- Seuil et mouvement : appui =
bMiddle && !bMiddleWasDown:MiddleHeld = 0, position de départ,bMiddleHadMouse,bMiddleMoved = false(l. 1128-1134) ; tenu ou relâché =else if (bMiddleWasDown):MiddleHeld += DeltaTime(durée réelle,DeltaTimenon borné ; leStepborné deTickSexCameran'est pas utilisé) etbMiddleMoved |= bMiddleHadMouse && bPanelMouse && Distance(...) > PanelClickMaxMove(l. 1138-1140) ; bascule à!bMiddle && MiddleHeld <= 0,2 && !bMiddleMoved(l. 1141) : 0,2 s inclus, 5 px exclus (>), conformes à la SPEC § 5.4 (« moins de 0,2 s », « 5 px près »).bMiddleWasDown = bMiddle;en fin (l. 1155). - Appel de l'événement :
PC->FindFunction(PCLeftMouseSexOn)(l. 1143),Toggle && Toggle->NumParms == 0(l. 1144),PC->ProcessEvent(Toggle, nullptr)(l. 1147) précédé de la ligneSexe : panneau bascule (clic molette, %.2f s); sinon la lignepanneau non bascule, evenement LeftMouseSexOn absent du PC(l. 1151). Aucun paramètre, aucun pointeur nul déréférencé (Toggletesté d'abord). - Un appui commencé dans un menu ne bascule rien : pendant un menu,
bMiddleWasDownest remis à faux à chaque image (l. 1031) etTickPanelClickn'est pas appelé ; un appui né pendant le menu n'a donc aucunMiddleHeldvalide. Réserve N1 : si le bouton est encore enfoncé à la fermeture du menu, l'appui est compté comme neuf à cet instant. - H1 étendu, justification :
MenuOnScreenrend vrai quand un champ de saisie garde le focus (.cppl. 340-341) ; sans retour du focus,bMenuOnScreenreste vrai etTickSexCamerasortirait avantTickPanelClick. Le retour du focus recalculebMenuOnScreendans la même image (l. 1024) avant le test de la l. 1027. Établi par lecture. QueIsPressed(MiddleMouseButton)soit vu parPlayerInputquand Slate a le focus : incertain (même hypothèse que pour les clics gauche et droit de H1), essai CAM-83. - Verdict PASS-STATIC (réserve N1).
4. Diff lu en entier
Chaque diff a été lu en entier (git diff --no-index -U2, 5 diffs .cpp et 3 diffs .h non vides) ; hunks du diff global (lignes de l'état final) :
| Fichier | Hunks | Contenu | Point |
|---|---|---|---|
.cpp |
133-134 | CoupleRootAboveSurface |
H3 |
.cpp |
176-178 | PCLeftMouseSexOn, PanelClickMaxHold, PanelClickMaxMove |
H5 |
.cpp |
465-500 | CoupleLowestRoot (H3), ComponentMesh, IsAdmittedBed, DescribeComponent (H2) |
H2, H3 |
.cpp |
526, 530 | CoupleSpotFree : IsAdmittedBed, DescribeComponent |
H2 |
.cpp |
969-973 | ObstacleReach |
H1 |
.cpp |
991, 998-1003, 1031, 1041-1044 | remises à faux, clic molette dans H1, appel | H5 |
.cpp |
1122-1155 | TickPanelClick |
H5 |
.cpp |
1210-1241 | TraceDown |
H3 |
.cpp |
1288 | LastSurfaceRefused.Reset() |
H4 |
.cpp |
1296-1306 | prise : GrabSurface, GrabHeight, ligne de prise |
H3 |
.cpp |
1361-1395 | glisser : hauteur (H3), bSurface et branche G-f (H4) |
H3, H4 |
.h |
91-92 | commentaire de GrabHeight |
H3 |
.h |
121-122 | LastSurfaceRefused |
H4 |
.h |
137-144 | TickPanelClick et 5 membres |
H5 |
- Aucun ajout non demandé : tout hunk se rattache à un point de la fiche (H1 à H5) ; ni STG ni STE touchés (contrôle 15).
- Non-régression B2p-C à B2p-G : G1 (
CoupleSpotFree,LastSpotBlocker,Blocker) garde la condition et le déplacement ; E2 conservé (H3) ; E1/E3 (TickCoupleBounds) hors diff ; G-a à G-d (TickSceneCamera,RecenterSceneCamerahors le seul renommage),ComputeLabelet G3 (NotifyCoupleTeleported, l. 1321-1335) hors diff ; H1/H2 de B2p (focus clavier) élargis au clic molette (annoncé) ; B2p-D : le glisser perd sa dépendance àbGrabHasHeight(voulu, SPEC § 5.2) etGrabHeightne sert plus qu'au journal (vérifié : seule lecture l. 1305). Aucune régression trouvée.
5. Verdict
| Point | Verdict |
|---|---|
| H1 (N7) | PASS-STATIC |
| H2 | PASS-STATIC |
| H3 (G-e) | PASS-STATIC, écart SPEC jugé acceptable |
| H4 (G-f) | PASS-STATIC |
| H5 (G-g) | PASS-STATIC |
| Contrôles transverses (types, includes, signatures, C4456/C4458/C4459 par lecture) | PASS-STATIC |
| Global | PASS-STATIC : aucun défaut bloquant. Non couvert : la compilation (BLOCKED-compilation, à confier à BUILD COMMUN-12) et tout comportement en jeu (reporté V7). |
6. Points à confirmer par l'utilisateur (cases)
- BUILD COMMUN-12 :
LifePlaycompile avec 0 erreur et 0 avertissement nouveau sous V7 ;LPCameraModeSubsystem.cppdoit figurer dans les unités compilées (C4456 / C4458 / C4459 et résidu N6). - Accepter l'écart de H3 à la SPEC (racine la plus basse du couple plutôt que racine du meneur).
- CAM-81 : glisser sur le lit de face et d'en haut ; vérifier la ligne
couple pris … racine a +N cm de la surface …et que la tête de lit ne porte pas le couple (R1) ; vérifier qu'aucune lignesurface refuseene désigne le plafond, un tapis ou un décor mince quand on vise le sol (N3). - CAM-82 : commode refusée, une seule ligne
surface refusee …; décider si une seconde visite de la même surface refusée dans la même prise doit réécrire la ligne (N2). - CAM-83 : clics gauche et droit sans bascule (partie PC, MCP sous UE-GO) ; Espace et clic molette basculent ; ligne
panneau bascule (clic molette, …);ProcessEventhors tick du monde sans anomalie (R4) ; clic molette vu parPlayerInputquand le filtre a le focus. - CAM-84 : hors sexe, rien ne change (Espace en pause, clics et molette comme avant).
- CAM-85 : ligne
place refusee … (maillage)présente.
Tours : 25 / 40
Constats
Défauts bloquants
Aucun (preuves : contrôles 1 à 15 et lecture point par point).
Défauts non bloquants
| # | Lieu | Constat | Niveau de preuve | État |
|---|---|---|---|---|
| N1 | .cpp l. 1031 et 1128, 1041-1045 |
bMiddleWasDown est remis à faux à chaque image de menu : si le bouton est encore enfoncé à la fermeture du menu, l'appui est compté comme neuf et un relâcher en 0,2 s au plus bascule le panneau. De même, si PC est nul quelques images (l. 1041-1045), bMiddleWasDown garde sa dernière valeur. Un clic qui commence et finit dans la même image n'est pas vu (IsPressed est un état). Tous cas très rares. |
estimé (lecture) | ouvert, négligeable |
| N2 | .cpp l. 1381-1385 |
LastSurfaceRefused n'est pas remis à vide quand le curseur repasse sur une place admise : revenir sur la même surface refusée dans la même prise n'écrit pas de seconde ligne (même traitement que LastSpotBlocker, l. 1396-1399). Lu comme « une ligne par changement de surface refusée ». |
établi (lecture) | ouvert, à confirmer (case CAM-82) |
| N3 | .cpp l. 1218-1241, 1376 |
Avec le canal Pawn, toute surface touchée au-dessus du sol qui n'est pas un lit est refusée en pièce connue : un tapis ou décor mince plus haut que le dessus de Room.Box, un plafond ou volume bloquant Pawn sous Pivot.Z + 150 (départ du tracé), ou la tête de lit (R1) peuvent refuser des places que le joueur juge valides. Le journal nomme le composant (surface refusee …), donc l'essai tranche d'emblée. |
incertain (essai : CAM-81 et CAM-82) | ouvert |
| N4 | .h l. 91-93 |
Le commentaire de GrabHeight est posé au-dessus de bGrabHasHeight (antérieur à H, B2p-D). Sans effet sur la compilation. |
établi | ouvert, cosmétique |
| N5 | IMPL | Écart de gabarit : voir § 1 (tête commune, « Écarts à la SPEC », « Ce qui n'a pas été fait », « Points à confirmer en VAL », Tours : absents). Le contenu est exact : MD5, lignes, périmètre et noms recomptés. Le diff global (136 / 24, 12 / 1) n'est pas dans l'IMPL ; il est ici. |
établi | non bloquant, à reporter à l'auteur |
| N6 | compilation | Le résidu C4459 vient des en-têtes moteur : un nom Toggle, Surface, Lowest ou Refused déclaré en portée globale par un en-tête inclus par CameraMode n'est excluable que par compilation. Grep sur Engine/Classes/*.h : rien. Toggle a un précédent de local compilé sous V7 (LPModInfoSubsystem.cpp:113, 288). |
estimé (faible probabilité) | à trancher par BUILD |
Non mesuré
Compilation et avertissements ; tout essai en jeu (CAM-81 à CAM-85, reportés V7) ; géométrie réelle des assets (tête de lit, tapis, plafond sur le canal Pawn) ; vue de IsPressed(MiddleMouseButton) par PlayerInput quand Slate a le focus ; contexte d'appel de ProcessEvent (R4) ; absence d'écriture dans STG / STE prouvée par les dates seulement (les instantanés ne contiennent pas ces fichiers) ; LPTestStringCompat et porte G-U3 (sans objet : aucun changement de chaîne, de configuration ni de compilation dans ce lot).
Fichiers à commiter (VAL)
A Docs/Migration/etat/CAM/CAM-B2p-H-VAL.md (dépôt du jeu, branche ue5.8). Fichiers modifiés par la VAL : ce livrable seulement ; fichiers de travail dans le dossier temporaire de session (scratchpad), hors dépôt.
À verser
lp-validate§ 1 : le crochetecriture-gardienrefuse le signe « supérieur à » même dans unechoentre guillemets (lu comme redirection, flèche->comprise) ; écrire « vers » dans les étiquettes. Un script.ps1du dossier temporaire, lancé parpwsh -NoProfile -File, évite les pièges de$dans Git Bash (foreach($x in …)y est mangé).lp-validate§ 1 : pour des instantanés « d'avant » successifs, le point Hn est le diffHnversH(n+1); la somme brute des diffs par point peut dépasser le global d'une ligne ajoutée puis remplacée par un point suivant : le noter et le recompter (+137 / −25contre+136 / −24ici, écart expliqué), l'égalité tient sur le net (lignes LF) et sur le.h.lp-ue-compat/lp-build:UObject::FindFunction(FName) const(Object.h:1258),ProcessEvent(UFunction*, void*)(Object.h:1490),UFunction::NumParms(Class.h:2574),FHitResult::GetComponent() const(HitResult.h:227) vérifiés en 5.8.