42 KiB
Fiche CAM-B2p-J-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-J-VAL : validation statique du correctif C++ J1 à J6 et contre-vérification de la DIAG (2026-10-14)
Copie D:\Game\LifePlay-master 5.8, branche ue5.8. Aucune compilation, aucun jeu, aucun éditeur, aucun commandlet, aucune écriture git. Seul fichier écrit dans le projet : ce livrable. Scripts de lecture et diffs dans le scratchpad (hors projet) : check1.ps1, hunks.ps1, diff_cpp.txt, diff_h.txt, diff_cpp_u0.txt (première passe) ; check2.ps1, diff2_cpp.txt, diff2_h.txt (reprise). Aucune modification de code, de config ou de doc validée : rien à inventorier sur une copie jetable.
Statut courant : voir la section « Reprise » en fin de fichier (verdict global mis à jour : PASS-STATIC). Les sections 1 à 6 et les Constats ci-dessous sont la première passe (verdict d'alors : FAIL sur D1), conservés tels quels.
1. Fiches amont relues
CAM-B2p-J-IMPL.md(DIAG § 1, correctif § 2, PC § 3, proposé § 4, essais § 5,5 bisvide « à compléter » à la première passe), lu en entier.CAM-B2p-I-IMPL.md(base : I0, I1, reprise D1 de la VAL) etCAM-B2p-I-VAL.md(verdicts et défauts D1 à D3 de B2p-I), lus pour le contexte ; défauts D1 à D3 de B2p-I recoupés avec le diff (voir 2, point J5).CAM-B2p-G-PC-IMPL.mdetCAM-B2p-G-PC-FICHE.md(nœuds 134, 408, 277, 40 de G-g (2)),CAM-B2p-R-IMPL.md(O1 de Room).- Journal d'essai
D:\Game\LifePlay_Backup_5.5\COMMUN-12\essais\commun12_LifePlay.log(24 682 lignes, UTC, relu aux passages cités). DumpCAM-B2p-G-PC-VAL_LPDumpFunction_20261014-135527.txt. MoteurD:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime.Config\DefaultInput.ini. - Conformité de l'IMPL à son gabarit (lp-doc/gabarits.md) : écart (D5) : pas de tête commune (
Fiche … — Niveau …), pas de section « Écarts à la SPEC », pas de « Points à confirmer en VAL » (remplacés par § 5 « Essais »), pas de ligneTours : …, § 5 bis vide.
2. Points à confirmer des IMPL (un par ligne)
Le § 5 de l'IMPL ne liste que des essais (V7). Les points ci-dessous suivent la fiche de la VAL (1 à 9) et les essais CAM-91 à CAM-95, CAM-86 à CAM-90.
| # | Point | Verdict | Preuve |
|---|---|---|---|
| 1 | DIAG § 1, faits établis (poses identiques, rotations +0, aucune ligne de refus, bascules LogViewport) |
PASS | § 3.1 |
| 1b | DIAG § 1.1, cause « GameOnly fige le curseur » | estimée, non établie, partiellement contredite (prises 2 et 3 de 12:38) | § 3.1, D2 |
| 1c | DIAG § 1.3, +22 cm par prise = molette de Room | estimée, non étayée (la bascule du panneau coïncide) ; +9 et Maj + molette établis | § 3.1, D6 |
| 1d | Autres causes (canal Pawn H3, G-f/H4, sélection) | écartées pour la rotation (établi), restent possibles pour le glisser avant J3 (estimé) | § 3.1 |
| 2 | J1 KeepMouseFree : conditions, API, absence de boucle, clavier |
PASS-STATIC, réserves D2 (couverture) et D4 (drapeau de curseur) | .cpp:1249-1285, moteur § 3.2 |
| 3 | J2 GrabCursor : position réelle, deltas, signe de Y, TraceScreen, seuil, rotation |
FAIL : D1 bloquant (échelle des deltas) ; reste PASS-STATIC (Y, tracé, seuil, bMouse && retiré, non-régression) |
.cpp:1590-1610, 1678-1681, DefaultInput.ini:16-17 |
| 4 | J3 : lignes de refus et témoins | PASS-STATIC (formats, cadences, témoin hors CAM), libellé « deltas bruts » inexact (D1) | § 3.4 |
| 5 | J4 Alt | PASS-STATIC (note N1) | .cpp:1208-1247 |
| 6 | J5 restauration | PASS-STATIC pour le front, le premier passage, SetConsumeCaptureMouseDown, la signature ; réserves D3, D4 (état d'entrée rendu hors du sexe) |
.cpp:1059-1071, 1287-1357 |
| 7 | J6 texte d'aide, ActionPause |
PASS-STATIC | .cpp:1964-1985 |
| 8 | Transverse : /we4456 /we4458 /we4459, C4244, includes, .h/.cpp |
PASS-STATIC ; compilation BLOCKED-compilation (à BUILD) | § 3.5 |
| 9 | § 3 PC : recette qui défait G-g (2) seule | PASS-STATIC | § 3.6 |
| E-91 | CAM-91 glisser et rotation panneau fermé, ligne souris liberee |
chemin de code lu ; reporté V7 (risque D1, D2) | |
| E-92 | CAM-92 lit posé, commode refusée | non touché par J ; reporté V7 | |
| E-93 | CAM-93 Alt bref / Alt tenu ; Espace après le PC | code PASS-STATIC ; Espace reporté (PC, UE-GO) | |
| E-94 | CAM-94 ligne fin de scene … touches inchangees |
format PASS-STATIC ; comportement reporté V7 (D3, D4) | |
| E-95 | CAM-95 ligne deplace pendant la prise hors CAM |
format PASS-STATIC ; reporté V7 | |
| E-86..90 | CAM-86 à CAM-90 (B2p-I) | inchangés par J (hunks hors AttachHelpIcon, ToggleControlsHelp) ; reporté V7 |
3. Critères rejoués (commande → résultat)
3.0 Entrée, fins de ligne, base
Commande : pwsh -NoProfile -File …\scratchpad\check1.ps1 (octets lus par [IO.File]::ReadAllBytes, MD5 par Get-FileHash, comptes d'octets 10 et 13). FileCheck.ps1 non rejoué (les fichiers sont non suivis par git, pas de manifeste comparable) : remplacé par ce comptage.
| Fichier | Attendu (fiche) | Obtenu | Verdict |
|---|---|---|---|
.cpp final |
MD5 9D9291021BBB44BD8AD49448494FAB3A, 2197 lignes, LF |
MD5 9D9291021BBB44BD8AD49448494FAB3A, 96 476 octets, LF 2197, CR 0, BOM non |
PASS |
.h final |
MD5 9D85465E284F626D00212FFAA331C4BB, 203 lignes, LF |
MD5 9D85465E284F626D00212FFAA331C4BB, 11 109 octets, LF 203, CR 0, BOM non |
PASS |
.cpp base CAM-B2p-I3 |
0F383EF7…, 1976 lignes |
MD5 0F383EF777DED71608347E17D4A0861F, LF 1976, CR 0 |
PASS |
.h base CAM-B2p-I3 |
6EDBBCCF…, 179 lignes |
MD5 6EDBBCCF61759B8C6EE4890DF9BC5FE7, LF 179, CR 0 |
PASS |
git status --short -- Source : LPCameraModeSubsystem.cpp et .h sont ?? (non suivis) : pas de git diff <tag> possible, diff par git diff --no-index contre l'instantané (code 1 = différences).
3.1 Contre-vérification de la DIAG § 1 (journal, dump, moteur)
| Affirmation | Source relue | Résultat | Niveau |
|---|---|---|---|
Prises existantes couple pris (deplacement) 12:36:24, 12:37:39, 12:38:15 |
journal 4412, 5160, 5475 | confirmées (heures exactes) | établi |
| Chaque pose à la même place | paires pris/pose : 4412/4414, 4416/4456, 4457/4459, 5160/5162, 5208/5210, 5475/5480, 5481/5520, 5973/5975, 6022-6028, 6190/6192, 6256/6295, 7268/7309, 21239/21241, 21591/21593 | coordonnées identiques dans les 14 paires relevées (2 sessions : 12:35 et 12:49) | établi |
| Rotations de +0 : 12:36:32, 12:37:41, 12:38:20, 12:38:26 | 4464 (« -0 »), 5166, 5527, 5589 | confirmées ; 21 lignes couple tourne de ±0 au total |
établi |
Aucune ligne surface refusee ni place refusee |
Grep des deux motifs sur tout le journal | 0 ligne | établi |
Bascules LogViewport GameOnly puis relâché |
5473-5474 (12:38:14.280 DoNotLock → LockOnCapture, CaptureDuringMouseDown → CapturePermanently, juste après panneau bascule 5472) ; 5533-5534 (12:38:21.540) ; retour 5478-5479 (12:38:16.701, au premier relâché) |
confirmées. Nouveau : le retour à CaptureDuringMouseDown vient du jeu, au premier relâché, sans ligne de bascule du panneau (même motif 4410-4411, 5158-5159, 5768-5769) |
établi |
FInputModeGameOnly::ApplyInputMode : haute précision et verrou |
PlayerController.cpp:6439-6451 : UseHighPrecisionMouseMovement, SetUserFocus, LockMouseToWidget, LockOnCapture, CapturePermanently (ou …IncludingInitialMouseDown si bConsumeCaptureMouseDown faux) |
confirmé mot pour mot | établi |
| Voie d'ouverture du panneau | dump 1034-1041 : SetInputMode_GameAndUIEx, InMouseLockMode='DoNotLock', bHideCursorDuringCapture='false', focus sur CursorREF ; dump 1171 : CallFunction_1394 SetInputMode_GameOnly |
confirmé (le dump 1171 est bien K2Node_CallFunction_1394) |
établi |
| Molette = +9 à 12:37:57 | journal 5286 : deplace hors prise de (+0, +0, +9) ; fleches=+0/+0 Maj=0 molette=+1.0 |
confirmé, sans Maj | établi |
| Maj + molette vers Z 165 à 171 | 5676 (12:38:37, Z 171, Maj=1 MoveObject=1), 5717 (147), 5718 (165), 5894, 5974 (170) |
confirmé | établi |
| Borne racine ≤ plafond − 120 | 3786 sol -102 plafond 283 (marge 80), 4739 racine au plus 163 (283 − 120 = 163) ; sol −102 : 163 + 102 = 265 cm |
confirmé | établi |
prise=0 MoveCamera=1 « 12:41 à 12:43 » |
Grep MoveCamera=1 ; boutons : 3829 (12:35:26) et toutes les 5 à 10 s depuis |
exact mais incomplet : présent dès 12:35:26 (clic droit hors du couple, orbite normale) | établi (imprécision) |
Cause du § 1.1 : estimée, non établie. Établis : les symptômes, la voie GameOnly du PC, les faits moteur. Non établi : « le curseur ne bouge pas pendant l'appui » (aucune position écrite dans le journal) et le lien GameOnly vers position figée.
Contradiction partielle : le retour à CaptureDuringMouseDown / DoNotLock se produit au premier relâché (5478-5479, 12:38:16.701). Les prises 2 (pris 5481, 12:38:17.088, pose 5520, même place) et 3 (rotation, 5521 à 5527, +0) ont eu lieu dans cet état, avec HideCursorDuringCapture resté vrai (dernier changement avant : 5368, 12:38:03.277 False → True ; suivant : 5525, 12:38:20.437). Soit l'utilisateur n'a pas bougé la souris (rien ne l'infirme), soit une autre cause fige le curseur : SceneViewport.cpp:756-758, 780-783 cache le curseur et passe en haute précision à l'appui quand HideCursorDuringCapture() est vrai, ce qui figerait la position même sans GameOnly. L'état qui marchait (COMMUN-11) est DoNotLock et HideCursorDuringCapture faux (dump 1040-1041).
Autres causes : H4 et G-f ne sont pas atteintes (aucune ligne de refus ; elles écrivent). H3 (canal Pawn) : le glisser ne l'atteint qu'après bGrabMoved, et avant J3 un échec de TraceCursor était muet (l'ancien if (bGrabMoved && TraceCursor(Aim)) n'écrivait rien) : possible pour le glisser, estimé. Pour la rotation, aucune dépendance au tracé : 4 rotations à +0 avec bMouse vrai à la prise indiquent que MouseX n'a pas varié (curseur figé ou souris immobile), estimé fort. La sélection fonctionne (les prises existent).
+22 cm par prise (§ 1.3, estimé par l'IMPL) : les deux épisodes de 12:38 coïncident chacun avec un panneau bascule à l'intérieur de la prise (5524 à 12:38:20.437 puis G3 à 5528 ; 5540 à 12:38:22.765 puis G3 à 5544), tandis que la prise de rotation 5584-5589, sans bascule, ne bouge rien. 22 n'est pas un multiple de 9. Le témoin hors prise de 12:35:42 donne +25 avec molette=-1.0 (3986), sens contraire du -9 de 6132. La molette de Room n'est donc pas établie comme source ; la bascule du panneau (clic molette pendant la prise) est un autre candidat. Le témoin J3 écrit molette= : il tranchera (D6).
3.2 Moteur 5.8 : API de J1 et de J5
| API | Source | Constat |
|---|---|---|
UGameViewportClient::GetMouseCaptureMode() const |
GameViewportClient.h:786 |
existe, public |
HideCursorDuringCapture() const |
GameViewportClient.h:831 |
existe (utile pour D2) |
FInputModeGameAndUI::SetLockMouseToViewportBehavior, SetHideCursorDuringCapture |
PlayerController.h:191, 194 |
existent |
FInputModeGameOnly::SetConsumeCaptureMouseDown |
PlayerController.h:219 |
existe |
FInputModeGameAndUI::ApplyInputMode |
PlayerController.cpp:6398-6414 |
SetFocusAndLocking(…WidgetToFocus…) : pas de focus déplacé sans widget (6315-6318), ReleaseMouseLock si DoNotLock, ReleaseMouseCapture, SetHideCursorDuringCapture, CaptureDuringMouseDown : le clavier reste à la vue, établi |
FInputModeGameOnly::ApplyInputMode |
PlayerController.cpp:6439-6451 |
consume ? CapturePermanently : CapturePermanently_IncludingInitialMouseDown : le mappage de J5 (Avant == CapturePermanently) est exact ; ne touche pas HideCursorDuringCapture (D4) |
APlayerController::SetInputMode |
PlayerController.cpp:6454-6468 |
un appel, sans événement Blueprint : pas de boucle avec le PC |
UPlayerInput::GetKeyValue |
PlayerInput.cpp:2199-2204 rend KeyState->Value.X ; Value.X = MassageAxisInput(…) (1264) |
valeur traitée, voir D1 |
UPlayerInput::GetRawKeyValue |
PlayerInput.h:760, PlayerInput.cpp:2206-2211 |
existe, rend RawValue.X (non traitée) |
DeprojectScreenPositionToWorld(float, float, …) |
PlayerController.cpp:2197-2200 |
même chemin que DeprojectMousePositionToWorld (2182-2195, UGameplayStatics::DeprojectScreenToWorld avec la position souris) : équivalent à écran identique |
| Signe de Y | SceneViewport.cpp:928-931 : MouseDelta.X += …, MouseDelta.Y -= CursorDelta.Y |
MouseY positif = vers le haut ; -GetKeyValue(MouseY) donne un Y d'écran vers le bas : signe correct |
3.3 J1 KeepMouseFree (.cpp:1249-1285, appel 1129)
- Conditions : appelée dans
TickSexCameraaprès le retour!bSexOn || bMenuOnScreen(1112-1122) : sexe vrai, hors menu (menu relevé toutes les 0,1 s,Tick→bMenuOnScreen). Aucun bouton tenu (1259-1260). SeulementCapturePermanentlyouCapturePermanently_IncludingInitialMouseDown(1265).TickSexCameraest appelé à chaque image parTickSwitchKey(ticker à 0 s,641,814) : exact (pas à 0,1 s). - Sexe : la fiche dit « conditions (sexe …) » : le sexe est le front de
GI.SexOn, pas un test du sexe des personnes ; la condition est donc « pendant la scène », sans limite aux modes Scene (aussi en POV). - Pas de boucle avec le PC : après l'appel, le mode est
CaptureDuringMouseDown(6412), la condition1265n'est plus vraie ; le PC ne réagit pas àSetInputMode. Si le PC remet GameOnly (fermeture du panneau, dump 1171), J1 le refait à l'image suivante : au plus une application par fermeture. Journal limité : une ligne toutes les 2 s (MouseFreeCooldown,1255, 1279-1284),%d/%dpour 2int32: conforme. - Clavier : voir 3.2, pas de
WidgetToFocus: le focus posé par GameOnly (6446) reste. Établi. - Réserves : D2 (J1 ne voit pas
CaptureDuringMouseDown+HideCursorDuringCapturevrai), D4 (drapeau non rendu).
3.4 J2 et J3 (TickCoupleMouse, .cpp:1367-1702)
GrabCursor: initialisé au clic àGrabMouseStart(1505-1509) ; à chaque image : position réelle si elle a bougé de 0,5 px au moins (1594-1597), sinon accumulation deRawDelta(1598-1602) ;GrabLastRealmis à jour seulement avecbMouse(1603-1606). Pas de double comptage (branches exclusives). Mélange réel/brut sans saut tant que l'échelle brute vaut 1 pixel : faux ici (D1).- D1 (bloquant) :
RawDeltalitInput->GetKeyValue(EKeys::MouseX/MouseY)(1593). Cette valeur estMassageAxisInput(PlayerInput.cpp:2305-2387) :NewVal *= AxisProps->Sensitivity(2337), puis FOV (2352) et lissage (2366, activé :DefaultInput.ini:78 bEnableMouseSmoothing=True). Le projet fixeSensitivity=0.070000pourMouseXetMouseY(DefaultInput.ini:16-17, déjà en8-9). Un déplacement de 100 px de souris donne donc ≈ 7 « px » dansGrabCursor(facteur 14 environ). Conséquences : seuil de glisserCoupleDragThreshold = 5(:136) franchi après ≈ 71 px de souris ; point viséTraceScreen(GrabCursor)14 fois plus lent que la main ; rotationCoupleTurnPerPixel = 0.3(:137) réduite à ≈ 0,02° par pixel. Le filet de J2, présenté comme « filet si J1 ne passe pas » (IMPL § 2 J2), ne tient donc pas ses promesses dans les états où le curseur reste figé (dont les états non couverts par J1, D2). Correction :GetRawKeyValue(valeur en pixels de la fenêtre,SceneViewport.cpp:928-931, cumulée dansRawValueAccumulator, copiée enRawValueà chaqueEvaluateKeyMapState,PlayerInput.cpp:1354-1361), ou division par la sensibilité. Le libellé « deltas bruts » des lignes J3 est inexact en l'état. - Signe de Y correct (3.2).
TraceScreen: même tracé queTraceCursor(Visibility, mêmes ignorés,CursorTraceLength) avec la position passée (1399-1411) ; appelé à la prise avecGrabMouseStart(1522) et au glisser avecGrabCursor(1612) : cohérents. Seuil :Distance(GrabMouseStart, GrabCursor) >= 5(1610). Rotation :Turn = (GrabCursor.X - GrabLastMouseX) * 0.3,GrabLastMouseXmis àfloat(GrabCursor.X)(1680-1681), initialMouseX(1510) : continu.bMouse &&: retiré des deux branches (1608,1678) ; la sélection exige toujoursbMouse(1456-1464, lignecurseur sans positionconservée). AucunbMouse &&ne bloque plus le glisser ni la rotation. - Non-régression B2p-D à H (diff lu, 22 retraits tous recoupés, voir 4) : pose (
1620-1675inchangé horsGrabPivotAfterCam), G-e (TraceDown,GrabHeight: intacts), G-f (1648-1658intact), G1 (1659-1670), N2 (LastSurfaceRefused.Reset()1669, conservé), caméra figée (1695-1700intact), G3 (1553-1567intact,GrabLeadStart). PASS-STATIC. - J3 formats
%contre arguments (relus un à un) :12822/2 ;1495-14964%(%.0f %.0f %s %.0f) pourMouseX, MouseY, chaîne, rayon;1540-15414/4 (%.0f %.0f %d %s) ;1549-15503/3 (%.0f %d %s) ;1583-15855/5 (%+.0f ×3 %+.1f %d) ;16162/2 ;12372/2 ;12931/1 ;1353-13567/7 (%d %d %d %s %s %s %s). Les%sconditionnels de tableaux de longueurs différentes décroissent enconst TCHAR*(motif déjà présent1048-1049,1237). - Cadences :
clic hors du couple2 s au plus (SelectMissLogTime,1492) ;deplace pendant la prise hors CAM1 s au plus (1579) ;ne vise aucune surfaceune fois par prise (bGrabAimWarnedremis à faux à la prise1508) ;glisser sans effetetrotation sans effetune fois par prise (au relâché). - Témoin « hors CAM » ne compte pas les pas de CAM :
GrabPivotAfterCam = Pivotà la prise (1509),= Pivot + Deltaaprès chaque déplacement du glisser (1667, avec le mêmeDeltaqueSetActorLocation) ; la rotation tourne autour du pivot (moyenne des positions : conservée, tolérance 1 cm1576). Le témoin met à jourGrabPivotAfterCammême quand la ligne est retenue par la cadence (1587). PASS-STATIC.
3.5 J4, J5, J6, transverse
- J4 (
1208-1247) :bAltKey = IsPressed(LeftAlt) ou IsPressed(RightAlt)(1213),bMiddle = bouton ou Alt;bPanelByAlt = bAltKey && !bMiddleButtonà l'appui (1220) ; seuils inchangésPanelClickMaxHold 0.2 setPanelClickMaxMove 5 px(:186-187,1232) ; fonction appelée seulement pendant le sexe hors menu (1112-1128) ;bMiddleWasDownremis à faux hors sexe ou menu (1076, 1116). Appui tenu ou glissée : pas de bascule (MiddleHeld > 0.2oubMiddleMoved).RotateCamera= clic molette,LeftAlt,RightAlt(DefaultInput.ini:107-109) : ouvert aux deux. Lignepanneau bascule (%s, %.2f s)2/2. Note N1. - J5 front :
bSexStateWasinitial faux (.h:180) ; au premier passage avecSexOnfaux : égalité, aucun appel (premier passage correct, pas de fin de scène fantôme) ; avecSexOnvrai dès le départ :BeginSexScene(1060-1071).BeginSexScene: signature des mappages, remise à zéro debMouseFreed,MouseFreeCount,MouseFreeCooldown.MappingSignature(318-337) :GetActionMappingsetGetAxisMappings,FCrc::StrCrc32(*Joined)(uint32) avec%08X, bitfieldsbShift/bCtrl/bAltconvertis enint; sans modification des mappages (lecture seule).EndSexScene(1296-1357) rend : prise levée (ReleaseCoupleGrab),bMiddleWasDown,bHelpBoxOpen, boîte d'aide et icône repliées, opacité deTextBlock_1(SetRenderOpacity(FadedLinesOpacity)puisReset, D3 de B2p-I traité),MoveCameraà faux si aucun bouton souris n'est tenu,SexC3à faux (déjà fait hors sexe parTickCoupleBounds,837-839: aucun état nouveau), mode d'entrée GameOnly sibMouseFreedet vue encore enCaptureDuringMouseDownet!MenuOnScreen(GI)(1335-1350), avecSetConsumeCaptureMouseDown(MouseCaptureBefore == CapturePermanently): mappage exact (3.2). Ligne finale 7/7. Réserves : D3 et D4 ; note N2 (MoveCameraavec Alt tenu). - J6 (
1964-1985) :Printfà 7%s(CAMERA : 1 + 2 + 2 ; COUPLE : 2) pour 7 arguments (1981-1984). « Mouse wheel: raise / lower the couple » : étayé par le journal (5286,Maj=0, +9). « Alt or middle click (short press) » : conforme à J4.ActionPause: GrepActionPause|"Pause"surLPCameraMode*= 0 ligne : retiré sans reste (déclaration201et argument1984). - Fins de ligne et includes : LF, 0 CR ; aucun nouvel
#includenécessaire (FInputModeGameAndUI,FInputModeGameOnlyparGameFramework/PlayerController.h:26,FCrc,FPlatformTimeparCoreMinimal.h,UTextBlock/UButtondéjà inclus7, 12) ; le diff n'ajoute aucun include..h: 24 lignes, un seul bloc contigu (l. 172-195), tout enprivate, aucunUPROPERTYniUFUNCTION(pas d'effet UHT). /we4456 /we4458 /we4459: (a) membres de la classe (.h:37-203) contre les nouveaux locaux et paramètres : aucun homonyme (Capture,Input,GI,ViewportClient,FreeMouse,Lines,HelpIcon,World,PC,Now,Nearest,Outside,Screen,RealCursor,RawDelta,CursorTravel,ScreenGap,bAim,Joined,Settings,Map,InputText,LinesText,MappingsNow,bStillFreed,bButtonHeld,GameOnly) ; (b) locaux englobants :Nowest déclaré dans deux blocs frères (1491dansif (!bOnCouple),1578dansif (Dist…)),Aimdans deux blocs frères (1521,1611, ancien), aucun nouveau local ne masqueInput,World,MouseX/Y,bMousedu niveau de la fonction ; (c) noms globaux ou d'espace anonyme deSource\LifePlay: Grep sur 21 identifiants en ligne d'indentation 0 ou 1 de tous les.cppet.h: aucun nom de portée fichier ni d'espace anonyme n'est homonyme. LesNow(LPBonusRewardSubsystem.cpp:811,LPDebugSubsystem.cpp:717,LPHairstyleSubsystem.cpp:169,LPModInfoSubsystem.cpp:215) sont des locaux de fonction, etCapture(LPSecondScreenSubsystem.h:34) un membre d'une autre classe : sans effet de masquage. L'auteur avait donc raison. Non vérifié : les noms globaux des en-têtes du moteur (impossible par lecture exhaustive) : à BUILD.- Conversions (C4244) :
static_cast<float>partout où undoubleva vers unfloat(1404,1680-1681) ;GrabLastMouseX = MouseX(float vers float) ;Nearestendouble;FVector2D(float, float)élargit sans perte ;%.0freçoit desdoubleou desfloatpromus. Aucune conversion rétrécissante détectée.
3.6 § 3 de l'IMPL : recette PC (dump …135527.txt)
| Nœud | Dump | Constat |
|---|---|---|
IfThenElse_40 |
1546-1550 | then → IfThenElse_134.execute, else → IfThenElse_41 ; execute ← 63.else, Condition ← CallFunction_125 |
IfThenElse_134 |
6513-6517 | execute ← 40.then, Condition ← VariableGet_22.SexOn, then → CallFunction_408, else → CallFunction_277 |
CallFunction_408 |
6509-6511 | LeftMouseSexOn(), execute ← 134.then, then vide |
CallFunction_277 |
4423-4426 | PlayClick(), execute ← 134.else, then → VariableSet_0 |
VariableGet_22 |
986-988 | SexOn → IfThenElse_15.Condition, IfThenElse_134.Condition |
IfThenElse_15 |
989-993 | Condition ← VariableGet_22, then vide, else → CallFunction_160 (inchangé) |
| Avant G-g (2) | CAM-B2p-G-PC-IMPL.md:35-36, 128-131 |
40.then → 277, 277.then → VariableSet_0 |
| En-tête | dump 6518 | PC :: EventGraph (1447 noeuds) |
La recette (instantané ; connect_pins 40.then → 277.execute : une sortie d'exécution n'a qu'un lien, il remplace 40 → 134, comme à l'aller G-g (appels 38-40) ; suppression de 134, qui emporte 22 → 134, 134.then → 408, 134.else → 277 ; suppression de 408, orphelin) restitue exactement 40.then → 277, garde 22 → 15 et ne touche pas les coupures G-g (1) (nœuds 387 et voisins). Nœuds supprimés : 134 et 408, soit 1447 → 1445 : cohérent. Relecture de 40, 277, 22, 15 : bien les quatre nœuds dont un voisin change. PASS-STATIC ; exécution = UE-GO.
4. Diff lu en entier
| Fichier | Base (CAM-B2p-I3) |
Final | git diff --no-index --numstat |
Recompte indépendant |
|---|---|---|---|---|
LPCameraModeSubsystem.cpp |
1976 lignes | 2197 | 243 22 |
hunks.ps1 : 29 hunks, +243 -22 ; lignes +/- de -U0 : plus=243 minus=22 |
LPCameraModeSubsystem.h |
179 | 203 | 24 0 |
1 hunk (@@ -169,6 +169,30 @@), +24, 0 retrait |
Répartition par point (nouveau .cpp ; les hunks mixtes J2/J3 sont partagés à l'estime, la somme J2 + J3 est exacte : 85 ajoutées, 13 retirées) :
| Point | Lignes .cpp |
+ | − |
|---|---|---|---|
| J1 | 1129 ; 1249-1286 |
39 | 0 |
| J2 | 1398-1399, 1404, 1505-1506, 1522, 1590-1610, 1612, 1678-1681 (part) |
≈ 33 | ≈ 9 |
| J3 | 1468, 1477-1485, 1490-1497, 1507-1509, 1533-1551, 1574-1588, 1613-1617, 1667 (part) |
≈ 52 | ≈ 4 |
| J4 | 1210-1214, 1220, 1237 |
7 | 2 |
| J5 | 318-338 (21) ; 1059-1071 (13) ; 1287-1358 (72) |
106 | 0 |
| J6 | 200 (retrait de ActionPause) ; 1966-1968, 1978, 1980, 1984 |
6 | 7 |
| Total | 243 | 22 |
Les 22 retraits recoupés un à un : ActionPause (1), bMiddle (1), UE_LOG du panneau (1), déclaration du lambda (1), DeprojectMousePositionToWorld (1), condition de projection (2), bOnCouple = true; break; déplacés (2), GrabOffset (1), if (bMouse && CoupleGrabMode == 1) (1), bGrabMoved |= (1), if (bGrabMoved && TraceCursor(Aim)) (1), else if (bMouse && CoupleGrabMode == 2) (1), Turn et GrabLastMouseX (2), commentaire d'aide (2), format et arguments d'aide (4) : total 22. Aucune ligne de B2p-C à I n'est retirée hors de ces 22. Ajouts non annoncés : aucun (tous rattachés à J1 à J6 ; la part « clic hors du couple » et Nearest relève de J3).
Aucun fichier de code hors LPCameraModeSubsystem.* n'est dans le périmètre de J ; les autres M/?? de git status (LPDebug, LPDirectControl, …) ne sont pas ce lot et n'ont pas été lus.
5. Verdict
| Point | Verdict |
|---|---|
| DIAG § 1, faits | PASS |
| DIAG § 1.1, cause | estimée (partiellement contredite, D2) ; autre cause possible : HideCursorDuringCapture vrai ; H3 muet avant J3 |
| J1 | PASS-STATIC, réserves D2, D4 |
| J2 | FAIL (D1 bloquant) |
| J3 | PASS-STATIC |
| J4 | PASS-STATIC |
| J5 | PASS-STATIC, réserves D3, D4 |
| J6 | PASS-STATIC |
| Transverse (warnings, includes, cohérence) | PASS-STATIC ; compilation BLOCKED-compilation (BUILD) |
| § 3 PC | PASS-STATIC (exécution : UE-GO) |
| Global (première passe) | FAIL : 1 défaut bloquant (D1). Non couvert : la compilation (à BUILD), tout comportement en jeu (V7). Les 5 autres défauts (D2 à D6) ne bloquent pas, mais D2 à D4 sont à corriger avec D1 pour que J1 et J5 tiennent leurs critères. Mis à jour par la section « Reprise » : PASS-STATIC. |
6. Points à confirmer par l'utilisateur (cases)
- D1 : reprise de l'IMPL (raw en pixels) avant BUILD. (faite, voir Reprise)
- D2 : élargir le déclencheur de J1 à
HideCursorDuringCapture()vrai, ou accepter que J2 seul couvre ces états. (fait, voir Reprise) - D3 et D4 : état d'entrée à rendre en fin de scène : mode, verrouillage et drapeau de curseur d'avant la scène (relevés à
BeginSexScene), ou ne rien rendre. (fait, voir Reprise) - D6 : suivre à V7 le témoin
molette=de CAM-95 et la lignepanneau basculepour attribuer le +22 cm. - UE-GO pour le PC (§ 3 de l'IMPL), puis V5 et V6 par un validateur distinct.
- V7 (COMMUN-13) : CAM-91 à CAM-95 et CAM-86 à CAM-90 après BUILD.
Tours : 35 / 40
Constats
Défauts bloquants
- D1. J2 lit des valeurs traitées, pas des pixels.
LPCameraModeSubsystem.cpp:1593:Input->GetKeyValue(EKeys::MouseX/MouseY).PlayerInput.cpp:2199-2204+1264+2337: sensibilité appliquée ;DefaultInput.ini:16-17:Sensitivity=0.070000. Effet : deltas ≈ 14 fois trop petits (seuil de glisser ≈ 71 px de souris, rotation ≈ 0,02°/px), donc le filet de J2 est quasi inopérant là où le curseur reste figé. Correction minimale :GetRawKeyValue(PlayerInput.h:760) pour les deux axes ; corriger le libellé des lignes J3 (« deltas bruts » ne l'est qu'après ce changement). Rien d'autre à changer dans J2.
Défauts non bloquants
- D2. J1 ne couvre pas l'état observé après le premier relâché. Journal 5478-5479 (12:38:16.701) :
CaptureDuringMouseDown/DoNotLock,HideCursorDuringCaptureresté vrai (5368 puis 5525). Les prises 2 et 3 (5481 à 5527) n'ont rien fait dans cet état, que.cpp:1265ignore.SceneViewport.cpp:756-758, 780-783: curseur caché et haute précision à l'appui quand ce drapeau est vrai. Proposition : déclencher aussi siViewportClient->HideCursorDuringCapture()(GameViewportClient.h:831) est vrai. - D3.
EndSexScenerend GameOnly alors que l'état d'avant la scène estCaptureDuringMouseDown/DoNotLock. Dernier changement avant la scène du 12:35:21 : journal 2549-2550 (12:34:54.870) puisHidevrai (3125)..cpp:1342-1343imposeCapturePermanently(premier clic consommé, curseur verrouillé) si J1 a agi une fois, même si le jeu a lui-même replacéCaptureDuringMouseDown(cas observé à chaque premier relâché). Le critère de la fiche « hors du sexe, rien d'autre ne change » n'est tenu que si l'état rendu est celui d'avant la scène. - D4.
HideCursorDuringCapturereste à faux après la scène..cpp:1277le met à faux ;FInputModeGameOnly::ApplyInputMode(PlayerController.cpp:6439-6451) ne le rétablit pas. Journal : vrai avant et pendant la plupart des scènes. À relever et rendre avec D3. - D5. IMPL hors gabarit (§ 1) et imprécision « 12:41 à 12:43 » (en réalité dès 12:35:26) ; § 5 bis vide.
- D6. Cause du +22 cm non établie. § 3.1 : coïncidence avec une bascule du panneau dans la prise ; +25 avec
molette=-1.0à 12:35:42. L'IMPL le dit « estimé » : correct ; la mention « seule voie connue » est trop affirmative.
Notes (sans défaut)
- N1.
bAltKey: Alt + Entrée (plein écran) ou Alt + Tab vifs (moins de 0,2 s, moins de 5 px) pourraient basculer le panneau pendant le sexe. À observer à V7. - N2.
EndSexScenemetMoveCameraà faux si aucun bouton souris n'est tenu : un Alt tenu (actionRotateCamera) à cet instant la remettra à vrai par le PC au besoin ; effet négligeable. - N3. La ligne
clic hors du couples'écrit à chaque clic d'orbite hors couple (une fois par 2 s) : bruit attendu. - N4. Les trois répartitions J2/J3 des hunks mixtes sont estimées (§ 4).
Non mesuré
Compilation (Build.ps1 -FromLog sans objet : aucun build de ce lot), LPTestStringCompat, comportement en jeu (CAM-86 à CAM-95), noms globaux des en-têtes du moteur contre /we4459, rôle exact du jeu qui replace CaptureDuringMouseDown au premier relâché (aucun SetInputMode correspondant dans le dump du PC : seuls 1034, 1171 et 2734 existent), position réelle du curseur pendant les prises du journal (jamais écrite).
Fichiers à commiter
A Docs/Migration/etat/CAM/CAM-B2p-J-VAL.md (ce livrable). Aucun autre fichier écrit dans le projet.
À verser
lp-validate § 1 ou skill CAM : UPlayerInput::GetKeyValue(MouseX/MouseY) rend une valeur traitée (sensibilité 0,07 du projet, FOV, lissage), GetRawKeyValue rend les pixels ; ne jamais s'en servir pour un déplacement en pixels. Et : le jeu repasse en CaptureDuringMouseDown au premier relâché après un GameOnly du PC (journal COMMUN-12), donc « rendre GameOnly » n'est pas un retour à l'état d'avant.
Reprise (2026-10-14) : validation statique de la reprise, instantané CAM-B2p-I4 vers final
R1. Fiches amont relues
CAM-B2p-J-IMPL.md § 5 bis (l. 124-140), relu ; la première passe de cette VAL ; instantané D:\Game\LifePlay_Backup_5.5\CAM-B2p-I4\Source\LifePlay\. Mêmes règles : aucune compilation, aucune écriture hors de ce livrable.
R2. Entrée et diff
Commande : pwsh -NoProfile -File …\scratchpad\check2.ps1 (octets, MD5, git diff --no-index --numstat et -U3, Select-String MouseCaptureBefore).
| Fichier | Attendu | Obtenu | Verdict |
|---|---|---|---|
.cpp base I4 |
9D929102…, 2197 lignes |
MD5 9D9291021BBB44BD8AD49448494FAB3A, LF 2197, CR 0 |
PASS (= entrée de la première passe) |
.h base I4 |
9D85465E…, 203 lignes |
MD5 9D85465E284F626D00212FFAA331C4BB, LF 203, CR 0 |
PASS |
.cpp final |
1F10631F904E0EAB74BAA896571F0A57, 2220 lignes, LF |
MD5 1F10631F904E0EAB74BAA896571F0A57, 98 554 octets, LF 2220, CR 0, BOM non |
PASS |
.h final |
9AEE8D04CF35C0C6EEDF226E3B0A86C3, 206 lignes, LF |
MD5 9AEE8D04CF35C0C6EEDF226E3B0A86C3, 11 242 octets, LF 206, CR 0, BOM non |
PASS |
Reste de MouseCaptureBefore |
0 | Select-String sur les deux fichiers : 0 ligne (grep d'homonymes : seules les 4 nouvelles variables .h:184-187 et leurs usages) |
PASS |
numstat : .cpp 44 21 (6 hunks), .h 5 2 (1 hunk). Recompte à la main des signes du -U3 : .cpp +44 −21 (hunks : KeepMouseFree +6 −6 ; journal de J1 +2 −2 ; BeginSexScene +12 −1 ; bButtonHeld +2 −1 ; EndSexScene +20 −10 ; RawDelta +2 −1), .h +5 −2. Concordant. Répartition : D1 +2 −1 ; D2 +8 −8 ; D3/D4 +32 −11 ; Alt dans bButtonHeld +2 −1 ; total +44 −21. Aucun hunk hors de ces cinq objets : aucun ajout non annoncé, aucune ligne de J1 à J6 hors de ces zones n'est touchée.
R3. Hunk par hunk
- D1 (
.cpp:1612-1613, hunk 6) :Input->GetRawKeyValue(EKeys::MouseX)et-Input->GetRawKeyValue(EKeys::MouseY).GetRawKeyValue:PlayerInput.h:760,PlayerInput.cpp:2206-2211(KeyState->RawValue.X).RawValueest copié de l'accumulateur à chaqueEvaluateKeyMapState(PlayerInput.cpp:1354-1361), etMouseX/MouseYportentUpdateAxisWithoutSamples(InputCoreTypes.cpp:535-536) : la valeur retombe à 0 sans mouvement, en pixels (SceneViewport.cpp:928-931). Signe de Y inchangé et correct. Aucune sensibilité, aucun FOV, aucun lissage. D1 levé. - D2 (hunks 1 et 2) :
bPermanent(capture permanente) oubHiddenOnPress = ViewportClient->HideCursorDuringCapture()(GameViewportClient.h:831,const, public) déclenche la libération ; l'ancien premier retour est conservé pour ce qui précède (viewport,PlayerInput, bouton tenu).bMouseFreed = trueinconditionnel ;MouseFreeCounttoujours incrémenté. Pas de boucle : aprèsFInputModeGameAndUIavecSetHideCursorDuringCapture(false)(PlayerController.cpp:6411) etCaptureDuringMouseDown(6412),bPermanentetbHiddenOnPresssont faux à l'image suivante ; il ne se redéclenche que lorsque le jeu repose lui-même GameOnly ouHidevrai (journal : à chaque fermeture du panneau, 5530, 5545). Format du journal :%d%d%dpourCapture,bHiddenOnPress ? 1 : 0,MouseFreeCount: 3/3. D2 levé (réserve N5). - D3/D4,
BeginSexScene(hunk 3) :const UGameInstance* GI,const UGameViewportClient* ViewportClient;GetMouseCaptureMode() const(GameViewportClient.h:786),GetMouseLockMode() const(821, définitionGameViewportClient.cpp:3495-3498),HideCursorDuringCapture() const: tous appelables sur un pointeurconst. Stockage enuint8(EMouseCaptureMode : uint8,EMouseLockMode : uint8,EngineBaseTypes.h:40, 56) etbool. Pas de viewport :bSavedMouseState = false, rien n'est rendu. Journal : 4%(%s %d %d %d) pour*MappingsAtSexStart, 2static_cast<int32>,bSavedHideCursor ? 1 : 0: 4/4. Relevé fait au front, c'est-à-dire l'état d'avant la scène observé à la première image (journal COMMUN-12 :CaptureDuringMouseDown,DoNotLock,Hidevrai avant la scène du 12:35:21, 2549-2550 puis 3125). - D3/D4,
EndSexScene(hunks 5 et 4) : rendu seulement sibMouseFreed && bSavedMouseState,PC, hors menu, et vue encore dans l'état posé par CAM :CaptureDuringMouseDownetDoNotLocket!HideCursorDuringCapture()(plus strict qu'avant : unHidevrai remis par le jeu empêche toute écriture). Ordre :SetInputMode(GameOnly)d'abord et seulement si la capture sauvée était permanente (Consumevrai seulement pourCapturePermanently, exact selonPlayerController.cpp:6450), puisSetMouseCaptureMode,SetMouseLockMode,SetHideCursorDuringCapture: ces trois méthodes ne font qu'écrire un champ avec journalLogViewport(GameViewportClient.cpp:3458-3511), sans opération Slate ; elles viennent donc aprèsApplyInputModeet ne sont pas écrasées par lui.GameOnlyne touchant pasHide(6439-6451), le troisième réglage rend bien le drapeau (D4). Si l'état de départ n'est pas permanent (cas du journal), aucunSetInputMode: seulement les trois champs, qui valent déjàCaptureDuringMouseDown,DoNotLocket leHided'origine.static_cast<EMouseCaptureMode>(uint8)etstatic_cast<EMouseLockMode>(uint8)sont licites (enums de baseuint8). Journal :FString::Printf%d %d %d/ 3 arguments ; la ligne finale (7/7) n'est pas modifiée par le diff,InputTextreste uneFStringaffichée par*InputText.bButtonHeldcompteLeftAltetRightAlt(note N2 levée). D3 et D4 levés. MouseCaptureBefore: retiré du.het du.cpp(R2, 0 reste).
R4. Homonymes C4456 / C4458 / C4459 des nouveaux noms
Nouveaux : bPermanent, bHiddenOnPress (locaux de KeepMouseFree), GI et ViewportClient (locaux de BeginSexScene, fonction sans autre local de ces noms), CaptureBefore (local d'un bloc de EndSexScene), membres bSavedMouseState, SavedCaptureMode, SavedLockMode, bSavedHideCursor.
- Membres de la classe (
.h:37-206) : aucun homonyme des locaux ; les 4 nouveaux membres n'ont pas de local du même nom. - Locaux englobants :
GIetViewportClientdeBeginSexScenesont seuls dans la fonction ; dansEndSexScene,CaptureBeforen'est déclaré qu'une fois etViewportClient(bloc interne, ancien) n'a pas d'homonyme englobant. - Globaux et espaces anonymes de
Source\LifePlay: Grep des sept noms dans tous les.cppet.h: seules occurrences dansLPCameraModeSubsystem.*(.h:184-187,.cpp:1267-1366). Aucun homonyme global. - Non vérifié : noms globaux des en-têtes du moteur (à BUILD).
Conversions : aucune nouvelle conversion rétrécissante (
uint8depuis un enum de baseuint8,GetRawKeyValueenfloat).
R5. Défauts D1 à D6 : décision
| Défaut | État | Raison |
|---|---|---|
| D1 (bloquant) | levé | R3-1 |
| D2 | levé | R3-2, réserve N5 |
| D3 | levé | R3-3, R3-4 : l'état rendu est celui d'avant la scène, pas un GameOnly imposé |
| D4 | levé | R3-4 : Hide rendu ; cas résiduel N6 |
| D5 | maintenu, non bloquant | § 5 bis ne corrige que le fond de la DIAG ; il n'ajoute ni tête (Fiche … — Niveau …), ni « Écarts à la SPEC », ni « Points à confirmer en VAL », ni ligne Tours (relu l. 124-143), et ne restitue pas l'intervalle exact (MoveCamera=1 dès 12:35:26) alors qu'il le nomme. À régler à la rédaction de clôture (DOC) |
| D6 | levé | § 5 bis déclare la cause du § 1.1 « estimée forte, non établie, aucune position au journal » et le +22 cm « non établi », coïncidant avec une bascule du panneau, tranché par le témoin hors CAM : c'est l'évaluation de cette VAL (« estimée » et « non étayée »). Le corps de la DIAG (§ 1.1 « Cause, établie » ; § 1.3 « seule voie connue ») n'a pas été réécrit : la correction est une note de lecture, jugée suffisante tant que le § 5 bis est cité avec la DIAG |
R6. Notes nouvelles (sans défaut)
- N5. J1 s'applique maintenant dès que
Hideest vrai hors bouton tenu : état par défaut du jeu (journal), donc au début de presque toute scène et à chaque retour deHideà vrai. Le relevébMenuOnScreena jusqu'à 0,1 s de retard : à l'ouverture d'un menu, J1 peut poser une foisGameAndUI(sans focus) avant quebMenuOnScreenne passe à vrai. Effet attendu faible ;EndSexScenene rend rien si un menu est ouvert. À regarder à V7 (menu ouvert pendant la scène). - N6. Rendu en fin de scène :
SetMouseLockModeetSetMouseCaptureModen'écrivent que le champ du viewport (pas d'opération Slate). Pour un état d'avant-scène non permanent mais verrouillé (LockAlways,LockOnCapturesans GameOnly), le verrou Slate levé parReleaseMouseLockne serait pas reposé. Cas absent du journal (état de départDoNotLock) ; à surveiller si le menu principal laisseLockAlways(journal 914) à l'entrée d'une scène. Si le jeu replace lui-même GameOnly après la détection de fin de scène,Hidepeut rester à faux (le rendu est alors sauté :bStillFreedfaux) ; cas sans témoin. - N1 (Alt + Entrée / Alt + Tab) inchangée. N2 levée (Alt compté).
R7. Verdict global mis à jour
| Point | Verdict |
|---|---|
| DIAG § 1, faits | PASS (inchangé) ; cause § 1.1 : estimée forte (accord avec § 5 bis) |
| J1 | PASS-STATIC (D2, D4 levés) |
| J2 | PASS-STATIC (D1 levé) |
| J3, J4, J6 | PASS-STATIC (inchangés ; libellé « deltas bruts » désormais exact) |
| J5 | PASS-STATIC (D3, D4 levés ; N2 levée) |
| Transverse | PASS-STATIC ; compilation BLOCKED-compilation (à BUILD) |
| § 3 PC | PASS-STATIC (inchangé) |
| Global | PASS-STATIC : aucun défaut bloquant ouvert. Ouvert non bloquant : D5 (gabarit), notes N1, N5, N6. Non couvert : compilation (BUILD), tout comportement en jeu (V7) ; UE-GO du PC. |
R8. Points à confirmer par l'utilisateur (cases)
- BUILD de
LPCameraModeSubsystem.cpp/.h(MD51F10631F…/9AEE8D04…), puis V7 (COMMUN-13) : CAM-91 à CAM-95, CAM-86 à CAM-90 ; lire en plus la lignedebut de scene … souris capture … verrou … curseur cacheetfin de scene … mode d'entree rendue (…). - V7 : menu ouvert pendant une scène (N5) ; fin de scène avec le panneau fermé juste avant.
- D5 : tête, « Écarts à la SPEC », « Points à confirmer » et
Toursde l'IMPL à la clôture. - UE-GO du PC (§ 3 de l'IMPL).
Tours (reprise) : 6 / 40 ; cumul avec la première passe : 41 (la reprise est une fiche distincte, budget de 40 respecté pour chacune).
Fichiers à commiter (reprise)
A Docs/Migration/etat/CAM/CAM-B2p-J-VAL.md (ce livrable, réécrit en entier avec la section Reprise). Aucun autre fichier écrit dans le projet.