269 lines
42 KiB
Markdown
269 lines
42 KiB
Markdown
|
|
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 bis` vide « à compléter » à la première passe), lu en entier.
|
|||
|
|
- `CAM-B2p-I-IMPL.md` (base : I0, I1, reprise D1 de la VAL) et `CAM-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.md` et `CAM-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). Dump `CAM-B2p-G-PC-VAL_LPDumpFunction_20261014-135527.txt`. Moteur `D:\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 ligne `Tours : …`, § 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 `TickSexCamera` aprè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`). Seulement `CapturePermanently` ou `CapturePermanently_IncludingInitialMouseDown` (`1265`). `TickSexCamera` est appelé à chaque image par `TickSwitchKey` (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 condition `1265` n'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`/`%d` pour 2 `int32` : conforme.
|
|||
|
|
- **Clavier** : voir 3.2, pas de `WidgetToFocus` : le focus posé par GameOnly (`6446`) reste. Établi.
|
|||
|
|
- **Réserves** : D2 (J1 ne voit pas `CaptureDuringMouseDown` + `HideCursorDuringCapture` vrai), 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 de `RawDelta` (`1598-1602`) ; `GrabLastReal` mis à jour seulement avec `bMouse` (`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)** : `RawDelta` lit `Input->GetKeyValue(EKeys::MouseX/MouseY)` (`1593`). Cette valeur est `MassageAxisInput` (`PlayerInput.cpp:2305-2387`) : `NewVal *= AxisProps->Sensitivity` (`2337`), puis FOV (`2352`) et lissage (`2366`, activé : `DefaultInput.ini:78 bEnableMouseSmoothing=True`). Le projet fixe `Sensitivity=0.070000` pour `MouseX` et `MouseY` (`DefaultInput.ini:16-17`, déjà en `8-9`). Un déplacement de 100 px de souris donne donc ≈ 7 « px » dans `GrabCursor` (facteur 14 environ). Conséquences : seuil de glisser `CoupleDragThreshold = 5` (`:136`) franchi après ≈ 71 px de souris ; point visé `TraceScreen(GrabCursor)` 14 fois plus lent que la main ; rotation `CoupleTurnPerPixel = 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 dans `RawValueAccumulator`, copiée en `RawValue` à chaque `EvaluateKeyMapState`, `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é que `TraceCursor` (Visibility, mêmes ignorés, `CursorTraceLength`) avec la position passée (`1399-1411`) ; appelé à la prise avec `GrabMouseStart` (`1522`) et au glisser avec `GrabCursor` (`1612`) : cohérents. **Seuil** : `Distance(GrabMouseStart, GrabCursor) >= 5` (`1610`). **Rotation** : `Turn = (GrabCursor.X - GrabLastMouseX) * 0.3`, `GrabLastMouseX` mis à `float(GrabCursor.X)` (`1680-1681`), initial `MouseX` (`1510`) : continu. **`bMouse &&`** : retiré des deux branches (`1608`, `1678`) ; la sélection exige toujours `bMouse` (`1456-1464`, ligne `curseur sans position` conservée). Aucun `bMouse &&` 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-1675` inchangé hors `GrabPivotAfterCam`), G-e (`TraceDown`, `GrabHeight` : intacts), G-f (`1648-1658` intact), G1 (`1659-1670`), N2 (`LastSurfaceRefused.Reset()` `1669`, conservé), caméra figée (`1695-1700` intact), G3 (`1553-1567` intact, `GrabLeadStart`). PASS-STATIC.
|
|||
|
|
- **J3 formats `%` contre arguments** (relus un à un) : `1282` 2/2 ; `1495-1496` 4 `%` (`%.0f %.0f %s %.0f`) pour `MouseX, MouseY, chaîne, rayon` ; `1540-1541` 4/4 (`%.0f %.0f %d %s`) ; `1549-1550` 3/3 (`%.0f %d %s`) ; `1583-1585` 5/5 (`%+.0f ×3 %+.1f %d`) ; `1616` 2/2 ; `1237` 2/2 ; `1293` 1/1 ; `1353-1356` 7/7 (`%d %d %d %s %s %s %s`). Les `%s` conditionnels de tableaux de longueurs différentes décroissent en `const TCHAR*` (motif déjà présent `1048-1049`, `1237`).
|
|||
|
|
- **Cadences** : `clic hors du couple` 2 s au plus (`SelectMissLogTime`, `1492`) ; `deplace pendant la prise hors CAM` 1 s au plus (`1579`) ; `ne vise aucune surface` une fois par prise (`bGrabAimWarned` remis à faux à la prise `1508`) ; `glisser sans effet` et `rotation sans effet` une fois par prise (au relâché).
|
|||
|
|
- **Témoin « hors CAM » ne compte pas les pas de CAM** : `GrabPivotAfterCam = Pivot` à la prise (`1509`), `= Pivot + Delta` après chaque déplacement du glisser (`1667`, avec le même `Delta` que `SetActorLocation`) ; la rotation tourne autour du pivot (moyenne des positions : conservée, tolérance 1 cm `1576`). Le témoin met à jour `GrabPivotAfterCam` mê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és `PanelClickMaxHold 0.2 s` et `PanelClickMaxMove 5 px` (`:186-187`, `1232`) ; fonction appelée seulement pendant le sexe hors menu (`1112-1128`) ; `bMiddleWasDown` remis à faux hors sexe ou menu (`1076, 1116`). Appui tenu ou glissée : pas de bascule (`MiddleHeld > 0.2` ou `bMiddleMoved`). `RotateCamera` = clic molette, `LeftAlt`, `RightAlt` (`DefaultInput.ini:107-109`) : ouvert aux deux. Ligne `panneau bascule (%s, %.2f s)` 2/2. Note N1.
|
|||
|
|
- **J5 front** : `bSexStateWas` initial faux (`.h:180`) ; au premier passage avec `SexOn` faux : égalité, aucun appel (premier passage correct, pas de fin de scène fantôme) ; avec `SexOn` vrai dès le départ : `BeginSexScene` (`1060-1071`). **`BeginSexScene`** : signature des mappages, remise à zéro de `bMouseFreed`, `MouseFreeCount`, `MouseFreeCooldown`. **`MappingSignature`** (`318-337`) : `GetActionMappings` et `GetAxisMappings`, `FCrc::StrCrc32(*Joined)` (`uint32`) avec `%08X`, bitfields `bShift/bCtrl/bAlt` convertis en `int` ; 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é de `TextBlock_1`** (`SetRenderOpacity(FadedLinesOpacity)` puis `Reset`, D3 de B2p-I traité), `MoveCamera` à faux **si aucun bouton souris n'est tenu**, `SexC3` à faux (**déjà fait hors sexe par `TickCoupleBounds`, `837-839`** : aucun état nouveau), mode d'entrée GameOnly si `bMouseFreed` et vue encore en `CaptureDuringMouseDown` et `!MenuOnScreen(GI)` (`1335-1350`), avec `SetConsumeCaptureMouseDown(MouseCaptureBefore == CapturePermanently)` : mappage exact (3.2). Ligne finale 7/7. Réserves : **D3** et **D4** ; note N2 (`MoveCamera` avec 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` : Grep `ActionPause|"Pause"` sur `LPCameraMode*` = 0 ligne : retiré sans reste (déclaration `201` et argument `1984`).
|
|||
|
|
- **Fins de ligne et includes** : LF, 0 CR ; aucun nouvel `#include` nécessaire (`FInputModeGameAndUI`, `FInputModeGameOnly` par `GameFramework/PlayerController.h:26`, `FCrc`, `FPlatformTime` par `CoreMinimal.h`, `UTextBlock`/`UButton` déjà inclus `7, 12`) ; le diff n'ajoute aucun include. `.h` : 24 lignes, un seul bloc contigu (l. 172-195), tout en `private`, aucun `UPROPERTY` ni `UFUNCTION` (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 : `Now` est déclaré dans deux blocs frères (`1491` dans `if (!bOnCouple)`, `1578` dans `if (Dist…)`), `Aim` dans deux blocs frères (`1521`, `1611`, ancien), aucun nouveau local ne masque `Input`, `World`, `MouseX/Y`, `bMouse` du niveau de la fonction ; (c) noms globaux ou d'espace anonyme de `Source\LifePlay` : Grep sur 21 identifiants en ligne d'indentation 0 ou 1 de tous les `.cpp` et `.h` : **aucun** nom de portée fichier ni d'espace anonyme n'est homonyme. Les `Now` (`LPBonusRewardSubsystem.cpp:811`, `LPDebugSubsystem.cpp:717`, `LPHairstyleSubsystem.cpp:169`, `LPModInfoSubsystem.cpp:215`) sont des locaux de fonction, et `Capture` (`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ù un `double` va vers un `float` (`1404`, `1680-1681`) ; `GrabLastMouseX = MouseX` (float vers float) ; `Nearest` en `double` ; `FVector2D(float, float)` élargit sans perte ; `%.0f` reçoit des `double` ou des `float` promus. 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 ligne `panneau bascule` pour 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`, `HideCursorDuringCapture` resté vrai (5368 puis 5525). Les prises 2 et 3 (5481 à 5527) n'ont rien fait dans cet état, que `.cpp:1265` ignore. `SceneViewport.cpp:756-758, 780-783` : curseur caché et haute précision à l'appui quand ce drapeau est vrai. Proposition : déclencher aussi si `ViewportClient->HideCursorDuringCapture()` (`GameViewportClient.h:831`) est vrai.
|
|||
|
|
- **D3. `EndSexScene` rend GameOnly alors que l'état d'avant la scène est `CaptureDuringMouseDown` / `DoNotLock`.** Dernier changement avant la scène du 12:35:21 : journal 2549-2550 (12:34:54.870) puis `Hide` vrai (3125). `.cpp:1342-1343` impose `CapturePermanently` (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. `HideCursorDuringCapture` reste à faux après la scène.** `.cpp:1277` le 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. `EndSexScene` met `MoveCamera` à faux si aucun bouton souris n'est tenu : un Alt tenu (action `RotateCamera`) à cet instant la remettra à vrai par le PC au besoin ; effet négligeable.
|
|||
|
|
- N3. La ligne `clic hors du couple` s'é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
|
|||
|
|
1. **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`). `RawValue` est copié de l'accumulateur à chaque `EvaluateKeyMapState` (`PlayerInput.cpp:1354-1361`), et `MouseX`/`MouseY` portent `UpdateAxisWithoutSamples` (`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é.**
|
|||
|
|
2. **D2** (hunks 1 et 2) : `bPermanent` (capture permanente) ou `bHiddenOnPress = 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 = true` inconditionnel ; `MouseFreeCount` toujours incrémenté. Pas de boucle : après `FInputModeGameAndUI` avec `SetHideCursorDuringCapture(false)` (`PlayerController.cpp:6411`) et `CaptureDuringMouseDown` (`6412`), `bPermanent` et `bHiddenOnPress` sont faux à l'image suivante ; il ne se redéclenche que lorsque le jeu repose lui-même GameOnly ou `Hide` vrai (journal : à chaque fermeture du panneau, 5530, 5545). Format du journal : `%d` `%d` `%d` pour `Capture`, `bHiddenOnPress ? 1 : 0`, `MouseFreeCount` : 3/3. **D2 levé** (réserve N5).
|
|||
|
|
3. **D3/D4, `BeginSexScene`** (hunk 3) : `const UGameInstance* GI`, `const UGameViewportClient* ViewportClient` ; `GetMouseCaptureMode() const` (`GameViewportClient.h:786`), `GetMouseLockMode() const` (`821`, définition `GameViewportClient.cpp:3495-3498`), `HideCursorDuringCapture() const` : tous appelables sur un pointeur `const`. Stockage en `uint8` (`EMouseCaptureMode : uint8`, `EMouseLockMode : uint8`, `EngineBaseTypes.h:40, 56`) et `bool`. Pas de viewport : `bSavedMouseState = false`, rien n'est rendu. Journal : 4 `%` (`%s %d %d %d`) pour `*MappingsAtSexStart`, 2 `static_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`, `Hide` vrai avant la scène du 12:35:21, 2549-2550 puis 3125).
|
|||
|
|
4. **D3/D4, `EndSexScene`** (hunks 5 et 4) : rendu seulement si `bMouseFreed && bSavedMouseState`, `PC`, hors menu, et **vue encore dans l'état posé par CAM** : `CaptureDuringMouseDown` **et** `DoNotLock` **et** `!HideCursorDuringCapture()` (plus strict qu'avant : un `Hide` vrai remis par le jeu empêche toute écriture). Ordre : `SetInputMode(GameOnly)` d'abord et seulement si la capture sauvée était permanente (`Consume` vrai seulement pour `CapturePermanently`, exact selon `PlayerController.cpp:6450`), puis `SetMouseCaptureMode`, `SetMouseLockMode`, `SetHideCursorDuringCapture` : ces trois méthodes ne font qu'écrire un champ avec journal `LogViewport` (`GameViewportClient.cpp:3458-3511`), sans opération Slate ; elles viennent donc après `ApplyInputMode` et ne sont pas écrasées par lui. `GameOnly` ne touchant pas `Hide` (`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), aucun `SetInputMode` : seulement les trois champs, qui valent déjà `CaptureDuringMouseDown`, `DoNotLock` et le `Hide` d'origine. `static_cast<EMouseCaptureMode>(uint8)` et `static_cast<EMouseLockMode>(uint8)` sont licites (enums de base `uint8`). Journal : `FString::Printf` `%d %d %d` / 3 arguments ; la ligne finale (`7/7`) n'est pas modifiée par le diff, `InputText` reste une `FString` affichée par `*InputText`. `bButtonHeld` compte `LeftAlt` et `RightAlt` (note N2 levée). **D3 et D4 levés.**
|
|||
|
|
5. `MouseCaptureBefore` : retiré du `.h` et 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 : `GI` et `ViewportClient` de `BeginSexScene` sont seuls dans la fonction ; dans `EndSexScene`, `CaptureBefore` n'est déclaré qu'une fois et `ViewportClient` (bloc interne, ancien) n'a pas d'homonyme englobant.
|
|||
|
|
- Globaux et espaces anonymes de `Source\LifePlay` : Grep des sept noms dans tous les `.cpp` et `.h` : seules occurrences dans `LPCameraModeSubsystem.*` (`.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 (`uint8` depuis un enum de base `uint8`, `GetRawKeyValue` en `float`).
|
|||
|
|
|
|||
|
|
### 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 `Hide` est vrai hors bouton tenu : état par défaut du jeu (journal), donc au début de presque toute scène et à chaque retour de `Hide` à vrai. Le relevé `bMenuOnScreen` a jusqu'à 0,1 s de retard : à l'ouverture d'un menu, J1 peut poser une fois `GameAndUI` (sans focus) avant que `bMenuOnScreen` ne passe à vrai. Effet attendu faible ; `EndSexScene` ne rend rien si un menu est ouvert. À regarder à V7 (menu ouvert pendant la scène).
|
|||
|
|
- N6. Rendu en fin de scène : `SetMouseLockMode` et `SetMouseCaptureMode` n'écrivent que le champ du viewport (pas d'opération Slate). Pour un état d'avant-scène non permanent mais verrouillé (`LockAlways`, `LockOnCapture` sans GameOnly), le verrou Slate levé par `ReleaseMouseLock` ne serait pas reposé. Cas absent du journal (état de départ `DoNotLock`) ; à surveiller si le menu principal laisse `LockAlways` (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, `Hide` peut rester à faux (le rendu est alors sauté : `bStillFreed` faux) ; 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` (MD5 `1F10631F…` / `9AEE8D04…`), puis V7 (COMMUN-13) : CAM-91 à CAM-95, CAM-86 à CAM-90 ; lire en plus la ligne `debut de scene … souris capture … verrou … curseur cache` et `fin 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 `Tours` de 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.
|