LifePlay-Revival/Docs/Migration/etat/ST/STE/STE-G3-IMPL.md

164 lines
11 KiB
Markdown
Raw Normal View History

Fiche STE-G3 — Niveau N2 — Modèle prévu (modèle de l'agent lp-impl) | utilisé claude-opus-5-5 — Agent lp-impl — Skills sk-protocol, ue-cpp-build, lp-build, lp-ue-compat (préchargés), sk-change-safety (invoqué)
# STE-G3-IMPL : `NotifyCoupleTeleported()`, reprise de `LastSafe` après une téléportation par CAM (2026-10-14)
**Résultat : réussi (écrit, non compilé).** Fonction publique ajoutée à `ULPShowCoupleSubsystem` : une seule
écriture de `LastSafe` à la place actuelle du meneur, aucun balayage, gardes avant toute écriture. Compilation
confiée au build COMMUN-11 (fiche § 3).
| Mesure | Avant (2026-10-14, entrée de fiche) | Après (2026-10-14) |
|---|---|---|
| MD5 `Source\LifePlay\LPShowCoupleSubsystem.h` | `57dc8cd468d2fb5de231bfbe25346389` | `44c721ee9e82bdfdf7571e493af70e39` |
| MD5 `Source\LifePlay\LPShowCoupleSubsystem.cpp` | `35cf128c8c3e059130e7cf48d9fa0454` | `3cdd572d78b691eef0a3f02b1b37a486` |
| Fins de ligne (`git ls-files --eol`) | `i/crlf w/crlf` (les deux) | `i/crlf w/crlf` (les deux) |
Commande des MD5 : `certutil -hashfile "<fichier>" MD5`. Mesuré, `git -C "D:/Game/LifePlay-master 5.8" diff --stat -- Source/LifePlay/LPShowCoupleSubsystem.h Source/LifePlay/LPShowCoupleSubsystem.cpp` :
```
Source/LifePlay/LPShowCoupleSubsystem.cpp | 19 +++++++++++++++++++
Source/LifePlay/LPShowCoupleSubsystem.h | 4 ++++
2 files changed, 23 insertions(+)
```
## 1. Fichiers modifiés
- `D:\Game\LifePlay-master 5.8\Source\LifePlay\LPShowCoupleSubsystem.h` l. 28-30 (section `public`, après
`Deinitialize`) : commentaire de deux lignes et déclaration `void NotifyCoupleTeleported();`.
- `D:\Game\LifePlay-master 5.8\Source\LifePlay\LPShowCoupleSubsystem.cpp` l. 806-824 (après `KeepTogether`) :
définition.
Diff résumé de la définition :
```cpp
void ULPShowCoupleSubsystem::NotifyCoupleTeleported()
{
ACharacter* Who = Lead.Get();
if (!bEngaged || !Who || !Partner.Get() || !GetWorld())
{
return;
}
const FVector Now = Who->GetActorLocation();
if (!(Now - LastSafe).IsNearlyZero())
{
UE_LOG(LogLifePlay, Warning, TEXT("Show couple : place reprise apres teleportation %s (ecart %.0f)"),
*Now.ToString(), FVector::Dist(LastSafe, Now));
}
LastSafe = Now;
LastBlocker.Reset();
}
```
(plus deux lignes de commentaire en tête du corps, non recopiées.)
### 1.1 Pour CAM : nom, signature, en-tête, appel
- **Nom** : `ULPShowCoupleSubsystem::NotifyCoupleTeleported`.
- **Signature** : `void NotifyCoupleTeleported();` (publique, non `const`, sans paramètre, sans retour).
- **En-tête** : `#include "LPShowCoupleSubsystem.h"` (même module `LifePlay`, classe `LIFEPLAY_API`,
`LPShowCoupleSubsystem.h:20`).
- **Appel depuis le C++, pas depuis un Blueprint** : B2p-F est « C++ `LPCameraModeSubsystem`, aucun asset »
(`CAM-COMMUN9-DIAG.md` l. 129 et l. 215) ; G3 est « appelée par B2p-D après une pose libre validée par G1 »
(l. 191-193) ; le glisser B2p-D est du C++ (`LPCameraModeSubsystem.cpp:1064-1068`). Donc **pas de `UFUNCTION`**
(fiche § 3 : seulement si un Blueprint l'appelle).
- Forme d'appel conseillée (même accès que `LPCameraModeSubsystem.cpp:287`, `UGameInstance::GetSubsystem`
`GameInstance.h:440`), **après** la boucle qui déplace le couple (`LPCameraModeSubsystem.cpp:1065-1068`) et
seulement si G1 a validé la place :
```cpp
if (ULPShowCoupleSubsystem* Show = GI->GetSubsystem<ULPShowCoupleSubsystem>())
{
Show->NotifyCoupleTeleported();
}
```
### 1.2 Grandeur reprise (point amont de la fiche § 3)
- `KeepTogether` écrit `LastSafe = Who->GetActorLocation();` avec `Who = Lead.Get()` (`.cpp:752`, `.cpp:804`) ;
`Engage` écrit la même grandeur (`LastSafe = InLead->GetActorLocation();`, `.cpp:400`). La fonction reprend
exactement celle-là : la place de l'acteur meneur (`Lead`), pas la boîte ni le partenaire. Établi.
- Effet sur l'image suivante : `KeepTogether` calcule `Delta = Now - LastSafe` (`.cpp:760-761`) ; si CAM n'a plus rien
bougé, `Delta` est nul et `KeepTogether` sort sans balayer (`.cpp:762-765`) ; sinon il balaie depuis la place libre
posée par CAM (`ResolveCoupleMove(…, LastSafe, Delta, …)`, `.cpp:792-793`). Établi par lecture.
### 1.3 États remis à zéro
- `LastBlocker` (« dernier bloquant ») : vidé. Il n'est lu que pour dédoublonner le journal (`.cpp:781` coque,
`.cpp:794` « bloque par ») ; aucun effet sur le mouvement. Conséquence : le prochain blocage (ou la coque) est
réécrit une fois au journal, utile pour l'essai CAM-74. Établi (toutes les occurrences lues : `.h:53`,
`.cpp:781, 790, 794, 798, 823`).
- Aucun autre état de balayage dans le sous-système : profondeur, normale et bloquant sont des variables locales du
résultat `Move` (`.cpp:792-799`). `Box`, `FittedPair`, `RejectedPair`, `LoggedExtent` (mesure de la boîte),
`bPawnLogged`, `SavedFurniture`, `SavedSeats`, `SavedPartnerMove` (collisions, mouvement gelé) ne sont pas des
états de balayage : non touchés. Établi par lecture de l'en-tête (`.h:45-75`).
- Résolveur partagé : `Grep "static "` sur `Plugins\LPAnimCore\Source\LPAnimCore\LPCoupleSimCore.cpp` → 1 résultat,
`static const TCHAR* Excluded[]` (l. 46), table constante : pas d'état gardé entre deux appels. `LPCoupleSim.h`
cherché seulement avec le motif `static … =` (0 résultat) : absence d'autre état statique **estimée**.
### 1.4 Gardes, appel répété, appel hors scène
- Gardes avant toute lecture ou écriture : `bEngaged` faux (hors scène, ou `Release` passé : `.cpp:668-674`), meneur
absent ou détruit (`Lead.Get()` nul), partenaire absent, monde absent (`GetWorld()` nul) → retour sans rien
changer, sans plantage (aucun déréférencement avant les gardes).
- Pas de garde sur la boîte (`Box`) : non nécessaire pour reprendre `LastSafe`.
- **Appel répété** : sans danger. `LastSafe` reçoit la même valeur (idempotent) ; `LastBlocker` est revidé ; la
ligne de journal n'est écrite que si la place a bougé de plus de `UE_KINDA_SMALL_NUMBER` (`Vector.h:600`).
- **Appel hors scène** : sans danger, la garde `bEngaged` sort avant toute écriture. Au premier tour d'une scène,
`Engage` repose de toute façon `LastSafe` sur le meneur (`.cpp:400`).
- Contrat pour CAM : n'appeler qu'après une pose **validée par G1**. Si la place posée recouvrait un meuble, la
fonction en ferait la nouvelle place sûre et `KeepTogether` ne dépénètrerait pas tant que le meneur ne bouge pas
(`Delta` nul, `.cpp:762-765`). Estimé par lecture.
### 1.5 API moteur relues (UE 5.8, `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\`)
- `TWeakObjectPtr::Get()` : `Runtime\Core\Public\UObject\WeakObjectPtrTemplates.h:141` (`[[nodiscard]]`, valeur utilisée).
- `UObject::GetWorld() const` : `Runtime\CoreUObject\Public\UObject\Object.h:711` (déjà appelé par le fichier,
`.cpp:289`, `.cpp:755` ; `UGameInstanceSubsystem` ne le redéfinit pas : `GameInstanceSubsystem.h` et
`Subsystem.h` sans `GetWorld`).
- `AActor::GetActorLocation() const` : `Runtime\Engine\Classes\GameFramework\Actor.h:2502`.
- `TVector::IsNearlyZero(T Tolerance = UE_KINDA_SMALL_NUMBER) const` : `Runtime\Core\Public\Math\Vector.h:600`.
- `TVector::ToString() const` : `Vector.h:861` ; `TVector::Dist(const TVector&, const TVector&)` statique, rend
`T` = `double` pour `FVector` : `Vector.h:1015` (format `%.0f`, comme `.cpp:796`).
- `FString::Reset(int32 NewReservedSize = 0)` : `Runtime\Core\Public\Containers\UnrealString.h.inl:332`.
- `UGameInstance::GetSubsystem<T>() const` (pour CAM) : `Runtime\Engine\Classes\Engine\GameInstance.h:440`.
- `LogLifePlay` : `Source\LifePlay\LifePlay.h:9`, inclus par `.cpp:24`.
## 2. Écarts à la SPEC
- E1 : `sk-change-safety` invoqué **après** les deux Edit et non avant. Instantané pris par l'orchestrateur et vérifié
ensuite : `D:\Game\LifePlay_Backup_5.5\STE-G3\Source\LifePlay\LPShowCoupleSubsystem.h` MD5
`57dc8cd468d2fb5de231bfbe25346389`, `.cpp` MD5 `35cf128c8c3e059130e7cf48d9fa0454` (identiques à l'entrée de
fiche), `manifest.csv` présent. Sans effet sur le résultat.
- E2 : la ligne `UE_LOG` est conditionnelle (écrite seulement si la place a changé), pour ne pas écrire une ligne par
appel sans déplacement. Elle reste une seule ligne, catégorie `LogLifePlay`, niveau `Warning` comme le reste du
fichier.
- E3 : pas de `UFUNCTION` : l'appelant est du C++ (§ 1.1), conforme à la fiche § 3.
- E4 : la fiche ne dit pas où placer la fonction dans le `.cpp` ; placée après `KeepTogether`, à la fin du fichier.
- Budget suivi : rubrique 9 de la fiche (20 tours), et non le budget N3 du message de lancement.
## 3. Instantané
Pris par l'orchestrateur (fiche § 2) : `D:\Game\LifePlay_Backup_5.5\STE-G3\` (2 fichiers + `manifest.csv`), relu par
MD5 le 2026-10-14 (§ 2 E1). Retour arrière (proposé, non lancé) : recopier les deux fichiers de l'instantané sur
`Source\LifePlay\` (`Tools\Restore.ps1 -Lot STE-G3`, à décider par l'orchestrateur).
## 4. Ce qui n'a pas été fait
- Aucune compilation (build COMMUN-11, `lp-builder`), aucun éditeur, MCP, commandlet ni jeu (fiche § 6).
- L'appel côté CAM (B2p-F) n'est pas écrit : fichier CAM, hors périmètre.
- Ligne STE-G3 du registre `STE-TACHES.md`, entrée CHG, commit : orchestrateur et gardien.
- Le mode « tourner » de la prise (`CoupleGrabMode == 2`, `LPCameraModeSubsystem.cpp:1071-1085`) déplace aussi le
meneur autour du pivot ; le DIAG ne prévoit l'appel qu'après le glisser. Question pour CAM, non traitée.
## 5. Points à confirmer en VAL
- Diff limité aux deux fichiers : `git diff --stat` = 2 fichiers, 23 insertions, 0 suppression.
- `LastSafe` écrit une seule fois, à `Lead.Get()->GetActorLocation()`, même grandeur que `.cpp:804`.
- Aucun appel à `ResolveCoupleMove` ni à un balayage ou recouvrement dans `NotifyCoupleTeleported`.
- Gardes `bEngaged`, meneur, partenaire, monde placées avant toute lecture ou écriture.
- `LastBlocker` seul état remis à zéro, lu seulement pour le journal (`.cpp:781`, `.cpp:794`).
- Déclaration en section `public` (`.h:30`), sans `UFUNCTION`.
- Fins de ligne CRLF conservées (`git ls-files --eol` : `w/crlf` pour les deux fichiers).
- Aucun nom local qui masque un membre (`Who`, `Now` : pas de membre de ce nom, `.h:45-75`).
- Build COMMUN-11 : `LPShowCoupleSubsystem.cpp` compilé, 0 erreur, 0 avertissement nouveau (C4458, C4456 compris).
- En jeu, CAM-74 : couple coincé, glisser vers le milieu de la pièce → ligne `Show couple : place reprise apres teleportation …` puis plus de `bloque par … profondeur 3` à chaque image.
- En jeu : volume de la ligne « place reprise » pendant un glisser continu (une ligne par image déplacée si CAM appelle à chaque image).
## 6. Fichiers à commiter
Dépôt jeu `D:\Game\LifePlay-master 5.8`, branche `ue5.8` :
- M Source/LifePlay/LPShowCoupleSubsystem.h
- M Source/LifePlay/LPShowCoupleSubsystem.cpp
- A Docs/Migration/etat/ST/STE/STE-G3-IMPL.md
Tours : 15 / 20